fastremap 1.15.2__tar.gz → 1.16.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 (33) hide show
  1. {fastremap-1.15.2 → fastremap-1.16.0}/ChangeLog +15 -0
  2. {fastremap-1.15.2/fastremap.egg-info → fastremap-1.16.0}/PKG-INFO +10 -1
  3. {fastremap-1.15.2 → fastremap-1.16.0}/README.md +9 -0
  4. {fastremap-1.15.2 → fastremap-1.16.0}/automated_test.py +73 -4
  5. {fastremap-1.15.2 → fastremap-1.16.0/fastremap.egg-info}/PKG-INFO +10 -1
  6. fastremap-1.16.0/fastremap.egg-info/pbr.json +1 -0
  7. {fastremap-1.15.2 → fastremap-1.16.0}/src/fastremap.pyx +134 -19
  8. fastremap-1.15.2/fastremap.egg-info/pbr.json +0 -1
  9. {fastremap-1.15.2 → fastremap-1.16.0}/.dockerignore +0 -0
  10. {fastremap-1.15.2 → fastremap-1.16.0}/.github/workflows/build_wheel.yml +0 -0
  11. {fastremap-1.15.2 → fastremap-1.16.0}/.github/workflows/test.yml +0 -0
  12. {fastremap-1.15.2 → fastremap-1.16.0}/AUTHORS +0 -0
  13. {fastremap-1.15.2 → fastremap-1.16.0}/LICENSE +0 -0
  14. {fastremap-1.15.2 → fastremap-1.16.0}/MANIFEST.in +0 -0
  15. {fastremap-1.15.2 → fastremap-1.16.0}/build_linux.sh +0 -0
  16. {fastremap-1.15.2 → fastremap-1.16.0}/fastremap.egg-info/SOURCES.txt +0 -0
  17. {fastremap-1.15.2 → fastremap-1.16.0}/fastremap.egg-info/dependency_links.txt +0 -0
  18. {fastremap-1.15.2 → fastremap-1.16.0}/fastremap.egg-info/not-zip-safe +0 -0
  19. {fastremap-1.15.2 → fastremap-1.16.0}/fastremap.egg-info/requires.txt +0 -0
  20. {fastremap-1.15.2 → fastremap-1.16.0}/fastremap.egg-info/top_level.txt +0 -0
  21. {fastremap-1.15.2 → fastremap-1.16.0}/manylinux1.Dockerfile +0 -0
  22. {fastremap-1.15.2 → fastremap-1.16.0}/manylinux2010.Dockerfile +0 -0
  23. {fastremap-1.15.2 → fastremap-1.16.0}/manylinux2014.Dockerfile +0 -0
  24. {fastremap-1.15.2 → fastremap-1.16.0}/pyproject.toml +0 -0
  25. {fastremap-1.15.2 → fastremap-1.16.0}/requirements.txt +0 -0
  26. {fastremap-1.15.2 → fastremap-1.16.0}/requirements_dev.txt +0 -0
  27. {fastremap-1.15.2 → fastremap-1.16.0}/setup.cfg +0 -0
  28. {fastremap-1.15.2 → fastremap-1.16.0}/setup.py +0 -0
  29. {fastremap-1.15.2 → fastremap-1.16.0}/src/fastremap.pxd +0 -0
  30. {fastremap-1.15.2 → fastremap-1.16.0}/src/ipt.hpp +0 -0
  31. {fastremap-1.15.2 → fastremap-1.16.0}/src/ska_flat_hash_map.hpp +0 -0
  32. {fastremap-1.15.2 → fastremap-1.16.0}/test.py +0 -0
  33. {fastremap-1.15.2 → fastremap-1.16.0}/tox.ini +0 -0
@@ -1,6 +1,21 @@
1
1
  CHANGES
2
2
  =======
3
3
 
4
+ 1.16.0
5
+ ------
6
+
7
+ * test: add a more stringent random test
8
+ * fix(unique): unique\_via\_sort returns proper data width
9
+ * fix(unique): axis=0, ndim=2 works for higher data widths
10
+ * fix(unique): edge case for uint64 range
11
+ * fix(unique): handle floating point
12
+ * test: make sure fastremap.unique matches np.unique
13
+ * test: sanity check that axis=0 works
14
+ * perf: accelerate special case of np.unique(x, axis=0) where x.ndim=2
15
+ * feat: add indices
16
+ * feat+test: add widen\_dtype and narrow\_dtype
17
+ * docs: show how to use "indices"
18
+
4
19
  1.15.2
