arraykit 0.6.2__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.
Files changed (27) hide show
  1. {arraykit-0.6.2/arraykit.egg-info → arraykit-0.6.3}/PKG-INFO +1 -1
  2. {arraykit-0.6.2 → arraykit-0.6.3}/README.rst +7 -1
  3. {arraykit-0.6.2 → arraykit-0.6.3/arraykit.egg-info}/PKG-INFO +1 -1
  4. {arraykit-0.6.2 → arraykit-0.6.3}/setup.py +1 -1
  5. {arraykit-0.6.2 → arraykit-0.6.3}/src/_arraykit.c +35 -62
  6. {arraykit-0.6.2 → arraykit-0.6.3}/LICENSE.txt +0 -0
  7. {arraykit-0.6.2 → arraykit-0.6.3}/MANIFEST.in +0 -0
  8. {arraykit-0.6.2 → arraykit-0.6.3}/arraykit.egg-info/SOURCES.txt +0 -0
  9. {arraykit-0.6.2 → arraykit-0.6.3}/arraykit.egg-info/dependency_links.txt +0 -0
  10. {arraykit-0.6.2 → arraykit-0.6.3}/arraykit.egg-info/requires.txt +0 -0
  11. {arraykit-0.6.2 → arraykit-0.6.3}/arraykit.egg-info/top_level.txt +0 -0
  12. {arraykit-0.6.2 → arraykit-0.6.3}/setup.cfg +0 -0
  13. {arraykit-0.6.2 → arraykit-0.6.3}/src/__init__.py +0 -0
  14. {arraykit-0.6.2 → arraykit-0.6.3}/src/__init__.pyi +0 -0
  15. {arraykit-0.6.2 → arraykit-0.6.3}/src/py.typed +0 -0
  16. {arraykit-0.6.2 → arraykit-0.6.3}/test/test_array_go.py +0 -0
  17. {arraykit-0.6.2 → arraykit-0.6.3}/test/test_block_index.py +0 -0
  18. {arraykit-0.6.2 → arraykit-0.6.3}/test/test_delimited_to_arrays.py +0 -0
  19. {arraykit-0.6.2 → arraykit-0.6.3}/test/test_delimited_to_arrays_integration.py +0 -0
  20. {arraykit-0.6.2 → arraykit-0.6.3}/test/test_delimited_to_arrays_property.py +0 -0
  21. {arraykit-0.6.2 → arraykit-0.6.3}/test/test_nonzero_1d.py +0 -0
  22. {arraykit-0.6.2 → arraykit-0.6.3}/test/test_nonzero_1d_property.py +0 -0
  23. {arraykit-0.6.2 → arraykit-0.6.3}/test/test_pyi.py +0 -0
  24. {arraykit-0.6.2 → arraykit-0.6.3}/test/test_split_after_count.py +0 -0
  25. {arraykit-0.6.2 → arraykit-0.6.3}/test/test_tri_map.py +0 -0
  26. {arraykit-0.6.2 → arraykit-0.6.3}/test/test_type_discovery.py +0 -0
  27. {arraykit-0.6.2 → arraykit-0.6.3}/test/test_util.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: arraykit
3
- Version: 0.6.2
3
+ Version: 0.6.3
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,10 +37,16 @@ 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
+
40
46
  0.6.2
41
47
  ............
42
48
 
43
- Extended ``nonzero_1d()`` to support non-contiguous arrays,
49
+ Extended ``nonzero_1d()`` to support non-contiguous arrays.
44
50
 
45
51
  Optimizations to ``TriMap`` when mapping to object and flexible dtypes.
46
52
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: arraykit
3
- Version: 0.6.2
3
+ Version: 0.6.3
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.6.2'
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 ERROR_NO_DIGITS 1
840
- #define ERROR_OVERFLOW 2
841
- #define ERROR_INVALID_CHARS 3
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 = ERROR_NO_DIGITS;
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 = ERROR_OVERFLOW;
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 = ERROR_OVERFLOW;
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 = ERROR_OVERFLOW;
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 = ERROR_OVERFLOW;
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 = ERROR_INVALID_CHARS;
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 = ERROR_INVALID_CHARS;
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 = ERROR_NO_DIGITS;
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 = ERROR_OVERFLOW;
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 = ERROR_OVERFLOW;
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 = ERROR_INVALID_CHARS;
1029
+ *error = AK_ERROR_INVALID_CHARS;
1030
1030
  return 0;
