arraykit 0.8.3__tar.gz → 0.9.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.
Files changed (40) hide show
  1. {arraykit-0.8.3/arraykit.egg-info → arraykit-0.9.0}/PKG-INFO +1 -1
  2. {arraykit-0.8.3 → arraykit-0.9.0}/README.rst +6 -0
  3. {arraykit-0.8.3 → arraykit-0.9.0/arraykit.egg-info}/PKG-INFO +1 -1
  4. {arraykit-0.8.3 → arraykit-0.9.0}/setup.py +1 -1
  5. {arraykit-0.8.3 → arraykit-0.9.0}/src/__init__.pyi +11 -7
  6. {arraykit-0.8.3 → arraykit-0.9.0}/src/tri_map.c +194 -8
  7. {arraykit-0.8.3 → arraykit-0.9.0}/test/test_tri_map.py +176 -0
  8. {arraykit-0.8.3 → arraykit-0.9.0}/LICENSE.txt +0 -0
  9. {arraykit-0.8.3 → arraykit-0.9.0}/MANIFEST.in +0 -0
  10. {arraykit-0.8.3 → arraykit-0.9.0}/arraykit.egg-info/SOURCES.txt +0 -0
  11. {arraykit-0.8.3 → arraykit-0.9.0}/arraykit.egg-info/dependency_links.txt +0 -0
  12. {arraykit-0.8.3 → arraykit-0.9.0}/arraykit.egg-info/requires.txt +0 -0
  13. {arraykit-0.8.3 → arraykit-0.9.0}/arraykit.egg-info/top_level.txt +0 -0
  14. {arraykit-0.8.3 → arraykit-0.9.0}/setup.cfg +0 -0
  15. {arraykit-0.8.3 → arraykit-0.9.0}/src/__init__.py +0 -0
  16. {arraykit-0.8.3 → arraykit-0.9.0}/src/_arraykit.c +0 -0
  17. {arraykit-0.8.3 → arraykit-0.9.0}/src/array_go.c +0 -0
  18. {arraykit-0.8.3 → arraykit-0.9.0}/src/array_go.h +0 -0
  19. {arraykit-0.8.3 → arraykit-0.9.0}/src/array_to_tuple.c +0 -0
  20. {arraykit-0.8.3 → arraykit-0.9.0}/src/array_to_tuple.h +0 -0
  21. {arraykit-0.8.3 → arraykit-0.9.0}/src/block_index.c +0 -0
  22. {arraykit-0.8.3 → arraykit-0.9.0}/src/block_index.h +0 -0
  23. {arraykit-0.8.3 → arraykit-0.9.0}/src/delimited_to_arrays.c +0 -0
  24. {arraykit-0.8.3 → arraykit-0.9.0}/src/delimited_to_arrays.h +0 -0
  25. {arraykit-0.8.3 → arraykit-0.9.0}/src/methods.c +0 -0
  26. {arraykit-0.8.3 → arraykit-0.9.0}/src/methods.h +0 -0
  27. {arraykit-0.8.3 → arraykit-0.9.0}/src/py.typed +0 -0
  28. {arraykit-0.8.3 → arraykit-0.9.0}/src/tri_map.h +0 -0
  29. {arraykit-0.8.3 → arraykit-0.9.0}/src/utilities.h +0 -0
  30. {arraykit-0.8.3 → arraykit-0.9.0}/test/test_array_go.py +0 -0
  31. {arraykit-0.8.3 → arraykit-0.9.0}/test/test_block_index.py +0 -0
  32. {arraykit-0.8.3 → arraykit-0.9.0}/test/test_delimited_to_arrays.py +0 -0
  33. {arraykit-0.8.3 → arraykit-0.9.0}/test/test_delimited_to_arrays_integration.py +0 -0
  34. {arraykit-0.8.3 → arraykit-0.9.0}/test/test_delimited_to_arrays_property.py +0 -0
  35. {arraykit-0.8.3 → arraykit-0.9.0}/test/test_nonzero_1d.py +0 -0
  36. {arraykit-0.8.3 → arraykit-0.9.0}/test/test_nonzero_1d_property.py +0 -0
  37. {arraykit-0.8.3 → arraykit-0.9.0}/test/test_pyi.py +0 -0
  38. {arraykit-0.8.3 → arraykit-0.9.0}/test/test_split_after_count.py +0 -0
  39. {arraykit-0.8.3 → arraykit-0.9.0}/test/test_type_discovery.py +0 -0
  40. {arraykit-0.8.3 → arraykit-0.9.0}/test/test_util.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: arraykit
3
- Version: 0.8.3
3
+ Version: 0.9.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
@@ -37,6 +37,12 @@ ArrayKit requires the following:
37
37
  What is New in ArrayKit
38
38
  -------------------------
39
39
 
40
+ 0.9.0
41
+ ............
42
+
43
+ Added ``TriMap.map_merge()``.
44
+
45
+
40
46
  0.8.3
41
47
  ............
42
48
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: arraykit
3
- Version: 0.8.3
3
+ Version: 0.9.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
@@ -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.3'
8
+ AK_VERSION = '0.9.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.
@@ -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 assumed to be contiguous and have NULL (not None) in each position
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 one
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 obbligates us to decref the filled value when assigning
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