5
20
  ------
6
21
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fastremap
3
- Version: 1.15.2
3
+ Version: 1.16.0
4
4
  Summary: Remap, mask, renumber, unique, and in-place transposition of 3D labeled images. Point cloud too.
5
5
  Home-page: https://github.com/seung-lab/fastremap/
6
6
  Author: William Silversmith
@@ -42,12 +42,18 @@ Renumber and relabel Numpy arrays at C++ speed and physically convert rectangula
42
42
  import fastremap
43
43
 
44
44
  uniq, cts = fastremap.unique(labels, return_counts=True) # may be much faster than np.unique
45
+
46
+ idxs = fastremap.indices(labels, 1231) # important for huge arrays
47
+
45
48
  labels, remapping = fastremap.renumber(labels, in_place=True) # relabel values from 1 and refit data type
46
49
  ptc = fastremap.point_cloud(labels) # dict of coordinates by label
47
50
 
48
51
  labels = fastremap.refit(labels) # resize the data type of the array to fit extrema
49
52
  labels = fastremap.refit(labels, value=-35) # resize the data type to fit the value provided
50
53
 
54
+ wider_dtype = fastremap.widen_dtype(np.uint32) # np.uint64
55
+ narrower_dtype = fastremap.narrow_dtype(np.uint32) # np.uint16
56
+
51
57
  # remap all occurances of 1 -> 2
52
58
  labels = fastremap.remap(labels, { 1: 2 }, preserve_missing_labels=True, in_place=True)
53
59
 
@@ -78,8 +84,11 @@ binaries = fastremap.tobytes(labels, (64,64,64), order="F")
78
84
  ## All Available Functions
79
85
  - **unique:** Faster implementation of `np.unique`.
80
86
  - **renumber:** Relabel array from 1 to N which can often use smaller datatypes.
87
+ - **indices:** Optimized search for matching values.
81
88
  - **remap:** Custom relabeling of values in an array from a dictionary.
82
89
  - **refit:** Resize the data type of an array to the smallest that can contain the most extreme values in it.
90
+ - **narrow_dtype:** Find the next sized up dtype. e.g. uint16 -> uint32
91
+ - **widen_dtype:** Find the next sized down dtype. e.g. uint16 -> uint8
83
92
  - **mask:** Zero out labels in an array specified by a given list.
84
93
  - **mask_except**: Zero out all labels except those specified in a given list.
85
94
  - **component_map**: Extract an int-to-int dictionary mapping of labels from one image containing component labels to another parent labels.
@@ -8,12 +8,18 @@ Renumber and relabel Numpy arrays at C++ speed and physically convert rectangula
8
8
  import fastremap
9
9
 
10
10
  uniq, cts = fastremap.unique(labels, return_counts=True) # may be much faster than np.unique
11
+
12
+ idxs = fastremap.indices(labels, 1231) # important for huge arrays
13
+
11
14
  labels, remapping = fastremap.renumber(labels, in_place=True) # relabel values from 1 and refit data type
12
15
  ptc = fastremap.point_cloud(labels) # dict of coordinates by label
13
16
 
14
17
  labels = fastremap.refit(labels) # resize the data type of the array to fit extrema
15
18
  labels = fastremap.refit(labels, value=-35) # resize the data type to fit the value provided
16
19
 
20
+ wider_dtype = fastremap.widen_dtype(np.uint32) # np.uint64
21
+ narrower_dtype = fastremap.narrow_dtype(np.uint32) # np.uint16
22
+
17
23
  # remap all occurances of 1 -> 2
18
24
  labels = fastremap.remap(labels, { 1: 2 }, preserve_missing_labels=True, in_place=True)
19
25
 
@@ -44,8 +50,11 @@ binaries = fastremap.tobytes(labels, (64,64,64), order="F")
44
50
  ## All Available Functions
45
51
  - **unique:** Faster implementation of `np.unique`.
46
52
  - **renumber:** Relabel array from 1 to N which can often use smaller datatypes.
53
+ - **indices:** Optimized search for matching values.
47
54
  - **remap:** Custom relabeling of values in an array from a dictionary.
48
55
  - **refit:** Resize the data type of an array to the smallest that can contain the most extreme values in it.