1031
1031
  }
1032
1032
  p++;
@@ -3535,32 +3535,9 @@ resolve_dtype_iter(PyObject *Py_UNUSED(m), PyObject *arg) {
3535
3535
  //------------------------------------------------------------------------------
3536
3536
  // general utility
3537
3537
 
3538
- #define NONZERO_APPEND_INDEX_RELATIVE { \
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
- #define NONZERO_APPEND_INDEX_ABSOLUTE { \
3550
- if (AK_UNLIKELY(count == capacity)) { \
3551
- capacity <<= 1; \
3552
- indices = (npy_int64*)realloc(indices, sizeof(npy_int64) * capacity);\
3553
- if (indices == NULL) { \
3554
- return NULL; \
3555
- } \
3556
- } \
3557
- indices[count++] = i; \
3558
- } \
3559
-
3560
- // 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 does not permit outperforming NumPy at 10_000_000 scale; but doing less optimizations does help. Using bit masks does not improve perforamnce over pointer arithmetic. Prescanning for all empty is very effective. Note that NumPy befits from first counting the nonzeros, then allocating only enough data for the expexted number.
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.
3561
3539
  static inline PyObject*
3562
3540
  AK_nonzero_1d(PyArrayObject* array) {
3563
- // 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
3564
3541
  PyObject* final;
3565
3542
  npy_intp count_max = PyArray_SIZE(array);
3566
3543
 
@@ -3573,8 +3550,8 @@ AK_nonzero_1d(PyArrayObject* array) {
3573
3550
  lldiv_t size_div = lldiv((long long)count_max, 8); // quot, rem
3574
3551
 
3575
3552
  Py_ssize_t count = 0;
3576
- // the maximum number of collected integers is equal to or less than count_max; for small count_max, we can just set that value; for large size, we set it to half the size
3577
- Py_ssize_t capacity = count_max < 1024 ? count_max : count_max / 8;
3553
+ // the maximum number of collected integers is equal to or less than count_max
3554
+ Py_ssize_t capacity = count_max;
3578
3555
  npy_int64* indices = (npy_int64*)malloc(sizeof(npy_int64) * capacity);
3579
3556
 
3580
3557
  NPY_BEGIN_THREADS_DEF;
@@ -3591,25 +3568,25 @@ AK_nonzero_1d(PyArrayObject* array) {
3591
3568
  p += 8; // no true within this 8 byte roll region
3592
3569
  continue;
3593
3570
  }
3594
- if (*p) {NONZERO_APPEND_INDEX_RELATIVE;}
3571
+ if (*p) {indices[count++] = p - p_start;}
3595
3572
  p++;
3596
- if (*p) {NONZERO_APPEND_INDEX_RELATIVE;}
3573
+ if (*p) {indices[count++] = p - p_start;}
3597
3574
  p++;
3598
- if (*p) {NONZERO_APPEND_INDEX_RELATIVE;}
3575
+ if (*p) {indices[count++] = p - p_start;}
3599
3576
  p++;
3600
- if (*p) {NONZERO_APPEND_INDEX_RELATIVE;}
3577
+ if (*p) {indices[count++] = p - p_start;}
3601
3578
  p++;
3602
- if (*p) {NONZERO_APPEND_INDEX_RELATIVE;}
3579
+ if (*p) {indices[count++] = p - p_start;}
3603
3580
  p++;
3604
- if (*p) {NONZERO_APPEND_INDEX_RELATIVE;}
3581
+ if (*p) {indices[count++] = p - p_start;}
3605
3582
  p++;
3606
- if (*p) {NONZERO_APPEND_INDEX_RELATIVE;}
3583
+ if (*p) {indices[count++] = p - p_start;}
3607
3584
  p++;
3608
- if (*p) {NONZERO_APPEND_INDEX_RELATIVE;}
3585
+ if (*p) {indices[count++] = p - p_start;}
3609
3586
  p++;
3610
3587
  }
3611
3588
  while (p < p_end) {
3612
- if (*p) {NONZERO_APPEND_INDEX_RELATIVE;}
3589
+ if (*p) {indices[count++] = p - p_start;}
3613
3590
  p++;
3614
3591
  }
3615
3592
  }
