1- from typing import List , Union
1+ from typing import List , Optional , Union
22
3- from .views import View
3+ import numpy as np
4+
5+ from .views import View , ViewType , array
46
57
68class BinOp :
@@ -20,11 +22,31 @@ def __init__(
2022 def get_type (dim : int , key_view_type : str ) -> str :
2123 return f"Kokkos::BinOp{ dim } D<{ key_view_type } >"
2224
25+ def _keys_array (self ) -> np .ndarray :
26+ return self .keys .data if isinstance (self .keys , ViewType ) else np .asarray (self .keys )
27+
28+ def num_bins (self ) -> int :
29+ raise NotImplementedError
30+
31+ def bin_indices (self ) -> np .ndarray :
32+ """Flat bin index per key, used by the interpreted (Debug) execution path."""
33+ raise NotImplementedError
34+
2335
2436class BinOp1D (BinOp ):
2537 def __init__ (self , keys : View , max_bins : int , min_value : float , max_value : float ):
2638 super ().__init__ (keys , max_bins , min_value , max_value )
2739
40+ def num_bins (self ) -> int :
41+ return self .max_bins
42+
43+ def bin_indices (self ) -> np .ndarray :
44+ keys_arr = self ._keys_array ()
45+ span = self .max_value - self .min_value
46+ scale = self .max_bins / span if span > 0 else 0.0
47+ idx = np .floor ((keys_arr - self .min_value ) * scale ).astype (np .int64 )
48+ return np .clip (idx , 0 , self .max_bins - 1 )
49+
2850
2951class BinOp3D (BinOp ):
3052 def __init__ (
@@ -36,28 +58,66 @@ def __init__(
3658 ):
3759 super ().__init__ (keys , max_bins , min_value , max_value )
3860
61+ def num_bins (self ) -> int :
62+ nbx , nby , nbz = self .max_bins
63+ return nbx * nby * nbz
64+
65+ def bin_indices (self ) -> np .ndarray :
66+ """Row-major flat index: ix * nby * nbz + iy * nbz + iz."""
67+ keys_arr = self ._keys_array ()
68+ nbx , nby , nbz = self .max_bins
69+ idx3 = np .empty ((keys_arr .shape [0 ], 3 ), dtype = np .int64 )
70+ for d , n in enumerate ((nbx , nby , nbz )):
71+ span = self .max_value [d ] - self .min_value [d ]
72+ scale = n / span if span > 0 else 0.0
73+ col = np .floor ((keys_arr [:, d ] - self .min_value [d ]) * scale ).astype (np .int64 )
74+ idx3 [:, d ] = np .clip (col , 0 , n - 1 )
75+ return idx3 [:, 0 ] * (nby * nbz ) + idx3 [:, 1 ] * nbz + idx3 [:, 2 ]
76+
3977
4078class BinSort :
4179 def __init__ (self , keys : View , bin_op : BinOp , sort_within_bins : bool = False ):
4280 self .keys = keys
4381 self .bin_op = bin_op
4482 self .sort_within_bins = sort_within_bins
83+ self ._permute_vector : Optional [np .ndarray ] = None
84+ self ._bin_count : Optional [np .ndarray ] = None
85+ self ._bin_offsets : Optional [np .ndarray ] = None
4586
4687 @staticmethod
4788 def get_type (key_view_type : str , bin_op_type : str , space : str ) -> str :
4889 return f"Kokkos::BinSort<{ key_view_type } ,{ bin_op_type } ,{ space } ,int>"
4990
5091 def sort (self , values : View ) -> None :
51- pass
92+ if self ._permute_vector is None :
93+ raise RuntimeError ("create_permute_vector() must be called before sort()" )
94+ data = values .data if isinstance (values , ViewType ) else values
95+ n = len (self ._permute_vector )
96+ data [:n ] = data [:n ][self ._permute_vector ]
5297
5398 def get_bin_count (self ) -> View :
54- pass
99+ return array ( self . _bin_count )
55100
56101 def get_bin_offsets (self ) -> View :
57- pass
102+ return array ( self . _bin_offsets )
58103
59104 def get_permute_vector (self ) -> View :
60- pass
105+ return array ( self . _permute_vector )
61106
62107 def create_permute_vector (self ) -> None :
63- pass
108+ """Counting sort by bin index (interpreted-execution fallback for Kokkos::BinSort)."""
109+ bin_ids = self .bin_op .bin_indices ()
110+ n_bins = self .bin_op .num_bins ()
111+
112+ counts = np .bincount (bin_ids , minlength = n_bins ).astype (np .int32 )
113+ offsets = np .zeros (n_bins , dtype = np .int32 )
114+ if n_bins > 1 :
115+ offsets [1 :] = np .cumsum (counts )[:- 1 ]
116+
117+ # Stable sort so ties (same bin) keep their original relative order,
118+ # matching sort_within_bins=False semantics.
119+ order = np .argsort (bin_ids , kind = "stable" ).astype (np .int32 )
120+
121+ self ._bin_count = counts
122+ self ._bin_offsets = offsets
123+ self ._permute_vector = order
0 commit comments