56
+ - **narrow_dtype:** Find the next sized up dtype. e.g. uint16 -> uint32
57
+ - **widen_dtype:** Find the next sized down dtype. e.g. uint16 -> uint8
49
58
  - **mask:** Zero out labels in an array specified by a given list.
50
59
  - **mask_except**: Zero out all labels except those specified in a given list.
51
60
  - **component_map**: Extract an int-to-int dictionary mapping of labels from one image containing component labels to another parent labels.
@@ -397,6 +397,29 @@ def test_minmax():
397
397
  assert minval == np.min(volume)
398
398
  assert maxval == np.max(volume)
399
399
 
400
+ @pytest.mark.parametrize("dtype", DTYPES)
401
+ def test_unique_axis_0(dtype):
402
+ arr = np.array([
403
+ [0,1],
404
+ [0,2],
405
+ [0,3],
406
+ [0,2],
407
+ [1,2],
408
+ [2,3],
409
+ ], dtype=dtype)
410
+
411
+ res = fastremap.unique(arr, axis=0)
412
+ ans = np.unique(arr, axis=0)
413
+
414
+ assert np.all(res == ans)
415
+
416
+ def test_unique_axis_0_random():
417
+ arr = np.random.randint(0,100000, size=[1000000,2], dtype=np.uint32)
418
+ a1 = fastremap.unique(arr, axis=0)
419
+ a2 = np.unique(arr, axis=0)
420
+ assert np.all(a1 == a2)
421
+
422
+
400
423
  @pytest.mark.parametrize("order", [ "C", "F" ])
401
424
  def test_unique(order):
402
425
  def reorder(arr):
@@ -610,9 +633,55 @@ def test_tobytes_misaligned(order):
610
633
  except ValueError:
611
634
  pass
612
635
 
613
-
614
-
615
-
616
-
636
+ def test_narrow_dtype():
637
+ assert fastremap.narrow_dtype(np.uint64) == np.uint32
638
+ assert fastremap.narrow_dtype(np.uint32) == np.uint16
639
+ assert fastremap.narrow_dtype(np.uint16) == np.uint8
640
+ assert fastremap.narrow_dtype(np.uint8) == np.uint8
641
+
642
+ assert fastremap.narrow_dtype(np.int64) == np.int32
643
+ assert fastremap.narrow_dtype(np.int32) == np.int16
644
+ assert fastremap.narrow_dtype(np.int16) == np.int8
645
+ assert fastremap.narrow_dtype(np.int8) == np.int8
646
+
647
+ assert fastremap.narrow_dtype(np.uint64, exotics=True) == np.uint32
648
+ assert fastremap.narrow_dtype(np.uint32, exotics=True) == np.uint16
649
+ assert fastremap.narrow_dtype(np.uint16, exotics=True) == np.uint8
650
+ assert fastremap.narrow_dtype(np.uint8, exotics=True) == np.uint8
651
+
652
+ assert fastremap.narrow_dtype(np.int64, exotics=True) == np.int32
653
+ assert fastremap.narrow_dtype(np.int32, exotics=True) == np.int16
654
+ assert fastremap.narrow_dtype(np.int16, exotics=True) == np.int8
655
+ assert fastremap.narrow_dtype(np.int8, exotics=True) == np.int8
656
+
657
+ assert fastremap.narrow_dtype(np.float64) == np.float32
658
+ assert fastremap.narrow_dtype(np.float32) == np.float32
659
+
660
+ assert fastremap.narrow_dtype(np.float64, exotics=True) == np.float32
661
+ assert fastremap.narrow_dtype(np.float32, exotics=True) == np.float16
662
+
663
+ assert fastremap.narrow_dtype(np.complex128) == np.complex64
664
+ assert fastremap.narrow_dtype(np.complex64) == np.complex64
665
+
666
+ def test_widen_dtype():
667
+ assert fastremap.widen_dtype(np.uint64) == np.uint64
668
+ assert fastremap.widen_dtype(np.uint32) == np.uint64
669
+ assert fastremap.widen_dtype(np.uint16) == np.uint32
670
+ assert fastremap.widen_dtype(np.uint8) == np.uint16
671
+
672
+ assert fastremap.widen_dtype(np.int64) == np.int64
673
+ assert fastremap.widen_dtype(np.int32) == np.int64
674
+ assert fastremap.widen_dtype(np.int16) == np.int32
675
+ assert fastremap.widen_dtype(np.int8) == np.int16
676
+
677
+ assert fastremap.widen_dtype(np.float64, exotics=True) == np.longdouble
678
+ assert fastremap.widen_dtype(np.float64) == np.float64
679
+ assert fastremap.widen_dtype(np.float32) == np.float64
680
+ assert fastremap.widen_dtype(np.float16) == np.float32
681
+
682
+ assert fastremap.widen_dtype(np.complex64) == np.complex64
683
+ assert fastremap.widen_dtype(np.complex64, exotics=True) == np.complex128
684
+ assert fastremap.widen_dtype(np.complex128, exotics=True) == np.clongdouble
685
+ assert fastremap.widen_dtype(np.clongdouble, exotics=True) == np.clongdouble
617
686
 