@@ -3618,25 +3595,25 @@ AK_nonzero_1d(PyArrayObject* array) {
3618
3595
  npy_intp i_end = count_max;
3619
3596
  npy_intp i_end_roll = count_max - size_div.rem;
3620
3597
  while (i < i_end_roll) {
3621
- if (*(npy_bool*)PyArray_GETPTR1(array, i)) {NONZERO_APPEND_INDEX_ABSOLUTE;}
3598
+ if (*(npy_bool*)PyArray_GETPTR1(array, i)) {indices[count++] = i;}
3622
3599
  i++;
3623
- if (*(npy_bool*)PyArray_GETPTR1(array, i)) {NONZERO_APPEND_INDEX_ABSOLUTE;}
3600
+ if (*(npy_bool*)PyArray_GETPTR1(array, i)) {indices[count++] = i;}
3624
3601
  i++;
3625
- if (*(npy_bool*)PyArray_GETPTR1(array, i)) {NONZERO_APPEND_INDEX_ABSOLUTE;}
3602
+ if (*(npy_bool*)PyArray_GETPTR1(array, i)) {indices[count++] = i;}
3626
3603
  i++;
3627
- if (*(npy_bool*)PyArray_GETPTR1(array, i)) {NONZERO_APPEND_INDEX_ABSOLUTE;}
3604
+ if (*(npy_bool*)PyArray_GETPTR1(array, i)) {indices[count++] = i;}
3628
3605
  i++;
3629
- if (*(npy_bool*)PyArray_GETPTR1(array, i)) {NONZERO_APPEND_INDEX_ABSOLUTE;}
3606
+ if (*(npy_bool*)PyArray_GETPTR1(array, i)) {indices[count++] = i;}
3630
3607
  i++;
3631
- if (*(npy_bool*)PyArray_GETPTR1(array, i)) {NONZERO_APPEND_INDEX_ABSOLUTE;}
3608
+ if (*(npy_bool*)PyArray_GETPTR1(array, i)) {indices[count++] = i;}
3632
3609
  i++;
3633
- if (*(npy_bool*)PyArray_GETPTR1(array, i)) {NONZERO_APPEND_INDEX_ABSOLUTE;}
3610
+ if (*(npy_bool*)PyArray_GETPTR1(array, i)) {indices[count++] = i;}
3634
3611
  i++;
3635
- if (*(npy_bool*)PyArray_GETPTR1(array, i)) {NONZERO_APPEND_INDEX_ABSOLUTE;}
3612
+ if (*(npy_bool*)PyArray_GETPTR1(array, i)) {indices[count++] = i;}
3636
3613
  i++;
3637
3614
  }
3638
3615
  while (i < i_end) {
3639
- if (*(npy_bool*)PyArray_GETPTR1(array, i)) {NONZERO_APPEND_INDEX_ABSOLUTE;}
3616
+ if (*(npy_bool*)PyArray_GETPTR1(array, i)) {indices[count++] = i;}
3640
3617
  i++;
3641
3618
  }
3642
3619
  }
@@ -3653,8 +3630,6 @@ AK_nonzero_1d(PyArrayObject* array) {
3653
3630
  PyArray_CLEARFLAGS((PyArrayObject*)final, NPY_ARRAY_WRITEABLE);
3654
3631
  return final;
3655
3632
  }
3656
- #undef NONZERO_APPEND_INDEX_RELATIVE
3657
- #undef NONZERO_APPEND_INDEX_ABSOLUTE
3658
3633
 
3659
3634
  static PyObject*
3660
3635
  nonzero_1d(PyObject *Py_UNUSED(m), PyObject *a) {
@@ -6102,14 +6077,12 @@ TriMap_register_unmatched_dst(TriMapObject *self) {
6102
6077
  return NULL;
6103
6078
  }
6104
6079
  // derive indices for unmatched locations, call each with register_one
6105
- // PyObject* nonzero = PyArray_Nonzero(dst_unmatched);
6106
6080
  PyArrayObject* indices = (PyArrayObject*)AK_nonzero_1d(dst_unmatched);
6107
6081
  if (indices == NULL) {
6108
6082
  Py_DECREF((PyObject*)dst_unmatched);
6109
6083
  return NULL;
6110
6084
  }
6111
6085
  // borrow ref to array in 1-element tuple
6112
- // PyArrayObject *indices = (PyArrayObject*)PyTuple_GET_ITEM(nonzero, 0);
6113
6086
  npy_int64 *index_data = (npy_int64 *)PyArray_DATA(indices);
6114
6087
  npy_intp index_len = PyArray_SIZE(indices);
6115
6088
 
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