1use mlx_internal_macros::generate_macro;
4
5use crate::{error::Result, utils::guard::Guarded, Array, Stream};
6
7#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
9pub enum SearchSide {
10 #[default]
12 Left,
13
14 Right,
16}
17
18impl SearchSide {
19 fn as_c_ptr(self) -> *const std::ffi::c_char {
20 match self {
21 Self::Left => c"left".as_ptr(),
22 Self::Right => c"right".as_ptr(),
23 }
24 }
25}
26
27impl Array {
28 pub fn search_sorted(&self, values: impl AsRef<Array>, side: SearchSide) -> Result<Array> {
42 let stream = Stream::thread_local_or_default();
43 Array::try_from_op(|res| unsafe {
44 mlx_sys::mlx_searchsorted(
45 res,
46 self.as_ptr(),
47 values.as_ref().as_ptr(),
48 side.as_c_ptr(),
49 stream.as_ref().as_ptr(),
50 )
51 })
52 }
53}
54
55pub fn sort_axis(a: impl AsRef<Array>, axis: i32) -> Result<Array> {
72 let stream = Stream::thread_local_or_default();
73 Array::try_from_op(|res| unsafe {
74 mlx_sys::mlx_sort_axis(res, a.as_ref().as_ptr(), axis, stream.as_ref().as_ptr())
75 })
76}
77
78#[generate_macro(customize(forwarding_shim = true))]
80#[deprecated(
81 since = "0.26.0",
82 note = "use `with_stream` or `with_device` around `sort_axis`"
83)]
84pub fn sort_axis_device(
85 a: impl AsRef<Array>,
86 axis: i32,
87 #[optional] stream: impl AsRef<Stream>,
88) -> Result<Array> {
89 crate::with_stream(stream.as_ref(), || sort_axis(a, axis))
90}
91
92pub fn sort(a: impl AsRef<Array>) -> Result<Array> {
107 let stream = Stream::thread_local_or_default();
108 Array::try_from_op(|res| unsafe {
109 mlx_sys::mlx_sort(res, a.as_ref().as_ptr(), stream.as_ref().as_ptr())
110 })
111}
112
113#[generate_macro(customize(forwarding_shim = true))]
115#[deprecated(
116 since = "0.26.0",
117 note = "use `with_stream` or `with_device` around `sort`"
118)]
119pub fn sort_device(a: impl AsRef<Array>, #[optional] stream: impl AsRef<Stream>) -> Result<Array> {
120 crate::with_stream(stream.as_ref(), || sort(a))
121}
122
123pub fn argsort_axis(a: impl AsRef<Array>, axis: i32) -> Result<Array> {
140 let stream = Stream::thread_local_or_default();
141 Array::try_from_op(|res| unsafe {
142 mlx_sys::mlx_argsort_axis(res, a.as_ref().as_ptr(), axis, stream.as_ref().as_ptr())
143 })
144}
145
146#[generate_macro(customize(forwarding_shim = true))]
148#[deprecated(
149 since = "0.26.0",
150 note = "use `with_stream` or `with_device` around `argsort_axis`"
151)]
152pub fn argsort_axis_device(
153 a: impl AsRef<Array>,
154 axis: i32,
155 #[optional] stream: impl AsRef<Stream>,
156) -> Result<Array> {
157 crate::with_stream(stream.as_ref(), || argsort_axis(a, axis))
158}
159
160pub fn argsort(a: impl AsRef<Array>) -> Result<Array> {
176 let stream = Stream::thread_local_or_default();
177 Array::try_from_op(|res| unsafe {
178 mlx_sys::mlx_argsort(res, a.as_ref().as_ptr(), stream.as_ref().as_ptr())
179 })
180}
181
182#[generate_macro(customize(forwarding_shim = true))]
184#[deprecated(
185 since = "0.26.0",
186 note = "use `with_stream` or `with_device` around `argsort`"
187)]
188pub fn argsort_device(
189 a: impl AsRef<Array>,
190 #[optional] stream: impl AsRef<Stream>,
191) -> Result<Array> {
192 crate::with_stream(stream.as_ref(), || argsort(a))
193}
194
195pub fn partition_axis(a: impl AsRef<Array>, kth: i32, axis: i32) -> Result<Array> {
219 let stream = Stream::thread_local_or_default();
220 Array::try_from_op(|res| unsafe {
221 mlx_sys::mlx_partition_axis(
222 res,
223 a.as_ref().as_ptr(),
224 kth,
225 axis,
226 stream.as_ref().as_ptr(),
227 )
228 })
229}
230
231#[generate_macro(customize(forwarding_shim = true))]
233#[deprecated(
234 since = "0.26.0",
235 note = "use `with_stream` or `with_device` around `partition_axis`"
236)]
237pub fn partition_axis_device(
238 a: impl AsRef<Array>,
239 kth: i32,
240 axis: i32,
241 #[optional] stream: impl AsRef<Stream>,
242) -> Result<Array> {
243 crate::with_stream(stream.as_ref(), || partition_axis(a, kth, axis))
244}
245
246pub fn partition(a: impl AsRef<Array>, kth: i32) -> Result<Array> {
268 let stream = Stream::thread_local_or_default();
269 Array::try_from_op(|res| unsafe {
270 mlx_sys::mlx_partition(res, a.as_ref().as_ptr(), kth, stream.as_ref().as_ptr())
271 })
272}
273
274#[generate_macro(customize(forwarding_shim = true))]
276#[deprecated(
277 since = "0.26.0",
278 note = "use `with_stream` or `with_device` around `partition`"
279)]
280pub fn partition_device(
281 a: impl AsRef<Array>,
282 kth: i32,
283 #[optional] stream: impl AsRef<Stream>,
284) -> Result<Array> {
285 crate::with_stream(stream.as_ref(), || partition(a, kth))
286}
287
288pub fn argpartition_axis(a: impl AsRef<Array>, kth: i32, axis: i32) -> Result<Array> {
312 let stream = Stream::thread_local_or_default();
313 Array::try_from_op(|res| unsafe {
314 mlx_sys::mlx_argpartition_axis(
315 res,
316 a.as_ref().as_ptr(),
317 kth,
318 axis,
319 stream.as_ref().as_ptr(),
320 )
321 })
322}
323
324#[generate_macro(customize(forwarding_shim = true))]
326#[deprecated(
327 since = "0.26.0",
328 note = "use `with_stream` or `with_device` around `argpartition_axis`"
329)]
330pub fn argpartition_axis_device(
331 a: impl AsRef<Array>,
332 kth: i32,
333 axis: i32,
334 #[optional] stream: impl AsRef<Stream>,
335) -> Result<Array> {
336 crate::with_stream(stream.as_ref(), || argpartition_axis(a, kth, axis))
337}
338
339pub fn argpartition(a: impl AsRef<Array>, kth: i32) -> Result<Array> {
362 let stream = Stream::thread_local_or_default();
363 Array::try_from_op(|res| unsafe {
364 mlx_sys::mlx_argpartition(res, a.as_ref().as_ptr(), kth, stream.as_ref().as_ptr())
365 })
366}
367
368#[generate_macro(customize(forwarding_shim = true))]
370#[deprecated(
371 since = "0.26.0",
372 note = "use `with_stream` or `with_device` around `argpartition`"
373)]
374pub fn argpartition_device(
375 a: impl AsRef<Array>,
376 kth: i32,
377 #[optional] stream: impl AsRef<Stream>,
378) -> Result<Array> {
379 crate::with_stream(stream.as_ref(), || argpartition(a, kth))
380}
381
382#[cfg(test)]
383mod tests {
384 use crate::Array;
385
386 #[test]
387 fn test_sort_with_invalid_axis() {
388 let a = Array::from_slice(&[1, 2, 3, 4, 5], &[5]);
389 let axis = 1;
390 let result = super::sort_axis(&a, axis);
391 assert!(result.is_err());
392 }
393
394 #[test]
395 fn test_partition_with_invalid_axis() {
396 let a = Array::from_slice(&[1, 2, 3, 4, 5], &[5]);
397 let kth = 2;
398 let axis = 1;
399 let result = super::partition_axis(&a, kth, axis);
400 assert!(result.is_err());
401 }
402
403 #[test]
404 fn test_partition_with_invalid_kth() {
405 let a = Array::from_slice(&[1, 2, 3, 4, 5], &[5]);
406 let kth = 5;
407 let axis = 0;
408 let result = super::partition_axis(&a, kth, axis);
409 assert!(result.is_err());
410 }
411
412 #[test]
413 fn test_partition_all_with_invalid_kth() {
414 let a = Array::from_slice(&[1, 2, 3, 4, 5], &[5]);
415 let kth = 5;
416 let result = super::partition(&a, kth);
417 assert!(result.is_err());
418 }
419}