618
687
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fastremap
3
- Version: 1.15.2
3
+ Version: 1.16.0
4
4
  Summary: Remap, mask, renumber, unique, and in-place transposition of 3D labeled images. Point cloud too.
5
5
  Home-page: https://github.com/seung-lab/fastremap/
6
6
  Author: William Silversmith
@@ -42,12 +42,18 @@ Renumber and relabel Numpy arrays at C++ speed and physically convert rectangula
42
42
  import fastremap
43
43
 
44
44
  uniq, cts = fastremap.unique(labels, return_counts=True) # may be much faster than np.unique
45
+
46
+ idxs = fastremap.indices(labels, 1231) # important for huge arrays
47
+
45
48
  labels, remapping = fastremap.renumber(labels, in_place=True) # relabel values from 1 and refit data type
46
49
  ptc = fastremap.point_cloud(labels) # dict of coordinates by label
47
50
 
48
51
  labels = fastremap.refit(labels) # resize the data type of the array to fit extrema
49
52
  labels = fastremap.refit(labels, value=-35) # resize the data type to fit the value provided
50
53
 
54
+ wider_dtype = fastremap.widen_dtype(np.uint32) # np.uint64
55
+ narrower_dtype = fastremap.narrow_dtype(np.uint32) # np.uint16
56
+
51
57
  # remap all occurances of 1 -> 2
52
58
  labels = fastremap.remap(labels, { 1: 2 }, preserve_missing_labels=True, in_place=True)
53
59
 
@@ -78,8 +84,11 @@ binaries = fastremap.tobytes(labels, (64,64,64), order="F")
78
84
  ## All Available Functions
79
85
  - **unique:** Faster implementation of `np.unique`.
80
86
  - **renumber:** Relabel array from 1 to N which can often use smaller datatypes.
87
+ - **indices:** Optimized search for matching values.
81
88
  - **remap:** Custom relabeling of values in an array from a dictionary.
82
89
  - **refit:** Resize the data type of an array to the smallest that can contain the most extreme values in it.
90
+ - **narrow_dtype:** Find the next sized up dtype. e.g. uint16 -> uint32
91
+ - **widen_dtype:** Find the next sized down dtype. e.g. uint16 -> uint8
83
92
  - **mask:** Zero out labels in an array specified by a given list.
84
93
  - **mask_except**: Zero out all labels except those specified in a given list.
85
94
  - **component_map**: Extract an int-to-int dictionary mapping of labels from one image containing component labels to another parent labels.
@@ -0,0 +1 @@
1
+ {"git_version": "a7c2749", "is_release": true}
@@ -12,7 +12,7 @@ constrained environments when format shifting.
12
12
 
13
13
  Author: William Silversmith
14
14
  Affiliation: Seung Lab, Princeton Neuroscience Institute
15
- Date: August 2018 - May 2022
15
+ Date: August 2018 - May 2025
16
16
  """
17
17
  from typing import Sequence, List
18
18
  cimport cython
@@ -101,6 +101,23 @@ def match_array_orders(*arrs, order="K"):
101
101
  else:
102
102
  return [ np.asfortranarray(arr) for arr in arrs ]
103
103
 
104
+ @cython.boundscheck(False)
105
+ @cython.wraparound(False) # turn off negative index wrapping for entire function
106
+ @cython.nonecheck(False)
107
+ def indices(cnp.ndarray[NUMBER, cast=True, ndim=1] arr, NUMBER value):
108
+ """
109
+ Search through an array and identify the indices where value matches the array.
110
+ """
111
+ cdef vector[uint64_t] all_indices
112
+ cdef uint64_t i = 0
113
+ cdef uint64_t size = arr.size
114
+
115
+ for i in range(size):
116
+ if arr[i] == value:
117
+ all_indices.push_back(i)
118
+
119
+ return np.asarray(all_indices, dtype=np.uint64)
120
+
104
121
  def renumber(arr, start=1, preserve_zero=True, in_place=False):
105
122
  """
