superintervals 0.3.2__tar.gz → 0.3.5__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.
- {superintervals-0.3.2/src/superintervals.egg-info → superintervals-0.3.5}/PKG-INFO +1 -1
- {superintervals-0.3.2 → superintervals-0.3.5}/pyproject.toml +1 -1
- {superintervals-0.3.2 → superintervals-0.3.5}/setup.py +0 -1
- {superintervals-0.3.2 → superintervals-0.3.5/src/superintervals.egg-info}/PKG-INFO +1 -1
- {superintervals-0.3.2 → superintervals-0.3.5}/src/superintervals.hpp +159 -59
- {superintervals-0.3.2 → superintervals-0.3.5}/LICENSE +0 -0
- {superintervals-0.3.2 → superintervals-0.3.5}/README.md +0 -0
- {superintervals-0.3.2 → superintervals-0.3.5}/setup.cfg +0 -0
- {superintervals-0.3.2 → superintervals-0.3.5}/src/superintervals/__init__.py +0 -0
- {superintervals-0.3.2 → superintervals-0.3.5}/src/superintervals/intervalmap.cpp +0 -0
- {superintervals-0.3.2 → superintervals-0.3.5}/src/superintervals/intervalmap.pxd +0 -0
- {superintervals-0.3.2 → superintervals-0.3.5}/src/superintervals/intervalmap.pyx +0 -0
- {superintervals-0.3.2 → superintervals-0.3.5}/src/superintervals.egg-info/SOURCES.txt +0 -0
- {superintervals-0.3.2 → superintervals-0.3.5}/src/superintervals.egg-info/dependency_links.txt +0 -0
- {superintervals-0.3.2 → superintervals-0.3.5}/src/superintervals.egg-info/requires.txt +0 -0
- {superintervals-0.3.2 → superintervals-0.3.5}/src/superintervals.egg-info/top_level.txt +0 -0
|
@@ -8,7 +8,7 @@ build-backend = "setuptools.build_meta"
|
|
|
8
8
|
|
|
9
9
|
[project]
|
|
10
10
|
name = "superintervals"
|
|
11
|
-
version = "0.3.
|
|
11
|
+
version = "0.3.5"
|
|
12
12
|
description = "Rapid interval intersections"
|
|
13
13
|
dependencies = ['Cython']
|
|
14
14
|
authors = [{name = "Kez Cleal", email = "clealk@cardiff.ac.uk"}]
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// Version 0.3.
|
|
1
|
+
// Version 0.3.5
|
|
2
2
|
#pragma once
|
|
3
3
|
|
|
4
4
|
#include <algorithm>
|
|
@@ -43,10 +43,19 @@ struct Interval {
|
|
|
43
43
|
* @tparam T The data type associated with each interval
|
|
44
44
|
*/
|
|
45
45
|
template<typename S, typename T>
|
|
46
|
+
|
|
46
47
|
class IntervalMap {
|
|
47
48
|
public:
|
|
48
49
|
std::vector<S> starts;
|
|
49
|
-
std::vector<S> ends;
|
|
50
|
+
// std::vector<S> ends;
|
|
51
|
+
|
|
52
|
+
#ifdef __AVX2__
|
|
53
|
+
alignas(32) std::vector<S> ends;
|
|
54
|
+
#elif defined(__ARM_NEON)
|
|
55
|
+
alignas(16) std::vector<S> ends;
|
|
56
|
+
#else
|
|
57
|
+
std::vector<S> ends;
|
|
58
|
+
#endif
|
|
50
59
|
std::vector<size_t> branch;
|
|
51
60
|
std::vector<T> data;
|
|
52
61
|
bool start_sorted, end_sorted;
|
|
@@ -259,7 +268,7 @@ class IntervalMap {
|
|
|
259
268
|
size_t length = starts.size();
|
|
260
269
|
size_t idx = 0;
|
|
261
270
|
while (length > 1) {
|
|
262
|
-
size_t half = length / 2;
|
|
271
|
+
const size_t half = length / 2;
|
|
263
272
|
idx += (starts[idx + half] <= value) * (length - half);
|
|
264
273
|
length = half;
|
|
265
274
|
}
|
|
@@ -282,7 +291,6 @@ class IntervalMap {
|
|
|
282
291
|
// First do exponential search if we have room
|
|
283
292
|
size_t search_right = right;
|
|
284
293
|
size_t bound = 1;
|
|
285
|
-
// Exponential search to find a smaller range
|
|
286
294
|
while (left > 0 && value < starts[left]) {
|
|
287
295
|
search_right = left;
|
|
288
296
|
left = (bound <= left) ? left - bound : 0;
|
|
@@ -291,7 +299,7 @@ class IntervalMap {
|
|
|
291
299
|
// Now do binary search in the range
|
|
292
300
|
size_t length = search_right - left;
|
|
293
301
|
while (length > 1) {
|
|
294
|
-
size_t half = length / 2;
|
|
302
|
+
const size_t half = length / 2;
|
|
295
303
|
left += (starts[left + half] < value) * (length - half);
|
|
296
304
|
length = half;
|
|
297
305
|
}
|
|
@@ -310,7 +318,7 @@ class IntervalMap {
|
|
|
310
318
|
if (starts.empty()) {
|
|
311
319
|
return;
|
|
312
320
|
}
|
|
313
|
-
size_t idx = upper_bound(end);
|
|
321
|
+
const size_t idx = upper_bound(end);
|
|
314
322
|
if (idx == SIZE_MAX) {
|
|
315
323
|
return;
|
|
316
324
|
}
|
|
@@ -345,7 +353,7 @@ class IntervalMap {
|
|
|
345
353
|
if (starts.empty()) {
|
|
346
354
|
return;
|
|
347
355
|
}
|
|
348
|
-
size_t idx = upper_bound(end);
|
|
356
|
+
const size_t idx = upper_bound(end);
|
|
349
357
|
if (idx == SIZE_MAX) {
|
|
350
358
|
return;
|
|
351
359
|
}
|
|
@@ -414,69 +422,159 @@ class IntervalMap {
|
|
|
414
422
|
}
|
|
415
423
|
size_t found = 0;
|
|
416
424
|
|
|
417
|
-
#
|
|
425
|
+
#if defined(SI_NOSIMD)
|
|
426
|
+
|
|
418
427
|
constexpr size_t block = 16;
|
|
419
|
-
|
|
428
|
+
constexpr simd_kind active_simd = simd_kind::none;
|
|
429
|
+
|
|
430
|
+
#elif defined(__AVX2__)
|
|
431
|
+
|
|
420
432
|
__m256i start_vec = _mm256_set1_epi32(start);
|
|
421
433
|
constexpr size_t simd_width = 256 / (sizeof(S) * 8);
|
|
422
|
-
constexpr size_t block = simd_width * 4;
|
|
423
|
-
|
|
434
|
+
constexpr size_t block = simd_width * 4; // 2 cache lines
|
|
435
|
+
constexpr simd_kind active_simd = simd_kind::avx2;
|
|
436
|
+
|
|
437
|
+
#elif defined(__ARM_NEON__) || defined(__aarch64__)
|
|
438
|
+
|
|
424
439
|
int32x4_t start_vec = vdupq_n_s32(start);
|
|
425
440
|
constexpr size_t simd_width = 128 / (sizeof(S) * 8);
|
|
426
441
|
uint32x4_t ones = vdupq_n_u32(1);
|
|
427
|
-
constexpr size_t block = simd_width *
|
|
428
|
-
|
|
442
|
+
constexpr size_t block = simd_width * 8; // 2 cache lines
|
|
443
|
+
constexpr simd_kind active_simd = simd_kind::neon;
|
|
444
|
+
|
|
445
|
+
#endif
|
|
429
446
|
|
|
430
447
|
while (i > 0) {
|
|
431
448
|
if (start <= ends[i]) {
|
|
432
449
|
++found;
|
|
433
450
|
--i;
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
451
|
+
// Types with width !=4 will use the no-simd path here
|
|
452
|
+
if constexpr (active_simd == simd_kind::none || sizeof(S) != 4) {
|
|
453
|
+
while (i > block) {
|
|
454
|
+
size_t count = 0;
|
|
455
|
+
for (size_t j = i; j > i - block; --j) {
|
|
456
|
+
count += (start <= ends[j]) ? 1 : 0;
|
|
457
|
+
}
|
|
458
|
+
found += count;
|
|
459
|
+
i -= block;
|
|
460
|
+
if (count < block && start > ends[i + 1]) { // check for a branch
|
|
461
|
+
break;
|
|
462
|
+
}
|
|
444
463
|
}
|
|
445
464
|
}
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
465
|
+
#if defined(__AVX2__)
|
|
466
|
+
else if constexpr (active_simd == simd_kind::avx2) {
|
|
467
|
+
// while (i > block) {
|
|
468
|
+
// size_t count = 0;
|
|
469
|
+
// for (size_t j = i - block + 1; j < i; j += simd_width) {
|
|
470
|
+
// __m256i ends_vec = _mm256_loadu_si256((__m256i*)(&ends[j - simd_width + 1]));
|
|
471
|
+
// __m256i cmp_mask = _mm256_cmpgt_epi32(start_vec, ends_vec);
|
|
472
|
+
// int mask = _mm256_movemask_ps(_mm256_castsi256_ps(cmp_mask));
|
|
473
|
+
// count += 8 - _mm_popcnt_u32(mask);
|
|
474
|
+
// }
|
|
475
|
+
// found += count;
|
|
476
|
+
// i -= block;
|
|
477
|
+
// if (count < block) {
|
|
478
|
+
// break;
|
|
479
|
+
// }
|
|
480
|
+
// }
|
|
481
|
+
|
|
482
|
+
while (i > block) {
|
|
483
|
+
size_t j = i - block + 1;
|
|
484
|
+
|
|
485
|
+
// Load all 4 vectors
|
|
486
|
+
__m256i ends_vec0 = _mm256_load_si256((__m256i*)(&ends[j]));
|
|
487
|
+
__m256i ends_vec1 = _mm256_load_si256((__m256i*)(&ends[j + simd_width]));
|
|
488
|
+
__m256i ends_vec2 = _mm256_load_si256((__m256i*)(&ends[j + 2 * simd_width]));
|
|
489
|
+
__m256i ends_vec3 = _mm256_load_si256((__m256i*)(&ends[j + 3 * simd_width]));
|
|
490
|
+
|
|
491
|
+
// Compare all vectors
|
|
492
|
+
__m256i cmp_mask0 = _mm256_cmpgt_epi32(start_vec, ends_vec0);
|
|
493
|
+
__m256i cmp_mask1 = _mm256_cmpgt_epi32(start_vec, ends_vec1);
|
|
494
|
+
__m256i cmp_mask2 = _mm256_cmpgt_epi32(start_vec, ends_vec2);
|
|
495
|
+
__m256i cmp_mask3 = _mm256_cmpgt_epi32(start_vec, ends_vec3);
|
|
496
|
+
|
|
497
|
+
// Extract masks
|
|
498
|
+
int mask0 = _mm256_movemask_ps(_mm256_castsi256_ps(cmp_mask0));
|
|
499
|
+
int mask1 = _mm256_movemask_ps(_mm256_castsi256_ps(cmp_mask1));
|
|
500
|
+
int mask2 = _mm256_movemask_ps(_mm256_castsi256_ps(cmp_mask2));
|
|
501
|
+
int mask3 = _mm256_movemask_ps(_mm256_castsi256_ps(cmp_mask3));
|
|
502
|
+
|
|
503
|
+
// Count and accumulate
|
|
504
|
+
size_t count = (8 - _mm_popcnt_u32(mask0)) + (8 - _mm_popcnt_u32(mask1)) +
|
|
505
|
+
(8 - _mm_popcnt_u32(mask2)) + (8 - _mm_popcnt_u32(mask3));
|
|
506
|
+
|
|
507
|
+
found += count;
|
|
508
|
+
i -= block;
|
|
509
|
+
if (count < block) {
|
|
510
|
+
break;
|
|
511
|
+
}
|
|
460
512
|
}
|
|
461
513
|
}
|
|
462
|
-
#elif defined(__ARM_NEON__) || defined(__aarch64__)
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
//
|
|
475
|
-
|
|
476
|
-
|
|
514
|
+
#elif defined(__ARM_NEON__) || defined(__aarch64__)
|
|
515
|
+
else { // NEON
|
|
516
|
+
// while (i > block) {
|
|
517
|
+
// size_t count = 0;
|
|
518
|
+
// uint32x4_t mask, bool_mask;
|
|
519
|
+
// for (size_t j = i - block + 1; j < i; j += simd_width) { // Neon 4 int32 at a time
|
|
520
|
+
// int32x4_t ends_vec = vld1q_s32(&ends[j]);
|
|
521
|
+
// mask = vcgtq_s32(start_vec, ends_vec); // start > ends[j]
|
|
522
|
+
// bool_mask = vaddq_u32(mask, ones);
|
|
523
|
+
// count += vaddvq_u32(bool_mask); // Sum all lanes
|
|
524
|
+
// }
|
|
525
|
+
// found += count;
|
|
526
|
+
// i -= block;
|
|
527
|
+
// if (count < block) { // check for overlap again, before checking for branch?
|
|
528
|
+
// break;
|
|
529
|
+
// }
|
|
530
|
+
// }
|
|
531
|
+
while (i > block) {
|
|
532
|
+
size_t j = i - block + 1;
|
|
533
|
+
|
|
534
|
+
// Load all 8 vectors
|
|
535
|
+
int32x4_t ends_vec0 = vld1q_s32(&ends[j]);
|
|
536
|
+
int32x4_t ends_vec1 = vld1q_s32(&ends[j + simd_width]);
|
|
537
|
+
int32x4_t ends_vec2 = vld1q_s32(&ends[j + 2 * simd_width]);
|
|
538
|
+
int32x4_t ends_vec3 = vld1q_s32(&ends[j + 3 * simd_width]);
|
|
539
|
+
int32x4_t ends_vec4 = vld1q_s32(&ends[j + 4 * simd_width]);
|
|
540
|
+
int32x4_t ends_vec5 = vld1q_s32(&ends[j + 5 * simd_width]);
|
|
541
|
+
int32x4_t ends_vec6 = vld1q_s32(&ends[j + 6 * simd_width]);
|
|
542
|
+
int32x4_t ends_vec7 = vld1q_s32(&ends[j + 7 * simd_width]);
|
|
543
|
+
|
|
544
|
+
// Compare all vectors
|
|
545
|
+
uint32x4_t mask0 = vcgtq_s32(start_vec, ends_vec0);
|
|
546
|
+
uint32x4_t mask1 = vcgtq_s32(start_vec, ends_vec1);
|
|
547
|
+
uint32x4_t mask2 = vcgtq_s32(start_vec, ends_vec2);
|
|
548
|
+
uint32x4_t mask3 = vcgtq_s32(start_vec, ends_vec3);
|
|
549
|
+
uint32x4_t mask4 = vcgtq_s32(start_vec, ends_vec4);
|
|
550
|
+
uint32x4_t mask5 = vcgtq_s32(start_vec, ends_vec5);
|
|
551
|
+
uint32x4_t mask6 = vcgtq_s32(start_vec, ends_vec6);
|
|
552
|
+
uint32x4_t mask7 = vcgtq_s32(start_vec, ends_vec7);
|
|
553
|
+
|
|
554
|
+
// Convert to boolean masks
|
|
555
|
+
uint32x4_t bool_mask0 = vaddq_u32(mask0, ones);
|
|
556
|
+
uint32x4_t bool_mask1 = vaddq_u32(mask1, ones);
|
|
557
|
+
uint32x4_t bool_mask2 = vaddq_u32(mask2, ones);
|
|
558
|
+
uint32x4_t bool_mask3 = vaddq_u32(mask3, ones);
|
|
559
|
+
uint32x4_t bool_mask4 = vaddq_u32(mask4, ones);
|
|
560
|
+
uint32x4_t bool_mask5 = vaddq_u32(mask5, ones);
|
|
561
|
+
uint32x4_t bool_mask6 = vaddq_u32(mask6, ones);
|
|
562
|
+
uint32x4_t bool_mask7 = vaddq_u32(mask7, ones);
|
|
563
|
+
|
|
564
|
+
// Sum all lanes and accumulate
|
|
565
|
+
size_t count = vaddvq_u32(bool_mask0) + vaddvq_u32(bool_mask1) +
|
|
566
|
+
vaddvq_u32(bool_mask2) + vaddvq_u32(bool_mask3) +
|
|
567
|
+
vaddvq_u32(bool_mask4) + vaddvq_u32(bool_mask5) +
|
|
568
|
+
vaddvq_u32(bool_mask6) + vaddvq_u32(bool_mask7);
|
|
569
|
+
|
|
570
|
+
found += count;
|
|
571
|
+
i -= block;
|
|
572
|
+
if (count < block) {
|
|
573
|
+
break;
|
|
574
|
+
}
|
|
477
575
|
}
|
|
478
576
|
}
|
|
479
|
-
#endif
|
|
577
|
+
#endif
|
|
480
578
|
} else {
|
|
481
579
|
if (branch[i] == SIZE_MAX) {
|
|
482
580
|
return found;
|
|
@@ -501,7 +599,7 @@ class IntervalMap {
|
|
|
501
599
|
if (starts.empty()) {
|
|
502
600
|
return 0;
|
|
503
601
|
}
|
|
504
|
-
size_t idx = upper_bound(end);
|
|
602
|
+
const size_t idx = upper_bound(end);
|
|
505
603
|
if (idx == SIZE_MAX) {
|
|
506
604
|
return 0;
|
|
507
605
|
}
|
|
@@ -532,7 +630,7 @@ class IntervalMap {
|
|
|
532
630
|
if (starts.empty()) {
|
|
533
631
|
return false;
|
|
534
632
|
}
|
|
535
|
-
size_t idx = upper_bound(end);
|
|
633
|
+
const size_t idx = upper_bound(end);
|
|
536
634
|
return idx != SIZE_MAX && start <= ends[idx];
|
|
537
635
|
}
|
|
538
636
|
|
|
@@ -546,7 +644,7 @@ class IntervalMap {
|
|
|
546
644
|
if (starts.empty()) {
|
|
547
645
|
return;
|
|
548
646
|
}
|
|
549
|
-
size_t idx = upper_bound(end);
|
|
647
|
+
const size_t idx = upper_bound(end);
|
|
550
648
|
if (idx == SIZE_MAX) {
|
|
551
649
|
return;
|
|
552
650
|
}
|
|
@@ -580,7 +678,7 @@ class IntervalMap {
|
|
|
580
678
|
if (starts.empty()) {
|
|
581
679
|
return;
|
|
582
680
|
}
|
|
583
|
-
size_t idx = upper_bound(end);
|
|
681
|
+
const size_t idx = upper_bound(end);
|
|
584
682
|
if (idx == SIZE_MAX) {
|
|
585
683
|
return;
|
|
586
684
|
}
|
|
@@ -613,7 +711,7 @@ class IntervalMap {
|
|
|
613
711
|
if (starts.empty()) {
|
|
614
712
|
return;
|
|
615
713
|
}
|
|
616
|
-
size_t idx = upper_bound(end);
|
|
714
|
+
const size_t idx = upper_bound(end);
|
|
617
715
|
if (idx == SIZE_MAX) {
|
|
618
716
|
return;
|
|
619
717
|
}
|
|
@@ -699,6 +797,8 @@ class IntervalMap {
|
|
|
699
797
|
|
|
700
798
|
protected:
|
|
701
799
|
|
|
800
|
+
enum class simd_kind { none, avx2, neon };
|
|
801
|
+
|
|
702
802
|
std::vector<Interval<S, T>> tmp;
|
|
703
803
|
|
|
704
804
|
template<typename CompareFunc>
|
|
@@ -842,4 +942,4 @@ private:
|
|
|
842
942
|
}
|
|
843
943
|
};
|
|
844
944
|
|
|
845
|
-
} // si
|
|
945
|
+
} // si
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{superintervals-0.3.2 → superintervals-0.3.5}/src/superintervals.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|