arraykit 0.8.3__tar.gz → 0.10.0__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.8.3/arraykit.egg-info → arraykit-0.10.0}/PKG-INFO +2 -1
- {arraykit-0.8.3 → arraykit-0.10.0}/README.rst +12 -0
- {arraykit-0.8.3 → arraykit-0.10.0/arraykit.egg-info}/PKG-INFO +2 -1
- {arraykit-0.8.3 → arraykit-0.10.0}/setup.py +2 -1
- {arraykit-0.8.3 → arraykit-0.10.0}/src/__init__.pyi +11 -7
- {arraykit-0.8.3 → arraykit-0.10.0}/src/tri_map.c +194 -8
- {arraykit-0.8.3 → arraykit-0.10.0}/test/test_tri_map.py +176 -0
- {arraykit-0.8.3 → arraykit-0.10.0}/LICENSE.txt +0 -0
- {arraykit-0.8.3 → arraykit-0.10.0}/MANIFEST.in +0 -0
- {arraykit-0.8.3 → arraykit-0.10.0}/arraykit.egg-info/SOURCES.txt +0 -0
- {arraykit-0.8.3 → arraykit-0.10.0}/arraykit.egg-info/dependency_links.txt +0 -0
- {arraykit-0.8.3 → arraykit-0.10.0}/arraykit.egg-info/requires.txt +0 -0
- {arraykit-0.8.3 → arraykit-0.10.0}/arraykit.egg-info/top_level.txt +0 -0
- {arraykit-0.8.3 → arraykit-0.10.0}/setup.cfg +0 -0
- {arraykit-0.8.3 → arraykit-0.10.0}/src/__init__.py +0 -0
- {arraykit-0.8.3 → arraykit-0.10.0}/src/_arraykit.c +0 -0
- {arraykit-0.8.3 → arraykit-0.10.0}/src/array_go.c +0 -0
- {arraykit-0.8.3 → arraykit-0.10.0}/src/array_go.h +0 -0
- {arraykit-0.8.3 → arraykit-0.10.0}/src/array_to_tuple.c +0 -0
- {arraykit-0.8.3 → arraykit-0.10.0}/src/array_to_tuple.h +0 -0
- {arraykit-0.8.3 → arraykit-0.10.0}/src/block_index.c +0 -0
- {arraykit-0.8.3 → arraykit-0.10.0}/src/block_index.h +0 -0
- {arraykit-0.8.3 → arraykit-0.10.0}/src/delimited_to_arrays.c +0 -0
- {arraykit-0.8.3 → arraykit-0.10.0}/src/delimited_to_arrays.h +0 -0
- {arraykit-0.8.3 → arraykit-0.10.0}/src/methods.c +0 -0
- {arraykit-0.8.3 → arraykit-0.10.0}/src/methods.h +0 -0
- {arraykit-0.8.3 → arraykit-0.10.0}/src/py.typed +0 -0
- {arraykit-0.8.3 → arraykit-0.10.0}/src/tri_map.h +0 -0
- {arraykit-0.8.3 → arraykit-0.10.0}/src/utilities.h +0 -0
- {arraykit-0.8.3 → arraykit-0.10.0}/test/test_array_go.py +0 -0
- {arraykit-0.8.3 → arraykit-0.10.0}/test/test_block_index.py +0 -0
- {arraykit-0.8.3 → arraykit-0.10.0}/test/test_delimited_to_arrays.py +0 -0
- {arraykit-0.8.3 → arraykit-0.10.0}/test/test_delimited_to_arrays_integration.py +0 -0
- {arraykit-0.8.3 → arraykit-0.10.0}/test/test_delimited_to_arrays_property.py +0 -0
- {arraykit-0.8.3 → arraykit-0.10.0}/test/test_nonzero_1d.py +0 -0
- {arraykit-0.8.3 → arraykit-0.10.0}/test/test_nonzero_1d_property.py +0 -0
- {arraykit-0.8.3 → arraykit-0.10.0}/test/test_pyi.py +0 -0
- {arraykit-0.8.3 → arraykit-0.10.0}/test/test_split_after_count.py +0 -0
- {arraykit-0.8.3 → arraykit-0.10.0}/test/test_type_discovery.py +0 -0
- {arraykit-0.8.3 → arraykit-0.10.0}/test/test_util.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: arraykit
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.10.0
|
|
4
4
|
Summary: Array utilities for StaticFrame
|
|
5
5
|
Home-page: https://github.com/static-frame/arraykit
|
|
6
6
|
Author: Christopher Ariza, Brandt Bucher, Charles Burkland
|
|
@@ -19,6 +19,7 @@ Classifier: Programming Language :: Python :: 3.9
|
|
|
19
19
|
Classifier: Programming Language :: Python :: 3.10
|
|
20
20
|
Classifier: Programming Language :: Python :: 3.11
|
|
21
21
|
Classifier: Programming Language :: Python :: 3.12
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
22
23
|
Classifier: Typing :: Typed
|
|
23
24
|
Requires-Python: >=3.9
|
|
24
25
|
License-File: LICENSE.txt
|
|
@@ -37,6 +37,18 @@ ArrayKit requires the following:
|
|
|
37
37
|
What is New in ArrayKit
|
|
38
38
|
-------------------------
|
|
39
39
|
|
|
40
|
+
0.10.0
|
|
41
|
+
............
|
|
42
|
+
|
|
43
|
+
Now building wheels for Python 3.13.
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
0.9.0
|
|
47
|
+
............
|
|
48
|
+
|
|
49
|
+
Added ``TriMap.map_merge()``.
|
|
50
|
+
|
|
51
|
+
|
|
40
52
|
0.8.3
|
|
41
53
|
............
|
|
42
54
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: arraykit
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.10.0
|
|
4
4
|
Summary: Array utilities for StaticFrame
|
|
5
5
|
Home-page: https://github.com/static-frame/arraykit
|
|
6
6
|
Author: Christopher Ariza, Brandt Bucher, Charles Burkland
|
|
@@ -19,6 +19,7 @@ Classifier: Programming Language :: Python :: 3.9
|
|
|
19
19
|
Classifier: Programming Language :: Python :: 3.10
|
|
20
20
|
Classifier: Programming Language :: Python :: 3.11
|
|
21
21
|
Classifier: Programming Language :: Python :: 3.12
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
22
23
|
Classifier: Typing :: Typed
|
|
23
24
|
Requires-Python: >=3.9
|
|
24
25
|
License-File: LICENSE.txt
|
|
@@ -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.
|
|
8
|
+
AK_VERSION = '0.10.0'
|
|
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.
|
|
@@ -72,6 +72,7 @@ setup(
|
|
|
72
72
|
'Programming Language :: Python :: 3.10',
|
|
73
73
|
'Programming Language :: Python :: 3.11',
|
|
74
74
|
'Programming Language :: Python :: 3.12',
|
|
75
|
+
'Programming Language :: Python :: 3.13',
|
|
75
76
|
'Typing :: Typed',
|
|
76
77
|
],
|
|
77
78
|
keywords='numpy array',
|
|
@@ -45,27 +45,31 @@ class ArrayGO:
|
|
|
45
45
|
def extend(self, __values: tp.Iterable[object]) -> None: ...
|
|
46
46
|
|
|
47
47
|
class TriMap:
|
|
48
|
-
def __init__(self, src_len: int, dst_len: int) -> None: ...
|
|
48
|
+
def __init__(self, /, src_len: int, dst_len: int) -> None: ...
|
|
49
49
|
def __repr__(self) -> str: ...
|
|
50
|
-
def register_one(self, src_from: int, dst_from: int) -> None: ...
|
|
50
|
+
def register_one(self, /, src_from: int, dst_from: int) -> None: ...
|
|
51
51
|
def register_unmatched_dst(self) -> None: ...
|
|
52
|
-
def register_many(self, src_from: int, dst_from: np.ndarray) -> None: ...
|
|
52
|
+
def register_many(self, /, src_from: int, dst_from: np.ndarray) -> None: ...
|
|
53
53
|
def finalize(self) -> None: ...
|
|
54
54
|
def is_many(self) -> bool: ...
|
|
55
55
|
def src_no_fill(self) -> bool: ...
|
|
56
56
|
def dst_no_fill(self) -> bool: ...
|
|
57
|
-
def map_src_no_fill(self, array_from: np.ndarray) -> np.ndarray: ...
|
|
58
|
-
def map_dst_no_fill(self, array_from: np.ndarray) -> np.ndarray: ...
|
|
59
|
-
def map_src_fill(self,
|
|
57
|
+
def map_src_no_fill(self, /, array_from: np.ndarray) -> np.ndarray: ...
|
|
58
|
+
def map_dst_no_fill(self, /, array_from: np.ndarray) -> np.ndarray: ...
|
|
59
|
+
def map_src_fill(self, /,
|
|
60
60
|
array_from: np.ndarray,
|
|
61
61
|
fill_value: tp.Any,
|
|
62
62
|
fill_value_dtype: np.dtype
|
|
63
63
|
) -> np.ndarray: ...
|
|
64
|
-
def map_dst_fill(self,
|
|
64
|
+
def map_dst_fill(self, /,
|
|
65
65
|
array_from: np.ndarray,
|
|
66
66
|
fill_value: tp.Any,
|
|
67
67
|
fill_value_dtype: np.dtype
|
|
68
68
|
) -> np.ndarray: ...
|
|
69
|
+
def map_merge(self, /,
|
|
70
|
+
array_from_src: np.ndarray,
|
|
71
|
+
array_from_dst: np.ndarray,
|
|
72
|
+
) -> np.ndarray: ...
|
|
69
73
|
|
|
70
74
|
class BlockIndex:
|
|
71
75
|
shape: tp.Tuple[int, int]
|
|
@@ -401,6 +401,7 @@ TriMap_finalize(TriMapObject *self, PyObject *Py_UNUSED(unused)) {
|
|
|
401
401
|
|
|
402
402
|
npy_intp dims[] = {tm->len};
|
|
403
403
|
|
|
404
|
+
// initialize all to False
|
|
404
405
|
final_src_match = PyArray_ZEROS(1, dims, NPY_BOOL, 0);
|
|
405
406
|
if (final_src_match == NULL) {
|
|
406
407
|
goto error;
|
|
@@ -772,7 +773,7 @@ AK_TM_transfer_object(TriMapObject* tm,
|
|
|
772
773
|
// NOTE: could use PyArray_Scalar instead of PyArray_GETITEM if we wanted to store scalars instead of Python objects; however, that is pretty uncommon for object arrays to store PyArray_Scalars
|
|
773
774
|
bool f_is_obj = PyArray_TYPE(array_from) == NPY_OBJECT;
|
|
774
775
|
|
|
775
|
-
// the passed in object array is
|
|
776
|
+
// the passed in object array is contiguous and have NULL (not None) in each position
|
|
776
777
|
PyObject** array_to_data = (PyObject**)PyArray_DATA(array_to);
|
|
777
778
|
PyObject* pyo;
|
|
778
779
|
void* f;
|
|
@@ -811,7 +812,7 @@ AK_TM_transfer_object(TriMapObject* tm,
|
|
|
811
812
|
Py_INCREF(pyo); // one more than we need
|
|
812
813
|
*t++ = pyo;
|
|
813
814
|
}
|
|
814
|
-
Py_DECREF(pyo); // remove the extra
|
|
815
|
+
Py_DECREF(pyo); // remove the extra ref
|
|
815
816
|
}
|
|
816
817
|
else { // from_dst, dst is an array
|
|
817
818
|
dst_pos = 0;
|
|
@@ -834,6 +835,92 @@ AK_TM_transfer_object(TriMapObject* tm,
|
|
|
834
835
|
return 0;
|
|
835
836
|
}
|
|
836
837
|
|
|
838
|
+
// Returns -1 on error. Specialized transfer from any type of an array to an object array. For usage with merge, Will only transfer if the destination is not NULL.
|
|
839
|
+
static inline int
|
|
840
|
+
AK_TM_transfer_object_if_null(TriMapObject* tm,
|
|
841
|
+
bool from_src,
|
|
842
|
+
PyArrayObject* array_from,
|
|
843
|
+
PyArrayObject* array_to
|
|
844
|
+
) {
|
|
845
|
+
Py_ssize_t one_count = from_src ? tm->src_one_count : tm->dst_one_count;
|
|
846
|
+
TriMapOne* one_pairs = from_src ? tm->src_one : tm->dst_one;
|
|
847
|
+
|
|
848
|
+
// NOTE: could use PyArray_Scalar instead of PyArray_GETITEM if we wanted to store scalars instead of Python objects; however, that is pretty uncommon for object arrays to store PyArray_Scalars
|
|
849
|
+
bool f_is_obj = PyArray_TYPE(array_from) == NPY_OBJECT;
|
|
850
|
+
|
|
851
|
+
// the passed in object array is contiguous and have NULL (not None) in each position
|
|
852
|
+
PyObject** array_to_data = (PyObject**)PyArray_DATA(array_to);
|
|
853
|
+
PyObject* pyo;
|
|
854
|
+
void* f;
|
|
855
|
+
TriMapOne* o = one_pairs;
|
|
856
|
+
TriMapOne* o_end = o + one_count;
|
|
857
|
+
for (; o < o_end; o++) {
|
|
858
|
+
if (array_to_data[o->to] == NULL) {
|
|
859
|
+
f = PyArray_GETPTR1(array_from, o->from);
|
|
860
|
+
if (f_is_obj) {
|
|
861
|
+
pyo = *(PyObject**)f;
|
|
862
|
+
Py_INCREF(pyo);
|
|
863
|
+
}
|
|
864
|
+
else { // will convert any value to an object
|
|
865
|
+
pyo = PyArray_GETITEM(array_from, f);
|
|
866
|
+
}
|
|
867
|
+
array_to_data[o->to] = pyo;
|
|
868
|
+
}
|
|
869
|
+
}
|
|
870
|
+
PyObject** t;
|
|
871
|
+
PyObject** t_end;
|
|
872
|
+
npy_intp dst_pos;
|
|
873
|
+
npy_int64 f_pos;
|
|
874
|
+
PyArrayObject* dst;
|
|
875
|
+
for (Py_ssize_t i = 0; i < tm->many_count; i++) {
|
|
876
|
+
t = array_to_data + tm->many_to[i].start;
|
|
877
|
+
t_end = array_to_data + tm->many_to[i].stop;
|
|
878
|
+
|
|
879
|
+
if (from_src) {
|
|
880
|
+
while (t < t_end) {
|
|
881
|
+
if (*t == NULL) {
|
|
882
|
+
f = PyArray_GETPTR1(array_from, tm->many_from[i].src);
|
|
883
|
+
if (f_is_obj) {
|
|
884
|
+
pyo = *(PyObject**)f;
|
|
885
|
+
Py_INCREF(pyo);
|
|
886
|
+
}
|
|
887
|
+
else {
|
|
888
|
+
pyo = PyArray_GETITEM(array_from, f); // given a new ref
|
|
889
|
+
}
|
|
890
|
+
*t++ = pyo;
|
|
891
|
+
}
|
|
892
|
+
else {
|
|
893
|
+
t++;
|
|
894
|
+
}
|
|
895
|
+
}
|
|
896
|
+
}
|
|
897
|
+
else { // from_dst, dst is an array
|
|
898
|
+
dst_pos = 0;
|
|
899
|
+
dst = tm->many_from[i].dst;
|
|
900
|
+
while (t < t_end) {
|
|
901
|
+
if (*t == NULL) {
|
|
902
|
+
f_pos = *(npy_int64*)PyArray_GETPTR1(dst, dst_pos);
|
|
903
|
+
f = PyArray_GETPTR1(array_from, f_pos);
|
|
904
|
+
if (f_is_obj) {
|
|
905
|
+
pyo = *(PyObject**)f;
|
|
906
|
+
Py_INCREF(pyo);
|
|
907
|
+
}
|
|
908
|
+
else {
|
|
909
|
+
pyo = PyArray_GETITEM(array_from, f);
|
|
910
|
+
}
|
|
911
|
+
*t++ = pyo;
|
|
912
|
+
dst_pos++;
|
|
913
|
+
}
|
|
914
|
+
else {
|
|
915
|
+
t++;
|
|
916
|
+
dst_pos++;
|
|
917
|
+
}
|
|
918
|
+
}
|
|
919
|
+
}
|
|
920
|
+
}
|
|
921
|
+
return 0;
|
|
922
|
+
}
|
|
923
|
+
|
|
837
924
|
// Returns -1 on error.
|
|
838
925
|
static inline int
|
|
839
926
|
AK_TM_fill_object(TriMapObject* tm,
|
|
@@ -855,7 +942,7 @@ AK_TM_fill_object(TriMapObject* tm,
|
|
|
855
942
|
return 0;
|
|
856
943
|
}
|
|
857
944
|
|
|
858
|
-
#define AK_TM_TRANSFER_FLEXIBLE(c_type) do {
|
|
945
|
+
#define AK_TM_TRANSFER_FLEXIBLE(c_type, from_src, array_from, array_to) do {\
|
|
859
946
|
Py_ssize_t one_count = from_src ? tm->src_one_count : tm->dst_one_count;\
|
|
860
947
|
TriMapOne* one_pairs = from_src ? tm->src_one : tm->dst_one; \
|
|
861
948
|
npy_intp t_element_size = PyArray_ITEMSIZE(array_to); \
|
|
@@ -1003,10 +1090,10 @@ AK_TM_map_no_fill(TriMapObject* tm,
|
|
|
1003
1090
|
}
|
|
1004
1091
|
}
|
|
1005
1092
|
else if (dtype_is_unicode) {
|
|
1006
|
-
AK_TM_TRANSFER_FLEXIBLE(Py_UCS4);
|
|
1093
|
+
AK_TM_TRANSFER_FLEXIBLE(Py_UCS4, from_src, array_from, array_to);
|
|
1007
1094
|
}
|
|
1008
1095
|
else if (dtype_is_string) {
|
|
1009
|
-
AK_TM_TRANSFER_FLEXIBLE(char);
|
|
1096
|
+
AK_TM_TRANSFER_FLEXIBLE(char, from_src, array_from, array_to);
|
|
1010
1097
|
}
|
|
1011
1098
|
else {
|
|
1012
1099
|
if (AK_TM_transfer_scalar(tm, from_src, array_from, array_to)) {
|
|
@@ -1048,6 +1135,102 @@ TriMap_map_dst_no_fill(TriMapObject *self, PyObject *arg) {
|
|
|
1048
1135
|
return AK_TM_map_no_fill(self, from_src, array_from);
|
|
1049
1136
|
}
|
|
1050
1137
|
|
|
1138
|
+
static inline PyObject *
|
|
1139
|
+
TriMap_map_merge(TriMapObject *tm, PyObject *args)
|
|
1140
|
+
{
|
|
1141
|
+
// both are "from_" arrays
|
|
1142
|
+
PyArrayObject* array_src;
|
|
1143
|
+
PyArrayObject* array_dst;
|
|
1144
|
+
|
|
1145
|
+
if (!PyArg_ParseTuple(args,
|
|
1146
|
+
"O!O!:map_merge",
|
|
1147
|
+
&PyArray_Type, &array_src,
|
|
1148
|
+
&PyArray_Type, &array_dst
|
|
1149
|
+
)) {
|
|
1150
|
+
return NULL;
|
|
1151
|
+
}
|
|
1152
|
+
if (!tm->finalized) {
|
|
1153
|
+
PyErr_SetString(PyExc_RuntimeError, "Finalization is required");
|
|
1154
|
+
return NULL;
|
|
1155
|
+
}
|
|
1156
|
+
if (!(PyArray_NDIM(array_src) == 1)) {
|
|
1157
|
+
PyErr_SetString(PyExc_TypeError, "Array src must be 1D");
|
|
1158
|
+
return NULL;
|
|
1159
|
+
}
|
|
1160
|
+
if (!(PyArray_NDIM(array_dst) == 1)) {
|
|
1161
|
+
PyErr_SetString(PyExc_TypeError, "Array dst must be 1D");
|
|
1162
|
+
return NULL;
|
|
1163
|
+
}
|
|
1164
|
+
// passing a borrowed refs; returns a new ref
|
|
1165
|
+
PyArray_Descr* dtype = AK_resolve_dtype(
|
|
1166
|
+
PyArray_DESCR(array_src),
|
|
1167
|
+
PyArray_DESCR(array_dst));
|
|
1168
|
+
bool dtype_is_obj = dtype->type_num == NPY_OBJECT;
|
|
1169
|
+
bool dtype_is_unicode = dtype->type_num == NPY_UNICODE;
|
|
1170
|
+
bool dtype_is_string = dtype->type_num == NPY_STRING;
|
|
1171
|
+
|
|
1172
|
+
npy_intp dims[] = {tm->len};
|
|
1173
|
+
|
|
1174
|
+
// create to array_to
|
|
1175
|
+
PyArrayObject* array_to;
|
|
1176
|
+
if (dtype_is_obj) {
|
|
1177
|
+
Py_DECREF(dtype); // not needed
|
|
1178
|
+
// will initialize to NULL, not None
|
|
1179
|
+
array_to = (PyArrayObject*)PyArray_SimpleNew(1, dims, NPY_OBJECT);
|
|
1180
|
+
}
|
|
1181
|
+
else if (dtype_is_unicode || dtype_is_string) {
|
|
1182
|
+
array_to = (PyArrayObject*)PyArray_Zeros(1, dims, dtype, 0); // steals dtype ref
|
|
1183
|
+
}
|
|
1184
|
+
else {
|
|
1185
|
+
array_to = (PyArrayObject*)PyArray_Empty(1, dims, dtype, 0); // steals dtype ref
|
|
1186
|
+
}
|
|
1187
|
+
if (array_to == NULL) {
|
|
1188
|
+
PyErr_SetNone(PyExc_MemoryError);
|
|
1189
|
+
return NULL;
|
|
1190
|
+
}
|
|
1191
|
+
|
|
1192
|
+
// if we have fill values in src, we need to transfer from dst
|
|
1193
|
+
bool transfer_from_dst = PyArray_SIZE((PyArrayObject*)tm->final_src_fill) != 0;
|
|
1194
|
+
|
|
1195
|
+
if (dtype_is_obj) {
|
|
1196
|
+
if (AK_TM_transfer_object(tm, true, array_src, array_to)) {
|
|
1197
|
+
Py_DECREF((PyObject*)array_to);
|
|
1198
|
+
return NULL;
|
|
1199
|
+
}
|
|
1200
|
+
if (transfer_from_dst) {
|
|
1201
|
+
if (AK_TM_transfer_object_if_null(tm, false, array_dst, array_to)) {
|
|
1202
|
+
Py_DECREF((PyObject*)array_to);
|
|
1203
|
+
return NULL;
|
|
1204
|
+
}
|
|
1205
|
+
}
|
|
1206
|
+
}
|
|
1207
|
+
else if (dtype_is_unicode) {
|
|
1208
|
+
AK_TM_TRANSFER_FLEXIBLE(Py_UCS4, true, array_src, array_to);
|
|
1209
|
+
if (transfer_from_dst) {
|
|
1210
|
+
AK_TM_TRANSFER_FLEXIBLE(Py_UCS4, false, array_dst, array_to);
|
|
1211
|
+
}
|
|
1212
|
+
}
|
|
1213
|
+
else if (dtype_is_string) {
|
|
1214
|
+
AK_TM_TRANSFER_FLEXIBLE(char, true, array_src, array_to);
|
|
1215
|
+
if (transfer_from_dst) {
|
|
1216
|
+
AK_TM_TRANSFER_FLEXIBLE(char, false, array_dst, array_to);
|
|
1217
|
+
}
|
|
1218
|
+
}
|
|
1219
|
+
else {
|
|
1220
|
+
if (AK_TM_transfer_scalar(tm, true, array_src, array_to)) {
|
|
1221
|
+
Py_DECREF((PyObject*)array_to);
|
|
1222
|
+
return NULL;
|
|
1223
|
+
}
|
|
1224
|
+
if (transfer_from_dst) {
|
|
1225
|
+
if (AK_TM_transfer_scalar(tm, false, array_dst, array_to)) {
|
|
1226
|
+
Py_DECREF((PyObject*)array_to);
|
|
1227
|
+
return NULL;
|
|
1228
|
+
}
|
|
1229
|
+
}
|
|
1230
|
+
}
|
|
1231
|
+
return (PyObject*)array_to;
|
|
1232
|
+
}
|
|
1233
|
+
|
|
1051
1234
|
// Returns NULL on error.
|
|
1052
1235
|
static inline PyObject *
|
|
1053
1236
|
AK_TM_map_fill(TriMapObject* tm,
|
|
@@ -1108,19 +1291,19 @@ AK_TM_map_fill(TriMapObject* tm,
|
|
|
1108
1291
|
}
|
|
1109
1292
|
}
|
|
1110
1293
|
else if (dtype_is_unicode) {
|
|
1111
|
-
AK_TM_TRANSFER_FLEXIBLE(Py_UCS4);
|
|
1294
|
+
AK_TM_TRANSFER_FLEXIBLE(Py_UCS4, from_src, array_from, array_to);
|
|
1112
1295
|
if (AK_TM_fill_unicode(tm, from_src, array_to, fill_value)) {
|
|
1113
1296
|
goto error;
|
|
1114
1297
|
}
|
|
1115
1298
|
}
|
|
1116
1299
|
else if (dtype_is_string) {
|
|
1117
|
-
AK_TM_TRANSFER_FLEXIBLE(char);
|
|
1300
|
+
AK_TM_TRANSFER_FLEXIBLE(char, from_src, array_from, array_to);
|
|
1118
1301
|
if (AK_TM_fill_string(tm, from_src, array_to, fill_value)) {
|
|
1119
1302
|
goto error;
|
|
1120
1303
|
}
|
|
1121
1304
|
}
|
|
1122
1305
|
else {
|
|
1123
|
-
// 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
|
|
1306
|
+
// 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 obligates us to decref the filled value when assigning
|
|
1124
1307
|
if (PyArray_FillWithScalar(array_to, fill_value)) { // -1 on error
|
|
1125
1308
|
goto error;
|
|
1126
1309
|
}
|
|
@@ -1180,6 +1363,8 @@ TriMap_map_dst_fill(TriMapObject *self, PyObject *args) {
|
|
|
1180
1363
|
return AK_TM_map_fill(self, from_src, array_from, fill_value, fill_value_dtype);
|
|
1181
1364
|
}
|
|
1182
1365
|
|
|
1366
|
+
|
|
1367
|
+
|
|
1183
1368
|
static PyMethodDef TriMap_methods[] = {
|
|
1184
1369
|
{"register_one", (PyCFunction)TriMap_register_one, METH_VARARGS, NULL},
|
|
1185
1370
|
{"register_unmatched_dst", (PyCFunction)TriMap_register_unmatched_dst, METH_NOARGS, NULL},
|
|
@@ -1192,6 +1377,7 @@ static PyMethodDef TriMap_methods[] = {
|
|
|
1192
1377
|
{"map_dst_no_fill", (PyCFunction)TriMap_map_dst_no_fill, METH_O, NULL},
|
|
1193
1378
|
{"map_src_fill", (PyCFunction)TriMap_map_src_fill, METH_VARARGS, NULL},
|
|
1194
1379
|
{"map_dst_fill", (PyCFunction)TriMap_map_dst_fill, METH_VARARGS, NULL},
|
|
1380
|
+
{"map_merge", (PyCFunction)TriMap_map_merge, METH_VARARGS, NULL},
|
|
1195
1381
|
{NULL},
|
|
1196
1382
|
};
|
|
1197
1383
|
|
|
@@ -1137,3 +1137,179 @@ class TestUnit(unittest.TestCase):
|
|
|
1137
1137
|
self.assertEqual(post_dst.dtype, np.dtype('datetime64[D]'))
|
|
1138
1138
|
self.assertEqual([str(dt) for dt in post_dst],
|
|
1139
1139
|
['2022-01-01', '2022-01-01', '2022-01-01', '1999-09-09', '1743-09-01', '1743-09-01', '1999-09-09', '2005-11-01'])
|
|
1140
|
+
|
|
1141
|
+
#---------------------------------------------------------------------------
|
|
1142
|
+
|
|
1143
|
+
def test_tri_map_merge_a(self) -> None:
|
|
1144
|
+
src = np.array([0, 200, 300, 400, 0], dtype=np.int64)
|
|
1145
|
+
dst = np.array([300, 400, 0, 200, 300], dtype=np.int64)
|
|
1146
|
+
|
|
1147
|
+
tm = TriMap(len(src), len(dst))
|
|
1148
|
+
tm.register_one(0, 2)
|
|
1149
|
+
tm.register_one(1, 3)
|
|
1150
|
+
tm.register_many(2, np.array([0, 4], dtype=np.dtype(np.int64)))
|
|
1151
|
+
tm.register_one(3, 1)
|
|
1152
|
+
tm.register_one(4, 2)
|
|
1153
|
+
|
|
1154
|
+
with self.assertRaises(RuntimeError):
|
|
1155
|
+
_ = tm.map_merge(src, dst)
|
|
1156
|
+
|
|
1157
|
+
tm.finalize()
|
|
1158
|
+
|
|
1159
|
+
with self.assertRaises(TypeError):
|
|
1160
|
+
_ = tm.map_merge(3, dst)
|
|
1161
|
+
|
|
1162
|
+
with self.assertRaises(TypeError):
|
|
1163
|
+
_ = tm.map_merge(src, 3)
|
|
1164
|
+
|
|
1165
|
+
with self.assertRaises(TypeError):
|
|
1166
|
+
_ = tm.map_merge(src.reshape(5, 1), dst)
|
|
1167
|
+
|
|
1168
|
+
with self.assertRaises(TypeError):
|
|
1169
|
+
_ = tm.map_merge(src, dst.reshape(5, 1))
|
|
1170
|
+
|
|
1171
|
+
|
|
1172
|
+
def test_tri_map_merge_a(self) -> None:
|
|
1173
|
+
src = np.array([0, 200, 300, 400, 0], dtype=np.int64)
|
|
1174
|
+
dst = np.array([300, 400, 0, 200, 300, 50, 50], dtype=np.int64)
|
|
1175
|
+
|
|
1176
|
+
tm = TriMap(len(src), len(dst))
|
|
1177
|
+
tm.register_one(0, 2)
|
|
1178
|
+
tm.register_one(1, 3)
|
|
1179
|
+
tm.register_many(2, np.array([0, 4], dtype=np.dtype(np.int64)))
|
|
1180
|
+
tm.register_one(3, 1)
|
|
1181
|
+
tm.register_one(4, 2)
|
|
1182
|
+
tm.register_unmatched_dst()
|
|
1183
|
+
tm.finalize()
|
|
1184
|
+
|
|
1185
|
+
post = tm.map_merge(src, dst)
|
|
1186
|
+
self.assertEqual(post.tolist(), [0, 200, 300, 300, 400, 0, 50, 50])
|
|
1187
|
+
|
|
1188
|
+
def test_tri_map_merge_b(self) -> None:
|
|
1189
|
+
src = np.array([0, 200, 300, 400], dtype=np.int64)
|
|
1190
|
+
dst = np.array([50, 80, 200, 300, 0, 200, 300, 70, 80], dtype=np.int32)
|
|
1191
|
+
|
|
1192
|
+
tm = TriMap(len(src), len(dst))
|
|
1193
|
+
tm.register_one(0, 4)
|
|
1194
|
+
tm.register_many(1, np.array([2, 5], dtype=np.dtype(np.int64)))
|
|
1195
|
+
tm.register_many(2, np.array([3, 6], dtype=np.dtype(np.int64)))
|
|
1196
|
+
tm.register_one(3, -1)
|
|
1197
|
+
tm.register_unmatched_dst()
|
|
1198
|
+
tm.finalize()
|
|
1199
|
+
|
|
1200
|
+
post = tm.map_merge(src, dst)
|
|
1201
|
+
self.assertEqual(post.tolist(), [0, 200, 200, 300, 300, 400, 50, 80, 70, 80])
|
|
1202
|
+
|
|
1203
|
+
def test_tri_map_merge_c(self) -> None:
|
|
1204
|
+
src = np.array([0, 200, 300, 400], dtype=np.int64)
|
|
1205
|
+
dst = np.array([400, 200, 300], dtype=np.int64)
|
|
1206
|
+
|
|
1207
|
+
tm = TriMap(len(src), len(dst))
|
|
1208
|
+
tm.register_one(0, -1)
|
|
1209
|
+
tm.register_one(1, 1)
|
|
1210
|
+
tm.register_one(2, 2)
|
|
1211
|
+
tm.register_one(3, 0)
|
|
1212
|
+
tm.register_unmatched_dst()
|
|
1213
|
+
tm.finalize()
|
|
1214
|
+
|
|
1215
|
+
post = tm.map_merge(src, dst)
|
|
1216
|
+
self.assertEqual(post.tolist(), [0, 200, 300, 400])
|
|
1217
|
+
|
|
1218
|
+
def test_tri_map_merge_d(self) -> None:
|
|
1219
|
+
src = np.array(['a', 'bbb', 'cc', 'dddd'])
|
|
1220
|
+
dst = np.array(['cc', 'a', 'a', 'ee', 'cc'])
|
|
1221
|
+
|
|
1222
|
+
tm = TriMap(len(src), len(dst))
|
|
1223
|
+
tm.register_many(0, np.array([1, 2], dtype=np.dtype(np.int64)))
|
|
1224
|
+
tm.register_one(1, -1)
|
|
1225
|
+
tm.register_many(2, np.array([0, 4], dtype=np.dtype(np.int64)))
|
|
1226
|
+
tm.register_one(3, -1)
|
|
1227
|
+
tm.register_unmatched_dst()
|
|
1228
|
+
tm.finalize()
|
|
1229
|
+
|
|
1230
|
+
post = tm.map_merge(src, dst)
|
|
1231
|
+
self.assertEqual(post.tolist(), ['a', 'a', 'bbb', 'cc', 'cc', 'dddd', 'ee'])
|
|
1232
|
+
|
|
1233
|
+
|
|
1234
|
+
|
|
1235
|
+
def test_tri_map_merge_e(self) -> None:
|
|
1236
|
+
src = np.array([None, False, -42, 'dddd'], dtype=object)
|
|
1237
|
+
dst = np.array([-42, None, None, 'ee', -42], dtype=object)
|
|
1238
|
+
|
|
1239
|
+
tm = TriMap(len(src), len(dst))
|
|
1240
|
+
tm.register_many(0, np.array([1, 2], dtype=np.dtype(np.int64)))
|
|
1241
|
+
tm.register_one(1, -1)
|
|
1242
|
+
tm.register_many(2, np.array([0, 4], dtype=np.dtype(np.int64)))
|
|
1243
|
+
tm.register_one(3, -1)
|
|
1244
|
+
tm.register_unmatched_dst()
|
|
1245
|
+
tm.finalize()
|
|
1246
|
+
|
|
1247
|
+
post = tm.map_merge(src, dst)
|
|
1248
|
+
self.assertEqual(post.tolist(), [None, None, False, -42, -42, 'dddd', 'ee'])
|
|
1249
|
+
|
|
1250
|
+
def test_tri_map_merge_f(self) -> None:
|
|
1251
|
+
src = np.array([None, False, -42,], dtype=object)
|
|
1252
|
+
dst = np.array([True, 'ee', 88], dtype=object)
|
|
1253
|
+
|
|
1254
|
+
tm = TriMap(len(src), len(dst))
|
|
1255
|
+
tm.register_one(0, -1)
|
|
1256
|
+
tm.register_one(1, -1)
|
|
1257
|
+
tm.register_one(2, -1)
|
|
1258
|
+
tm.register_unmatched_dst()
|
|
1259
|
+
tm.finalize()
|
|
1260
|
+
|
|
1261
|
+
post = tm.map_merge(src, dst)
|
|
1262
|
+
self.assertEqual(post.tolist(), [None, False, -42, True, 'ee', 88])
|
|
1263
|
+
|
|
1264
|
+
def test_tri_map_merge_g(self) -> None:
|
|
1265
|
+
src = np.array([None, False, -42,], dtype=object)
|
|
1266
|
+
dst = np.array([None, False, -42, 'ee', 'ff'], dtype=object)
|
|
1267
|
+
|
|
1268
|
+
tm = TriMap(len(src), len(dst))
|
|
1269
|
+
tm.register_one(0, 0)
|
|
1270
|
+
tm.register_one(1, 1)
|
|
1271
|
+
tm.register_one(2, 2)
|
|
1272
|
+
tm.register_unmatched_dst()
|
|
1273
|
+
tm.finalize()
|
|
1274
|
+
|
|
1275
|
+
post = tm.map_merge(src, dst)
|
|
1276
|
+
self.assertEqual(post.tolist(), [None, False, -42, 'ee', 'ff'])
|
|
1277
|
+
|
|
1278
|
+
def test_tri_map_merge_h(self) -> None:
|
|
1279
|
+
src = np.array([0, 200, 300, 40], dtype=np.int64)
|
|
1280
|
+
dst = np.array([0, 200, 300, 40, 50], dtype=np.int64)
|
|
1281
|
+
|
|
1282
|
+
tm = TriMap(len(src), len(dst))
|
|
1283
|
+
tm.register_one(0, 0)
|
|
1284
|
+
tm.register_one(1, 1)
|
|
1285
|
+
tm.register_one(2, 2)
|
|
1286
|
+
tm.register_one(3, 3)
|
|
1287
|
+
tm.register_unmatched_dst()
|
|
1288
|
+
tm.finalize()
|
|
1289
|
+
|
|
1290
|
+
post = tm.map_merge(src, dst)
|
|
1291
|
+
self.assertEqual(post.tolist(), [0, 200, 300, 40, 50])
|
|
1292
|
+
|
|
1293
|
+
def test_tri_map_merge_i(self) -> None:
|
|
1294
|
+
src = np.array(['2022-01', '1954-03', '1743-09', '1988-12'], dtype=np.datetime64)
|
|
1295
|
+
dst = np.array(['1743-09', '2022-01', '2022-01', '2022-01', '1743-09', '2005-11'], dtype=np.datetime64)
|
|
1296
|
+
|
|
1297
|
+
tm = TriMap(len(src), len(dst))
|
|
1298
|
+
tm.register_many(0, np.array([1, 2, 3], dtype=np.dtype(np.int64)))
|
|
1299
|
+
tm.register_one(1, -1)
|
|
1300
|
+
tm.register_many(2, np.array([0, 4], dtype=np.dtype(np.int64)))
|
|
1301
|
+
tm.register_one(3, -1)
|
|
1302
|
+
tm.register_unmatched_dst()
|
|
1303
|
+
tm.finalize()
|
|
1304
|
+
|
|
1305
|
+
post = tm.map_merge(src, dst)
|
|
1306
|
+
self.assertEqual(list(post),
|
|
1307
|
+
[np.datetime64('2022-01'),
|
|
1308
|
+
np.datetime64('2022-01'),
|
|
1309
|
+
np.datetime64('2022-01'),
|
|
1310
|
+
np.datetime64('1954-03'),
|
|
1311
|
+
np.datetime64('1743-09'),
|
|
1312
|
+
np.datetime64('1743-09'),
|
|
1313
|
+
np.datetime64('1988-12'),
|
|
1314
|
+
np.datetime64('2005-11')]
|
|
1315
|
+
)
|
|
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
|
|
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
|