106
123
  renumber(arr, start=1, preserve_zero=True, in_place=False)
@@ -339,6 +356,83 @@ def fit_dtype(dtype, value, exotics=False):
339
356
  dtype, value
340
357
  ))
341
358
 
359
+ def widen_dtype(dtype, exotics:bool = False):
360
+ """
361
+ Widen the given dtype to the next size
362
+ of the same type. For example,
363
+ int8 -> int16 or uint32 -> uint64
364
+
365
+ 64-bit types will map to themselves.
366
+
367
+ Return: upgraded dtype
368
+ """
369
+ dtype = np.dtype(dtype)
370
+
371
+ if np.issubdtype(dtype, np.floating):
372
+ sequence = [ np.float16, np.float32, np.float64 ]
373
+ if exotics:
374
+ sequence += [ np.longdouble ]
375
+ elif np.issubdtype(dtype, np.unsignedinteger):
376
+ sequence = [ np.uint8, np.uint16, np.uint32, np.uint64 ]
377
+ elif np.issubdtype(dtype, np.complexfloating):
378
+ sequence = [ np.complex64 ]
379
+ if exotics:
380
+ sequence += [ np.complex128, np.clongdouble ]
381
+ elif np.issubdtype(dtype, np.integer):
382
+ sequence = [ np.int8, np.int16, np.int32, np.int64 ]
383
+ elif np.issubdtype(dtype, (np.intp, np.uintp)):
384
+ return dtype
385
+ elif exotics:
386
+ raise ValueError(
387
+ f"Unsupported dtype: {dtype}\n"
388
+ )
389
+ else:
390
+ raise ValueError(
391
+ f"Unsupported dtype: {dtype}\n"
392
+ f"Only standard floats, integers, and complex types are supported."
393
+ f"For additional types (e.g. long double, complex128, clongdouble), enable exotics."
394
+ )
395
+
396
+ idx = sequence.index(dtype)
397
+ return sequence[min(idx+1, len(sequence) - 1)]
398
+
399
+ def narrow_dtype(dtype, exotics:bool = False):
400
+ """
401
+ Widen the given dtype to the next size
402
+ of the same type. For example,
403
+ int16 -> int8 or uint64 -> uint32
404
+
405
+ 8-bit types will map to themselves.
406
+
407
+ exotics: include float16
408
+
409
+ Return: upgraded dtype
410
+ """
411
+ dtype = np.dtype(dtype)
412
+ if dtype.itemsize == 1:
413
+ return dtype
414
+
415
+ if np.issubdtype(dtype, np.floating):
416
+ sequence = [ np.float32, np.float64, np.longdouble ]
417
+ if exotics:
418
+ sequence = [ np.float16 ] + sequence
419
+ elif np.issubdtype(dtype, np.unsignedinteger):
420
+ sequence = [ np.uint8, np.uint16, np.uint32, np.uint64 ]
421
+ elif np.issubdtype(dtype, np.complexfloating):
422
+ sequence = [ np.complex64, np.complex128, np.clongdouble ]
423
+ elif np.issubdtype(dtype, np.integer):
424
+ sequence = [ np.int8, np.int16, np.int32, np.int64 ]
425
+ elif np.issubdtype(dtype, (np.intp, np.uintp)):
426
+ return dtype
427
+ else:
428
+ raise ValueError(
429
+ f"Unsupported dtype: {dtype}\n"
430
+ f"Only standard floats, integers, and complex types are supported."
431
+ )
432
+
433
+ idx = sequence.index(dtype)
434
+ return sequence[max(idx-1, 0)]
435
+
342
436
  def mask(arr, labels, in_place=False, value=0):
