arraykit 0.6.1__tar.gz → 0.6.3__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.
- {arraykit-0.6.1/arraykit.egg-info → arraykit-0.6.3}/PKG-INFO +1 -1
- {arraykit-0.6.1 → arraykit-0.6.3}/README.rst +14 -0
- {arraykit-0.6.1 → arraykit-0.6.3/arraykit.egg-info}/PKG-INFO +1 -1
- {arraykit-0.6.1 → arraykit-0.6.3}/setup.py +1 -1
- {arraykit-0.6.1 → arraykit-0.6.3}/src/_arraykit.c +278 -297
- {arraykit-0.6.1 → arraykit-0.6.3}/test/test_nonzero_1d.py +16 -1
- {arraykit-0.6.1 → arraykit-0.6.3}/test/test_tri_map.py +15 -1
- {arraykit-0.6.1 → arraykit-0.6.3}/LICENSE.txt +0 -0
- {arraykit-0.6.1 → arraykit-0.6.3}/MANIFEST.in +0 -0
- {arraykit-0.6.1 → arraykit-0.6.3}/arraykit.egg-info/SOURCES.txt +0 -0
- {arraykit-0.6.1 → arraykit-0.6.3}/arraykit.egg-info/dependency_links.txt +0 -0
- {arraykit-0.6.1 → arraykit-0.6.3}/arraykit.egg-info/requires.txt +0 -0
- {arraykit-0.6.1 → arraykit-0.6.3}/arraykit.egg-info/top_level.txt +0 -0
- {arraykit-0.6.1 → arraykit-0.6.3}/setup.cfg +0 -0
- {arraykit-0.6.1 → arraykit-0.6.3}/src/__init__.py +0 -0
- {arraykit-0.6.1 → arraykit-0.6.3}/src/__init__.pyi +0 -0
- {arraykit-0.6.1 → arraykit-0.6.3}/src/py.typed +0 -0
- {arraykit-0.6.1 → arraykit-0.6.3}/test/test_array_go.py +0 -0
- {arraykit-0.6.1 → arraykit-0.6.3}/test/test_block_index.py +0 -0
- {arraykit-0.6.1 → arraykit-0.6.3}/test/test_delimited_to_arrays.py +0 -0
- {arraykit-0.6.1 → arraykit-0.6.3}/test/test_delimited_to_arrays_integration.py +0 -0
- {arraykit-0.6.1 → arraykit-0.6.3}/test/test_delimited_to_arrays_property.py +0 -0
- {arraykit-0.6.1 → arraykit-0.6.3}/test/test_nonzero_1d_property.py +0 -0
- {arraykit-0.6.1 → arraykit-0.6.3}/test/test_pyi.py +0 -0
- {arraykit-0.6.1 → arraykit-0.6.3}/test/test_split_after_count.py +0 -0
- {arraykit-0.6.1 → arraykit-0.6.3}/test/test_type_discovery.py +0 -0
- {arraykit-0.6.1 → arraykit-0.6.3}/test/test_util.py +0 -0
|
@@ -37,6 +37,20 @@ ArrayKit requires the following:
|
|
|
37
37
|
What is New in ArrayKit
|
|
38
38
|
-------------------------
|
|
39
39
|
|
|
40
|
+
0.6.3
|
|
41
|
+
............
|
|
42
|
+
|
|
43
|
+
Optimized memory allocation strategy for ``nonzero_1d()``.
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
0.6.2
|
|
47
|
+
............
|
|
48
|
+
|
|
49
|
+
Extended ``nonzero_1d()`` to support non-contiguous arrays.
|
|
50
|
+
|
|
51
|
+
Optimizations to ``TriMap`` when mapping to object and flexible dtypes.
|
|
52
|
+
|
|
53
|
+
|
|
40
54
|
0.6.1
|
|
41
55
|
............
|
|
42
56
|
|
|
@@ -5,7 +5,7 @@ from setuptools import Extension # type: ignore
|
|
|
5
5
|
from setuptools import setup
|
|
6
6
|
from pathlib import Path
|
|
7
7
|
|
|
8
|
-
AK_VERSION = '0.6.
|
|
8
|
+
AK_VERSION = '0.6.3'
|
|
9
9
|
|
|
10
10
|
def get_long_description() -> str:
|
|
11
11
|
return '''The ArrayKit library provides utilities for creating and transforming NumPy arrays, implementing performance-critical StaticFrame operations as Python C extensions.
|
|
@@ -836,9 +836,9 @@ AK_TP_ResolveLineResetField(AK_TypeParser* tp,
|
|
|
836
836
|
static char* TRUE_LOWER = "true";
|
|
837
837
|
static char* TRUE_UPPER = "TRUE";
|
|
838
838
|
|
|
839
|
-
#define
|
|
840
|
-
#define
|
|
841
|
-
#define
|
|
839
|
+
#define AK_ERROR_NO_DIGITS 1
|
|
840
|
+
#define AK_ERROR_OVERFLOW 2
|
|
841
|
+
#define AK_ERROR_INVALID_CHARS 3
|
|
842
842
|
|
|
843
843
|
// Convert a Py_UCS4 array to a signed integer. Extended from pandas/_libs/src/parser/tokenizer.c. Sets `error` to values greater than 0 on error; never sets error on success.
|
|
844
844
|
static inline npy_int64
|
|
@@ -866,7 +866,7 @@ AK_UCS4_to_int64(Py_UCS4 *p_item, Py_UCS4 *end, int *error, char tsep)
|
|
|
866
866
|
|
|
867
867
|
// Check that there is a first digit.
|
|
868
868
|
if (!AK_is_digit(*p)) {
|
|
869
|
-
*error =
|
|
869
|
+
*error = AK_ERROR_NO_DIGITS;
|
|
870
870
|
return 0;
|
|
871
871
|
}
|
|
872
872
|
if (isneg) {
|
|
@@ -891,7 +891,7 @@ AK_UCS4_to_int64(Py_UCS4 *p_item, Py_UCS4 *end, int *error, char tsep)
|
|
|
891
891
|
if (p >= end) return number;
|
|
892
892
|
d = *p;
|
|
893
893
|
} else {
|
|
894
|
-
*error =
|
|
894
|
+
*error = AK_ERROR_OVERFLOW;
|
|
895
895
|
return 0;
|
|
896
896
|
}
|
|
897
897
|
}
|
|
@@ -904,7 +904,7 @@ AK_UCS4_to_int64(Py_UCS4 *p_item, Py_UCS4 *end, int *error, char tsep)
|
|
|
904
904
|
if (p >= end) return number;
|
|
905
905
|
d = *p;
|
|
906
906
|
} else {
|
|
907
|
-
*error =
|
|
907
|
+
*error = AK_ERROR_OVERFLOW;
|
|
908
908
|
return 0;
|
|
909
909
|
}
|
|
910
910
|
}
|
|
@@ -931,7 +931,7 @@ AK_UCS4_to_int64(Py_UCS4 *p_item, Py_UCS4 *end, int *error, char tsep)
|
|
|
931
931
|
if (p >= end) return number;
|
|
932
932
|
d = *p;
|
|
933
933
|
} else {
|
|
934
|
-
*error =
|
|
934
|
+
*error = AK_ERROR_OVERFLOW;
|
|
935
935
|
return 0;
|
|
936
936
|
}
|
|
937
937
|
}
|
|
@@ -944,7 +944,7 @@ AK_UCS4_to_int64(Py_UCS4 *p_item, Py_UCS4 *end, int *error, char tsep)
|
|
|
944
944
|
if (p >= end) return number;
|
|
945
945
|
d = *p;
|
|
946
946
|
} else {
|
|
947
|
-
*error =
|
|
947
|
+
*error = AK_ERROR_OVERFLOW;
|
|
948
948
|
return 0;
|
|
949
949
|
}
|
|
950
950
|
}
|
|
@@ -952,7 +952,7 @@ AK_UCS4_to_int64(Py_UCS4 *p_item, Py_UCS4 *end, int *error, char tsep)
|
|
|
952
952
|
}
|
|
953
953
|
while (p < end) {
|
|
954
954
|
if (!AK_is_space(*p)) {
|
|
955
|
-
*error =
|
|
955
|
+
*error = AK_ERROR_INVALID_CHARS;
|
|
956
956
|
return 0;
|
|
957
957
|
}
|
|
958
958
|
p++;
|
|
@@ -975,7 +975,7 @@ AK_UCS4_to_uint64(Py_UCS4 *p_item, Py_UCS4 *end, int *error, char tsep)
|
|
|
975
975
|
if (p >= end) return number;
|
|
976
976
|
}
|
|
977
977
|
if (*p == '-') {
|
|
978
|
-
*error =
|
|
978
|
+
*error = AK_ERROR_INVALID_CHARS;
|
|
979
979
|
return 0;
|
|
980
980
|
} else if (*p == '+') {
|
|
981
981
|
p++;
|
|
@@ -984,7 +984,7 @@ AK_UCS4_to_uint64(Py_UCS4 *p_item, Py_UCS4 *end, int *error, char tsep)
|
|
|
984
984
|
|
|
985
985
|
// Check that there is a first digit.
|
|
986
986
|
if (!AK_is_digit(*p)) {
|
|
987
|
-
*error =
|
|
987
|
+
*error = AK_ERROR_NO_DIGITS;
|
|
988
988
|
return 0;
|
|
989
989
|
}
|
|
990
990
|
// If number is less than pre_max, at least one more digit can be processed without overflowing.
|
|
@@ -1006,7 +1006,7 @@ AK_UCS4_to_uint64(Py_UCS4 *p_item, Py_UCS4 *end, int *error, char tsep)
|
|
|
1006
1006
|
if (p >= end) return number;
|
|
1007
1007
|
d = *p;
|
|
1008
1008
|
} else {
|
|
1009
|
-
*error =
|
|
1009
|
+
*error = AK_ERROR_OVERFLOW;
|
|
1010
1010
|
return 0;
|
|
1011
1011
|
}
|
|
1012
1012
|
}
|
|
@@ -1019,14 +1019,14 @@ AK_UCS4_to_uint64(Py_UCS4 *p_item, Py_UCS4 *end, int *error, char tsep)
|
|
|
1019
1019
|
if (p >= end) return number;
|
|
1020
1020
|
d = *p;
|
|
1021
1021
|
} else {
|
|
1022
|
-
*error =
|
|
1022
|
+
*error = AK_ERROR_OVERFLOW;
|
|
1023
1023
|
return 0;
|
|
1024
1024
|
}
|
|
1025
1025
|
}
|
|
1026
1026
|
}
|
|
1027
1027
|
while (p < end) {
|
|
1028
1028
|
if (!AK_is_space(*p)) {
|
|
1029
|
-
*error =
|
|
1029
|
+
*error = AK_ERROR_INVALID_CHARS;
|
|
1030
1030
|
return 0;
|
|
1031
1031
|
}
|
|
1032
1032
|
p++;
|
|
@@ -3535,21 +3535,9 @@ resolve_dtype_iter(PyObject *Py_UNUSED(m), PyObject *arg) {
|
|
|
3535
3535
|
//------------------------------------------------------------------------------
|
|
3536
3536
|
// general utility
|
|
3537
3537
|
|
|
3538
|
-
|
|
3539
|
-
if (AK_UNLIKELY(count == capacity)) { \
|
|
3540
|
-
capacity <<= 1; \
|
|
3541
|
-
indices = (npy_int64*)realloc(indices, sizeof(npy_int64) * capacity);\
|
|
3542
|
-
if (indices == NULL) { \
|
|
3543
|
-
return NULL; \
|
|
3544
|
-
} \
|
|
3545
|
-
} \
|
|
3546
|
-
indices[count++] = p - p_start; \
|
|
3547
|
-
} \
|
|
3548
|
-
|
|
3549
|
-
// Given a Boolean, contiguous 1D array, return the index positions in an int64 array.
|
|
3538
|
+
// Given a Boolean, contiguous 1D array, return the index positions in an int64 array. Through experimentation it has been verified that doing full-size allocation of memory provides the best performance at all scales. Using NpyIter, or using, bit masks does not improve performance over pointer arithmetic. Prescanning for all empty is very effective. Note that NumPy benefits from first counting the nonzeros, then allocating only enough data for the expexted number of indices.
|
|
3550
3539
|
static inline PyObject*
|
|
3551
3540
|
AK_nonzero_1d(PyArrayObject* array) {
|
|
3552
|
-
// the maxiumum number of indices we could return is the size of the array; if this is under a certain number, probably better to just allocate that rather than reallocate
|
|
3553
3541
|
PyObject* final;
|
|
3554
3542
|
npy_intp count_max = PyArray_SIZE(array);
|
|
3555
3543
|
|
|
@@ -3562,116 +3550,75 @@ AK_nonzero_1d(PyArrayObject* array) {
|
|
|
3562
3550
|
lldiv_t size_div = lldiv((long long)count_max, 8); // quot, rem
|
|
3563
3551
|
|
|
3564
3552
|
Py_ssize_t count = 0;
|
|
3565
|
-
// the maximum number of collected integers is equal to or less than count_max
|
|
3566
|
-
Py_ssize_t capacity = count_max
|
|
3553
|
+
// the maximum number of collected integers is equal to or less than count_max
|
|
3554
|
+
Py_ssize_t capacity = count_max;
|
|
3567
3555
|
npy_int64* indices = (npy_int64*)malloc(sizeof(npy_int64) * capacity);
|
|
3568
3556
|
|
|
3569
|
-
// array is contiguous, 1d, boolean
|
|
3570
|
-
npy_bool* p_start = (npy_bool*)PyArray_DATA(array);
|
|
3571
|
-
npy_bool* p = p_start;
|
|
3572
|
-
npy_bool* p_end = p + count_max;
|
|
3573
|
-
npy_bool* p_end_roll = p_end - size_div.rem;
|
|
3574
|
-
|
|
3575
3557
|
NPY_BEGIN_THREADS_DEF;
|
|
3576
3558
|
NPY_BEGIN_THREADS;
|
|
3577
|
-
// Through experimentation it has been verified that doing full-size allocation of memory does not permit outperforming NumPy at 10_000_000 scale; but doing less optimizations does help.
|
|
3578
|
-
// Using bit masks does not improve perforamnce over pointer arithmetic.
|
|
3579
|
-
// Prescanning for all empty is very effective.
|
|
3580
3559
|
|
|
3581
|
-
|
|
3582
|
-
|
|
3583
|
-
|
|
3584
|
-
|
|
3560
|
+
if (PyArray_IS_C_CONTIGUOUS(array)) {
|
|
3561
|
+
npy_bool* p_start = (npy_bool*)PyArray_DATA(array);
|
|
3562
|
+
npy_bool* p = p_start;
|
|
3563
|
+
npy_bool* p_end = p + count_max;
|
|
3564
|
+
npy_bool* p_end_roll = p_end - size_div.rem;
|
|
3565
|
+
|
|
3566
|
+
while (p < p_end_roll) {
|
|
3567
|
+
if (*(npy_uint64*)p == 0) {
|
|
3568
|
+
p += 8; // no true within this 8 byte roll region
|
|
3569
|
+
continue;
|
|
3570
|
+
}
|
|
3571
|
+
if (*p) {indices[count++] = p - p_start;}
|
|
3572
|
+
p++;
|
|
3573
|
+
if (*p) {indices[count++] = p - p_start;}
|
|
3574
|
+
p++;
|
|
3575
|
+
if (*p) {indices[count++] = p - p_start;}
|
|
3576
|
+
p++;
|
|
3577
|
+
if (*p) {indices[count++] = p - p_start;}
|
|
3578
|
+
p++;
|
|
3579
|
+
if (*p) {indices[count++] = p - p_start;}
|
|
3580
|
+
p++;
|
|
3581
|
+
if (*p) {indices[count++] = p - p_start;}
|
|
3582
|
+
p++;
|
|
3583
|
+
if (*p) {indices[count++] = p - p_start;}
|
|
3584
|
+
p++;
|
|
3585
|
+
if (*p) {indices[count++] = p - p_start;}
|
|
3586
|
+
p++;
|
|
3587
|
+
}
|
|
3588
|
+
while (p < p_end) {
|
|
3589
|
+
if (*p) {indices[count++] = p - p_start;}
|
|
3590
|
+
p++;
|
|
3585
3591
|
}
|
|
3586
|
-
if (*p) {NONZERO_APPEND_INDEX;}
|
|
3587
|
-
p++;
|
|
3588
|
-
if (*p) {NONZERO_APPEND_INDEX;}
|
|
3589
|
-
p++;
|
|
3590
|
-
if (*p) {NONZERO_APPEND_INDEX;}
|
|
3591
|
-
p++;
|
|
3592
|
-
if (*p) {NONZERO_APPEND_INDEX;}
|
|
3593
|
-
p++;
|
|
3594
|
-
if (*p) {NONZERO_APPEND_INDEX;}
|
|
3595
|
-
p++;
|
|
3596
|
-
if (*p) {NONZERO_APPEND_INDEX;}
|
|
3597
|
-
p++;
|
|
3598
|
-
if (*p) {NONZERO_APPEND_INDEX;}
|
|
3599
|
-
p++;
|
|
3600
|
-
if (*p) {NONZERO_APPEND_INDEX;}
|
|
3601
|
-
p++;
|
|
3602
3592
|
}
|
|
3603
|
-
|
|
3604
|
-
|
|
3605
|
-
|
|
3593
|
+
else {
|
|
3594
|
+
npy_intp i = 0; // position within Boolean array
|
|
3595
|
+
npy_intp i_end = count_max;
|
|
3596
|
+
npy_intp i_end_roll = count_max - size_div.rem;
|
|
3597
|
+
while (i < i_end_roll) {
|
|
3598
|
+
if (*(npy_bool*)PyArray_GETPTR1(array, i)) {indices[count++] = i;}
|
|
3599
|
+
i++;
|
|
3600
|
+
if (*(npy_bool*)PyArray_GETPTR1(array, i)) {indices[count++] = i;}
|
|
3601
|
+
i++;
|
|
3602
|
+
if (*(npy_bool*)PyArray_GETPTR1(array, i)) {indices[count++] = i;}
|
|
3603
|
+
i++;
|
|
3604
|
+
if (*(npy_bool*)PyArray_GETPTR1(array, i)) {indices[count++] = i;}
|
|
3605
|
+
i++;
|
|
3606
|
+
if (*(npy_bool*)PyArray_GETPTR1(array, i)) {indices[count++] = i;}
|
|
3607
|
+
i++;
|
|
3608
|
+
if (*(npy_bool*)PyArray_GETPTR1(array, i)) {indices[count++] = i;}
|
|
3609
|
+
i++;
|
|
3610
|
+
if (*(npy_bool*)PyArray_GETPTR1(array, i)) {indices[count++] = i;}
|
|
3611
|
+
i++;
|
|
3612
|
+
if (*(npy_bool*)PyArray_GETPTR1(array, i)) {indices[count++] = i;}
|
|
3613
|
+
i++;
|
|
3614
|
+
}
|
|
3615
|
+
while (i < i_end) {
|
|
3616
|
+
if (*(npy_bool*)PyArray_GETPTR1(array, i)) {indices[count++] = i;}
|
|
3617
|
+
i++;
|
|
3618
|
+
}
|
|
3606
3619
|
}
|
|
3607
3620
|
NPY_END_THREADS;
|
|
3608
3621
|
|
|
3609
|
-
// npy_uint64 roll;
|
|
3610
|
-
// while (p < p_end_roll) {
|
|
3611
|
-
// roll = *(npy_uint64*)p;
|
|
3612
|
-
// if (roll == 0) {
|
|
3613
|
-
// p += 8; // no true within this 8 byte roll region
|
|
3614
|
-
// continue;
|
|
3615
|
-
// }
|
|
3616
|
-
// // this order depends on byte order
|
|
3617
|
-
// if (roll & 0xFF) {NONZERO_APPEND_OFFSET(0);}
|
|
3618
|
-
// if (roll & 0xFF00) {NONZERO_APPEND_OFFSET(1);}
|
|
3619
|
-
// if (roll & 0xFF0000) {NONZERO_APPEND_OFFSET(2);}
|
|
3620
|
-
// if (roll & 0xFF000000) {NONZERO_APPEND_OFFSET(3);}
|
|
3621
|
-
// if (roll & 0xFF00000000) {NONZERO_APPEND_OFFSET(4);}
|
|
3622
|
-
// if (roll & 0xFF0000000000) {NONZERO_APPEND_OFFSET(5);}
|
|
3623
|
-
// if (roll & 0xFF000000000000) {NONZERO_APPEND_OFFSET(6);}
|
|
3624
|
-
// if (roll & 0xFF00000000000000) {NONZERO_APPEND_OFFSET(7);}
|
|
3625
|
-
// p += 8;
|
|
3626
|
-
// }
|
|
3627
|
-
// while (p < p_end) {
|
|
3628
|
-
// if (*p) {NONZERO_APPEND_OFFSET(0);}
|
|
3629
|
-
// p++;
|
|
3630
|
-
// }
|
|
3631
|
-
|
|
3632
|
-
|
|
3633
|
-
// while (p < p_end_roll) {
|
|
3634
|
-
// if (*(npy_uint64*)p == 0) {
|
|
3635
|
-
// p += 8; // no true within this roll region
|
|
3636
|
-
// continue;
|
|
3637
|
-
// }
|
|
3638
|
-
// if (AK_UNLIKELY(count + 8 >= capacity)) {
|
|
3639
|
-
// capacity <<= 1;
|
|
3640
|
-
// indices = (npy_int64*)realloc(indices, sizeof(npy_int64) * capacity);
|
|
3641
|
-
// if (indices == NULL) {
|
|
3642
|
-
// return NULL;
|
|
3643
|
-
// }
|
|
3644
|
-
// }
|
|
3645
|
-
// if (*p) {indices[count++] = p - p_start;}
|
|
3646
|
-
// p++;
|
|
3647
|
-
// if (*p) {indices[count++] = p - p_start;}
|
|
3648
|
-
// p++;
|
|
3649
|
-
// if (*p) {indices[count++] = p - p_start;}
|
|
3650
|
-
// p++;
|
|
3651
|
-
// if (*p) {indices[count++] = p - p_start;}
|
|
3652
|
-
// p++;
|
|
3653
|
-
// if (*p) {indices[count++] = p - p_start;}
|
|
3654
|
-
// p++;
|
|
3655
|
-
// if (*p) {indices[count++] = p - p_start;}
|
|
3656
|
-
// p++;
|
|
3657
|
-
// if (*p) {indices[count++] = p - p_start;}
|
|
3658
|
-
// p++;
|
|
3659
|
-
// if (*p) {indices[count++] = p - p_start;}
|
|
3660
|
-
// p++;
|
|
3661
|
-
// }
|
|
3662
|
-
// // at most three more indices remain
|
|
3663
|
-
// if (AK_UNLIKELY(count + 7 >= capacity)) {
|
|
3664
|
-
// capacity <<= 1;
|
|
3665
|
-
// indices = (npy_int64*)realloc(indices, sizeof(npy_int64) * capacity);
|
|
3666
|
-
// if (indices == NULL) {
|
|
3667
|
-
// return NULL;
|
|
3668
|
-
// }
|
|
3669
|
-
// }
|
|
3670
|
-
// while (p < p_end) {
|
|
3671
|
-
// if (*p) {indices[count++] = p - p_start;}
|
|
3672
|
-
// p++;
|
|
3673
|
-
// }
|
|
3674
|
-
|
|
3675
3622
|
npy_intp dims = {count};
|
|
3676
3623
|
final = PyArray_SimpleNewFromData(1, &dims, NPY_INT64, (void*)indices);
|
|
3677
3624
|
if (!final) {
|
|
@@ -3683,7 +3630,6 @@ AK_nonzero_1d(PyArrayObject* array) {
|
|
|
3683
3630
|
PyArray_CLEARFLAGS((PyArrayObject*)final, NPY_ARRAY_WRITEABLE);
|
|
3684
3631
|
return final;
|
|
3685
3632
|
}
|
|
3686
|
-
#undef NONZERO_APPEND_INDEX
|
|
3687
3633
|
|
|
3688
3634
|
static PyObject*
|
|
3689
3635
|
nonzero_1d(PyObject *Py_UNUSED(m), PyObject *a) {
|
|
@@ -3697,10 +3643,6 @@ nonzero_1d(PyObject *Py_UNUSED(m), PyObject *a) {
|
|
|
3697
3643
|
PyErr_SetString(PyExc_ValueError, "Array must be of type bool");
|
|
3698
3644
|
return NULL;
|
|
3699
3645
|
}
|
|
3700
|
-
if (!PyArray_IS_C_CONTIGUOUS(array)) {
|
|
3701
|
-
PyErr_SetString(PyExc_ValueError, "Array must be contiguous");
|
|
3702
|
-
return NULL;
|
|
3703
|
-
}
|
|
3704
3646
|
return AK_nonzero_1d(array);
|
|
3705
3647
|
}
|
|
3706
3648
|
|
|
@@ -5869,8 +5811,6 @@ typedef struct TriMapObject {
|
|
|
5869
5811
|
Py_ssize_t src_len;
|
|
5870
5812
|
Py_ssize_t dst_len;
|
|
5871
5813
|
Py_ssize_t len;
|
|
5872
|
-
// Py_ssize_t src_connected;
|
|
5873
|
-
// Py_ssize_t dst_connected;
|
|
5874
5814
|
bool is_many;
|
|
5875
5815
|
bool finalized;
|
|
5876
5816
|
|
|
@@ -5932,8 +5872,6 @@ TriMap_init(PyObject *self, PyObject *args, PyObject *kwargs) {
|
|
|
5932
5872
|
tm->is_many = false;
|
|
5933
5873
|
tm->finalized = false;
|
|
5934
5874
|
tm->len = 0;
|
|
5935
|
-
// tm->src_connected = 0;
|
|
5936
|
-
// tm->dst_connected = 0;
|
|
5937
5875
|
|
|
5938
5876
|
// we create arrays, and also pre-extract pointers to array data for fast insertion; we keep the array for optimal summing routines
|
|
5939
5877
|
npy_intp dims_src_len[] = {src_len};
|
|
@@ -6039,7 +5977,7 @@ TriMap_repr(TriMapObject *self) {
|
|
|
6039
5977
|
is_finalized);
|
|
6040
5978
|
}
|
|
6041
5979
|
|
|
6042
|
-
// Provide the integer positions connecting the `src` to the `dst`. If there is no match to `src` or `dst`, the unmatched position can be provided with -1. From each side, a connection is documented to the current `len`. Each time this is called `len` is incremented, indicating the inrease in position
|
|
5980
|
+
// Provide the integer positions connecting the `src` to the `dst`. If there is no match to `src` or `dst`, the unmatched position can be provided with -1. From each side, a connection is documented to the current `len`. Each time this is called `len` is incremented, indicating the inrease in position in the `final`. Return NULL on error.
|
|
6043
5981
|
|
|
6044
5982
|
// Inner function for calling from C; returns 0 on success, -1 on error. Exceptions will be set on error.
|
|
6045
5983
|
static inline int
|
|
@@ -6062,7 +6000,6 @@ AK_TM_register_one(TriMapObject* tm, Py_ssize_t src_from, Py_ssize_t dst_from) {
|
|
|
6062
6000
|
}
|
|
6063
6001
|
tm->src_one[tm->src_one_count] = (TriMapOne){src_from, tm->len};
|
|
6064
6002
|
tm->src_one_count += 1;
|
|
6065
|
-
// tm->src_connected += 1;
|
|
6066
6003
|
}
|
|
6067
6004
|
if (dst_matched) {
|
|
6068
6005
|
if (AK_UNLIKELY(tm->dst_one_count == tm->dst_one_capacity)) {
|
|
@@ -6076,7 +6013,6 @@ AK_TM_register_one(TriMapObject* tm, Py_ssize_t src_from, Py_ssize_t dst_from) {
|
|
|
6076
6013
|
}
|
|
6077
6014
|
tm->dst_one[tm->dst_one_count] = (TriMapOne){dst_from, tm->len};
|
|
6078
6015
|
tm->dst_one_count += 1;
|
|
6079
|
-
// tm->dst_connected += 1;
|
|
6080
6016
|
}
|
|
6081
6017
|
if (src_matched && dst_matched) {
|
|
6082
6018
|
if (!tm->is_many) {
|
|
@@ -6141,14 +6077,12 @@ TriMap_register_unmatched_dst(TriMapObject *self) {
|
|
|
6141
6077
|
return NULL;
|
|
6142
6078
|
}
|
|
6143
6079
|
// derive indices for unmatched locations, call each with register_one
|
|
6144
|
-
// PyObject* nonzero = PyArray_Nonzero(dst_unmatched);
|
|
6145
6080
|
PyArrayObject* indices = (PyArrayObject*)AK_nonzero_1d(dst_unmatched);
|
|
6146
6081
|
if (indices == NULL) {
|
|
6147
6082
|
Py_DECREF((PyObject*)dst_unmatched);
|
|
6148
6083
|
return NULL;
|
|
6149
6084
|
}
|
|
6150
6085
|
// borrow ref to array in 1-element tuple
|
|
6151
|
-
// PyArrayObject *indices = (PyArrayObject*)PyTuple_GET_ITEM(nonzero, 0);
|
|
6152
6086
|
npy_int64 *index_data = (npy_int64 *)PyArray_DATA(indices);
|
|
6153
6087
|
npy_intp index_len = PyArray_SIZE(indices);
|
|
6154
6088
|
|
|
@@ -6215,8 +6149,6 @@ TriMap_register_many(TriMapObject *self, PyObject *args) {
|
|
|
6215
6149
|
npy_int64 pos = *(npy_int64*)PyArray_GETPTR1(dst_from, i); // always int64
|
|
6216
6150
|
self->dst_match_data[pos] = NPY_TRUE;
|
|
6217
6151
|
}
|
|
6218
|
-
// self->src_connected += increment;
|
|
6219
|
-
// self->dst_connected += increment;
|
|
6220
6152
|
self->len += increment;
|
|
6221
6153
|
self->is_many = true;
|
|
6222
6154
|
Py_RETURN_NONE;
|
|
@@ -6359,7 +6291,7 @@ TriMap_dst_no_fill(TriMapObject *self, PyObject *Py_UNUSED(unused)) {
|
|
|
6359
6291
|
Py_RETURN_FALSE;
|
|
6360
6292
|
}
|
|
6361
6293
|
|
|
6362
|
-
# define
|
|
6294
|
+
# define AK_TM_TRANSFER_SCALAR(npy_type_to, npy_type_from) do { \
|
|
6363
6295
|
npy_type_to* array_to_data = (npy_type_to*)PyArray_DATA(array_to); \
|
|
6364
6296
|
TriMapOne* o = one_pairs; \
|
|
6365
6297
|
TriMapOne* o_end = o + one_count; \
|
|
@@ -6396,57 +6328,11 @@ TriMap_dst_no_fill(TriMapObject *self, PyObject *Py_UNUSED(unused)) {
|
|
|
6396
6328
|
} \
|
|
6397
6329
|
} \
|
|
6398
6330
|
} \
|
|
6399
|
-
}
|
|
6400
|
-
|
|
6401
|
-
// The elsize of the `to` array will be equal to or greater than the from array
|
|
6402
|
-
#define TRANSFER_FLEXIBLE(c_type) { \
|
|
6403
|
-
npy_intp t_element_size = PyArray_DESCR(array_to)->elsize; \
|
|
6404
|
-
npy_intp t_element_cp = t_element_size / sizeof(c_type); \
|
|
6405
|
-
npy_intp f_element_size = PyArray_DESCR(array_from)->elsize; \
|
|
6406
|
-
npy_intp f_element_cp = f_element_size / sizeof(c_type); \
|
|
6407
|
-
npy_intp gap = t_element_size - f_element_size; \
|
|
6408
|
-
c_type* array_to_data = (c_type*)PyArray_DATA(array_to); \
|
|
6409
|
-
c_type* f; \
|
|
6410
|
-
c_type* t; \
|
|
6411
|
-
c_type* t_end; \
|
|
6412
|
-
npy_intp dst_pos; \
|
|
6413
|
-
npy_int64 f_pos; \
|
|
6414
|
-
PyArrayObject* dst; \
|
|
6415
|
-
TriMapOne* o = one_pairs; \
|
|
6416
|
-
TriMapOne* o_end = o + one_count; \
|
|
6417
|
-
for (; o < o_end; o++) { \
|
|
6418
|
-
f = (c_type*)PyArray_GETPTR1(array_from, o->from); \
|
|
6419
|
-
t = array_to_data + t_element_cp * o->to; \
|
|
6420
|
-
memcpy(t, f, f_element_size); \
|
|
6421
|
-
memset(t + f_element_cp, '\0', gap); \
|
|
6422
|
-
} \
|
|
6423
|
-
for (Py_ssize_t i = 0; i < tm->many_count; i++) { \
|
|
6424
|
-
t = array_to_data + t_element_cp * tm->many_to[i].start; \
|
|
6425
|
-
t_end = array_to_data + t_element_cp * tm->many_to[i].stop; \
|
|
6426
|
-
if (from_src) { \
|
|
6427
|
-
f = (c_type*)PyArray_GETPTR1(array_from, tm->many_from[i].src);\
|
|
6428
|
-
for (; t < t_end; t += t_element_cp) { \
|
|
6429
|
-
memcpy(t, f, f_element_size); \
|
|
6430
|
-
memset(t + f_element_cp, '\0', gap); \
|
|
6431
|
-
} \
|
|
6432
|
-
} \
|
|
6433
|
-
else { \
|
|
6434
|
-
dst_pos = 0; \
|
|
6435
|
-
dst = tm->many_from[i].dst; \
|
|
6436
|
-
for (; t < t_end; t += t_element_cp) { \
|
|
6437
|
-
f_pos = *(npy_int64*)PyArray_GETPTR1(dst, dst_pos); \
|
|
6438
|
-
f = (c_type*)PyArray_GETPTR1(array_from, f_pos); \
|
|
6439
|
-
memcpy(t, f, f_element_size); \
|
|
6440
|
-
memset(t + f_element_cp, '\0', gap); \
|
|
6441
|
-
dst_pos++; \
|
|
6442
|
-
} \
|
|
6443
|
-
} \
|
|
6444
|
-
} \
|
|
6445
|
-
} \
|
|
6331
|
+
} while (0) \
|
|
6446
6332
|
|
|
6447
6333
|
// Based on `tm` state, transfer from src or from dst (depending on `from_src`) to a `array_to`, a newly created contiguous array that is compatible with the values in `array_from`. Returns -1 on error. This only needs to match to / from type combinations that are possible from `resolve_dtype`, i.e., bool never goes to integer.
|
|
6448
6334
|
static inline int
|
|
6449
|
-
|
|
6335
|
+
AK_TM_transfer_scalar(TriMapObject* tm,
|
|
6450
6336
|
bool from_src,
|
|
6451
6337
|
PyArrayObject* array_from,
|
|
6452
6338
|
PyArrayObject* array_to) {
|
|
@@ -6455,206 +6341,194 @@ AK_TM_transfer(TriMapObject* tm,
|
|
|
6455
6341
|
|
|
6456
6342
|
switch(PyArray_TYPE(array_to)){
|
|
6457
6343
|
case NPY_BOOL:
|
|
6458
|
-
|
|
6344
|
+
AK_TM_TRANSFER_SCALAR(npy_bool, npy_bool);
|
|
6459
6345
|
return 0;
|
|
6460
6346
|
case NPY_INT64:
|
|
6461
6347
|
switch (PyArray_TYPE(array_from)) {
|
|
6462
6348
|
case NPY_INT64:
|
|
6463
|
-
|
|
6349
|
+
AK_TM_TRANSFER_SCALAR(npy_int64, npy_int64);
|
|
6464
6350
|
return 0;
|
|
6465
6351
|
case NPY_INT32:
|
|
6466
|
-
|
|
6352
|
+
AK_TM_TRANSFER_SCALAR(npy_int64, npy_int32);
|
|
6467
6353
|
return 0;
|
|
6468
6354
|
case NPY_INT16:
|
|
6469
|
-
|
|
6355
|
+
AK_TM_TRANSFER_SCALAR(npy_int64, npy_int16);
|
|
6470
6356
|
return 0;
|
|
6471
6357
|
case NPY_INT8:
|
|
6472
|
-
|
|
6358
|
+
AK_TM_TRANSFER_SCALAR(npy_int64, npy_int8);
|
|
6473
6359
|
return 0;
|
|
6474
6360
|
case NPY_UINT32:
|
|
6475
|
-
|
|
6361
|
+
AK_TM_TRANSFER_SCALAR(npy_int64, npy_uint32);
|
|
6476
6362
|
return 0;
|
|
6477
6363
|
case NPY_UINT16:
|
|
6478
|
-
|
|
6364
|
+
AK_TM_TRANSFER_SCALAR(npy_int64, npy_uint16);
|
|
6479
6365
|
return 0;
|
|
6480
6366
|
case NPY_UINT8:
|
|
6481
|
-
|
|
6367
|
+
AK_TM_TRANSFER_SCALAR(npy_int64, npy_uint8);
|
|
6482
6368
|
return 0;
|
|
6483
6369
|
}
|
|
6484
6370
|
break;
|
|
6485
6371
|
case NPY_INT32:
|
|
6486
6372
|
switch (PyArray_TYPE(array_from)) {
|
|
6487
6373
|
case NPY_INT32:
|
|
6488
|
-
|
|
6374
|
+
AK_TM_TRANSFER_SCALAR(npy_int32, npy_int32);
|
|
6489
6375
|
return 0;
|
|
6490
6376
|
case NPY_INT16:
|
|
6491
|
-
|
|
6377
|
+
AK_TM_TRANSFER_SCALAR(npy_int32, npy_int16);
|
|
6492
6378
|
return 0;
|
|
6493
6379
|
case NPY_INT8:
|
|
6494
|
-
|
|
6380
|
+
AK_TM_TRANSFER_SCALAR(npy_int32, npy_int8);
|
|
6495
6381
|
return 0;
|
|
6496
6382
|
case NPY_UINT16:
|
|
6497
|
-
|
|
6383
|
+
AK_TM_TRANSFER_SCALAR(npy_int32, npy_uint16);
|
|
6498
6384
|
return 0;
|
|
6499
6385
|
case NPY_UINT8:
|
|
6500
|
-
|
|
6386
|
+
AK_TM_TRANSFER_SCALAR(npy_int32, npy_uint8);
|
|
6501
6387
|
return 0;
|
|
6502
6388
|
}
|
|
6503
6389
|
break;
|
|
6504
6390
|
case NPY_INT16:
|
|
6505
6391
|
switch (PyArray_TYPE(array_from)) {
|
|
6506
6392
|
case NPY_INT16:
|
|
6507
|
-
|
|
6393
|
+
AK_TM_TRANSFER_SCALAR(npy_int16, npy_int16);
|
|
6508
6394
|
return 0;
|
|
6509
6395
|
case NPY_INT8:
|
|
6510
|
-
|
|
6396
|
+
AK_TM_TRANSFER_SCALAR(npy_int16, npy_int8);
|
|
6511
6397
|
return 0;
|
|
6512
6398
|
case NPY_UINT8:
|
|
6513
|
-
|
|
6399
|
+
AK_TM_TRANSFER_SCALAR(npy_int16, npy_uint8);
|
|
6514
6400
|
return 0;
|
|
6515
6401
|
}
|
|
6516
6402
|
break;
|
|
6517
6403
|
case NPY_INT8:
|
|
6518
|
-
|
|
6404
|
+
AK_TM_TRANSFER_SCALAR(npy_int8, npy_int8);
|
|
6519
6405
|
return 0;
|
|
6520
6406
|
case NPY_UINT64:
|
|
6521
6407
|
switch (PyArray_TYPE(array_from)) {
|
|
6522
6408
|
case NPY_UINT64:
|
|
6523
|
-
|
|
6409
|
+
AK_TM_TRANSFER_SCALAR(npy_uint64, npy_uint64);
|
|
6524
6410
|
return 0;
|
|
6525
6411
|
case NPY_UINT32:
|
|
6526
|
-
|
|
6412
|
+
AK_TM_TRANSFER_SCALAR(npy_uint64, npy_uint32);
|
|
6527
6413
|
return 0;
|
|
6528
6414
|
case NPY_UINT16:
|
|
6529
|
-
|
|
6415
|
+
AK_TM_TRANSFER_SCALAR(npy_uint64, npy_uint16);
|
|
6530
6416
|
return 0;
|
|
6531
6417
|
case NPY_UINT8:
|
|
6532
|
-
|
|
6418
|
+
AK_TM_TRANSFER_SCALAR(npy_uint64, npy_uint8);
|
|
6533
6419
|
return 0;
|
|
6534
6420
|
}
|
|
6535
6421
|
break;
|
|
6536
6422
|
case NPY_UINT32:
|
|
6537
6423
|
switch (PyArray_TYPE(array_from)) {
|
|
6538
6424
|
case NPY_UINT32:
|
|
6539
|
-
|
|
6425
|
+
AK_TM_TRANSFER_SCALAR(npy_uint32, npy_uint32);
|
|
6540
6426
|
return 0;
|
|
6541
6427
|
case NPY_UINT16:
|
|
6542
|
-
|
|
6428
|
+
AK_TM_TRANSFER_SCALAR(npy_uint32, npy_uint16);
|
|
6543
6429
|
return 0;
|
|
6544
6430
|
case NPY_UINT8:
|
|
6545
|
-
|
|
6431
|
+
AK_TM_TRANSFER_SCALAR(npy_uint32, npy_uint8);
|
|
6546
6432
|
return 0;
|
|
6547
6433
|
}
|
|
6548
6434
|
break;
|
|
6549
6435
|
case NPY_UINT16:
|
|
6550
6436
|
switch (PyArray_TYPE(array_from)) {
|
|
6551
6437
|
case NPY_UINT16:
|
|
6552
|
-
|
|
6438
|
+
AK_TM_TRANSFER_SCALAR(npy_uint16, npy_uint16);
|
|
6553
6439
|
return 0;
|
|
6554
6440
|
case NPY_UINT8:
|
|
6555
|
-
|
|
6441
|
+
AK_TM_TRANSFER_SCALAR(npy_uint16, npy_uint8);
|
|
6556
6442
|
return 0;
|
|
6557
6443
|
}
|
|
6558
6444
|
break;
|
|
6559
6445
|
case NPY_UINT8:
|
|
6560
|
-
|
|
6446
|
+
AK_TM_TRANSFER_SCALAR(npy_uint8, npy_uint8);
|
|
6561
6447
|
return 0;
|
|
6562
6448
|
case NPY_FLOAT64:
|
|
6563
6449
|
switch (PyArray_TYPE(array_from)) {
|
|
6564
6450
|
case NPY_FLOAT64:
|
|
6565
|
-
|
|
6451
|
+
AK_TM_TRANSFER_SCALAR(npy_float64, npy_float64);
|
|
6566
6452
|
return 0;
|
|
6567
6453
|
case NPY_FLOAT32:
|
|
6568
|
-
|
|
6454
|
+
AK_TM_TRANSFER_SCALAR(npy_float64, npy_float32);
|
|
6569
6455
|
return 0;
|
|
6570
6456
|
case NPY_FLOAT16:
|
|
6571
|
-
|
|
6457
|
+
AK_TM_TRANSFER_SCALAR(npy_float64, npy_float16);
|
|
6572
6458
|
return 0;
|
|
6573
6459
|
case NPY_INT64:
|
|
6574
|
-
|
|
6460
|
+
AK_TM_TRANSFER_SCALAR(npy_float64, npy_int64);
|
|
6575
6461
|
return 0;
|
|
6576
6462
|
case NPY_INT32:
|
|
6577
|
-
|
|
6463
|
+
AK_TM_TRANSFER_SCALAR(npy_float64, npy_int32);
|
|
6578
6464
|
return 0;
|
|
6579
6465
|
case NPY_INT16:
|
|
6580
|
-
|
|
6466
|
+
AK_TM_TRANSFER_SCALAR(npy_float64, npy_int16);
|
|
6581
6467
|
return 0;
|
|
6582
6468
|
case NPY_INT8:
|
|
6583
|
-
|
|
6469
|
+
AK_TM_TRANSFER_SCALAR(npy_float64, npy_int8);
|
|
6584
6470
|
return 0;
|
|
6585
6471
|
case NPY_UINT64:
|
|
6586
|
-
|
|
6472
|
+
AK_TM_TRANSFER_SCALAR(npy_float64, npy_uint64);
|
|
6587
6473
|
return 0;
|
|
6588
6474
|
case NPY_UINT32:
|
|
6589
|
-
|
|
6475
|
+
AK_TM_TRANSFER_SCALAR(npy_float64, npy_uint32);
|
|
6590
6476
|
return 0;
|
|
6591
6477
|
case NPY_UINT16:
|
|
6592
|
-
|
|
6478
|
+
AK_TM_TRANSFER_SCALAR(npy_float64, npy_uint16);
|
|
6593
6479
|
return 0;
|
|
6594
6480
|
case NPY_UINT8:
|
|
6595
|
-
|
|
6481
|
+
AK_TM_TRANSFER_SCALAR(npy_float64, npy_uint8);
|
|
6596
6482
|
return 0;
|
|
6597
6483
|
}
|
|
6598
6484
|
break;
|
|
6599
6485
|
case NPY_FLOAT32:
|
|
6600
6486
|
switch (PyArray_TYPE(array_from)) {
|
|
6601
6487
|
case NPY_FLOAT32:
|
|
6602
|
-
|
|
6488
|
+
AK_TM_TRANSFER_SCALAR(npy_float32, npy_float32);
|
|
6603
6489
|
return 0;
|
|
6604
6490
|
case NPY_FLOAT16:
|
|
6605
|
-
|
|
6491
|
+
AK_TM_TRANSFER_SCALAR(npy_float32, npy_float16);
|
|
6606
6492
|
return 0;
|
|
6607
6493
|
case NPY_INT16:
|
|
6608
|
-
|
|
6494
|
+
AK_TM_TRANSFER_SCALAR(npy_float32, npy_int16);
|
|
6609
6495
|
return 0;
|
|
6610
6496
|
case NPY_INT8:
|
|
6611
|
-
|
|
6497
|
+
AK_TM_TRANSFER_SCALAR(npy_float32, npy_int8);
|
|
6612
6498
|
return 0;
|
|
6613
6499
|
case NPY_UINT16:
|
|
6614
|
-
|
|
6500
|
+
AK_TM_TRANSFER_SCALAR(npy_float32, npy_uint16);
|
|
6615
6501
|
return 0;
|
|
6616
6502
|
case NPY_UINT8:
|
|
6617
|
-
|
|
6503
|
+
AK_TM_TRANSFER_SCALAR(npy_float32, npy_uint8);
|
|
6618
6504
|
return 0;
|
|
6619
6505
|
}
|
|
6620
6506
|
break;
|
|
6621
6507
|
case NPY_FLOAT16:
|
|
6622
6508
|
switch (PyArray_TYPE(array_from)) {
|
|
6623
6509
|
case NPY_FLOAT16:
|
|
6624
|
-
|
|
6510
|
+
AK_TM_TRANSFER_SCALAR(npy_float16, npy_float16);
|
|
6625
6511
|
return 0;
|
|
6626
6512
|
case NPY_INT8:
|
|
6627
|
-
|
|
6513
|
+
AK_TM_TRANSFER_SCALAR(npy_float16, npy_int8);
|
|
6628
6514
|
return 0;
|
|
6629
6515
|
case NPY_UINT16:
|
|
6630
|
-
|
|
6516
|
+
AK_TM_TRANSFER_SCALAR(npy_float16, npy_uint16);
|
|
6631
6517
|
return 0;
|
|
6632
6518
|
case NPY_UINT8:
|
|
6633
|
-
|
|
6519
|
+
AK_TM_TRANSFER_SCALAR(npy_float16, npy_uint8);
|
|
6634
6520
|
return 0;
|
|
6635
6521
|
}
|
|
6636
6522
|
break;
|
|
6637
|
-
case NPY_UNICODE: {
|
|
6638
|
-
TRANSFER_FLEXIBLE(Py_UCS4);
|
|
6639
|
-
return 0;
|
|
6640
|
-
}
|
|
6641
|
-
case NPY_STRING: {
|
|
6642
|
-
TRANSFER_FLEXIBLE(char);
|
|
6643
|
-
return 0;
|
|
6644
|
-
}
|
|
6645
6523
|
case NPY_DATETIME: {
|
|
6646
|
-
|
|
6524
|
+
AK_TM_TRANSFER_SCALAR(npy_int64, npy_int64);
|
|
6647
6525
|
return 0;
|
|
6648
6526
|
}
|
|
6649
6527
|
}
|
|
6650
|
-
// AK_DEBUG_MSG_OBJ("array_to", (PyObject*)array_to);
|
|
6651
|
-
// AK_DEBUG_MSG_OBJ("array_from", (PyObject*)array_from);
|
|
6652
6528
|
PyErr_SetString(PyExc_TypeError, "No handling for types");
|
|
6653
6529
|
return -1;
|
|
6654
6530
|
}
|
|
6655
|
-
|
|
6656
|
-
#undef TRANSFER_SCALARS
|
|
6657
|
-
#undef TRANSFER_FLEXIBLE
|
|
6531
|
+
#undef AK_TM_TRANSFER_SCALAR
|
|
6658
6532
|
|
|
6659
6533
|
// Returns -1 on error. Specialized transfer from any type of an array to an object array.
|
|
6660
6534
|
static inline int
|
|
@@ -6740,12 +6614,10 @@ AK_TM_fill_object(TriMapObject* tm,
|
|
|
6740
6614
|
|
|
6741
6615
|
PyArrayObject* final_fill = (PyArrayObject*)(from_src
|
|
6742
6616
|
? tm->final_src_fill : tm->final_dst_fill);
|
|
6743
|
-
|
|
6744
6617
|
PyObject** array_to_data = (PyObject**)PyArray_DATA(array_to);
|
|
6745
6618
|
npy_int64* p = (npy_int64*)PyArray_DATA(final_fill);
|
|
6746
6619
|
npy_int64* p_end = p + PyArray_SIZE(final_fill);
|
|
6747
6620
|
PyObject** target;
|
|
6748
|
-
// npy_int64 pos;
|
|
6749
6621
|
while (p < p_end) {
|
|
6750
6622
|
target = array_to_data + *p++;
|
|
6751
6623
|
Py_INCREF(fill_value);
|
|
@@ -6754,29 +6626,117 @@ AK_TM_fill_object(TriMapObject* tm,
|
|
|
6754
6626
|
return 0;
|
|
6755
6627
|
}
|
|
6756
6628
|
|
|
6757
|
-
|
|
6758
|
-
|
|
6759
|
-
|
|
6760
|
-
|
|
6761
|
-
|
|
6762
|
-
|
|
6763
|
-
|
|
6764
|
-
|
|
6765
|
-
|
|
6766
|
-
|
|
6767
|
-
|
|
6768
|
-
|
|
6769
|
-
|
|
6770
|
-
|
|
6771
|
-
|
|
6772
|
-
|
|
6773
|
-
|
|
6774
|
-
|
|
6775
|
-
|
|
6776
|
-
|
|
6777
|
-
|
|
6778
|
-
|
|
6629
|
+
#define AK_TM_TRANSFER_FLEXIBLE(c_type) do { \
|
|
6630
|
+
Py_ssize_t one_count = from_src ? tm->src_one_count : tm->dst_one_count;\
|
|
6631
|
+
TriMapOne* one_pairs = from_src ? tm->src_one : tm->dst_one; \
|
|
6632
|
+
npy_intp t_element_size = PyArray_DESCR(array_to)->elsize; \
|
|
6633
|
+
npy_intp t_element_cp = t_element_size / sizeof(c_type); \
|
|
6634
|
+
npy_intp f_element_size = PyArray_DESCR(array_from)->elsize; \
|
|
6635
|
+
c_type* array_to_data = (c_type*)PyArray_DATA(array_to); \
|
|
6636
|
+
c_type* f; \
|
|
6637
|
+
c_type* t; \
|
|
6638
|
+
c_type* t_end; \
|
|
6639
|
+
npy_intp dst_pos; \
|
|
6640
|
+
npy_int64 f_pos; \
|
|
6641
|
+
PyArrayObject* dst; \
|
|
6642
|
+
TriMapOne* o = one_pairs; \
|
|
6643
|
+
TriMapOne* o_end = o + one_count; \
|
|
6644
|
+
for (; o < o_end; o++) { \
|
|
6645
|
+
f = (c_type*)PyArray_GETPTR1(array_from, o->from); \
|
|
6646
|
+
t = array_to_data + t_element_cp * o->to; \
|
|
6647
|
+
memcpy(t, f, f_element_size); \
|
|
6648
|
+
} \
|
|
6649
|
+
for (Py_ssize_t i = 0; i < tm->many_count; i++) { \
|
|
6650
|
+
t = array_to_data + t_element_cp * tm->many_to[i].start; \
|
|
6651
|
+
t_end = array_to_data + t_element_cp * tm->many_to[i].stop; \
|
|
6652
|
+
if (from_src) { \
|
|
6653
|
+
f = (c_type*)PyArray_GETPTR1(array_from, tm->many_from[i].src);\
|
|
6654
|
+
for (; t < t_end; t += t_element_cp) { \
|
|
6655
|
+
memcpy(t, f, f_element_size); \
|
|
6656
|
+
} \
|
|
6657
|
+
} \
|
|
6658
|
+
else { \
|
|
6659
|
+
dst_pos = 0; \
|
|
6660
|
+
dst = tm->many_from[i].dst; \
|
|
6661
|
+
for (; t < t_end; t += t_element_cp) { \
|
|
6662
|
+
f_pos = *(npy_int64*)PyArray_GETPTR1(dst, dst_pos); \
|
|
6663
|
+
f = (c_type*)PyArray_GETPTR1(array_from, f_pos); \
|
|
6664
|
+
memcpy(t, f, f_element_size); \
|
|
6665
|
+
dst_pos++; \
|
|
6666
|
+
} \
|
|
6667
|
+
} \
|
|
6668
|
+
} \
|
|
6669
|
+
} while (0) \
|
|
6670
|
+
|
|
6671
|
+
// Returns -1 on error.
|
|
6672
|
+
static inline int
|
|
6673
|
+
AK_TM_fill_unicode(TriMapObject* tm,
|
|
6674
|
+
bool from_src,
|
|
6675
|
+
PyArrayObject* array_to,
|
|
6676
|
+
PyObject* fill_value) {
|
|
6677
|
+
PyArrayObject* final_fill = (PyArrayObject*)(from_src
|
|
6678
|
+
? tm->final_src_fill : tm->final_dst_fill);
|
|
6679
|
+
|
|
6680
|
+
Py_UCS4* array_to_data = (Py_UCS4*)PyArray_DATA(array_to);
|
|
6681
|
+
// code points per element
|
|
6682
|
+
npy_intp cp = PyArray_DESCR(array_to)->elsize / UCS4_SIZE;
|
|
6683
|
+
|
|
6684
|
+
bool decref_fill_value = false;
|
|
6685
|
+
if (PyBytes_Check(fill_value)) {
|
|
6686
|
+
fill_value = PyUnicode_FromEncodedObject(fill_value, "utf-8", NULL);
|
|
6687
|
+
if (fill_value == NULL) {
|
|
6688
|
+
return -1;
|
|
6689
|
+
}
|
|
6690
|
+
decref_fill_value = true;
|
|
6691
|
+
}
|
|
6692
|
+
else if (!PyUnicode_Check(fill_value)) {
|
|
6693
|
+
return -1;
|
|
6694
|
+
}
|
|
6695
|
+
Py_ssize_t fill_cp = PyUnicode_GET_LENGTH(fill_value) * UCS4_SIZE; // code points
|
|
6696
|
+
// p is the index position to fill
|
|
6697
|
+
npy_int64* p = (npy_int64*)PyArray_DATA(final_fill);
|
|
6698
|
+
npy_int64* p_end = p + PyArray_SIZE(final_fill);
|
|
6699
|
+
Py_UCS4* target;
|
|
6700
|
+
while (p < p_end) {
|
|
6701
|
+
target = array_to_data + (*p * cp);
|
|
6702
|
+
// disabling copying a null
|
|
6703
|
+
if (PyUnicode_AsUCS4(fill_value, target, fill_cp, 0) == NULL) {
|
|
6704
|
+
return -1;
|
|
6705
|
+
}
|
|
6706
|
+
p++;
|
|
6707
|
+
}
|
|
6708
|
+
if (decref_fill_value) {
|
|
6709
|
+
Py_DECREF(fill_value);
|
|
6710
|
+
}
|
|
6711
|
+
return 0;
|
|
6712
|
+
}
|
|
6713
|
+
|
|
6714
|
+
// Returns -1 on error.
|
|
6715
|
+
static inline int
|
|
6716
|
+
AK_TM_fill_string(TriMapObject* tm,
|
|
6717
|
+
bool from_src,
|
|
6718
|
+
PyArrayObject* array_to,
|
|
6719
|
+
PyObject* fill_value) {
|
|
6720
|
+
PyArrayObject* final_fill = (PyArrayObject*)(from_src
|
|
6721
|
+
? tm->final_src_fill : tm->final_dst_fill);
|
|
6779
6722
|
|
|
6723
|
+
char* array_to_data = (char*)PyArray_DATA(array_to);
|
|
6724
|
+
npy_intp cp = PyArray_DESCR(array_to)->elsize;
|
|
6725
|
+
if (!PyBytes_Check(fill_value)) {
|
|
6726
|
+
return -1;
|
|
6727
|
+
}
|
|
6728
|
+
Py_ssize_t fill_cp = PyBytes_GET_SIZE(fill_value);
|
|
6729
|
+
const char* fill_data = PyBytes_AS_STRING(fill_value);
|
|
6730
|
+
// p is the index position to fill
|
|
6731
|
+
npy_int64* p = (npy_int64*)PyArray_DATA(final_fill);
|
|
6732
|
+
npy_int64* p_end = p + PyArray_SIZE(final_fill);
|
|
6733
|
+
char* target;
|
|
6734
|
+
while (p < p_end) {
|
|
6735
|
+
target = array_to_data + (*p++ * cp);
|
|
6736
|
+
memcpy(target, fill_data, fill_cp);
|
|
6737
|
+
}
|
|
6738
|
+
return 0;
|
|
6739
|
+
}
|
|
6780
6740
|
|
|
6781
6741
|
// Returns NULL on error.
|
|
6782
6742
|
static inline PyObject*
|
|
@@ -6790,6 +6750,9 @@ AK_TM_map_no_fill(TriMapObject* tm,
|
|
|
6790
6750
|
npy_intp dims[] = {tm->len};
|
|
6791
6751
|
PyArrayObject* array_to;
|
|
6792
6752
|
bool dtype_is_obj = PyArray_TYPE(array_from) == NPY_OBJECT;
|
|
6753
|
+
bool dtype_is_unicode = PyArray_TYPE(array_from) == NPY_UNICODE;
|
|
6754
|
+
bool dtype_is_string = PyArray_TYPE(array_from) == NPY_STRING;
|
|
6755
|
+
|
|
6793
6756
|
// create to array
|
|
6794
6757
|
if (dtype_is_obj) { // initializes values to NULL
|
|
6795
6758
|
array_to = (PyArrayObject*)PyArray_SimpleNew(1, dims, NPY_OBJECT);
|
|
@@ -6810,8 +6773,14 @@ AK_TM_map_no_fill(TriMapObject* tm,
|
|
|
6810
6773
|
return NULL;
|
|
6811
6774
|
}
|
|
6812
6775
|
}
|
|
6776
|
+
else if (dtype_is_unicode) {
|
|
6777
|
+
AK_TM_TRANSFER_FLEXIBLE(Py_UCS4);
|
|
6778
|
+
}
|
|
6779
|
+
else if (dtype_is_string) {
|
|
6780
|
+
AK_TM_TRANSFER_FLEXIBLE(char);
|
|
6781
|
+
}
|
|
6813
6782
|
else {
|
|
6814
|
-
if (
|
|
6783
|
+
if (AK_TM_transfer_scalar(tm, from_src, array_from, array_to)) {
|
|
6815
6784
|
Py_DECREF((PyObject*)array_to);
|
|
6816
6785
|
return NULL;
|
|
6817
6786
|
}
|
|
@@ -6864,15 +6833,22 @@ AK_TM_map_fill(TriMapObject* tm,
|
|
|
6864
6833
|
// passing a borrowed ref; returns a new ref
|
|
6865
6834
|
PyArray_Descr* dtype = AK_resolve_dtype(PyArray_DESCR(array_from), fill_value_dtype);
|
|
6866
6835
|
bool dtype_is_obj = dtype->type_num == NPY_OBJECT;
|
|
6836
|
+
bool dtype_is_unicode = dtype->type_num == NPY_UNICODE;
|
|
6837
|
+
bool dtype_is_string = dtype->type_num == NPY_STRING;
|
|
6867
6838
|
|
|
6868
6839
|
npy_intp dims[] = {tm->len};
|
|
6869
6840
|
PyArrayObject* array_to;
|
|
6841
|
+
|
|
6870
6842
|
if (dtype_is_obj) {
|
|
6871
6843
|
Py_DECREF(dtype); // not needed
|
|
6872
6844
|
// will initialize to NULL, not None
|
|
6873
6845
|
array_to = (PyArrayObject*)PyArray_SimpleNew(1, dims, NPY_OBJECT);
|
|
6874
6846
|
Py_INCREF(array_from); // normalize refs when casting
|
|
6875
6847
|
}
|
|
6848
|
+
else if (dtype_is_unicode || dtype_is_string) {
|
|
6849
|
+
array_to = (PyArrayObject*)PyArray_Zeros(1, dims, dtype, 0); // steals dtype ref
|
|
6850
|
+
Py_INCREF(array_from); // normalize refs when casting
|
|
6851
|
+
}
|
|
6876
6852
|
else {
|
|
6877
6853
|
array_to = (PyArrayObject*)PyArray_Empty(1, dims, dtype, 0); // steals dtype ref
|
|
6878
6854
|
if (PyArray_TYPE(array_from) == NPY_DATETIME &&
|
|
@@ -6893,44 +6869,51 @@ AK_TM_map_fill(TriMapObject* tm,
|
|
|
6893
6869
|
Py_DECREF((PyObject*)array_from);
|
|
6894
6870
|
return NULL;
|
|
6895
6871
|
}
|
|
6872
|
+
// array_from, array_to inc refed and dec refed on error
|
|
6896
6873
|
if (dtype_is_obj) {
|
|
6897
6874
|
if (AK_TM_transfer_object(tm, from_src, array_from, array_to)) {
|
|
6898
|
-
|
|
6899
|
-
Py_DECREF((PyObject*)array_from);
|
|
6900
|
-
return NULL;
|
|
6875
|
+
goto error;
|
|
6901
6876
|
}
|
|
6902
6877
|
if (AK_TM_fill_object(tm, from_src, array_to, fill_value)) {
|
|
6903
|
-
|
|
6904
|
-
|
|
6905
|
-
|
|
6878
|
+
goto error;
|
|
6879
|
+
}
|
|
6880
|
+
}
|
|
6881
|
+
else if (dtype_is_unicode) {
|
|
6882
|
+
AK_TM_TRANSFER_FLEXIBLE(Py_UCS4);
|
|
6883
|
+
if (AK_TM_fill_unicode(tm, from_src, array_to, fill_value)) {
|
|
6884
|
+
goto error;
|
|
6885
|
+
}
|
|
6886
|
+
}
|
|
6887
|
+
else if (dtype_is_string) {
|
|
6888
|
+
AK_TM_TRANSFER_FLEXIBLE(char);
|
|
6889
|
+
if (AK_TM_fill_string(tm, from_src, array_to, fill_value)) {
|
|
6890
|
+
goto error;
|
|
6906
6891
|
}
|
|
6907
6892
|
}
|
|
6908
|
-
// TODO: add special hanldig for unicode/bytes
|
|
6909
6893
|
else {
|
|
6910
6894
|
// Most simple is to fill with scalar, then overwrite values as needed; for object and flexible dtypes this is not efficient; for object dtypes, this obbligates us to decref the filled value when assigning
|
|
6911
6895
|
if (PyArray_FillWithScalar(array_to, fill_value)) { // -1 on error
|
|
6912
|
-
|
|
6913
|
-
Py_DECREF((PyObject*)array_from);
|
|
6914
|
-
return NULL;
|
|
6896
|
+
goto error;
|
|
6915
6897
|
}
|
|
6916
|
-
if (
|
|
6917
|
-
|
|
6918
|
-
Py_DECREF((PyObject*)array_from);
|
|
6919
|
-
return NULL;
|
|
6898
|
+
if (AK_TM_transfer_scalar(tm, from_src, array_from, array_to)) {
|
|
6899
|
+
goto error;
|
|
6920
6900
|
}
|
|
6921
6901
|
}
|
|
6922
|
-
|
|
6923
6902
|
Py_DECREF((PyObject*)array_from); // ref inc for this function
|
|
6924
6903
|
PyArray_CLEARFLAGS(array_to, NPY_ARRAY_WRITEABLE);
|
|
6925
6904
|
return (PyObject*)array_to;
|
|
6905
|
+
error:
|
|
6906
|
+
Py_DECREF((PyObject*)array_to);
|
|
6907
|
+
Py_DECREF((PyObject*)array_from);
|
|
6908
|
+
return NULL;
|
|
6926
6909
|
}
|
|
6910
|
+
#undef AK_TM_TRANSFER_FLEXIBLE
|
|
6927
6911
|
|
|
6928
6912
|
static PyObject*
|
|
6929
6913
|
TriMap_map_src_fill(TriMapObject *self, PyObject *args) {
|
|
6930
6914
|
PyArrayObject* array_from;
|
|
6931
6915
|
PyObject* fill_value;
|
|
6932
6916
|
PyArray_Descr* fill_value_dtype;
|
|
6933
|
-
|
|
6934
6917
|
if (!PyArg_ParseTuple(args,
|
|
6935
6918
|
"O!OO!:map_src_fill",
|
|
6936
6919
|
&PyArray_Type, &array_from,
|
|
@@ -6952,7 +6935,6 @@ TriMap_map_dst_fill(TriMapObject *self, PyObject *args) {
|
|
|
6952
6935
|
PyArrayObject* array_from;
|
|
6953
6936
|
PyObject* fill_value;
|
|
6954
6937
|
PyArray_Descr* fill_value_dtype;
|
|
6955
|
-
|
|
6956
6938
|
if (!PyArg_ParseTuple(args,
|
|
6957
6939
|
"O!OO!:map_dst_fill",
|
|
6958
6940
|
&PyArray_Type, &array_from,
|
|
@@ -6969,7 +6951,6 @@ TriMap_map_dst_fill(TriMapObject *self, PyObject *args) {
|
|
|
6969
6951
|
return AK_TM_map_fill(self, from_src, array_from, fill_value, fill_value_dtype);
|
|
6970
6952
|
}
|
|
6971
6953
|
|
|
6972
|
-
|
|
6973
6954
|
static PyMethodDef TriMap_methods[] = {
|
|
6974
6955
|
{"register_one", (PyCFunction)TriMap_register_one, METH_VARARGS, NULL},
|
|
6975
6956
|
{"register_unmatched_dst", (PyCFunction)TriMap_register_unmatched_dst, METH_NOARGS, NULL},
|
|
@@ -83,4 +83,19 @@ class TestUnit(unittest.TestCase):
|
|
|
83
83
|
a1[999] = True
|
|
84
84
|
self.assertEqual(nonzero_1d(a1).tolist(), [999, 9_999_999])
|
|
85
85
|
a1[0] = True
|
|
86
|
-
self.assertEqual(nonzero_1d(a1).tolist(), [0, 999, 9_999_999])
|
|
86
|
+
self.assertEqual(nonzero_1d(a1).tolist(), [0, 999, 9_999_999])
|
|
87
|
+
|
|
88
|
+
def test_nonzero_1d_f(self) -> None:
|
|
89
|
+
# non-contiguous
|
|
90
|
+
a1 = np.arange(40).reshape(10, 4) % 3 == 0
|
|
91
|
+
a2 = a1[:, 3]
|
|
92
|
+
self.assertEqual(nonzero_1d(a2).tolist(), [0, 3, 6, 9])
|
|
93
|
+
|
|
94
|
+
a3 = a1[:, 1]
|
|
95
|
+
self.assertEqual(nonzero_1d(a3).tolist(), [2, 5, 8])
|
|
96
|
+
|
|
97
|
+
def test_nonzero_1d_g(self) -> None:
|
|
98
|
+
a1 = np.arange(20).reshape(4, 5) % 3 == 0
|
|
99
|
+
a2 = a1[:, 4]
|
|
100
|
+
# array([False, True, False, False])
|
|
101
|
+
self.assertEqual(nonzero_1d(a2).tolist(), [1])
|
|
@@ -975,6 +975,21 @@ class TestUnit(unittest.TestCase):
|
|
|
975
975
|
post_dst = tm.map_dst_no_fill(dst)
|
|
976
976
|
self.assertEqual(post_dst.tolist(), [b'a', b'bbb', b'cc', b'cc', b'dddd', b'a'])
|
|
977
977
|
|
|
978
|
+
def test_tri_map_map_bytes_a(self) -> None:
|
|
979
|
+
src = np.array([b'a', b'bbb', b'cc'], dtype=np.bytes_)
|
|
980
|
+
dst = np.array([b'cc', b'dddd', b'eee'], dtype=np.bytes_)
|
|
981
|
+
|
|
982
|
+
tm = TriMap(len(src), len(dst))
|
|
983
|
+
tm.register_one(0, -1)
|
|
984
|
+
tm.register_one(1, -1)
|
|
985
|
+
tm.register_one(2, 0)
|
|
986
|
+
tm.register_unmatched_dst()
|
|
987
|
+
tm.finalize()
|
|
988
|
+
|
|
989
|
+
post_src = tm.map_src_fill(src, b'--', np.dtype(np.bytes_))
|
|
990
|
+
post_dst = tm.map_dst_fill(dst, b'--', np.dtype(np.bytes_))
|
|
991
|
+
self.assertEqual(post_src.tolist(), [b'a', b'bbb', b'cc', b'--', b'--'])
|
|
992
|
+
self.assertEqual(post_dst.tolist(), [b'--', b'--', b'cc', b'dddd', b'eee'])
|
|
978
993
|
#---------------------------------------------------------------------------
|
|
979
994
|
|
|
980
995
|
def test_tri_map_map_unicode_a(self) -> None:
|
|
@@ -994,7 +1009,6 @@ class TestUnit(unittest.TestCase):
|
|
|
994
1009
|
post_dst = tm.map_dst_fill(dst, '====', np.array('====').dtype)
|
|
995
1010
|
self.assertEqual(post_dst.tolist(), ['a', 'a', 'a', '====', 'cc', 'cc', '===='])
|
|
996
1011
|
|
|
997
|
-
|
|
998
1012
|
def test_tri_map_map_unicode_b(self) -> None:
|
|
999
1013
|
src = np.array(['a', 'bbb', 'cc', 'dddd'])
|
|
1000
1014
|
dst = np.array(['cc', 'a', 'a', 'a', 'cc'])
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|