343
437
  """
344
438
  mask(arr, labels, in_place=False, value=0)
@@ -777,19 +871,24 @@ def unique(labels, return_index=False, return_inverse=False, return_counts=False
777
871
  if not isinstance(labels, np.ndarray):
778
872
  labels = np.array(labels)
779
873
 
780
- if not np.issubdtype(labels.dtype, np.integer):
781
- raise TypeError("fastremap.unique only supports integer types.")
782
-
783
874
  # These flags are currently unsupported so call uncle and
784
875
  # use the standard implementation instead.
785
- if axis is not None:
786
- return np.unique(
787
- labels,
788
- return_index=return_index,
789
- return_inverse=return_inverse,
790
- return_counts=return_counts,
791
- axis=axis
792
- )
876
+ if (axis is not None) or (not np.issubdtype(labels.dtype, np.integer)):
877
+ if (
878
+ axis == 0
879
+ and (labels.ndim == 2 and np.dtype(labels.dtype).itemsize < 8)
880
+ and not (return_index or return_inverse or return_counts)
881
+ and labels.flags.c_contiguous
882
+ ):
883
+ return two_axis_unique(labels)
884
+ else:
885
+ return np.unique(
886
+ labels,
887
+ return_index=return_index,
888
+ return_inverse=return_inverse,
889
+ return_counts=return_counts,
890
+ axis=axis
891
+ )
793
892
 
794
893
  cdef size_t voxels = labels.size
795
894
 
@@ -799,12 +898,10 @@ def unique(labels, return_index=False, return_inverse=False, return_counts=False
799
898
  labels_orig = labels
800
899
  labels = reshape(labels, (voxels,))
801
900
 
802
- cdef int64_t max_label
803
- cdef int64_t min_label
901
+ max_label = 0
902
+ min_label = 0
804
903
  if voxels > 0:
805
904
  min_label, max_label = minmax(labels)
806
- else:
807
- min_label, max_label = (0, 0)
808
905
 
809
906
  def c_order_index(arr):
810
907
  if len(shape) > 1 and fortran_order:
@@ -819,9 +916,9 @@ def unique(labels, return_index=False, return_inverse=False, return_counts=False
819
916
  counts = np.array([], dtype=np.uint32)
820
917
  index = np.array([], dtype=np.uint64)
821
918
  inverse = np.array([], dtype=np.uintp)
822
- elif min_label >= 0 and max_label < <int64_t>voxels:
919
+ elif min_label >= 0 and max_label < int(voxels):
823
920
  uniq, index, counts, inverse = unique_via_array(labels, max_label, return_index=return_index, return_inverse=return_inverse)
824
- elif (max_label - min_label) <= <int64_t>voxels:
921
+ elif (max_label - min_label) <= int(voxels):
825
922
  uniq, index, counts, inverse = unique_via_shifted_array(labels, min_label, max_label, return_index=return_index, return_inverse=return_inverse)
826
923
  elif float(pixel_pairs(labels)) / float(voxels) > 0.66:
827
924
  uniq, index, counts, inverse = unique_via_renumber(labels, return_index=return_index, return_inverse=return_inverse)
@@ -845,6 +942,23 @@ def unique(labels, return_index=False, return_inverse=False, return_counts=False
845
942
  return tuple(results)
846
943
  return uniq
847
944
 
945
+ def two_axis_unique(labels):
946
+ """
947
+ Faster replacement for np.unique(labels, axis=0)
948
+ when ndim = 2 and the dtype can be widened.
949
+
950
+ This special case is useful for sorting edge lists.
951
+ """
952
+ dtype = labels.dtype
953
+ wide_dtype = widen_dtype(dtype)
954
+
955
+ labels = labels[:, [1,0]].reshape(-1, order="C")
956
+ labels = labels.view(wide_dtype)
957
+ labels = unique(labels)
958
+ N = len(labels)
959
+ labels = labels.view(dtype).reshape((N, 2), order="C")
960
+ return labels[:,[1,0]]
961
+
848
962
  def unique_via_shifted_array(labels, min_label=None, max_label=None, return_index=False, return_inverse=False):
849
963
  if min_label is None or max_label is None:
850
964
  min_label, max_label = minmax(labels)
@@ -895,9 +1009,10 @@ def unique_via_sort(cnp.ndarray[ALLINT, ndim=1] labels):
895
1009
  uniq.push_back(cur)
896
1010
  counts.push_back(accum)
897
1011
 
1012
+ dtype = labels.dtype
898
1013
  del labels
899
1014
 
900
- return np.array(uniq), np.array(counts)
1015
+ return np.array(uniq, dtype=dtype), np.array(counts, dtype=np.uint64)
901
1016
 
902
1017
  @cython.boundscheck(False)
903
1018
  @cython.wraparound(False) # turn off negative index wrapping for entire function
@@ -1 +0,0 @@
1
- {"git_version": "b766561", "is_release": true}
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