diff --git a/encodings/alp/benches/alp_compress.rs b/encodings/alp/benches/alp_compress.rs index 1f35d2e1d66..8569307f7ea 100644 --- a/encodings/alp/benches/alp_compress.rs +++ b/encodings/alp/benches/alp_compress.rs @@ -15,14 +15,12 @@ use vortex_alp::decompress_into_array; use vortex_array::LEGACY_SESSION; use vortex_array::VortexSessionExecute; use vortex_array::arrays::PrimitiveArray; -use vortex_array::compute::warm_up_vtables; use vortex_array::dtype::NativePType; use vortex_array::validity::Validity; use vortex_buffer::Buffer; use vortex_buffer::buffer; fn main() { - warm_up_vtables(); divan::main(); } diff --git a/encodings/fastlanes/benches/bitpacking_take.rs b/encodings/fastlanes/benches/bitpacking_take.rs index 271ba447af2..f9522d3bfc9 100644 --- a/encodings/fastlanes/benches/bitpacking_take.rs +++ b/encodings/fastlanes/benches/bitpacking_take.rs @@ -15,14 +15,12 @@ use vortex_array::LEGACY_SESSION; use vortex_array::RecursiveCanonical; use vortex_array::VortexSessionExecute; use vortex_array::arrays::PrimitiveArray; -use vortex_array::compute::warm_up_vtables; use vortex_array::validity::Validity; use vortex_buffer::Buffer; use vortex_buffer::buffer; use vortex_fastlanes::bitpack_compress::bitpack_to_best_bit_width; fn main() { - warm_up_vtables(); divan::main(); } diff --git a/encodings/fastlanes/benches/canonicalize_bench.rs b/encodings/fastlanes/benches/canonicalize_bench.rs index c568a2e61dc..81a6a5c62a4 100644 --- a/encodings/fastlanes/benches/canonicalize_bench.rs +++ b/encodings/fastlanes/benches/canonicalize_bench.rs @@ -13,14 +13,12 @@ use vortex_array::VortexSessionExecute; use vortex_array::arrays::ChunkedArray; use vortex_array::builders::ArrayBuilder; use vortex_array::builders::PrimitiveBuilder; -use vortex_array::compute::warm_up_vtables; use vortex_array::session::ArraySession; use vortex_error::VortexExpect; use vortex_fastlanes::bitpack_compress::test_harness::make_array; use vortex_session::VortexSession; fn main() { - warm_up_vtables(); divan::main(); } diff --git a/encodings/fastlanes/benches/compute_between.rs b/encodings/fastlanes/benches/compute_between.rs index d3bc7cc6259..f6c389cb228 100644 --- a/encodings/fastlanes/benches/compute_between.rs +++ b/encodings/fastlanes/benches/compute_between.rs @@ -11,13 +11,11 @@ use vortex_array::ArrayRef; use vortex_array::IntoArray; use vortex_array::ToCanonical; use vortex_array::arrays::PrimitiveArray; -use vortex_array::compute::warm_up_vtables; use vortex_array::dtype::NativePType; use vortex_error::VortexExpect; use vortex_fastlanes::bitpack_compress::bitpack_to_best_bit_width; fn main() { - warm_up_vtables(); divan::main(); } diff --git a/encodings/fastlanes/public-api.lock b/encodings/fastlanes/public-api.lock index 31ed7a06c02..b8086473960 100644 --- a/encodings/fastlanes/public-api.lock +++ b/encodings/fastlanes/public-api.lock @@ -420,12 +420,6 @@ impl vortex_array::arrays::slice::SliceReduce for vortex_fastlanes::FoR pub fn vortex_fastlanes::FoR::slice(array: &Self::Array, range: core::ops::range::Range) -> vortex_error::VortexResult> -impl vortex_array::compute::is_sorted::IsSortedKernel for vortex_fastlanes::FoR - -pub fn vortex_fastlanes::FoR::is_sorted(&self, array: &vortex_fastlanes::FoRArray) -> vortex_error::VortexResult> - -pub fn vortex_fastlanes::FoR::is_strict_sorted(&self, array: &vortex_fastlanes::FoRArray) -> vortex_error::VortexResult> - impl vortex_array::scalar_fn::fns::binary::compare::CompareKernel for vortex_fastlanes::FoR pub fn vortex_fastlanes::FoR::compare(lhs: &vortex_fastlanes::FoRArray, rhs: &vortex_array::array::ArrayRef, operator: vortex_array::scalar_fn::fns::operators::CompareOperator, _ctx: &mut vortex_array::executor::ExecutionCtx) -> vortex_error::VortexResult> diff --git a/encodings/fastlanes/src/for/compute/is_sorted.rs b/encodings/fastlanes/src/for/compute/is_sorted.rs index 3ae38faf2cf..110c2b575f6 100644 --- a/encodings/fastlanes/src/for/compute/is_sorted.rs +++ b/encodings/fastlanes/src/for/compute/is_sorted.rs @@ -1,17 +1,19 @@ // SPDX-License-Identifier: Apache-2.0 // SPDX-FileCopyrightText: Copyright the Vortex contributors +use vortex_array::ArrayRef; +use vortex_array::ExecutionCtx; use vortex_array::IntoArray; use vortex_array::ToCanonical; -use vortex_array::compute::IsSortedKernel; -use vortex_array::compute::IsSortedKernelAdapter; -use vortex_array::compute::is_sorted; -use vortex_array::compute::is_strict_sorted; -use vortex_array::register_kernel; +use vortex_array::aggregate_fn::AggregateFnRef; +use vortex_array::aggregate_fn::fns::is_sorted::IsSorted; +use vortex_array::aggregate_fn::fns::is_sorted::is_sorted; +use vortex_array::aggregate_fn::fns::is_sorted::is_strict_sorted; +use vortex_array::aggregate_fn::kernels::DynAggregateKernel; +use vortex_array::scalar::Scalar; use vortex_error::VortexResult; use crate::FoR; -use crate::FoRArray; /// FoR can express sortedness directly on its encoded form. /// @@ -71,33 +73,46 @@ use crate::FoRArray; /// Addition is order-preserving, so all the wrapped values preserve their order and they're all /// represented as unsigned values larger than 127 so they also preserve their order with the /// unwrapped values. -impl IsSortedKernel for FoR { - fn is_sorted(&self, array: &FoRArray) -> VortexResult> { - let encoded = array.encoded().to_primitive(); - is_sorted( - &encoded - .reinterpret_cast(encoded.ptype().to_unsigned()) - .into_array(), - ) - } +#[derive(Debug)] +pub(crate) struct FoRIsSortedKernel; + +impl DynAggregateKernel for FoRIsSortedKernel { + fn aggregate( + &self, + aggregate_fn: &AggregateFnRef, + batch: &ArrayRef, + ctx: &mut ExecutionCtx, + ) -> VortexResult> { + let Some(options) = aggregate_fn.as_opt::() else { + return Ok(None); + }; + + let Some(array) = batch.as_opt::() else { + return Ok(None); + }; - fn is_strict_sorted(&self, array: &FoRArray) -> VortexResult> { let encoded = array.encoded().to_primitive(); - is_strict_sorted( - &encoded - .reinterpret_cast(encoded.ptype().to_unsigned()) - .into_array(), - ) + let unsigned_array = encoded + .reinterpret_cast(encoded.ptype().to_unsigned()) + .into_array(); + + let result = if options.strict { + is_strict_sorted(&unsigned_array, ctx)? + } else { + is_sorted(&unsigned_array, ctx)? + }; + + Ok(Some(IsSorted::make_partial(batch, result, options.strict)?)) } } -register_kernel!(IsSortedKernelAdapter(FoR).lift()); - #[cfg(test)] mod test { use vortex_array::IntoArray; + use vortex_array::LEGACY_SESSION; + use vortex_array::VortexSessionExecute; + use vortex_array::aggregate_fn::fns::is_sorted::is_sorted; use vortex_array::arrays::PrimitiveArray; - use vortex_array::compute::is_sorted; use vortex_array::validity::Validity; use vortex_buffer::buffer; @@ -105,10 +120,12 @@ mod test { #[test] fn test_sorted() { + let mut ctx = LEGACY_SESSION.create_execution_ctx(); + let a = PrimitiveArray::new(buffer![-1, 0, i8::MAX], Validity::NonNullable); let b = FoRArray::encode(a).unwrap(); assert!( - is_sorted(&b.clone().into_array()).unwrap().unwrap(), + is_sorted(&b.clone().into_array(), &mut ctx).unwrap(), "{}", b.encoded().display_values() ); @@ -116,7 +133,7 @@ mod test { let a = PrimitiveArray::new(buffer![i8::MIN, 0, i8::MAX], Validity::NonNullable); let b = FoRArray::encode(a).unwrap(); assert!( - is_sorted(&b.clone().into_array()).unwrap().unwrap(), + is_sorted(&b.clone().into_array(), &mut ctx).unwrap(), "{}", b.encoded().display_values() ); @@ -124,7 +141,7 @@ mod test { let a = PrimitiveArray::new(buffer![i8::MIN, 0, 30, 127], Validity::NonNullable); let b = FoRArray::encode(a).unwrap(); assert!( - is_sorted(&b.clone().into_array()).unwrap().unwrap(), + is_sorted(&b.clone().into_array(), &mut ctx).unwrap(), "{}", b.encoded().display_values() ); @@ -132,7 +149,7 @@ mod test { let a = PrimitiveArray::new(buffer![i8::MIN, -3, -1], Validity::NonNullable); let b = FoRArray::encode(a).unwrap(); assert!( - is_sorted(&b.clone().into_array()).unwrap().unwrap(), + is_sorted(&b.clone().into_array(), &mut ctx).unwrap(), "{}", b.encoded().display_values() ); @@ -140,7 +157,7 @@ mod test { let a = PrimitiveArray::new(buffer![-10, -3, -1], Validity::NonNullable); let b = FoRArray::encode(a).unwrap(); assert!( - is_sorted(&b.clone().into_array()).unwrap().unwrap(), + is_sorted(&b.clone().into_array(), &mut ctx).unwrap(), "{}", b.encoded().display_values() ); @@ -148,7 +165,7 @@ mod test { let a = PrimitiveArray::new(buffer![-10, -11, -1], Validity::NonNullable); let b = FoRArray::encode(a).unwrap(); assert!( - !is_sorted(&b.clone().into_array()).unwrap().unwrap(), + !is_sorted(&b.clone().into_array(), &mut ctx).unwrap(), "{}", b.encoded().display_values() ); @@ -156,7 +173,7 @@ mod test { let a = PrimitiveArray::new(buffer![-10, i8::MIN, -1], Validity::NonNullable); let b = FoRArray::encode(a).unwrap(); assert!( - !is_sorted(&b.clone().into_array()).unwrap().unwrap(), + !is_sorted(&b.clone().into_array(), &mut ctx).unwrap(), "{}", b.encoded().display_values() ); diff --git a/encodings/fastlanes/src/for/compute/mod.rs b/encodings/fastlanes/src/for/compute/mod.rs index 4eec5d9ed6f..921cc7affe7 100644 --- a/encodings/fastlanes/src/for/compute/mod.rs +++ b/encodings/fastlanes/src/for/compute/mod.rs @@ -4,7 +4,7 @@ mod cast; mod compare; pub(crate) mod is_constant; -mod is_sorted; +pub(crate) mod is_sorted; use vortex_array::ArrayRef; use vortex_array::DynArray; diff --git a/encodings/fastlanes/src/lib.rs b/encodings/fastlanes/src/lib.rs index 60658e95d47..d5ada9ec5e7 100644 --- a/encodings/fastlanes/src/lib.rs +++ b/encodings/fastlanes/src/lib.rs @@ -18,8 +18,10 @@ pub(crate) const FL_CHUNK_SIZE: usize = 1024; use bitpacking::compute::is_constant::BitPackedIsConstantKernel; use r#for::compute::is_constant::FoRIsConstantKernel; +use r#for::compute::is_sorted::FoRIsSortedKernel; use vortex_array::aggregate_fn::AggregateFnVTable; use vortex_array::aggregate_fn::fns::is_constant::IsConstant; +use vortex_array::aggregate_fn::fns::is_sorted::IsSorted; use vortex_array::aggregate_fn::session::AggregateFnSessionExt; use vortex_array::session::ArraySessionExt; use vortex_session::VortexSession; @@ -42,6 +44,11 @@ pub fn initialize(session: &mut VortexSession) { Some(IsConstant.id()), &FoRIsConstantKernel, ); + session.aggregate_fns().register_aggregate_kernel( + FoR::ID, + Some(IsSorted.id()), + &FoRIsSortedKernel, + ); } #[cfg(test)] diff --git a/encodings/fsst/benches/chunked_dict_fsst_builder.rs b/encodings/fsst/benches/chunked_dict_fsst_builder.rs index 901dd6f1836..25f151bb1df 100644 --- a/encodings/fsst/benches/chunked_dict_fsst_builder.rs +++ b/encodings/fsst/benches/chunked_dict_fsst_builder.rs @@ -10,7 +10,6 @@ use vortex_array::IntoArray; use vortex_array::VortexSessionExecute; use vortex_array::arrays::ChunkedArray; use vortex_array::builders::builder_with_capacity; -use vortex_array::compute::warm_up_vtables; use vortex_array::dtype::NativePType; use vortex_array::session::ArraySession; use vortex_error::VortexExpect; @@ -18,7 +17,6 @@ use vortex_fsst::test_utils::gen_dict_fsst_test_data; use vortex_session::VortexSession; fn main() { - warm_up_vtables(); divan::main(); } diff --git a/encodings/fsst/benches/fsst_compress.rs b/encodings/fsst/benches/fsst_compress.rs index 8b5942a91bd..444dff1b5ad 100644 --- a/encodings/fsst/benches/fsst_compress.rs +++ b/encodings/fsst/benches/fsst_compress.rs @@ -19,7 +19,6 @@ use vortex_array::arrays::VarBinArray; use vortex_array::builders::ArrayBuilder; use vortex_array::builders::VarBinViewBuilder; use vortex_array::builtins::ArrayBuiltins; -use vortex_array::compute::warm_up_vtables; use vortex_array::dtype::DType; use vortex_array::dtype::Nullability; use vortex_array::scalar::Scalar; @@ -30,7 +29,6 @@ use vortex_fsst::fsst_train_compressor; use vortex_session::VortexSession; fn main() { - warm_up_vtables(); divan::main(); } diff --git a/encodings/fsst/benches/fsst_url_compare.rs b/encodings/fsst/benches/fsst_url_compare.rs index 6dc3ddbe087..1b11e49a5ce 100644 --- a/encodings/fsst/benches/fsst_url_compare.rs +++ b/encodings/fsst/benches/fsst_url_compare.rs @@ -12,7 +12,6 @@ use vortex_array::VortexSessionExecute; use vortex_array::arrays::ConstantArray; use vortex_array::arrays::VarBinArray; use vortex_array::builtins::ArrayBuiltins; -use vortex_array::compute::warm_up_vtables; use vortex_array::expr::like; use vortex_array::expr::lit; use vortex_array::expr::root; @@ -28,7 +27,6 @@ use vortex_fsst::test_utils::generate_url_data; use vortex_session::VortexSession; fn main() { - warm_up_vtables(); divan::main(); } diff --git a/encodings/runend/benches/run_end_compress.rs b/encodings/runend/benches/run_end_compress.rs index 04fcfce1323..bac8175b37a 100644 --- a/encodings/runend/benches/run_end_compress.rs +++ b/encodings/runend/benches/run_end_compress.rs @@ -11,7 +11,6 @@ use vortex_array::RecursiveCanonical; use vortex_array::VortexSessionExecute; use vortex_array::arrays::PrimitiveArray; use vortex_array::arrays::VarBinViewArray; -use vortex_array::compute::warm_up_vtables; use vortex_array::dtype::IntegerPType; use vortex_array::validity::Validity; use vortex_buffer::Buffer; @@ -19,7 +18,6 @@ use vortex_runend::RunEndArray; use vortex_runend::compress::runend_encode; fn main() { - warm_up_vtables(); divan::main(); } diff --git a/encodings/runend/benches/run_end_decode.rs b/encodings/runend/benches/run_end_decode.rs index 9f64beabff5..b2ee2aaf3ab 100644 --- a/encodings/runend/benches/run_end_decode.rs +++ b/encodings/runend/benches/run_end_decode.rs @@ -8,14 +8,12 @@ use std::fmt; use divan::Bencher; use vortex_array::arrays::BoolArray; use vortex_array::arrays::PrimitiveArray; -use vortex_array::compute::warm_up_vtables; use vortex_array::validity::Validity; use vortex_buffer::BitBuffer; use vortex_buffer::BufferMut; use vortex_runend::decompress_bool::runend_decode_bools; fn main() { - warm_up_vtables(); divan::main(); } diff --git a/encodings/runend/benches/run_end_null_count.rs b/encodings/runend/benches/run_end_null_count.rs index 4a3b8823e2c..a7cf310d1fa 100644 --- a/encodings/runend/benches/run_end_null_count.rs +++ b/encodings/runend/benches/run_end_null_count.rs @@ -10,12 +10,10 @@ use rand::rngs::StdRng; use vortex_array::DynArray; use vortex_array::IntoArray; use vortex_array::arrays::PrimitiveArray; -use vortex_array::compute::warm_up_vtables; use vortex_buffer::Buffer; use vortex_runend::RunEndArray; fn main() { - warm_up_vtables(); divan::main(); } diff --git a/encodings/runend/public-api.lock b/encodings/runend/public-api.lock index c4c4bb326b4..a78046051d0 100644 --- a/encodings/runend/public-api.lock +++ b/encodings/runend/public-api.lock @@ -34,12 +34,6 @@ impl vortex_array::arrays::filter::kernel::FilterKernel for vortex_runend::RunEn pub fn vortex_runend::RunEnd::filter(array: &vortex_runend::RunEndArray, mask: &vortex_mask::Mask, ctx: &mut vortex_array::executor::ExecutionCtx) -> vortex_error::VortexResult> -impl vortex_array::compute::is_sorted::IsSortedKernel for vortex_runend::RunEnd - -pub fn vortex_runend::RunEnd::is_sorted(&self, array: &vortex_runend::RunEndArray) -> vortex_error::VortexResult> - -pub fn vortex_runend::RunEnd::is_strict_sorted(&self, array: &vortex_runend::RunEndArray) -> vortex_error::VortexResult> - impl vortex_array::scalar_fn::fns::binary::compare::CompareKernel for vortex_runend::RunEnd pub fn vortex_runend::RunEnd::compare(lhs: &vortex_runend::RunEndArray, rhs: &vortex_array::array::ArrayRef, operator: vortex_array::scalar_fn::fns::operators::CompareOperator, ctx: &mut vortex_array::executor::ExecutionCtx) -> vortex_error::VortexResult> diff --git a/encodings/runend/src/compute/is_sorted.rs b/encodings/runend/src/compute/is_sorted.rs index 0ee9d07695b..b0d00bfb146 100644 --- a/encodings/runend/src/compute/is_sorted.rs +++ b/encodings/runend/src/compute/is_sorted.rs @@ -1,25 +1,49 @@ // SPDX-License-Identifier: Apache-2.0 // SPDX-FileCopyrightText: Copyright the Vortex contributors +use vortex_array::ArrayRef; +use vortex_array::ExecutionCtx; use vortex_array::IntoArray as _; -use vortex_array::compute::IsSortedKernel; -use vortex_array::compute::IsSortedKernelAdapter; -use vortex_array::compute::is_sorted; -use vortex_array::compute::is_strict_sorted; -use vortex_array::register_kernel; +use vortex_array::aggregate_fn::AggregateFnRef; +use vortex_array::aggregate_fn::fns::is_sorted::IsSorted; +use vortex_array::aggregate_fn::fns::is_sorted::is_sorted; +use vortex_array::aggregate_fn::fns::is_sorted::is_strict_sorted; +use vortex_array::aggregate_fn::kernels::DynAggregateKernel; +use vortex_array::scalar::Scalar; use vortex_error::VortexResult; use crate::RunEnd; -use crate::RunEndArray; -impl IsSortedKernel for RunEnd { - fn is_sorted(&self, array: &RunEndArray) -> VortexResult> { - is_sorted(array.values()) - } +/// RunEnd-specific is_sorted kernel. +/// +/// Non-strict: values array sorted implies the run-end array is sorted. +/// Strict: must canonicalize since runs repeat values. +#[derive(Debug)] +pub(crate) struct RunEndIsSortedKernel; + +impl DynAggregateKernel for RunEndIsSortedKernel { + fn aggregate( + &self, + aggregate_fn: &AggregateFnRef, + batch: &ArrayRef, + ctx: &mut ExecutionCtx, + ) -> VortexResult> { + let Some(options) = aggregate_fn.as_opt::() else { + return Ok(None); + }; + + let Some(array) = batch.as_opt::() else { + return Ok(None); + }; - fn is_strict_sorted(&self, array: &RunEndArray) -> VortexResult> { - is_strict_sorted(&array.to_canonical()?.into_array()) + let result = if options.strict { + // Strict sort with run-end encoding means we need to canonicalize + // since run-end encoding repeats values. + is_strict_sorted(&array.to_canonical()?.into_array(), ctx)? + } else { + is_sorted(array.values(), ctx)? + }; + + Ok(Some(IsSorted::make_partial(batch, result, options.strict)?)) } } - -register_kernel!(IsSortedKernelAdapter(RunEnd).lift()); diff --git a/encodings/runend/src/compute/mod.rs b/encodings/runend/src/compute/mod.rs index ad554d97128..0e4f4ce8d1a 100644 --- a/encodings/runend/src/compute/mod.rs +++ b/encodings/runend/src/compute/mod.rs @@ -6,7 +6,7 @@ mod compare; mod fill_null; pub(crate) mod filter; pub(crate) mod is_constant; -mod is_sorted; +pub(crate) mod is_sorted; pub(crate) mod min_max; pub(crate) mod take; pub(crate) mod take_from; diff --git a/encodings/runend/src/lib.rs b/encodings/runend/src/lib.rs index 29b71db8019..bbd8f218bea 100644 --- a/encodings/runend/src/lib.rs +++ b/encodings/runend/src/lib.rs @@ -28,6 +28,7 @@ pub mod _benchmarking { use vortex_array::aggregate_fn::AggregateFnVTable; use vortex_array::aggregate_fn::fns::is_constant::IsConstant; +use vortex_array::aggregate_fn::fns::is_sorted::IsSorted; use vortex_array::aggregate_fn::fns::min_max::MinMax; use vortex_array::aggregate_fn::session::AggregateFnSessionExt; use vortex_array::session::ArraySessionExt; @@ -48,6 +49,11 @@ pub fn initialize(session: &mut VortexSession) { Some(IsConstant.id()), &compute::is_constant::RunEndIsConstantKernel, ); + session.aggregate_fns().register_aggregate_kernel( + RunEnd::ID, + Some(IsSorted.id()), + &compute::is_sorted::RunEndIsSortedKernel, + ); } #[cfg(test)] diff --git a/encodings/sequence/public-api.lock b/encodings/sequence/public-api.lock index c1a2b4b28ac..2696a1d1457 100644 --- a/encodings/sequence/public-api.lock +++ b/encodings/sequence/public-api.lock @@ -22,12 +22,6 @@ impl vortex_array::arrays::slice::SliceReduce for vortex_sequence::Sequence pub fn vortex_sequence::Sequence::slice(array: &Self::Array, range: core::ops::range::Range) -> vortex_error::VortexResult> -impl vortex_array::compute::is_sorted::IsSortedKernel for vortex_sequence::Sequence - -pub fn vortex_sequence::Sequence::is_sorted(&self, array: &vortex_sequence::SequenceArray) -> vortex_error::VortexResult> - -pub fn vortex_sequence::Sequence::is_strict_sorted(&self, array: &vortex_sequence::SequenceArray) -> vortex_error::VortexResult> - impl vortex_array::scalar_fn::fns::binary::compare::CompareKernel for vortex_sequence::Sequence pub fn vortex_sequence::Sequence::compare(lhs: &vortex_sequence::SequenceArray, rhs: &vortex_array::array::ArrayRef, operator: vortex_array::scalar_fn::fns::operators::CompareOperator, _ctx: &mut vortex_array::executor::ExecutionCtx) -> vortex_error::VortexResult> diff --git a/encodings/sequence/src/compute/is_sorted.rs b/encodings/sequence/src/compute/is_sorted.rs index e5bc11d01b5..c930246508f 100644 --- a/encodings/sequence/src/compute/is_sorted.rs +++ b/encodings/sequence/src/compute/is_sorted.rs @@ -2,29 +2,51 @@ // SPDX-FileCopyrightText: Copyright the Vortex contributors use num_traits::zero; -use vortex_array::compute::IsSortedKernel; -use vortex_array::compute::IsSortedKernelAdapter; +use vortex_array::ArrayRef; +use vortex_array::ExecutionCtx; +use vortex_array::aggregate_fn::AggregateFnRef; +use vortex_array::aggregate_fn::fns::is_sorted::IsSorted; +use vortex_array::aggregate_fn::kernels::DynAggregateKernel; use vortex_array::match_each_native_ptype; -use vortex_array::register_kernel; +use vortex_array::scalar::Scalar; use vortex_error::VortexResult; use crate::Sequence; -use crate::SequenceArray; -impl IsSortedKernel for Sequence { - fn is_sorted(&self, array: &SequenceArray) -> VortexResult> { - let m = array.multiplier(); - match_each_native_ptype!(m.ptype(), |P| { - m.cast::

().map(|x| Some(x >= zero::

())) - }) - } +/// Sequence-specific is_sorted kernel. +/// +/// A sequence `A[i] = base + i * multiplier` is sorted iff multiplier >= 0, +/// and strict sorted iff multiplier > 0. +#[derive(Debug)] +pub(crate) struct SequenceIsSortedKernel; + +impl DynAggregateKernel for SequenceIsSortedKernel { + fn aggregate( + &self, + aggregate_fn: &AggregateFnRef, + batch: &ArrayRef, + ctx: &mut ExecutionCtx, + ) -> VortexResult> { + let _ = ctx; + let Some(options) = aggregate_fn.as_opt::() else { + return Ok(None); + }; + + let Some(array) = batch.as_opt::() else { + return Ok(None); + }; - fn is_strict_sorted(&self, array: &SequenceArray) -> VortexResult> { let m = array.multiplier(); - match_each_native_ptype!(m.ptype(), |P| { - m.cast::

().map(|x| Some(x > zero::

())) - }) + let result = match_each_native_ptype!(m.ptype(), |P| { + m.cast::

().map(|x| { + if options.strict { + x > zero::

() + } else { + x >= zero::

() + } + }) + })?; + + Ok(Some(IsSorted::make_partial(batch, result, options.strict)?)) } } - -register_kernel!(IsSortedKernelAdapter(Sequence).lift()); diff --git a/encodings/sequence/src/compute/mod.rs b/encodings/sequence/src/compute/mod.rs index f07ae940f13..2cf0ec5cc2e 100644 --- a/encodings/sequence/src/compute/mod.rs +++ b/encodings/sequence/src/compute/mod.rs @@ -4,7 +4,7 @@ mod cast; pub(crate) mod compare; mod filter; -mod is_sorted; +pub(crate) mod is_sorted; mod list_contains; pub(crate) mod min_max; mod slice; diff --git a/encodings/sequence/src/lib.rs b/encodings/sequence/src/lib.rs index 1688548fe61..14aad87ca75 100644 --- a/encodings/sequence/src/lib.rs +++ b/encodings/sequence/src/lib.rs @@ -16,6 +16,7 @@ pub use array::SequenceArray; pub use array::SequenceArrayParts; pub use compress::sequence_encode; use vortex_array::aggregate_fn::AggregateFnVTable; +use vortex_array::aggregate_fn::fns::is_sorted::IsSorted; use vortex_array::aggregate_fn::fns::min_max::MinMax; use vortex_array::aggregate_fn::session::AggregateFnSessionExt; use vortex_array::session::ArraySessionExt; @@ -25,12 +26,17 @@ use vortex_session::VortexSession; pub fn initialize(session: &mut VortexSession) { session.arrays().register(Sequence::ID, Sequence); - // Register the Sequence-specific min/max aggregate kernel. + // Register the Sequence-specific aggregate kernels. session.aggregate_fns().register_aggregate_kernel( Sequence::ID, Some(MinMax.id()), &compute::min_max::SequenceMinMaxKernel, ); + session.aggregate_fns().register_aggregate_kernel( + Sequence::ID, + Some(IsSorted.id()), + &compute::is_sorted::SequenceIsSortedKernel, + ); } // TODO(joe): hook up to the compressor diff --git a/vortex-array/benches/chunked_dict_builder.rs b/vortex-array/benches/chunked_dict_builder.rs index 297c2c820db..8b72d37eb3b 100644 --- a/vortex-array/benches/chunked_dict_builder.rs +++ b/vortex-array/benches/chunked_dict_builder.rs @@ -11,14 +11,12 @@ use vortex_array::DynArray; use vortex_array::VortexSessionExecute; use vortex_array::arrays::dict_test::gen_dict_primitive_chunks; use vortex_array::builders::builder_with_capacity; -use vortex_array::compute::warm_up_vtables; use vortex_array::dtype::NativePType; use vortex_array::session::ArraySession; use vortex_error::VortexExpect; use vortex_session::VortexSession; fn main() { - warm_up_vtables(); divan::main(); } diff --git a/vortex-array/benches/dict_compare.rs b/vortex-array/benches/dict_compare.rs index 57f2b9a1bba..0b1945bf370 100644 --- a/vortex-array/benches/dict_compare.rs +++ b/vortex-array/benches/dict_compare.rs @@ -17,7 +17,6 @@ use vortex_array::arrays::dict_test::gen_primitive_for_dict; use vortex_array::arrays::dict_test::gen_varbin_words; use vortex_array::builders::dict::dict_encode; use vortex_array::builtins::ArrayBuiltins; -use vortex_array::compute::warm_up_vtables; use vortex_array::expr::eq; use vortex_array::expr::lit; use vortex_array::expr::root; @@ -25,7 +24,6 @@ use vortex_array::scalar_fn::fns::operators::Operator; use vortex_session::VortexSession; fn main() { - warm_up_vtables(); divan::main(); } diff --git a/vortex-array/benches/dict_compress.rs b/vortex-array/benches/dict_compress.rs index 4d85335e4ee..b52d66a031c 100644 --- a/vortex-array/benches/dict_compress.rs +++ b/vortex-array/benches/dict_compress.rs @@ -12,11 +12,9 @@ use vortex_array::arrays::VarBinViewArray; use vortex_array::arrays::dict_test::gen_primitive_for_dict; use vortex_array::arrays::dict_test::gen_varbin_words; use vortex_array::builders::dict::dict_encode; -use vortex_array::compute::warm_up_vtables; use vortex_array::dtype::NativePType; fn main() { - warm_up_vtables(); divan::main(); } diff --git a/vortex-array/benches/dict_mask.rs b/vortex-array/benches/dict_mask.rs index eca43aab6da..60ecc0b9c53 100644 --- a/vortex-array/benches/dict_mask.rs +++ b/vortex-array/benches/dict_mask.rs @@ -13,12 +13,10 @@ use vortex_array::VortexSessionExecute; use vortex_array::arrays::DictArray; use vortex_array::arrays::PrimitiveArray; use vortex_array::builtins::ArrayBuiltins; -use vortex_array::compute::warm_up_vtables; use vortex_mask::Mask; use vortex_session::VortexSession; fn main() { - warm_up_vtables(); divan::main(); } diff --git a/vortex-array/benches/dict_unreferenced_mask.rs b/vortex-array/benches/dict_unreferenced_mask.rs index b15b9622f83..a33c3ac6550 100644 --- a/vortex-array/benches/dict_unreferenced_mask.rs +++ b/vortex-array/benches/dict_unreferenced_mask.rs @@ -10,10 +10,8 @@ use rand::rngs::StdRng; use vortex_array::IntoArray; use vortex_array::arrays::DictArray; use vortex_array::arrays::PrimitiveArray; -use vortex_array::compute::warm_up_vtables; fn main() { - warm_up_vtables(); divan::main(); } diff --git a/vortex-array/public-api.lock b/vortex-array/public-api.lock index 5f37ffc6887..c8ed0c94938 100644 --- a/vortex-array/public-api.lock +++ b/vortex-array/public-api.lock @@ -70,9 +70,7 @@ pub fn vortex_array::aggregate_fn::fns::is_constant::IsConstant::empty_partial(& pub fn vortex_array::aggregate_fn::fns::is_constant::IsConstant::finalize(&self, partials: vortex_array::ArrayRef) -> vortex_error::VortexResult -pub fn vortex_array::aggregate_fn::fns::is_constant::IsConstant::finalize_scalar(&self, partial: vortex_array::scalar::Scalar) -> vortex_error::VortexResult - -pub fn vortex_array::aggregate_fn::fns::is_constant::IsConstant::flush(&self, partial: &mut Self::Partial) -> vortex_error::VortexResult +pub fn vortex_array::aggregate_fn::fns::is_constant::IsConstant::finalize_scalar(&self, partial: &Self::Partial) -> vortex_error::VortexResult pub fn vortex_array::aggregate_fn::fns::is_constant::IsConstant::id(&self) -> vortex_array::aggregate_fn::AggregateFnId @@ -80,16 +78,114 @@ pub fn vortex_array::aggregate_fn::fns::is_constant::IsConstant::is_saturated(&s pub fn vortex_array::aggregate_fn::fns::is_constant::IsConstant::partial_dtype(&self, _options: &Self::Options, input_dtype: &vortex_array::dtype::DType) -> core::option::Option +pub fn vortex_array::aggregate_fn::fns::is_constant::IsConstant::reset(&self, partial: &mut Self::Partial) + pub fn vortex_array::aggregate_fn::fns::is_constant::IsConstant::return_dtype(&self, _options: &Self::Options, input_dtype: &vortex_array::dtype::DType) -> core::option::Option pub fn vortex_array::aggregate_fn::fns::is_constant::IsConstant::serialize(&self, options: &Self::Options) -> vortex_error::VortexResult>> +pub fn vortex_array::aggregate_fn::fns::is_constant::IsConstant::to_scalar(&self, partial: &Self::Partial) -> vortex_error::VortexResult + pub struct vortex_array::aggregate_fn::fns::is_constant::IsConstantPartial pub fn vortex_array::aggregate_fn::fns::is_constant::is_constant(array: &vortex_array::ArrayRef, ctx: &mut vortex_array::ExecutionCtx) -> vortex_error::VortexResult pub fn vortex_array::aggregate_fn::fns::is_constant::make_is_constant_partial_dtype(element_dtype: &vortex_array::dtype::DType) -> vortex_array::dtype::DType +pub mod vortex_array::aggregate_fn::fns::is_sorted + +pub struct vortex_array::aggregate_fn::fns::is_sorted::IsSorted + +impl vortex_array::aggregate_fn::fns::is_sorted::IsSorted + +pub fn vortex_array::aggregate_fn::fns::is_sorted::IsSorted::make_partial(batch: &vortex_array::ArrayRef, is_sorted: bool, strict: bool) -> vortex_error::VortexResult + +impl core::clone::Clone for vortex_array::aggregate_fn::fns::is_sorted::IsSorted + +pub fn vortex_array::aggregate_fn::fns::is_sorted::IsSorted::clone(&self) -> vortex_array::aggregate_fn::fns::is_sorted::IsSorted + +impl core::fmt::Debug for vortex_array::aggregate_fn::fns::is_sorted::IsSorted + +pub fn vortex_array::aggregate_fn::fns::is_sorted::IsSorted::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result + +impl vortex_array::aggregate_fn::AggregateFnVTable for vortex_array::aggregate_fn::fns::is_sorted::IsSorted + +pub type vortex_array::aggregate_fn::fns::is_sorted::IsSorted::Options = vortex_array::aggregate_fn::fns::is_sorted::IsSortedOptions + +pub type vortex_array::aggregate_fn::fns::is_sorted::IsSorted::Partial = vortex_array::aggregate_fn::fns::is_sorted::IsSortedPartial + +pub fn vortex_array::aggregate_fn::fns::is_sorted::IsSorted::accumulate(&self, partial: &mut Self::Partial, batch: &vortex_array::Columnar, ctx: &mut vortex_array::ExecutionCtx) -> vortex_error::VortexResult<()> + +pub fn vortex_array::aggregate_fn::fns::is_sorted::IsSorted::coerce_args(&self, options: &Self::Options, input_dtype: &vortex_array::dtype::DType) -> vortex_error::VortexResult + +pub fn vortex_array::aggregate_fn::fns::is_sorted::IsSorted::combine_partials(&self, partial: &mut Self::Partial, other: vortex_array::scalar::Scalar) -> vortex_error::VortexResult<()> + +pub fn vortex_array::aggregate_fn::fns::is_sorted::IsSorted::deserialize(&self, _metadata: &[u8], _session: &vortex_session::VortexSession) -> vortex_error::VortexResult + +pub fn vortex_array::aggregate_fn::fns::is_sorted::IsSorted::empty_partial(&self, options: &Self::Options, input_dtype: &vortex_array::dtype::DType) -> vortex_error::VortexResult + +pub fn vortex_array::aggregate_fn::fns::is_sorted::IsSorted::finalize(&self, partials: vortex_array::ArrayRef) -> vortex_error::VortexResult + +pub fn vortex_array::aggregate_fn::fns::is_sorted::IsSorted::finalize_scalar(&self, partial: &Self::Partial) -> vortex_error::VortexResult + +pub fn vortex_array::aggregate_fn::fns::is_sorted::IsSorted::id(&self) -> vortex_array::aggregate_fn::AggregateFnId + +pub fn vortex_array::aggregate_fn::fns::is_sorted::IsSorted::is_saturated(&self, partial: &Self::Partial) -> bool + +pub fn vortex_array::aggregate_fn::fns::is_sorted::IsSorted::partial_dtype(&self, _options: &Self::Options, input_dtype: &vortex_array::dtype::DType) -> core::option::Option + +pub fn vortex_array::aggregate_fn::fns::is_sorted::IsSorted::reset(&self, partial: &mut Self::Partial) + +pub fn vortex_array::aggregate_fn::fns::is_sorted::IsSorted::return_dtype(&self, _options: &Self::Options, input_dtype: &vortex_array::dtype::DType) -> core::option::Option + +pub fn vortex_array::aggregate_fn::fns::is_sorted::IsSorted::serialize(&self, options: &Self::Options) -> vortex_error::VortexResult>> + +pub fn vortex_array::aggregate_fn::fns::is_sorted::IsSorted::to_scalar(&self, partial: &Self::Partial) -> vortex_error::VortexResult + +pub struct vortex_array::aggregate_fn::fns::is_sorted::IsSortedOptions + +pub vortex_array::aggregate_fn::fns::is_sorted::IsSortedOptions::strict: bool + +impl core::clone::Clone for vortex_array::aggregate_fn::fns::is_sorted::IsSortedOptions + +pub fn vortex_array::aggregate_fn::fns::is_sorted::IsSortedOptions::clone(&self) -> vortex_array::aggregate_fn::fns::is_sorted::IsSortedOptions + +impl core::cmp::Eq for vortex_array::aggregate_fn::fns::is_sorted::IsSortedOptions + +impl core::cmp::PartialEq for vortex_array::aggregate_fn::fns::is_sorted::IsSortedOptions + +pub fn vortex_array::aggregate_fn::fns::is_sorted::IsSortedOptions::eq(&self, other: &vortex_array::aggregate_fn::fns::is_sorted::IsSortedOptions) -> bool + +impl core::fmt::Debug for vortex_array::aggregate_fn::fns::is_sorted::IsSortedOptions + +pub fn vortex_array::aggregate_fn::fns::is_sorted::IsSortedOptions::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result + +impl core::fmt::Display for vortex_array::aggregate_fn::fns::is_sorted::IsSortedOptions + +pub fn vortex_array::aggregate_fn::fns::is_sorted::IsSortedOptions::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result + +impl core::hash::Hash for vortex_array::aggregate_fn::fns::is_sorted::IsSortedOptions + +pub fn vortex_array::aggregate_fn::fns::is_sorted::IsSortedOptions::hash<__H: core::hash::Hasher>(&self, state: &mut __H) + +impl core::marker::StructuralPartialEq for vortex_array::aggregate_fn::fns::is_sorted::IsSortedOptions + +pub struct vortex_array::aggregate_fn::fns::is_sorted::IsSortedPartial + +pub trait vortex_array::aggregate_fn::fns::is_sorted::IsSortedIteratorExt where ::Item: core::cmp::PartialOrd: core::iter::traits::iterator::Iterator + +pub fn vortex_array::aggregate_fn::fns::is_sorted::IsSortedIteratorExt::is_strict_sorted(self) -> bool where Self: core::marker::Sized, Self::Item: core::cmp::PartialOrd + +impl vortex_array::aggregate_fn::fns::is_sorted::IsSortedIteratorExt for T where T: core::iter::traits::iterator::Iterator + ?core::marker::Sized, ::Item: core::cmp::PartialOrd + +pub fn T::is_strict_sorted(self) -> bool where Self: core::marker::Sized, Self::Item: core::cmp::PartialOrd + +pub fn vortex_array::aggregate_fn::fns::is_sorted::is_sorted(array: &vortex_array::ArrayRef, ctx: &mut vortex_array::ExecutionCtx) -> vortex_error::VortexResult + +pub fn vortex_array::aggregate_fn::fns::is_sorted::is_strict_sorted(array: &vortex_array::ArrayRef, ctx: &mut vortex_array::ExecutionCtx) -> vortex_error::VortexResult + +pub fn vortex_array::aggregate_fn::fns::is_sorted::make_is_sorted_partial_dtype(element_dtype: &vortex_array::dtype::DType) -> vortex_array::dtype::DType + pub mod vortex_array::aggregate_fn::fns::min_max pub struct vortex_array::aggregate_fn::fns::min_max::MinMax @@ -120,9 +216,7 @@ pub fn vortex_array::aggregate_fn::fns::min_max::MinMax::empty_partial(&self, _o pub fn vortex_array::aggregate_fn::fns::min_max::MinMax::finalize(&self, partials: vortex_array::ArrayRef) -> vortex_error::VortexResult -pub fn vortex_array::aggregate_fn::fns::min_max::MinMax::finalize_scalar(&self, partial: vortex_array::scalar::Scalar) -> vortex_error::VortexResult - -pub fn vortex_array::aggregate_fn::fns::min_max::MinMax::flush(&self, partial: &mut Self::Partial) -> vortex_error::VortexResult +pub fn vortex_array::aggregate_fn::fns::min_max::MinMax::finalize_scalar(&self, partial: &Self::Partial) -> vortex_error::VortexResult pub fn vortex_array::aggregate_fn::fns::min_max::MinMax::id(&self) -> vortex_array::aggregate_fn::AggregateFnId @@ -130,10 +224,14 @@ pub fn vortex_array::aggregate_fn::fns::min_max::MinMax::is_saturated(&self, _pa pub fn vortex_array::aggregate_fn::fns::min_max::MinMax::partial_dtype(&self, options: &Self::Options, input_dtype: &vortex_array::dtype::DType) -> core::option::Option +pub fn vortex_array::aggregate_fn::fns::min_max::MinMax::reset(&self, partial: &mut Self::Partial) + pub fn vortex_array::aggregate_fn::fns::min_max::MinMax::return_dtype(&self, _options: &Self::Options, input_dtype: &vortex_array::dtype::DType) -> core::option::Option pub fn vortex_array::aggregate_fn::fns::min_max::MinMax::serialize(&self, options: &Self::Options) -> vortex_error::VortexResult>> +pub fn vortex_array::aggregate_fn::fns::min_max::MinMax::to_scalar(&self, partial: &Self::Partial) -> vortex_error::VortexResult + pub struct vortex_array::aggregate_fn::fns::min_max::MinMaxPartial pub struct vortex_array::aggregate_fn::fns::min_max::MinMaxResult @@ -196,9 +294,7 @@ pub fn vortex_array::aggregate_fn::fns::nan_count::NanCount::empty_partial(&self pub fn vortex_array::aggregate_fn::fns::nan_count::NanCount::finalize(&self, partials: vortex_array::ArrayRef) -> vortex_error::VortexResult -pub fn vortex_array::aggregate_fn::fns::nan_count::NanCount::finalize_scalar(&self, partial: vortex_array::scalar::Scalar) -> vortex_error::VortexResult - -pub fn vortex_array::aggregate_fn::fns::nan_count::NanCount::flush(&self, partial: &mut Self::Partial) -> vortex_error::VortexResult +pub fn vortex_array::aggregate_fn::fns::nan_count::NanCount::finalize_scalar(&self, partial: &Self::Partial) -> vortex_error::VortexResult pub fn vortex_array::aggregate_fn::fns::nan_count::NanCount::id(&self) -> vortex_array::aggregate_fn::AggregateFnId @@ -206,10 +302,14 @@ pub fn vortex_array::aggregate_fn::fns::nan_count::NanCount::is_saturated(&self, pub fn vortex_array::aggregate_fn::fns::nan_count::NanCount::partial_dtype(&self, options: &Self::Options, input_dtype: &vortex_array::dtype::DType) -> core::option::Option +pub fn vortex_array::aggregate_fn::fns::nan_count::NanCount::reset(&self, partial: &mut Self::Partial) + pub fn vortex_array::aggregate_fn::fns::nan_count::NanCount::return_dtype(&self, _options: &Self::Options, input_dtype: &vortex_array::dtype::DType) -> core::option::Option pub fn vortex_array::aggregate_fn::fns::nan_count::NanCount::serialize(&self, options: &Self::Options) -> vortex_error::VortexResult>> +pub fn vortex_array::aggregate_fn::fns::nan_count::NanCount::to_scalar(&self, partial: &Self::Partial) -> vortex_error::VortexResult + pub fn vortex_array::aggregate_fn::fns::nan_count::nan_count(array: &vortex_array::ArrayRef, ctx: &mut vortex_array::ExecutionCtx) -> vortex_error::VortexResult pub mod vortex_array::aggregate_fn::fns::sum @@ -256,9 +356,7 @@ pub fn vortex_array::aggregate_fn::fns::sum::Sum::empty_partial(&self, options: pub fn vortex_array::aggregate_fn::fns::sum::Sum::finalize(&self, partials: vortex_array::ArrayRef) -> vortex_error::VortexResult -pub fn vortex_array::aggregate_fn::fns::sum::Sum::finalize_scalar(&self, partial: vortex_array::scalar::Scalar) -> vortex_error::VortexResult - -pub fn vortex_array::aggregate_fn::fns::sum::Sum::flush(&self, partial: &mut Self::Partial) -> vortex_error::VortexResult +pub fn vortex_array::aggregate_fn::fns::sum::Sum::finalize_scalar(&self, partial: &Self::Partial) -> vortex_error::VortexResult pub fn vortex_array::aggregate_fn::fns::sum::Sum::id(&self) -> vortex_array::aggregate_fn::AggregateFnId @@ -266,10 +364,14 @@ pub fn vortex_array::aggregate_fn::fns::sum::Sum::is_saturated(&self, partial: & pub fn vortex_array::aggregate_fn::fns::sum::Sum::partial_dtype(&self, options: &Self::Options, input_dtype: &vortex_array::dtype::DType) -> core::option::Option +pub fn vortex_array::aggregate_fn::fns::sum::Sum::reset(&self, partial: &mut Self::Partial) + pub fn vortex_array::aggregate_fn::fns::sum::Sum::return_dtype(&self, _options: &Self::Options, input_dtype: &vortex_array::dtype::DType) -> core::option::Option pub fn vortex_array::aggregate_fn::fns::sum::Sum::serialize(&self, options: &Self::Options) -> vortex_error::VortexResult>> +pub fn vortex_array::aggregate_fn::fns::sum::Sum::to_scalar(&self, partial: &Self::Partial) -> vortex_error::VortexResult + pub struct vortex_array::aggregate_fn::fns::sum::SumPartial pub fn vortex_array::aggregate_fn::fns::sum::sum(array: &vortex_array::ArrayRef, ctx: &mut vortex_array::ExecutionCtx) -> vortex_error::VortexResult @@ -490,9 +592,7 @@ pub fn vortex_array::aggregate_fn::AggregateFnVTable::empty_partial(&self, optio pub fn vortex_array::aggregate_fn::AggregateFnVTable::finalize(&self, states: vortex_array::ArrayRef) -> vortex_error::VortexResult -pub fn vortex_array::aggregate_fn::AggregateFnVTable::finalize_scalar(&self, state: vortex_array::scalar::Scalar) -> vortex_error::VortexResult - -pub fn vortex_array::aggregate_fn::AggregateFnVTable::flush(&self, partial: &mut Self::Partial) -> vortex_error::VortexResult +pub fn vortex_array::aggregate_fn::AggregateFnVTable::finalize_scalar(&self, partial: &Self::Partial) -> vortex_error::VortexResult pub fn vortex_array::aggregate_fn::AggregateFnVTable::id(&self) -> vortex_array::aggregate_fn::AggregateFnId @@ -500,10 +600,14 @@ pub fn vortex_array::aggregate_fn::AggregateFnVTable::is_saturated(&self, state: pub fn vortex_array::aggregate_fn::AggregateFnVTable::partial_dtype(&self, options: &Self::Options, input_dtype: &vortex_array::dtype::DType) -> core::option::Option +pub fn vortex_array::aggregate_fn::AggregateFnVTable::reset(&self, partial: &mut Self::Partial) + pub fn vortex_array::aggregate_fn::AggregateFnVTable::return_dtype(&self, options: &Self::Options, input_dtype: &vortex_array::dtype::DType) -> core::option::Option pub fn vortex_array::aggregate_fn::AggregateFnVTable::serialize(&self, options: &Self::Options) -> vortex_error::VortexResult>> +pub fn vortex_array::aggregate_fn::AggregateFnVTable::to_scalar(&self, partial: &Self::Partial) -> vortex_error::VortexResult + impl vortex_array::aggregate_fn::AggregateFnVTable for vortex_array::aggregate_fn::fns::is_constant::IsConstant pub type vortex_array::aggregate_fn::fns::is_constant::IsConstant::Options = vortex_array::aggregate_fn::EmptyOptions @@ -522,9 +626,7 @@ pub fn vortex_array::aggregate_fn::fns::is_constant::IsConstant::empty_partial(& pub fn vortex_array::aggregate_fn::fns::is_constant::IsConstant::finalize(&self, partials: vortex_array::ArrayRef) -> vortex_error::VortexResult -pub fn vortex_array::aggregate_fn::fns::is_constant::IsConstant::finalize_scalar(&self, partial: vortex_array::scalar::Scalar) -> vortex_error::VortexResult - -pub fn vortex_array::aggregate_fn::fns::is_constant::IsConstant::flush(&self, partial: &mut Self::Partial) -> vortex_error::VortexResult +pub fn vortex_array::aggregate_fn::fns::is_constant::IsConstant::finalize_scalar(&self, partial: &Self::Partial) -> vortex_error::VortexResult pub fn vortex_array::aggregate_fn::fns::is_constant::IsConstant::id(&self) -> vortex_array::aggregate_fn::AggregateFnId @@ -532,10 +634,48 @@ pub fn vortex_array::aggregate_fn::fns::is_constant::IsConstant::is_saturated(&s pub fn vortex_array::aggregate_fn::fns::is_constant::IsConstant::partial_dtype(&self, _options: &Self::Options, input_dtype: &vortex_array::dtype::DType) -> core::option::Option +pub fn vortex_array::aggregate_fn::fns::is_constant::IsConstant::reset(&self, partial: &mut Self::Partial) + pub fn vortex_array::aggregate_fn::fns::is_constant::IsConstant::return_dtype(&self, _options: &Self::Options, input_dtype: &vortex_array::dtype::DType) -> core::option::Option pub fn vortex_array::aggregate_fn::fns::is_constant::IsConstant::serialize(&self, options: &Self::Options) -> vortex_error::VortexResult>> +pub fn vortex_array::aggregate_fn::fns::is_constant::IsConstant::to_scalar(&self, partial: &Self::Partial) -> vortex_error::VortexResult + +impl vortex_array::aggregate_fn::AggregateFnVTable for vortex_array::aggregate_fn::fns::is_sorted::IsSorted + +pub type vortex_array::aggregate_fn::fns::is_sorted::IsSorted::Options = vortex_array::aggregate_fn::fns::is_sorted::IsSortedOptions + +pub type vortex_array::aggregate_fn::fns::is_sorted::IsSorted::Partial = vortex_array::aggregate_fn::fns::is_sorted::IsSortedPartial + +pub fn vortex_array::aggregate_fn::fns::is_sorted::IsSorted::accumulate(&self, partial: &mut Self::Partial, batch: &vortex_array::Columnar, ctx: &mut vortex_array::ExecutionCtx) -> vortex_error::VortexResult<()> + +pub fn vortex_array::aggregate_fn::fns::is_sorted::IsSorted::coerce_args(&self, options: &Self::Options, input_dtype: &vortex_array::dtype::DType) -> vortex_error::VortexResult + +pub fn vortex_array::aggregate_fn::fns::is_sorted::IsSorted::combine_partials(&self, partial: &mut Self::Partial, other: vortex_array::scalar::Scalar) -> vortex_error::VortexResult<()> + +pub fn vortex_array::aggregate_fn::fns::is_sorted::IsSorted::deserialize(&self, _metadata: &[u8], _session: &vortex_session::VortexSession) -> vortex_error::VortexResult + +pub fn vortex_array::aggregate_fn::fns::is_sorted::IsSorted::empty_partial(&self, options: &Self::Options, input_dtype: &vortex_array::dtype::DType) -> vortex_error::VortexResult + +pub fn vortex_array::aggregate_fn::fns::is_sorted::IsSorted::finalize(&self, partials: vortex_array::ArrayRef) -> vortex_error::VortexResult + +pub fn vortex_array::aggregate_fn::fns::is_sorted::IsSorted::finalize_scalar(&self, partial: &Self::Partial) -> vortex_error::VortexResult + +pub fn vortex_array::aggregate_fn::fns::is_sorted::IsSorted::id(&self) -> vortex_array::aggregate_fn::AggregateFnId + +pub fn vortex_array::aggregate_fn::fns::is_sorted::IsSorted::is_saturated(&self, partial: &Self::Partial) -> bool + +pub fn vortex_array::aggregate_fn::fns::is_sorted::IsSorted::partial_dtype(&self, _options: &Self::Options, input_dtype: &vortex_array::dtype::DType) -> core::option::Option + +pub fn vortex_array::aggregate_fn::fns::is_sorted::IsSorted::reset(&self, partial: &mut Self::Partial) + +pub fn vortex_array::aggregate_fn::fns::is_sorted::IsSorted::return_dtype(&self, _options: &Self::Options, input_dtype: &vortex_array::dtype::DType) -> core::option::Option + +pub fn vortex_array::aggregate_fn::fns::is_sorted::IsSorted::serialize(&self, options: &Self::Options) -> vortex_error::VortexResult>> + +pub fn vortex_array::aggregate_fn::fns::is_sorted::IsSorted::to_scalar(&self, partial: &Self::Partial) -> vortex_error::VortexResult + impl vortex_array::aggregate_fn::AggregateFnVTable for vortex_array::aggregate_fn::fns::min_max::MinMax pub type vortex_array::aggregate_fn::fns::min_max::MinMax::Options = vortex_array::aggregate_fn::EmptyOptions @@ -554,9 +694,7 @@ pub fn vortex_array::aggregate_fn::fns::min_max::MinMax::empty_partial(&self, _o pub fn vortex_array::aggregate_fn::fns::min_max::MinMax::finalize(&self, partials: vortex_array::ArrayRef) -> vortex_error::VortexResult -pub fn vortex_array::aggregate_fn::fns::min_max::MinMax::finalize_scalar(&self, partial: vortex_array::scalar::Scalar) -> vortex_error::VortexResult - -pub fn vortex_array::aggregate_fn::fns::min_max::MinMax::flush(&self, partial: &mut Self::Partial) -> vortex_error::VortexResult +pub fn vortex_array::aggregate_fn::fns::min_max::MinMax::finalize_scalar(&self, partial: &Self::Partial) -> vortex_error::VortexResult pub fn vortex_array::aggregate_fn::fns::min_max::MinMax::id(&self) -> vortex_array::aggregate_fn::AggregateFnId @@ -564,10 +702,14 @@ pub fn vortex_array::aggregate_fn::fns::min_max::MinMax::is_saturated(&self, _pa pub fn vortex_array::aggregate_fn::fns::min_max::MinMax::partial_dtype(&self, options: &Self::Options, input_dtype: &vortex_array::dtype::DType) -> core::option::Option +pub fn vortex_array::aggregate_fn::fns::min_max::MinMax::reset(&self, partial: &mut Self::Partial) + pub fn vortex_array::aggregate_fn::fns::min_max::MinMax::return_dtype(&self, _options: &Self::Options, input_dtype: &vortex_array::dtype::DType) -> core::option::Option pub fn vortex_array::aggregate_fn::fns::min_max::MinMax::serialize(&self, options: &Self::Options) -> vortex_error::VortexResult>> +pub fn vortex_array::aggregate_fn::fns::min_max::MinMax::to_scalar(&self, partial: &Self::Partial) -> vortex_error::VortexResult + impl vortex_array::aggregate_fn::AggregateFnVTable for vortex_array::aggregate_fn::fns::nan_count::NanCount pub type vortex_array::aggregate_fn::fns::nan_count::NanCount::Options = vortex_array::aggregate_fn::EmptyOptions @@ -586,9 +728,7 @@ pub fn vortex_array::aggregate_fn::fns::nan_count::NanCount::empty_partial(&self pub fn vortex_array::aggregate_fn::fns::nan_count::NanCount::finalize(&self, partials: vortex_array::ArrayRef) -> vortex_error::VortexResult -pub fn vortex_array::aggregate_fn::fns::nan_count::NanCount::finalize_scalar(&self, partial: vortex_array::scalar::Scalar) -> vortex_error::VortexResult - -pub fn vortex_array::aggregate_fn::fns::nan_count::NanCount::flush(&self, partial: &mut Self::Partial) -> vortex_error::VortexResult +pub fn vortex_array::aggregate_fn::fns::nan_count::NanCount::finalize_scalar(&self, partial: &Self::Partial) -> vortex_error::VortexResult pub fn vortex_array::aggregate_fn::fns::nan_count::NanCount::id(&self) -> vortex_array::aggregate_fn::AggregateFnId @@ -596,10 +736,14 @@ pub fn vortex_array::aggregate_fn::fns::nan_count::NanCount::is_saturated(&self, pub fn vortex_array::aggregate_fn::fns::nan_count::NanCount::partial_dtype(&self, options: &Self::Options, input_dtype: &vortex_array::dtype::DType) -> core::option::Option +pub fn vortex_array::aggregate_fn::fns::nan_count::NanCount::reset(&self, partial: &mut Self::Partial) + pub fn vortex_array::aggregate_fn::fns::nan_count::NanCount::return_dtype(&self, _options: &Self::Options, input_dtype: &vortex_array::dtype::DType) -> core::option::Option pub fn vortex_array::aggregate_fn::fns::nan_count::NanCount::serialize(&self, options: &Self::Options) -> vortex_error::VortexResult>> +pub fn vortex_array::aggregate_fn::fns::nan_count::NanCount::to_scalar(&self, partial: &Self::Partial) -> vortex_error::VortexResult + impl vortex_array::aggregate_fn::AggregateFnVTable for vortex_array::aggregate_fn::fns::sum::Sum pub type vortex_array::aggregate_fn::fns::sum::Sum::Options = vortex_array::aggregate_fn::EmptyOptions @@ -618,9 +762,7 @@ pub fn vortex_array::aggregate_fn::fns::sum::Sum::empty_partial(&self, options: pub fn vortex_array::aggregate_fn::fns::sum::Sum::finalize(&self, partials: vortex_array::ArrayRef) -> vortex_error::VortexResult -pub fn vortex_array::aggregate_fn::fns::sum::Sum::finalize_scalar(&self, partial: vortex_array::scalar::Scalar) -> vortex_error::VortexResult - -pub fn vortex_array::aggregate_fn::fns::sum::Sum::flush(&self, partial: &mut Self::Partial) -> vortex_error::VortexResult +pub fn vortex_array::aggregate_fn::fns::sum::Sum::finalize_scalar(&self, partial: &Self::Partial) -> vortex_error::VortexResult pub fn vortex_array::aggregate_fn::fns::sum::Sum::id(&self) -> vortex_array::aggregate_fn::AggregateFnId @@ -628,10 +770,14 @@ pub fn vortex_array::aggregate_fn::fns::sum::Sum::is_saturated(&self, partial: & pub fn vortex_array::aggregate_fn::fns::sum::Sum::partial_dtype(&self, options: &Self::Options, input_dtype: &vortex_array::dtype::DType) -> core::option::Option +pub fn vortex_array::aggregate_fn::fns::sum::Sum::reset(&self, partial: &mut Self::Partial) + pub fn vortex_array::aggregate_fn::fns::sum::Sum::return_dtype(&self, _options: &Self::Options, input_dtype: &vortex_array::dtype::DType) -> core::option::Option pub fn vortex_array::aggregate_fn::fns::sum::Sum::serialize(&self, options: &Self::Options) -> vortex_error::VortexResult>> +pub fn vortex_array::aggregate_fn::fns::sum::Sum::to_scalar(&self, partial: &Self::Partial) -> vortex_error::VortexResult + pub trait vortex_array::aggregate_fn::AggregateFnVTableExt: vortex_array::aggregate_fn::AggregateFnVTable pub fn vortex_array::aggregate_fn::AggregateFnVTableExt::bind(&self, options: Self::Options) -> vortex_array::aggregate_fn::AggregateFnRef @@ -710,12 +856,6 @@ impl vortex_array::arrays::slice::SliceReduce for vortex_array::arrays::Bool pub fn vortex_array::arrays::Bool::slice(array: &Self::Array, range: core::ops::range::Range) -> vortex_error::VortexResult> -impl vortex_array::compute::IsSortedKernel for vortex_array::arrays::Bool - -pub fn vortex_array::arrays::Bool::is_sorted(&self, array: &vortex_array::arrays::BoolArray) -> vortex_error::VortexResult> - -pub fn vortex_array::arrays::Bool::is_strict_sorted(&self, array: &vortex_array::arrays::BoolArray) -> vortex_error::VortexResult> - impl vortex_array::optimizer::rules::ArrayParentReduceRule for vortex_array::arrays::bool::BoolMaskedValidityRule pub type vortex_array::arrays::bool::BoolMaskedValidityRule::Parent = vortex_array::arrays::Masked @@ -926,12 +1066,6 @@ impl vortex_array::arrays::slice::SliceKernel for vortex_array::arrays::Chunked pub fn vortex_array::arrays::Chunked::slice(array: &Self::Array, range: core::ops::range::Range, _ctx: &mut vortex_array::ExecutionCtx) -> vortex_error::VortexResult> -impl vortex_array::compute::IsSortedKernel for vortex_array::arrays::Chunked - -pub fn vortex_array::arrays::Chunked::is_sorted(&self, array: &vortex_array::arrays::ChunkedArray) -> vortex_error::VortexResult> - -pub fn vortex_array::arrays::Chunked::is_strict_sorted(&self, array: &vortex_array::arrays::ChunkedArray) -> vortex_error::VortexResult> - impl vortex_array::scalar_fn::fns::cast::CastReduce for vortex_array::arrays::Chunked pub fn vortex_array::arrays::Chunked::cast(array: &vortex_array::arrays::ChunkedArray, dtype: &vortex_array::dtype::DType) -> vortex_error::VortexResult> @@ -1298,12 +1432,6 @@ impl vortex_array::arrays::slice::SliceReduce for vortex_array::arrays::Decimal pub fn vortex_array::arrays::Decimal::slice(array: &Self::Array, range: core::ops::range::Range) -> vortex_error::VortexResult> -impl vortex_array::compute::IsSortedKernel for vortex_array::arrays::Decimal - -pub fn vortex_array::arrays::Decimal::is_sorted(&self, array: &vortex_array::arrays::DecimalArray) -> vortex_error::VortexResult> - -pub fn vortex_array::arrays::Decimal::is_strict_sorted(&self, array: &vortex_array::arrays::DecimalArray) -> vortex_error::VortexResult> - impl vortex_array::optimizer::rules::ArrayParentReduceRule for vortex_array::arrays::decimal::DecimalMaskedValidityRule pub type vortex_array::arrays::decimal::DecimalMaskedValidityRule::Parent = vortex_array::arrays::Masked @@ -1514,12 +1642,6 @@ impl vortex_array::arrays::slice::SliceReduce for vortex_array::arrays::dict::Di pub fn vortex_array::arrays::dict::Dict::slice(array: &Self::Array, range: core::ops::range::Range) -> vortex_error::VortexResult> -impl vortex_array::compute::IsSortedKernel for vortex_array::arrays::dict::Dict - -pub fn vortex_array::arrays::dict::Dict::is_sorted(&self, array: &vortex_array::arrays::dict::DictArray) -> vortex_error::VortexResult> - -pub fn vortex_array::arrays::dict::Dict::is_strict_sorted(&self, array: &vortex_array::arrays::dict::DictArray) -> vortex_error::VortexResult> - impl vortex_array::scalar_fn::fns::binary::CompareKernel for vortex_array::arrays::dict::Dict pub fn vortex_array::arrays::dict::Dict::compare(lhs: &vortex_array::arrays::dict::DictArray, rhs: &vortex_array::ArrayRef, operator: vortex_array::scalar_fn::fns::operators::CompareOperator, ctx: &mut vortex_array::ExecutionCtx) -> vortex_error::VortexResult> @@ -1624,12 +1746,6 @@ impl vortex_array::arrays::slice::SliceReduce for vortex_array::arrays::dict::Di pub fn vortex_array::arrays::dict::Dict::slice(array: &Self::Array, range: core::ops::range::Range) -> vortex_error::VortexResult> -impl vortex_array::compute::IsSortedKernel for vortex_array::arrays::dict::Dict - -pub fn vortex_array::arrays::dict::Dict::is_sorted(&self, array: &vortex_array::arrays::dict::DictArray) -> vortex_error::VortexResult> - -pub fn vortex_array::arrays::dict::Dict::is_strict_sorted(&self, array: &vortex_array::arrays::dict::DictArray) -> vortex_error::VortexResult> - impl vortex_array::scalar_fn::fns::binary::CompareKernel for vortex_array::arrays::dict::Dict pub fn vortex_array::arrays::dict::Dict::compare(lhs: &vortex_array::arrays::dict::DictArray, rhs: &vortex_array::ArrayRef, operator: vortex_array::scalar_fn::fns::operators::CompareOperator, ctx: &mut vortex_array::ExecutionCtx) -> vortex_error::VortexResult> @@ -1934,12 +2050,6 @@ impl vortex_array::arrays::slice::SliceReduce for vortex_array::arrays::Extensio pub fn vortex_array::arrays::Extension::slice(array: &Self::Array, range: core::ops::range::Range) -> vortex_error::VortexResult> -impl vortex_array::compute::IsSortedKernel for vortex_array::arrays::Extension - -pub fn vortex_array::arrays::Extension::is_sorted(&self, array: &vortex_array::arrays::ExtensionArray) -> vortex_error::VortexResult> - -pub fn vortex_array::arrays::Extension::is_strict_sorted(&self, array: &vortex_array::arrays::ExtensionArray) -> vortex_error::VortexResult> - impl vortex_array::scalar_fn::fns::binary::CompareKernel for vortex_array::arrays::Extension pub fn vortex_array::arrays::Extension::compare(lhs: &vortex_array::arrays::ExtensionArray, rhs: &vortex_array::ArrayRef, operator: vortex_array::scalar_fn::fns::operators::CompareOperator, _ctx: &mut vortex_array::ExecutionCtx) -> vortex_error::VortexResult> @@ -2296,12 +2406,6 @@ impl vortex_array::arrays::slice::SliceReduce for vortex_array::arrays::FixedSiz pub fn vortex_array::arrays::FixedSizeList::slice(array: &Self::Array, range: core::ops::range::Range) -> vortex_error::VortexResult> -impl vortex_array::compute::IsSortedKernel for vortex_array::arrays::FixedSizeList - -pub fn vortex_array::arrays::FixedSizeList::is_sorted(&self, _array: &vortex_array::arrays::FixedSizeListArray) -> vortex_error::VortexResult> - -pub fn vortex_array::arrays::FixedSizeList::is_strict_sorted(&self, _array: &vortex_array::arrays::FixedSizeListArray) -> vortex_error::VortexResult> - impl vortex_array::scalar_fn::fns::cast::CastReduce for vortex_array::arrays::FixedSizeList pub fn vortex_array::arrays::FixedSizeList::cast(array: &vortex_array::arrays::FixedSizeListArray, dtype: &vortex_array::dtype::DType) -> vortex_error::VortexResult> @@ -2450,12 +2554,6 @@ impl vortex_array::arrays::slice::SliceReduce for vortex_array::arrays::List pub fn vortex_array::arrays::List::slice(array: &Self::Array, range: core::ops::range::Range) -> vortex_error::VortexResult> -impl vortex_array::compute::IsSortedKernel for vortex_array::arrays::List - -pub fn vortex_array::arrays::List::is_sorted(&self, _array: &vortex_array::arrays::ListArray) -> vortex_error::VortexResult> - -pub fn vortex_array::arrays::List::is_strict_sorted(&self, _array: &vortex_array::arrays::ListArray) -> vortex_error::VortexResult> - impl vortex_array::scalar_fn::fns::cast::CastReduce for vortex_array::arrays::List pub fn vortex_array::arrays::List::cast(array: &vortex_array::arrays::ListArray, dtype: &vortex_array::dtype::DType) -> vortex_error::VortexResult> @@ -2624,12 +2722,6 @@ impl vortex_array::arrays::slice::SliceReduce for vortex_array::arrays::ListView pub fn vortex_array::arrays::ListView::slice(array: &Self::Array, range: core::ops::range::Range) -> vortex_error::VortexResult> -impl vortex_array::compute::IsSortedKernel for vortex_array::arrays::ListView - -pub fn vortex_array::arrays::ListView::is_sorted(&self, _array: &vortex_array::arrays::ListViewArray) -> vortex_error::VortexResult> - -pub fn vortex_array::arrays::ListView::is_strict_sorted(&self, _array: &vortex_array::arrays::ListViewArray) -> vortex_error::VortexResult> - impl vortex_array::scalar_fn::fns::cast::CastReduce for vortex_array::arrays::ListView pub fn vortex_array::arrays::ListView::cast(array: &vortex_array::arrays::ListViewArray, dtype: &vortex_array::dtype::DType) -> vortex_error::VortexResult> @@ -3142,12 +3234,6 @@ impl vortex_array::arrays::slice::SliceReduce for vortex_array::arrays::Primitiv pub fn vortex_array::arrays::Primitive::slice(array: &Self::Array, range: core::ops::range::Range) -> vortex_error::VortexResult> -impl vortex_array::compute::IsSortedKernel for vortex_array::arrays::Primitive - -pub fn vortex_array::arrays::Primitive::is_sorted(&self, array: &vortex_array::arrays::PrimitiveArray) -> vortex_error::VortexResult> - -pub fn vortex_array::arrays::Primitive::is_strict_sorted(&self, array: &vortex_array::arrays::PrimitiveArray) -> vortex_error::VortexResult> - impl vortex_array::optimizer::rules::ArrayParentReduceRule for vortex_array::arrays::primitive::PrimitiveMaskedValidityRule pub type vortex_array::arrays::primitive::PrimitiveMaskedValidityRule::Parent = vortex_array::arrays::Masked @@ -4140,12 +4226,6 @@ impl vortex_array::arrays::slice::SliceReduce for vortex_array::arrays::VarBin pub fn vortex_array::arrays::VarBin::slice(array: &Self::Array, range: core::ops::range::Range) -> vortex_error::VortexResult> -impl vortex_array::compute::IsSortedKernel for vortex_array::arrays::VarBin - -pub fn vortex_array::arrays::VarBin::is_sorted(&self, array: &vortex_array::arrays::VarBinArray) -> vortex_error::VortexResult> - -pub fn vortex_array::arrays::VarBin::is_strict_sorted(&self, array: &vortex_array::arrays::VarBinArray) -> vortex_error::VortexResult> - impl vortex_array::scalar_fn::fns::binary::CompareKernel for vortex_array::arrays::VarBin pub fn vortex_array::arrays::VarBin::compare(lhs: &vortex_array::arrays::VarBinArray, rhs: &vortex_array::ArrayRef, operator: vortex_array::scalar_fn::fns::operators::CompareOperator, ctx: &mut vortex_array::ExecutionCtx) -> vortex_error::VortexResult> @@ -4548,12 +4628,6 @@ impl vortex_array::arrays::slice::SliceReduce for vortex_array::arrays::VarBinVi pub fn vortex_array::arrays::VarBinView::slice(array: &Self::Array, range: core::ops::range::Range) -> vortex_error::VortexResult> -impl vortex_array::compute::IsSortedKernel for vortex_array::arrays::VarBinView - -pub fn vortex_array::arrays::VarBinView::is_sorted(&self, array: &vortex_array::arrays::VarBinViewArray) -> vortex_error::VortexResult> - -pub fn vortex_array::arrays::VarBinView::is_strict_sorted(&self, array: &vortex_array::arrays::VarBinViewArray) -> vortex_error::VortexResult> - impl vortex_array::scalar_fn::fns::cast::CastReduce for vortex_array::arrays::VarBinView pub fn vortex_array::arrays::VarBinView::cast(array: &vortex_array::arrays::VarBinViewArray, dtype: &vortex_array::dtype::DType) -> vortex_error::VortexResult> @@ -4766,12 +4840,6 @@ impl vortex_array::arrays::slice::SliceReduce for vortex_array::arrays::Bool pub fn vortex_array::arrays::Bool::slice(array: &Self::Array, range: core::ops::range::Range) -> vortex_error::VortexResult> -impl vortex_array::compute::IsSortedKernel for vortex_array::arrays::Bool - -pub fn vortex_array::arrays::Bool::is_sorted(&self, array: &vortex_array::arrays::BoolArray) -> vortex_error::VortexResult> - -pub fn vortex_array::arrays::Bool::is_strict_sorted(&self, array: &vortex_array::arrays::BoolArray) -> vortex_error::VortexResult> - impl vortex_array::optimizer::rules::ArrayParentReduceRule for vortex_array::arrays::bool::BoolMaskedValidityRule pub type vortex_array::arrays::bool::BoolMaskedValidityRule::Parent = vortex_array::arrays::Masked @@ -4954,12 +5022,6 @@ impl vortex_array::arrays::slice::SliceKernel for vortex_array::arrays::Chunked pub fn vortex_array::arrays::Chunked::slice(array: &Self::Array, range: core::ops::range::Range, _ctx: &mut vortex_array::ExecutionCtx) -> vortex_error::VortexResult> -impl vortex_array::compute::IsSortedKernel for vortex_array::arrays::Chunked - -pub fn vortex_array::arrays::Chunked::is_sorted(&self, array: &vortex_array::arrays::ChunkedArray) -> vortex_error::VortexResult> - -pub fn vortex_array::arrays::Chunked::is_strict_sorted(&self, array: &vortex_array::arrays::ChunkedArray) -> vortex_error::VortexResult> - impl vortex_array::scalar_fn::fns::cast::CastReduce for vortex_array::arrays::Chunked pub fn vortex_array::arrays::Chunked::cast(array: &vortex_array::arrays::ChunkedArray, dtype: &vortex_array::dtype::DType) -> vortex_error::VortexResult> @@ -5260,12 +5322,6 @@ impl vortex_array::arrays::slice::SliceReduce for vortex_array::arrays::Decimal pub fn vortex_array::arrays::Decimal::slice(array: &Self::Array, range: core::ops::range::Range) -> vortex_error::VortexResult> -impl vortex_array::compute::IsSortedKernel for vortex_array::arrays::Decimal - -pub fn vortex_array::arrays::Decimal::is_sorted(&self, array: &vortex_array::arrays::DecimalArray) -> vortex_error::VortexResult> - -pub fn vortex_array::arrays::Decimal::is_strict_sorted(&self, array: &vortex_array::arrays::DecimalArray) -> vortex_error::VortexResult> - impl vortex_array::optimizer::rules::ArrayParentReduceRule for vortex_array::arrays::decimal::DecimalMaskedValidityRule pub type vortex_array::arrays::decimal::DecimalMaskedValidityRule::Parent = vortex_array::arrays::Masked @@ -5444,12 +5500,6 @@ impl vortex_array::arrays::slice::SliceReduce for vortex_array::arrays::dict::Di pub fn vortex_array::arrays::dict::Dict::slice(array: &Self::Array, range: core::ops::range::Range) -> vortex_error::VortexResult> -impl vortex_array::compute::IsSortedKernel for vortex_array::arrays::dict::Dict - -pub fn vortex_array::arrays::dict::Dict::is_sorted(&self, array: &vortex_array::arrays::dict::DictArray) -> vortex_error::VortexResult> - -pub fn vortex_array::arrays::dict::Dict::is_strict_sorted(&self, array: &vortex_array::arrays::dict::DictArray) -> vortex_error::VortexResult> - impl vortex_array::scalar_fn::fns::binary::CompareKernel for vortex_array::arrays::dict::Dict pub fn vortex_array::arrays::dict::Dict::compare(lhs: &vortex_array::arrays::dict::DictArray, rhs: &vortex_array::ArrayRef, operator: vortex_array::scalar_fn::fns::operators::CompareOperator, ctx: &mut vortex_array::ExecutionCtx) -> vortex_error::VortexResult> @@ -5612,12 +5662,6 @@ impl vortex_array::arrays::slice::SliceReduce for vortex_array::arrays::Extensio pub fn vortex_array::arrays::Extension::slice(array: &Self::Array, range: core::ops::range::Range) -> vortex_error::VortexResult> -impl vortex_array::compute::IsSortedKernel for vortex_array::arrays::Extension - -pub fn vortex_array::arrays::Extension::is_sorted(&self, array: &vortex_array::arrays::ExtensionArray) -> vortex_error::VortexResult> - -pub fn vortex_array::arrays::Extension::is_strict_sorted(&self, array: &vortex_array::arrays::ExtensionArray) -> vortex_error::VortexResult> - impl vortex_array::scalar_fn::fns::binary::CompareKernel for vortex_array::arrays::Extension pub fn vortex_array::arrays::Extension::compare(lhs: &vortex_array::arrays::ExtensionArray, rhs: &vortex_array::ArrayRef, operator: vortex_array::scalar_fn::fns::operators::CompareOperator, _ctx: &mut vortex_array::ExecutionCtx) -> vortex_error::VortexResult> @@ -5888,12 +5932,6 @@ impl vortex_array::arrays::slice::SliceReduce for vortex_array::arrays::FixedSiz pub fn vortex_array::arrays::FixedSizeList::slice(array: &Self::Array, range: core::ops::range::Range) -> vortex_error::VortexResult> -impl vortex_array::compute::IsSortedKernel for vortex_array::arrays::FixedSizeList - -pub fn vortex_array::arrays::FixedSizeList::is_sorted(&self, _array: &vortex_array::arrays::FixedSizeListArray) -> vortex_error::VortexResult> - -pub fn vortex_array::arrays::FixedSizeList::is_strict_sorted(&self, _array: &vortex_array::arrays::FixedSizeListArray) -> vortex_error::VortexResult> - impl vortex_array::scalar_fn::fns::cast::CastReduce for vortex_array::arrays::FixedSizeList pub fn vortex_array::arrays::FixedSizeList::cast(array: &vortex_array::arrays::FixedSizeListArray, dtype: &vortex_array::dtype::DType) -> vortex_error::VortexResult> @@ -6040,12 +6078,6 @@ impl vortex_array::arrays::slice::SliceReduce for vortex_array::arrays::List pub fn vortex_array::arrays::List::slice(array: &Self::Array, range: core::ops::range::Range) -> vortex_error::VortexResult> -impl vortex_array::compute::IsSortedKernel for vortex_array::arrays::List - -pub fn vortex_array::arrays::List::is_sorted(&self, _array: &vortex_array::arrays::ListArray) -> vortex_error::VortexResult> - -pub fn vortex_array::arrays::List::is_strict_sorted(&self, _array: &vortex_array::arrays::ListArray) -> vortex_error::VortexResult> - impl vortex_array::scalar_fn::fns::cast::CastReduce for vortex_array::arrays::List pub fn vortex_array::arrays::List::cast(array: &vortex_array::arrays::ListArray, dtype: &vortex_array::dtype::DType) -> vortex_error::VortexResult> @@ -6192,12 +6224,6 @@ impl vortex_array::arrays::slice::SliceReduce for vortex_array::arrays::ListView pub fn vortex_array::arrays::ListView::slice(array: &Self::Array, range: core::ops::range::Range) -> vortex_error::VortexResult> -impl vortex_array::compute::IsSortedKernel for vortex_array::arrays::ListView - -pub fn vortex_array::arrays::ListView::is_sorted(&self, _array: &vortex_array::arrays::ListViewArray) -> vortex_error::VortexResult> - -pub fn vortex_array::arrays::ListView::is_strict_sorted(&self, _array: &vortex_array::arrays::ListViewArray) -> vortex_error::VortexResult> - impl vortex_array::scalar_fn::fns::cast::CastReduce for vortex_array::arrays::ListView pub fn vortex_array::arrays::ListView::cast(array: &vortex_array::arrays::ListViewArray, dtype: &vortex_array::dtype::DType) -> vortex_error::VortexResult> @@ -6618,12 +6644,6 @@ impl vortex_array::arrays::slice::SliceReduce for vortex_array::arrays::Primitiv pub fn vortex_array::arrays::Primitive::slice(array: &Self::Array, range: core::ops::range::Range) -> vortex_error::VortexResult> -impl vortex_array::compute::IsSortedKernel for vortex_array::arrays::Primitive - -pub fn vortex_array::arrays::Primitive::is_sorted(&self, array: &vortex_array::arrays::PrimitiveArray) -> vortex_error::VortexResult> - -pub fn vortex_array::arrays::Primitive::is_strict_sorted(&self, array: &vortex_array::arrays::PrimitiveArray) -> vortex_error::VortexResult> - impl vortex_array::optimizer::rules::ArrayParentReduceRule for vortex_array::arrays::primitive::PrimitiveMaskedValidityRule pub type vortex_array::arrays::primitive::PrimitiveMaskedValidityRule::Parent = vortex_array::arrays::Masked @@ -7432,12 +7452,6 @@ impl vortex_array::arrays::slice::SliceReduce for vortex_array::arrays::VarBin pub fn vortex_array::arrays::VarBin::slice(array: &Self::Array, range: core::ops::range::Range) -> vortex_error::VortexResult> -impl vortex_array::compute::IsSortedKernel for vortex_array::arrays::VarBin - -pub fn vortex_array::arrays::VarBin::is_sorted(&self, array: &vortex_array::arrays::VarBinArray) -> vortex_error::VortexResult> - -pub fn vortex_array::arrays::VarBin::is_strict_sorted(&self, array: &vortex_array::arrays::VarBinArray) -> vortex_error::VortexResult> - impl vortex_array::scalar_fn::fns::binary::CompareKernel for vortex_array::arrays::VarBin pub fn vortex_array::arrays::VarBin::compare(lhs: &vortex_array::arrays::VarBinArray, rhs: &vortex_array::ArrayRef, operator: vortex_array::scalar_fn::fns::operators::CompareOperator, ctx: &mut vortex_array::ExecutionCtx) -> vortex_error::VortexResult> @@ -7654,12 +7668,6 @@ impl vortex_array::arrays::slice::SliceReduce for vortex_array::arrays::VarBinVi pub fn vortex_array::arrays::VarBinView::slice(array: &Self::Array, range: core::ops::range::Range) -> vortex_error::VortexResult> -impl vortex_array::compute::IsSortedKernel for vortex_array::arrays::VarBinView - -pub fn vortex_array::arrays::VarBinView::is_sorted(&self, array: &vortex_array::arrays::VarBinViewArray) -> vortex_error::VortexResult> - -pub fn vortex_array::arrays::VarBinView::is_strict_sorted(&self, array: &vortex_array::arrays::VarBinViewArray) -> vortex_error::VortexResult> - impl vortex_array::scalar_fn::fns::cast::CastReduce for vortex_array::arrays::VarBinView pub fn vortex_array::arrays::VarBinView::cast(array: &vortex_array::arrays::VarBinViewArray, dtype: &vortex_array::dtype::DType) -> vortex_error::VortexResult> @@ -9596,24 +9604,6 @@ impl vortex_array::compute::Options for vortex_array::compute::IsConstantOpts pub fn vortex_array::compute::IsConstantOpts::as_any(&self) -> &dyn core::any::Any -pub struct vortex_array::compute::IsSortedKernelAdapter(pub V) - -impl vortex_array::compute::IsSortedKernelAdapter - -pub const fn vortex_array::compute::IsSortedKernelAdapter::lift(&'static self) -> vortex_array::compute::IsSortedKernelRef - -impl core::fmt::Debug for vortex_array::compute::IsSortedKernelAdapter - -pub fn vortex_array::compute::IsSortedKernelAdapter::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result - -impl vortex_array::compute::Kernel for vortex_array::compute::IsSortedKernelAdapter - -pub fn vortex_array::compute::IsSortedKernelAdapter::invoke(&self, args: &vortex_array::compute::InvocationArgs<'_>) -> vortex_error::VortexResult> - -pub struct vortex_array::compute::IsSortedKernelRef(_) - -impl inventory::Collect for vortex_array::compute::IsSortedKernelRef - pub struct vortex_array::compute::MinMaxResult pub vortex_array::compute::MinMaxResult::max: vortex_array::scalar::Scalar @@ -9662,94 +9652,10 @@ pub fn vortex_array::compute::ComputeFnVTable::return_dtype(&self, args: &vortex pub fn vortex_array::compute::ComputeFnVTable::return_len(&self, args: &vortex_array::compute::InvocationArgs<'_>) -> vortex_error::VortexResult -pub trait vortex_array::compute::IsSortedIteratorExt where ::Item: core::cmp::PartialOrd: core::iter::traits::iterator::Iterator - -pub fn vortex_array::compute::IsSortedIteratorExt::is_strict_sorted(self) -> bool where Self: core::marker::Sized, Self::Item: core::cmp::PartialOrd - -impl vortex_array::compute::IsSortedIteratorExt for T where T: core::iter::traits::iterator::Iterator + ?core::marker::Sized, ::Item: core::cmp::PartialOrd - -pub fn T::is_strict_sorted(self) -> bool where Self: core::marker::Sized, Self::Item: core::cmp::PartialOrd - -pub trait vortex_array::compute::IsSortedKernel: vortex_array::vtable::VTable - -pub fn vortex_array::compute::IsSortedKernel::is_sorted(&self, array: &Self::Array) -> vortex_error::VortexResult> - -pub fn vortex_array::compute::IsSortedKernel::is_strict_sorted(&self, array: &Self::Array) -> vortex_error::VortexResult> - -impl vortex_array::compute::IsSortedKernel for vortex_array::arrays::Bool - -pub fn vortex_array::arrays::Bool::is_sorted(&self, array: &vortex_array::arrays::BoolArray) -> vortex_error::VortexResult> - -pub fn vortex_array::arrays::Bool::is_strict_sorted(&self, array: &vortex_array::arrays::BoolArray) -> vortex_error::VortexResult> - -impl vortex_array::compute::IsSortedKernel for vortex_array::arrays::Chunked - -pub fn vortex_array::arrays::Chunked::is_sorted(&self, array: &vortex_array::arrays::ChunkedArray) -> vortex_error::VortexResult> - -pub fn vortex_array::arrays::Chunked::is_strict_sorted(&self, array: &vortex_array::arrays::ChunkedArray) -> vortex_error::VortexResult> - -impl vortex_array::compute::IsSortedKernel for vortex_array::arrays::Decimal - -pub fn vortex_array::arrays::Decimal::is_sorted(&self, array: &vortex_array::arrays::DecimalArray) -> vortex_error::VortexResult> - -pub fn vortex_array::arrays::Decimal::is_strict_sorted(&self, array: &vortex_array::arrays::DecimalArray) -> vortex_error::VortexResult> - -impl vortex_array::compute::IsSortedKernel for vortex_array::arrays::Extension - -pub fn vortex_array::arrays::Extension::is_sorted(&self, array: &vortex_array::arrays::ExtensionArray) -> vortex_error::VortexResult> - -pub fn vortex_array::arrays::Extension::is_strict_sorted(&self, array: &vortex_array::arrays::ExtensionArray) -> vortex_error::VortexResult> - -impl vortex_array::compute::IsSortedKernel for vortex_array::arrays::FixedSizeList - -pub fn vortex_array::arrays::FixedSizeList::is_sorted(&self, _array: &vortex_array::arrays::FixedSizeListArray) -> vortex_error::VortexResult> - -pub fn vortex_array::arrays::FixedSizeList::is_strict_sorted(&self, _array: &vortex_array::arrays::FixedSizeListArray) -> vortex_error::VortexResult> - -impl vortex_array::compute::IsSortedKernel for vortex_array::arrays::List - -pub fn vortex_array::arrays::List::is_sorted(&self, _array: &vortex_array::arrays::ListArray) -> vortex_error::VortexResult> - -pub fn vortex_array::arrays::List::is_strict_sorted(&self, _array: &vortex_array::arrays::ListArray) -> vortex_error::VortexResult> - -impl vortex_array::compute::IsSortedKernel for vortex_array::arrays::ListView - -pub fn vortex_array::arrays::ListView::is_sorted(&self, _array: &vortex_array::arrays::ListViewArray) -> vortex_error::VortexResult> - -pub fn vortex_array::arrays::ListView::is_strict_sorted(&self, _array: &vortex_array::arrays::ListViewArray) -> vortex_error::VortexResult> - -impl vortex_array::compute::IsSortedKernel for vortex_array::arrays::Primitive - -pub fn vortex_array::arrays::Primitive::is_sorted(&self, array: &vortex_array::arrays::PrimitiveArray) -> vortex_error::VortexResult> - -pub fn vortex_array::arrays::Primitive::is_strict_sorted(&self, array: &vortex_array::arrays::PrimitiveArray) -> vortex_error::VortexResult> - -impl vortex_array::compute::IsSortedKernel for vortex_array::arrays::VarBin - -pub fn vortex_array::arrays::VarBin::is_sorted(&self, array: &vortex_array::arrays::VarBinArray) -> vortex_error::VortexResult> - -pub fn vortex_array::arrays::VarBin::is_strict_sorted(&self, array: &vortex_array::arrays::VarBinArray) -> vortex_error::VortexResult> - -impl vortex_array::compute::IsSortedKernel for vortex_array::arrays::VarBinView - -pub fn vortex_array::arrays::VarBinView::is_sorted(&self, array: &vortex_array::arrays::VarBinViewArray) -> vortex_error::VortexResult> - -pub fn vortex_array::arrays::VarBinView::is_strict_sorted(&self, array: &vortex_array::arrays::VarBinViewArray) -> vortex_error::VortexResult> - -impl vortex_array::compute::IsSortedKernel for vortex_array::arrays::dict::Dict - -pub fn vortex_array::arrays::dict::Dict::is_sorted(&self, array: &vortex_array::arrays::dict::DictArray) -> vortex_error::VortexResult> - -pub fn vortex_array::arrays::dict::Dict::is_strict_sorted(&self, array: &vortex_array::arrays::dict::DictArray) -> vortex_error::VortexResult> - pub trait vortex_array::compute::Kernel: 'static + core::marker::Send + core::marker::Sync + core::fmt::Debug pub fn vortex_array::compute::Kernel::invoke(&self, args: &vortex_array::compute::InvocationArgs<'_>) -> vortex_error::VortexResult> -impl vortex_array::compute::Kernel for vortex_array::compute::IsSortedKernelAdapter - -pub fn vortex_array::compute::IsSortedKernelAdapter::invoke(&self, args: &vortex_array::compute::InvocationArgs<'_>) -> vortex_error::VortexResult> - pub trait vortex_array::compute::Options: 'static pub fn vortex_array::compute::Options::as_any(&self) -> &dyn core::any::Any @@ -9772,8 +9678,6 @@ pub fn vortex_array::compute::is_constant_opts(array: &vortex_array::ArrayRef, _ pub fn vortex_array::compute::is_sorted(array: &vortex_array::ArrayRef) -> vortex_error::VortexResult> -pub fn vortex_array::compute::is_sorted_opts(array: &vortex_array::ArrayRef, strict: bool) -> vortex_error::VortexResult> - pub fn vortex_array::compute::is_strict_sorted(array: &vortex_array::ArrayRef) -> vortex_error::VortexResult> pub fn vortex_array::compute::min_max(array: &vortex_array::ArrayRef) -> vortex_error::VortexResult> @@ -9782,8 +9686,6 @@ pub fn vortex_array::compute::nan_count(array: &vortex_array::ArrayRef) -> vorte pub fn vortex_array::compute::sum(array: &vortex_array::ArrayRef) -> vortex_error::VortexResult -pub fn vortex_array::compute::warm_up_vtables() - pub mod vortex_array::display pub enum vortex_array::display::DisplayOptions diff --git a/vortex-array/src/aggregate_fn/accumulator.rs b/vortex-array/src/aggregate_fn/accumulator.rs index 107b13d0985..95d5268b969 100644 --- a/vortex-array/src/aggregate_fn/accumulator.rs +++ b/vortex-array/src/aggregate_fn/accumulator.rs @@ -146,7 +146,8 @@ impl DynAccumulator for Accumulator { } fn flush(&mut self) -> VortexResult { - let partial = self.vtable.flush(&mut self.partial)?; + let partial = self.vtable.to_scalar(&self.partial)?; + self.vtable.reset(&mut self.partial); #[cfg(debug_assertions)] { @@ -162,8 +163,8 @@ impl DynAccumulator for Accumulator { } fn finish(&mut self) -> VortexResult { - let partial = self.flush()?; - let result = self.vtable.finalize_scalar(partial)?; + let result = self.vtable.finalize_scalar(&self.partial)?; + self.vtable.reset(&mut self.partial); vortex_ensure!( result.dtype() == &self.return_dtype, diff --git a/vortex-array/src/aggregate_fn/fns/is_constant/mod.rs b/vortex-array/src/aggregate_fn/fns/is_constant/mod.rs index d71cfd19d91..98e7ff4bde3 100644 --- a/vortex-array/src/aggregate_fn/fns/is_constant/mod.rs +++ b/vortex-array/src/aggregate_fn/fns/is_constant/mod.rs @@ -315,9 +315,9 @@ impl AggregateFnVTable for IsConstant { Ok(()) } - fn flush(&self, partial: &mut Self::Partial) -> VortexResult { + fn to_scalar(&self, partial: &Self::Partial) -> VortexResult { let dtype = make_is_constant_partial_dtype(&partial.element_dtype); - let result = match &partial.first_value { + Ok(match &partial.first_value { None => { // Empty accumulator — return null struct. Scalar::null(dtype) @@ -331,13 +331,12 @@ impl AggregateFnVTable for IsConstant { .cast(&partial.element_dtype.as_nullable())?, ], ), - }; + }) + } - // Reset state. + fn reset(&self, partial: &mut Self::Partial) { partial.is_constant = true; partial.first_value = None; - - Ok(result) } #[inline] @@ -414,17 +413,12 @@ impl AggregateFnVTable for IsConstant { partials.get_item(NAMES.get(0).vortex_expect("out of bounds").clone()) } - fn finalize_scalar(&self, partial: Scalar) -> VortexResult { - if partial.is_null() { + fn finalize_scalar(&self, partial: &Self::Partial) -> VortexResult { + if partial.first_value.is_none() { // Empty accumulator → return false. return Ok(Scalar::bool(false, Nullability::NonNullable)); } - let is_constant_val = partial - .as_struct() - .field_by_idx(0) - .map(|s| s.as_bool().value().unwrap_or(false)) - .unwrap_or(false); - Ok(Scalar::bool(is_constant_val, Nullability::NonNullable)) + Ok(Scalar::bool(partial.is_constant, Nullability::NonNullable)) } } diff --git a/vortex-array/src/aggregate_fn/fns/is_sorted/bool.rs b/vortex-array/src/aggregate_fn/fns/is_sorted/bool.rs new file mode 100644 index 00000000000..ab515e713d9 --- /dev/null +++ b/vortex-array/src/aggregate_fn/fns/is_sorted/bool.rs @@ -0,0 +1,43 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: Copyright the Vortex contributors + +use vortex_error::VortexResult; +use vortex_mask::Mask; + +use super::IsSortedIteratorExt; +use crate::arrays::BoolArray; + +pub(super) fn check_bool_sorted(array: &BoolArray, strict: bool) -> VortexResult { + match array.validity_mask()? { + Mask::AllFalse(_) => Ok(!strict), + Mask::AllTrue(_) => { + let values = array.to_bit_buffer(); + Ok(if strict { + values.iter().is_strict_sorted() + } else { + values.iter().is_sorted() + }) + } + Mask::Values(mask_values) => { + if strict { + let validity_buffer = mask_values.bit_buffer(); + let values = array.to_bit_buffer(); + Ok(validity_buffer + .iter() + .zip(values.iter()) + .map(|(is_valid, value)| is_valid.then_some(value)) + .is_strict_sorted()) + } else { + let set_indices = mask_values.bit_buffer().set_indices(); + let values = array.to_bit_buffer(); + let values_iter = set_indices.map(|idx| + // Safety: + // All idxs are in-bounds for the array. + unsafe { + values.value_unchecked(idx) + }); + Ok(values_iter.is_sorted()) + } + } + } +} diff --git a/vortex-array/src/aggregate_fn/fns/is_sorted/decimal.rs b/vortex-array/src/aggregate_fn/fns/is_sorted/decimal.rs new file mode 100644 index 00000000000..e56858fd015 --- /dev/null +++ b/vortex-array/src/aggregate_fn/fns/is_sorted/decimal.rs @@ -0,0 +1,50 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: Copyright the Vortex contributors + +use itertools::Itertools; +use vortex_error::VortexResult; +use vortex_mask::Mask; + +use super::IsSortedIteratorExt; +use crate::arrays::DecimalArray; +use crate::dtype::NativeDecimalType; +use crate::match_each_decimal_value_type; + +pub(super) fn check_decimal_sorted(array: &DecimalArray, strict: bool) -> VortexResult { + match_each_decimal_value_type!(array.values_type(), |S| { + compute_is_sorted::(array, strict) + }) +} + +fn compute_is_sorted(array: &DecimalArray, strict: bool) -> VortexResult +where + dyn Iterator: IsSortedIteratorExt, +{ + match array.validity_mask()? { + Mask::AllFalse(_) => Ok(!strict), + Mask::AllTrue(_) => { + let buf = array.buffer::(); + let iter = buf.iter().copied(); + + Ok(if strict { + IsSortedIteratorExt::is_strict_sorted(iter) + } else { + iter.is_sorted() + }) + } + Mask::Values(mask_values) => { + let values = array.buffer::(); + let iter = mask_values + .bit_buffer() + .iter() + .zip_eq(values) + .map(|(is_valid, v)| is_valid.then_some(v)); + + Ok(if strict { + IsSortedIteratorExt::is_strict_sorted(iter) + } else { + iter.is_sorted() + }) + } + } +} diff --git a/vortex-array/src/aggregate_fn/fns/is_sorted/extension.rs b/vortex-array/src/aggregate_fn/fns/is_sorted/extension.rs new file mode 100644 index 00000000000..2839cb5756f --- /dev/null +++ b/vortex-array/src/aggregate_fn/fns/is_sorted/extension.rs @@ -0,0 +1,21 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: Copyright the Vortex contributors + +use vortex_error::VortexResult; + +use crate::ExecutionCtx; +use crate::aggregate_fn::fns::is_sorted::is_sorted; +use crate::aggregate_fn::fns::is_sorted::is_strict_sorted; +use crate::arrays::ExtensionArray; + +pub(super) fn check_extension_sorted( + array: &ExtensionArray, + strict: bool, + ctx: &mut ExecutionCtx, +) -> VortexResult { + if strict { + is_strict_sorted(array.storage_array(), ctx) + } else { + is_sorted(array.storage_array(), ctx) + } +} diff --git a/vortex-array/src/aggregate_fn/fns/is_sorted/mod.rs b/vortex-array/src/aggregate_fn/fns/is_sorted/mod.rs new file mode 100644 index 00000000000..8a9c4e295f2 --- /dev/null +++ b/vortex-array/src/aggregate_fn/fns/is_sorted/mod.rs @@ -0,0 +1,690 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: Copyright the Vortex contributors + +mod bool; +mod decimal; +mod extension; +mod primitive; +mod varbin; + +use std::fmt; +use std::fmt::Display; +use std::fmt::Formatter; + +use vortex_error::VortexExpect; +use vortex_error::VortexResult; + +use self::bool::check_bool_sorted; +use self::decimal::check_decimal_sorted; +use self::extension::check_extension_sorted; +use self::primitive::check_primitive_sorted; +use self::varbin::check_varbinview_sorted; +use crate::ArrayRef; +use crate::Canonical; +use crate::Columnar; +use crate::DynArray; +use crate::ExecutionCtx; +use crate::IntoArray; +use crate::aggregate_fn::Accumulator; +use crate::aggregate_fn::AggregateFnId; +use crate::aggregate_fn::AggregateFnVTable; +use crate::aggregate_fn::DynAccumulator; +use crate::arrays::Constant; +use crate::arrays::Null; +use crate::builtins::ArrayBuiltins; +use crate::dtype::DType; +use crate::dtype::FieldNames; +use crate::dtype::Nullability; +use crate::dtype::StructFields; +use crate::expr::stats::Precision; +use crate::expr::stats::Stat; +use crate::expr::stats::StatsProviderExt; +use crate::scalar::Scalar; + +/// Options for the `is_sorted` aggregate function. +#[derive(Clone, Debug, PartialEq, Eq, Hash)] +pub struct IsSortedOptions { + /// If true, check for strictly ascending order (no duplicates). + pub strict: bool, +} + +impl Display for IsSortedOptions { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + write!(f, "strict={}", self.strict) + } +} + +/// Compute whether an array is sorted in non-decreasing order. +/// +/// Returns `true` for empty arrays and arrays of length 1. +/// Returns `false` for struct, list, and fixed-size list arrays. +pub fn is_sorted(array: &ArrayRef, ctx: &mut ExecutionCtx) -> VortexResult { + is_sorted_impl(array, false, ctx) +} + +/// Compute whether an array is strictly sorted in increasing order (no duplicates). +/// +/// Returns `true` for empty arrays and arrays of length 1. +/// Returns `false` for struct, list, and fixed-size list arrays. +pub fn is_strict_sorted(array: &ArrayRef, ctx: &mut ExecutionCtx) -> VortexResult { + is_sorted_impl(array, true, ctx) +} + +fn is_sorted_impl(array: &ArrayRef, strict: bool, ctx: &mut ExecutionCtx) -> VortexResult { + let stat = if strict { + Stat::IsStrictSorted + } else { + Stat::IsSorted + }; + + // Short-circuit using cached array statistics. + if let Some(Precision::Exact(value)) = array.statistics().get_as::(stat) { + return Ok(value); + } + + // Arrays with 0 or 1 elements are (strict) sorted. + if array.len() <= 1 { + return Ok(true); + } + + // Constant and null arrays are always sorted, but not strict sorted. + if array.is::() || array.is::() { + let result = !strict; + cache_is_sorted(array, strict, result); + return Ok(result); + } + + // We don't support sorting struct arrays. + if array.dtype().is_struct() { + return Ok(false); + } + + // Short-circuit for unsupported dtypes. + if IsSorted + .return_dtype(&IsSortedOptions { strict }, array.dtype()) + .is_none() + { + return Ok(false); + } + + // Enforce strictness before we even try to check if the array is sorted. + if strict { + let invalid_count = array.invalid_count()?; + match invalid_count { + // We can keep going + 0 => {} + // If we have a potential null value - it has to be the first one. + 1 => { + if !array.is_invalid(0)? { + cache_is_sorted(array, strict, false); + return Ok(false); + } + } + _ => { + cache_is_sorted(array, strict, false); + return Ok(false); + } + } + } + + // Compute using Accumulator. + let mut acc = + Accumulator::try_new(IsSorted, IsSortedOptions { strict }, array.dtype().clone())?; + acc.accumulate(array, ctx)?; + let result_scalar = acc.finish()?; + + let result = result_scalar.as_bool().value().unwrap_or(false); + + // Cache the computed result as statistics. + cache_is_sorted(array, strict, result); + + Ok(result) +} + +fn cache_is_sorted(array: &ArrayRef, strict: bool, result: bool) { + let array_stats = array.statistics(); + if strict { + if result { + array_stats.set(Stat::IsSorted, Precision::Exact(true.into())); + array_stats.set(Stat::IsStrictSorted, Precision::Exact(true.into())); + } else { + array_stats.set(Stat::IsStrictSorted, Precision::Exact(false.into())); + } + } else if result { + array_stats.set(Stat::IsSorted, Precision::Exact(true.into())); + } else { + array_stats.set(Stat::IsSorted, Precision::Exact(false.into())); + array_stats.set(Stat::IsStrictSorted, Precision::Exact(false.into())); + } +} + +/// Aggregate function vtable for `is_sorted`. +/// +/// Returns `Bool(NonNullable)` scalar. +/// The partial state is a nullable struct `{is_sorted: Bool(NN), first_value: T?, last_value: T?}`. +/// A null struct means the accumulator has seen no data yet (empty). +#[derive(Clone, Debug)] +pub struct IsSorted; + +impl IsSorted { + /// Build a partial scalar from a kernel's `is_sorted` result. + /// + /// Kernels that compute `is_sorted` by delegating to child arrays can call this + /// to package the boolean result into the partial struct format expected by the + /// accumulator, avoiding duplicated boilerplate. + pub fn make_partial(batch: &ArrayRef, is_sorted: bool, strict: bool) -> VortexResult { + let partial_dtype = make_is_sorted_partial_dtype(batch.dtype()); + if batch.is_empty() { + return Ok(Scalar::null(partial_dtype)); + } + let first_value = batch.scalar_at(0)?.into_nullable(); + let last_value = batch.scalar_at(batch.len() - 1)?.into_nullable(); + // SAFETY: We constructed partial_dtype and the children match its field dtypes exactly. + Ok(unsafe { + Scalar::struct_unchecked( + partial_dtype, + [ + Scalar::bool(is_sorted, Nullability::NonNullable), + Scalar::bool(strict, Nullability::NonNullable), + first_value, + last_value, + ], + ) + }) + } +} + +/// Partial accumulator state for is_sorted. +pub struct IsSortedPartial { + is_sorted: bool, + strict: bool, + /// None = empty (no values seen). + first_value: Option, + last_value: Option, + element_dtype: DType, +} + +static NAMES: std::sync::LazyLock = std::sync::LazyLock::new(|| { + FieldNames::from(["is_sorted", "strict", "first_value", "last_value"]) +}); + +pub fn make_is_sorted_partial_dtype(element_dtype: &DType) -> DType { + DType::Struct( + StructFields::new( + NAMES.clone(), + vec![ + DType::Bool(Nullability::NonNullable), + DType::Bool(Nullability::NonNullable), + element_dtype.as_nullable(), + element_dtype.as_nullable(), + ], + ), + Nullability::Nullable, + ) +} + +impl AggregateFnVTable for IsSorted { + type Options = IsSortedOptions; + type Partial = IsSortedPartial; + + fn id(&self) -> AggregateFnId { + AggregateFnId::new_ref("vortex.is_sorted") + } + + fn return_dtype(&self, _options: &Self::Options, input_dtype: &DType) -> Option { + match input_dtype { + DType::Null | DType::Struct(..) | DType::List(..) | DType::FixedSizeList(..) => None, + _ => Some(DType::Bool(Nullability::NonNullable)), + } + } + + fn partial_dtype(&self, _options: &Self::Options, input_dtype: &DType) -> Option { + match input_dtype { + DType::Null | DType::Struct(..) | DType::List(..) | DType::FixedSizeList(..) => None, + _ => Some(make_is_sorted_partial_dtype(input_dtype)), + } + } + + fn empty_partial( + &self, + options: &Self::Options, + input_dtype: &DType, + ) -> VortexResult { + Ok(IsSortedPartial { + is_sorted: true, + strict: options.strict, + first_value: None, + last_value: None, + element_dtype: input_dtype.clone(), + }) + } + + fn combine_partials(&self, partial: &mut Self::Partial, other: Scalar) -> VortexResult<()> { + if !partial.is_sorted { + return Ok(()); + } + + // Null struct means the other accumulator was empty, skip it. + if other.is_null() { + return Ok(()); + } + + let other_is_sorted = other + .as_struct() + .field_by_idx(0) + .map(|s| s.as_bool().value().unwrap_or(false)) + .unwrap_or(false); + + let other_first = other.as_struct().field_by_idx(2); + let other_last = other.as_struct().field_by_idx(3); + + if !other_is_sorted { + partial.is_sorted = false; + // Still update last_value for correctness if needed, but we're done. + if let Some(last) = other_last { + partial.last_value = Some(last); + } + return Ok(()); + } + + // Check boundary: self.last_value vs other.first_value + if let Some(ref self_last) = partial.last_value + && let Some(ref other_first_val) = other_first + { + if !self_last.is_null() && !other_first_val.is_null() { + let boundary_ok = if partial.strict { + *self_last < *other_first_val + } else { + *self_last <= *other_first_val + }; + if !boundary_ok { + partial.is_sorted = false; + } + } else if !self_last.is_null() && other_first_val.is_null() { + // non-null before null violates sort order + partial.is_sorted = false; + } else if self_last.is_null() && other_first_val.is_null() && partial.strict { + // both null with strict: violates strict sort + partial.is_sorted = false; + } + } + + // Update first_value if this is the first non-empty chunk. + if partial.first_value.is_none() { + partial.first_value = other_first; + } + if let Some(last) = other_last { + partial.last_value = Some(last); + } + + Ok(()) + } + + fn to_scalar(&self, partial: &Self::Partial) -> VortexResult { + let dtype = make_is_sorted_partial_dtype(&partial.element_dtype); + Ok(match (&partial.first_value, &partial.last_value) { + (None, _) => { + // Empty accumulator — return null struct. + Scalar::null(dtype) + } + (Some(first_value), Some(last_value)) => { + // SAFETY: We constructed partial_dtype and the children match its field dtypes. + unsafe { + Scalar::struct_unchecked( + dtype, + [ + Scalar::bool(partial.is_sorted, Nullability::NonNullable), + Scalar::bool(partial.strict, Nullability::NonNullable), + first_value.clone(), + last_value.clone(), + ], + ) + } + } + (Some(first_value), None) => { + // SAFETY: We constructed partial_dtype and the children match its field dtypes. + unsafe { + Scalar::struct_unchecked( + dtype, + [ + Scalar::bool(partial.is_sorted, Nullability::NonNullable), + Scalar::bool(partial.strict, Nullability::NonNullable), + first_value.clone(), + first_value.clone(), + ], + ) + } + } + }) + } + + fn reset(&self, partial: &mut Self::Partial) { + partial.is_sorted = true; + partial.first_value = None; + partial.last_value = None; + } + + #[inline] + fn is_saturated(&self, partial: &Self::Partial) -> bool { + !partial.is_sorted + } + + fn accumulate( + &self, + partial: &mut Self::Partial, + batch: &Columnar, + ctx: &mut ExecutionCtx, + ) -> VortexResult<()> { + if !partial.is_sorted { + return Ok(()); + } + + match batch { + Columnar::Constant(c) => { + // Constant arrays are sorted but not strict sorted (if len > 1). + let value = c.scalar().clone().into_nullable(); + if partial.strict && c.len() > 1 { + partial.is_sorted = false; + } + + // Check boundary with previous chunk. + if let Some(ref self_last) = partial.last_value { + if !self_last.is_null() && !value.is_null() { + let boundary_ok = if partial.strict { + *self_last < value + } else { + *self_last <= value + }; + if !boundary_ok { + partial.is_sorted = false; + } + } else if (!self_last.is_null() && value.is_null()) + || (self_last.is_null() && value.is_null() && partial.strict) + { + partial.is_sorted = false; + } + } + + if partial.first_value.is_none() { + partial.first_value = Some(value.clone()); + } + partial.last_value = Some(value); + Ok(()) + } + Columnar::Canonical(c) => { + if c.is_empty() { + return Ok(()); + } + + let array_ref = c.clone().into_array(); + + // Check boundary with previous chunk. + let first_value = array_ref.scalar_at(0)?.into_nullable(); + if let Some(ref self_last) = partial.last_value { + if !self_last.is_null() && !first_value.is_null() { + let boundary_ok = if partial.strict { + *self_last < first_value + } else { + *self_last <= first_value + }; + if !boundary_ok { + partial.is_sorted = false; + partial.last_value = + Some(array_ref.scalar_at(array_ref.len() - 1)?.into_nullable()); + if partial.first_value.is_none() { + partial.first_value = Some(first_value); + } + return Ok(()); + } + } else if (!self_last.is_null() && first_value.is_null()) + || (self_last.is_null() && first_value.is_null() && partial.strict) + { + partial.is_sorted = false; + partial.last_value = + Some(array_ref.scalar_at(array_ref.len() - 1)?.into_nullable()); + if partial.first_value.is_none() { + partial.first_value = Some(first_value); + } + return Ok(()); + } + } + + // Check within-batch sortedness. + let batch_is_sorted = match c { + Canonical::Primitive(p) => check_primitive_sorted(p, partial.strict)?, + Canonical::Bool(b) => check_bool_sorted(b, partial.strict)?, + Canonical::VarBinView(v) => check_varbinview_sorted(v, partial.strict)?, + Canonical::Decimal(d) => check_decimal_sorted(d, partial.strict)?, + Canonical::Extension(e) => check_extension_sorted(e, partial.strict, ctx)?, + Canonical::Null(_) => !partial.strict, + // Struct, List, FixedSizeList should have been filtered out by return_dtype + _ => unreachable!(), + }; + + if !batch_is_sorted { + partial.is_sorted = false; + } + + if partial.first_value.is_none() { + partial.first_value = Some(first_value); + } + partial.last_value = + Some(array_ref.scalar_at(array_ref.len() - 1)?.into_nullable()); + Ok(()) + } + } + } + + fn finalize(&self, partials: ArrayRef) -> VortexResult { + partials.get_item(NAMES.get(0).vortex_expect("out of bounds").clone()) + } + + fn finalize_scalar(&self, partial: &Self::Partial) -> VortexResult { + if partial.first_value.is_none() { + // Empty accumulator → vacuously sorted. + return Ok(Scalar::bool(true, Nullability::NonNullable)); + } + Ok(Scalar::bool(partial.is_sorted, Nullability::NonNullable)) + } +} + +#[expect( + clippy::wrong_self_convention, + reason = "is_* naming follows Iterator::is_sorted convention" +)] +/// Helper methods to check sortedness with strictness. +pub trait IsSortedIteratorExt: Iterator +where + ::Item: PartialOrd, +{ + fn is_strict_sorted(self) -> bool + where + Self: Sized, + Self::Item: PartialOrd, + { + self.is_sorted_by(|a, b| a < b) + } +} + +impl IsSortedIteratorExt for T +where + T: Iterator + ?Sized, + T::Item: PartialOrd, +{ +} + +#[cfg(test)] +mod tests { + use rstest::rstest; + use vortex_buffer::buffer; + use vortex_error::VortexExpect; + use vortex_error::VortexResult; + + use crate::IntoArray; + use crate::LEGACY_SESSION; + use crate::VortexSessionExecute; + use crate::aggregate_fn::fns::is_sorted::is_sorted; + use crate::aggregate_fn::fns::is_sorted::is_strict_sorted; + use crate::arrays::BoolArray; + use crate::arrays::PrimitiveArray; + use crate::validity::Validity; + + // Tests migrated from compute/is_sorted.rs + #[test] + fn test_is_sorted() -> VortexResult<()> { + let mut ctx = LEGACY_SESSION.create_execution_ctx(); + + let arr = PrimitiveArray::new(buffer!(0, 1, 2, 3), Validity::AllValid).into_array(); + assert!(is_sorted(&arr, &mut ctx)?); + + let arr = PrimitiveArray::new( + buffer!(0, 1, 2, 3), + Validity::Array(BoolArray::from_iter([false, true, true, true]).into_array()), + ) + .into_array(); + assert!(is_sorted(&arr, &mut ctx)?); + + let arr = PrimitiveArray::new( + buffer!(0, 1, 2, 3), + Validity::Array(BoolArray::from_iter([true, false, true, true]).into_array()), + ) + .into_array(); + assert!(!is_sorted(&arr, &mut ctx)?); + + let arr = PrimitiveArray::new(buffer!(0, 1, 3, 2), Validity::AllValid).into_array(); + assert!(!is_sorted(&arr, &mut ctx)?); + + let arr = PrimitiveArray::new( + buffer!(0, 1, 3, 2), + Validity::Array(BoolArray::from_iter([false, true, true, true]).into_array()), + ) + .into_array(); + assert!(!is_sorted(&arr, &mut ctx)?); + + Ok(()) + } + + #[test] + fn test_is_strict_sorted() -> VortexResult<()> { + let mut ctx = LEGACY_SESSION.create_execution_ctx(); + + let arr = PrimitiveArray::new(buffer!(0, 1, 2, 3), Validity::AllValid).into_array(); + assert!(is_strict_sorted(&arr, &mut ctx)?); + + let arr = PrimitiveArray::new( + buffer!(0, 1, 2, 3), + Validity::Array(BoolArray::from_iter([false, true, true, true]).into_array()), + ) + .into_array(); + assert!(is_strict_sorted(&arr, &mut ctx)?); + + let arr = PrimitiveArray::new( + buffer!(0, 1, 2, 3), + Validity::Array(BoolArray::from_iter([true, false, true, true]).into_array()), + ) + .into_array(); + assert!(!is_strict_sorted(&arr, &mut ctx)?); + + let arr = PrimitiveArray::new( + buffer!(0, 1, 3, 2), + Validity::Array(BoolArray::from_iter([false, true, true, true]).into_array()), + ) + .into_array(); + assert!(!is_strict_sorted(&arr, &mut ctx)?); + + Ok(()) + } + + // Tests migrated from arrays/primitive/compute/is_sorted.rs + #[rstest] + #[case(PrimitiveArray::from_iter([1, 2, 3, 4, 5]), true)] + #[case(PrimitiveArray::from_iter([1, 1, 2, 3, 4, 5]), true)] + #[case(PrimitiveArray::from_option_iter([None, None, Some(1i32), Some(2)]), true)] + #[case(PrimitiveArray::from_option_iter([None, None, Some(1i32), Some(1)]), true)] + #[case(PrimitiveArray::from_option_iter([None, Some(5_u8), None]), false)] + fn test_primitive_is_sorted(#[case] array: PrimitiveArray, #[case] expected: bool) { + let mut ctx = LEGACY_SESSION.create_execution_ctx(); + assert_eq!( + is_sorted(&array.into_array(), &mut ctx) + .vortex_expect("operation should succeed in test"), + expected + ); + } + + #[rstest] + #[case(PrimitiveArray::from_iter([1, 2, 3, 4, 5]), true)] + #[case(PrimitiveArray::from_iter([1, 1, 2, 3, 4, 5]), false)] + #[case(PrimitiveArray::from_option_iter([None, None, Some(1i32), Some(2), None]), false)] + #[case(PrimitiveArray::from_option_iter([None, None, Some(1i32), Some(1), None]), false)] + #[case(PrimitiveArray::from_option_iter([None, Some(5_u8), None]), false)] + fn test_primitive_is_strict_sorted(#[case] array: PrimitiveArray, #[case] expected: bool) { + let mut ctx = LEGACY_SESSION.create_execution_ctx(); + assert_eq!( + is_strict_sorted(&array.into_array(), &mut ctx) + .vortex_expect("operation should succeed in test"), + expected + ); + } + + // Tests migrated from arrays/decimal/compute/is_sorted.rs + #[test] + fn test_decimal_is_sorted() -> VortexResult<()> { + use arrow_array::types::Decimal128Type; + use arrow_cast::parse::parse_decimal; + + use crate::arrays::DecimalArray; + use crate::dtype::DecimalDType; + + let mut ctx = LEGACY_SESSION.create_execution_ctx(); + let dtype = DecimalDType::new(19, 2); + let i100 = + parse_decimal::("100.00", dtype.precision(), dtype.scale()).unwrap(); + let i200 = + parse_decimal::("200.00", dtype.precision(), dtype.scale()).unwrap(); + + let sorted = buffer![i100, i200, i200]; + let unsorted = buffer![i200, i100, i200]; + + let sorted_array = DecimalArray::new(sorted, dtype, Validity::NonNullable); + let unsorted_array = DecimalArray::new(unsorted, dtype, Validity::NonNullable); + + assert!(is_sorted(&sorted_array.into_array(), &mut ctx)?); + assert!(!is_sorted(&unsorted_array.into_array(), &mut ctx)?); + + Ok(()) + } + + #[test] + fn test_decimal_is_strict_sorted() -> VortexResult<()> { + use arrow_array::types::Decimal128Type; + use arrow_cast::parse::parse_decimal; + + use crate::arrays::DecimalArray; + use crate::dtype::DecimalDType; + + let mut ctx = LEGACY_SESSION.create_execution_ctx(); + let dtype = DecimalDType::new(19, 2); + let i100 = + parse_decimal::("100.00", dtype.precision(), dtype.scale()).unwrap(); + let i200 = + parse_decimal::("200.00", dtype.precision(), dtype.scale()).unwrap(); + let i300 = + parse_decimal::("300.00", dtype.precision(), dtype.scale()).unwrap(); + + let strict_sorted = buffer![i100, i200, i300]; + let sorted = buffer![i100, i200, i200]; + + let dtype = DecimalDType::new(19, 2); + + let strict_sorted_array = DecimalArray::new(strict_sorted, dtype, Validity::NonNullable); + let sorted_array = DecimalArray::new(sorted, dtype, Validity::NonNullable); + + assert!(is_strict_sorted( + &strict_sorted_array.into_array(), + &mut ctx + )?); + assert!(!is_strict_sorted(&sorted_array.into_array(), &mut ctx)?); + + Ok(()) + } +} diff --git a/vortex-array/src/aggregate_fn/fns/is_sorted/primitive.rs b/vortex-array/src/aggregate_fn/fns/is_sorted/primitive.rs new file mode 100644 index 00000000000..21c80e7bd45 --- /dev/null +++ b/vortex-array/src/aggregate_fn/fns/is_sorted/primitive.rs @@ -0,0 +1,45 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: Copyright the Vortex contributors + +use itertools::Itertools; +use vortex_error::VortexResult; +use vortex_mask::Mask; + +use super::IsSortedIteratorExt; +use crate::arrays::PrimitiveArray; +use crate::arrays::primitive::NativeValue; +use crate::dtype::NativePType; +use crate::match_each_native_ptype; + +pub(super) fn check_primitive_sorted(array: &PrimitiveArray, strict: bool) -> VortexResult { + match_each_native_ptype!(array.ptype(), |P| { compute_is_sorted::

(array, strict) }) +} + +fn compute_is_sorted(array: &PrimitiveArray, strict: bool) -> VortexResult { + match array.validity_mask()? { + Mask::AllFalse(_) => Ok(!strict), + Mask::AllTrue(_) => { + let slice = array.as_slice::(); + let iter = slice.iter().copied().map(NativeValue); + + Ok(if strict { + iter.is_strict_sorted() + } else { + iter.is_sorted() + }) + } + Mask::Values(mask_values) => { + let iter = mask_values + .bit_buffer() + .iter() + .zip_eq(array.as_slice::()) + .map(|(is_valid, value)| is_valid.then_some(NativeValue(*value))); + + Ok(if strict { + iter.is_strict_sorted() + } else { + iter.is_sorted() + }) + } + } +} diff --git a/vortex-array/src/aggregate_fn/fns/is_sorted/varbin.rs b/vortex-array/src/aggregate_fn/fns/is_sorted/varbin.rs new file mode 100644 index 00000000000..84529ef16c7 --- /dev/null +++ b/vortex-array/src/aggregate_fn/fns/is_sorted/varbin.rs @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: Copyright the Vortex contributors + +use vortex_error::VortexResult; + +use super::IsSortedIteratorExt; +use crate::accessor::ArrayAccessor; +use crate::arrays::VarBinViewArray; + +pub(super) fn check_varbinview_sorted(array: &VarBinViewArray, strict: bool) -> VortexResult { + Ok(if strict { + array.with_iterator(|bytes_iter| bytes_iter.is_strict_sorted()) + } else { + array.with_iterator(|bytes_iter| bytes_iter.is_sorted()) + }) +} diff --git a/vortex-array/src/aggregate_fn/fns/min_max/mod.rs b/vortex-array/src/aggregate_fn/fns/min_max/mod.rs index e8225930dd3..2241cefcc3b 100644 --- a/vortex-array/src/aggregate_fn/fns/min_max/mod.rs +++ b/vortex-array/src/aggregate_fn/fns/min_max/mod.rs @@ -210,13 +210,17 @@ impl AggregateFnVTable for MinMax { Ok(()) } - fn flush(&self, partial: &mut Self::Partial) -> VortexResult { + fn to_scalar(&self, partial: &Self::Partial) -> VortexResult { let dtype = make_minmax_dtype(&partial.element_dtype); - let result = match (partial.min.take(), partial.max.take()) { - (Some(min), Some(max)) => Scalar::struct_(dtype, vec![min, max]), + Ok(match (&partial.min, &partial.max) { + (Some(min), Some(max)) => Scalar::struct_(dtype, vec![min.clone(), max.clone()]), _ => Scalar::null(dtype), - }; - Ok(result) + }) + } + + fn reset(&self, partial: &mut Self::Partial) { + partial.min = None; + partial.max = None; } #[inline] @@ -266,8 +270,8 @@ impl AggregateFnVTable for MinMax { Ok(partials) } - fn finalize_scalar(&self, partial: Scalar) -> VortexResult { - Ok(partial) + fn finalize_scalar(&self, partial: &Self::Partial) -> VortexResult { + self.to_scalar(partial) } } @@ -450,7 +454,7 @@ mod tests { let scalar2 = Scalar::struct_(struct_dtype, vec![Scalar::from(2i32), Scalar::from(10i32)]); MinMax.combine_partials(&mut state, scalar2)?; - let result = MinMaxResult::from_scalar(MinMax.flush(&mut state)?)? + let result = MinMaxResult::from_scalar(MinMax.to_scalar(&state)?)? .vortex_expect("should have result"); assert_eq!(result.min, Scalar::from(2i32)); assert_eq!(result.max, Scalar::from(15i32)); diff --git a/vortex-array/src/aggregate_fn/fns/mod.rs b/vortex-array/src/aggregate_fn/fns/mod.rs index b890375d124..4c233ba4d27 100644 --- a/vortex-array/src/aggregate_fn/fns/mod.rs +++ b/vortex-array/src/aggregate_fn/fns/mod.rs @@ -2,6 +2,7 @@ // SPDX-FileCopyrightText: Copyright the Vortex contributors pub mod is_constant; +pub mod is_sorted; pub mod min_max; pub mod nan_count; pub mod sum; diff --git a/vortex-array/src/aggregate_fn/fns/nan_count/mod.rs b/vortex-array/src/aggregate_fn/fns/nan_count/mod.rs index 3cf2cfa6ca1..f60d50f2a20 100644 --- a/vortex-array/src/aggregate_fn/fns/nan_count/mod.rs +++ b/vortex-array/src/aggregate_fn/fns/nan_count/mod.rs @@ -115,10 +115,12 @@ impl AggregateFnVTable for NanCount { Ok(()) } - fn flush(&self, partial: &mut Self::Partial) -> VortexResult { - let result = Scalar::primitive(*partial, NonNullable); + fn to_scalar(&self, partial: &Self::Partial) -> VortexResult { + Ok(Scalar::primitive(*partial, NonNullable)) + } + + fn reset(&self, partial: &mut Self::Partial) { *partial = 0; - Ok(result) } #[inline] @@ -157,8 +159,8 @@ impl AggregateFnVTable for NanCount { Ok(partials) } - fn finalize_scalar(&self, partial: Scalar) -> VortexResult { - Ok(partial) + fn finalize_scalar(&self, partial: &Self::Partial) -> VortexResult { + self.to_scalar(partial) } } @@ -236,7 +238,8 @@ mod tests { let scalar2 = Scalar::primitive(3u64, Nullability::NonNullable); NanCount.combine_partials(&mut state, scalar2)?; - let result = NanCount.flush(&mut state)?; + let result = NanCount.to_scalar(&state)?; + NanCount.reset(&mut state); assert_eq!(result.as_primitive().typed_value::(), Some(8)); Ok(()) } diff --git a/vortex-array/src/aggregate_fn/fns/sum/decimal.rs b/vortex-array/src/aggregate_fn/fns/sum/decimal.rs index 82b6857b2ab..91fd48e73ea 100644 --- a/vortex-array/src/aggregate_fn/fns/sum/decimal.rs +++ b/vortex-array/src/aggregate_fn/fns/sum/decimal.rs @@ -365,7 +365,7 @@ mod tests { let small = Scalar::decimal(DecimalValue::from(9i64), DecimalDType::new(14, 0), Nullable); Sum.combine_partials(&mut state, small)?; - let result = Sum.flush(&mut state)?; + let result = Sum.to_scalar(&state)?; assert!(!result.is_null()); assert_eq!( result.as_decimal().decimal_value(), @@ -396,7 +396,7 @@ mod tests { Scalar::decimal(DecimalValue::from(1i64), DecimalDType::new(14, 0), Nullable); Sum.combine_partials(&mut state, one_more)?; - let result = Sum.flush(&mut state)?; + let result = Sum.to_scalar(&state)?; assert!(result.is_null()); assert_eq!( result.dtype(), @@ -425,7 +425,7 @@ mod tests { ); Sum.combine_partials(&mut state, one_more)?; - let result = Sum.flush(&mut state)?; + let result = Sum.to_scalar(&state)?; assert!(result.is_null()); Ok(()) } @@ -458,7 +458,7 @@ mod tests { let mut ctx = LEGACY_SESSION.create_execution_ctx(); Sum.accumulate(&mut state, &columnar, &mut ctx)?; - let result = Sum.flush(&mut state)?; + let result = Sum.to_scalar(&state)?; assert!(result.is_null()); Ok(()) } diff --git a/vortex-array/src/aggregate_fn/fns/sum/mod.rs b/vortex-array/src/aggregate_fn/fns/sum/mod.rs index 6ef11472099..4f35fa4c3c5 100644 --- a/vortex-array/src/aggregate_fn/fns/sum/mod.rs +++ b/vortex-array/src/aggregate_fn/fns/sum/mod.rs @@ -180,8 +180,8 @@ impl AggregateFnVTable for Sum { Ok(()) } - fn flush(&self, partial: &mut Self::Partial) -> VortexResult { - let result = match &partial.current { + fn to_scalar(&self, partial: &Self::Partial) -> VortexResult { + Ok(match &partial.current { None => Scalar::null(partial.return_dtype.as_nullable()), Some(SumState::Unsigned(v)) => Scalar::primitive(*v, Nullability::Nullable), Some(SumState::Signed(v)) => Scalar::primitive(*v, Nullability::Nullable), @@ -193,12 +193,11 @@ impl AggregateFnVTable for Sum { .vortex_expect("return dtype must be decimal"); Scalar::decimal(*value, decimal_dtype, Nullability::Nullable) } - }; + }) + } - // Reset the state + fn reset(&self, partial: &mut Self::Partial) { partial.current = Some(make_zero_state(&partial.return_dtype)); - - Ok(result) } #[inline] @@ -250,8 +249,8 @@ impl AggregateFnVTable for Sum { Ok(partials) } - fn finalize_scalar(&self, partial: Scalar) -> VortexResult { - Ok(partial) + fn finalize_scalar(&self, partial: &Self::Partial) -> VortexResult { + self.to_scalar(partial) } } @@ -461,7 +460,8 @@ mod tests { let scalar2 = Scalar::primitive(50i64, Nullable); Sum.combine_partials(&mut state, scalar2)?; - let result = Sum.flush(&mut state)?; + let result = Sum.to_scalar(&state)?; + Sum.reset(&mut state); assert_eq!(result.as_primitive().typed_value::(), Some(150)); Ok(()) } diff --git a/vortex-array/src/aggregate_fn/session.rs b/vortex-array/src/aggregate_fn/session.rs index 6d331492a7e..0fc54f81052 100644 --- a/vortex-array/src/aggregate_fn/session.rs +++ b/vortex-array/src/aggregate_fn/session.rs @@ -13,6 +13,7 @@ use crate::aggregate_fn::AggregateFnId; use crate::aggregate_fn::AggregateFnPluginRef; use crate::aggregate_fn::AggregateFnVTable; use crate::aggregate_fn::fns::is_constant::IsConstant; +use crate::aggregate_fn::fns::is_sorted::IsSorted; use crate::aggregate_fn::fns::min_max::MinMax; use crate::aggregate_fn::kernels::DynAggregateKernel; use crate::aggregate_fn::kernels::DynGroupedAggregateKernel; @@ -20,6 +21,7 @@ use crate::arrays::Chunked; use crate::arrays::Dict; use crate::arrays::chunked::compute::aggregate::ChunkedArrayAggregate; use crate::arrays::dict::compute::is_constant::DictIsConstantKernel; +use crate::arrays::dict::compute::is_sorted::DictIsSortedKernel; use crate::arrays::dict::compute::min_max::DictMinMaxKernel; use crate::vtable::ArrayId; @@ -49,6 +51,7 @@ impl Default for AggregateFnSession { this.register_aggregate_kernel(Chunked::ID, None, &ChunkedArrayAggregate); this.register_aggregate_kernel(Dict::ID, Some(MinMax.id()), &DictMinMaxKernel); this.register_aggregate_kernel(Dict::ID, Some(IsConstant.id()), &DictIsConstantKernel); + this.register_aggregate_kernel(Dict::ID, Some(IsSorted.id()), &DictIsSortedKernel); this } diff --git a/vortex-array/src/aggregate_fn/vtable.rs b/vortex-array/src/aggregate_fn/vtable.rs index 3843ad29383..feaebe61f56 100644 --- a/vortex-array/src/aggregate_fn/vtable.rs +++ b/vortex-array/src/aggregate_fn/vtable.rs @@ -92,13 +92,14 @@ pub trait AggregateFnVTable: 'static + Sized + Clone + Send + Sync { /// Combine partial scalar state into the accumulator. fn combine_partials(&self, partial: &mut Self::Partial, other: Scalar) -> VortexResult<()>; - /// Flush the partial aggregate for the given accumulator state. + /// Convert the partial state into a partial scalar. /// - /// The returned scalar must have the same DType as specified by `state_dtype` for the + /// The returned scalar must have the same DType as specified by `partial_dtype` for the /// options and input dtype used to construct the state. - /// - /// The internal state of the accumulator is reset to the empty state after flushing. - fn flush(&self, partial: &mut Self::Partial) -> VortexResult; + fn to_scalar(&self, partial: &Self::Partial) -> VortexResult; + + /// Reset the state of the accumulator to an empty group. + fn reset(&self, partial: &mut Self::Partial); /// Is the partial accumulator state is "saturated", i.e. has it reached a state where the /// final result is fully determined. @@ -122,8 +123,9 @@ pub trait AggregateFnVTable: 'static + Sized + Clone + Send + Sync { /// /// The provided `state` has dtype as specified by `state_dtype`, the result scalar must have /// dtype as specified by `return_dtype`. - fn finalize_scalar(&self, state: Scalar) -> VortexResult { - let array = ConstantArray::new(state, 1).into_array(); + fn finalize_scalar(&self, partial: &Self::Partial) -> VortexResult { + let scalar = self.to_scalar(partial)?; + let array = ConstantArray::new(scalar, 1).into_array(); let result = self.finalize(array)?; result.scalar_at(0) } diff --git a/vortex-array/src/arrays/bool/compute/is_sorted.rs b/vortex-array/src/arrays/bool/compute/is_sorted.rs deleted file mode 100644 index 7cb7fb55968..00000000000 --- a/vortex-array/src/arrays/bool/compute/is_sorted.rs +++ /dev/null @@ -1,54 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: Copyright the Vortex contributors - -use vortex_error::VortexResult; -use vortex_mask::Mask; - -use crate::arrays::Bool; -use crate::arrays::BoolArray; -use crate::compute::IsSortedIteratorExt; -use crate::compute::IsSortedKernel; -use crate::compute::IsSortedKernelAdapter; -use crate::register_kernel; - -impl IsSortedKernel for Bool { - fn is_sorted(&self, array: &BoolArray) -> VortexResult> { - match array.validity_mask()? { - Mask::AllFalse(_) => Ok(Some(true)), - Mask::AllTrue(_) => Ok(Some(array.to_bit_buffer().iter().is_sorted())), - Mask::Values(mask_values) => { - let set_indices = mask_values.bit_buffer().set_indices(); - let values = array.to_bit_buffer(); - let values_iter = set_indices.map(|idx| - // Safety: - // All idxs are in-bounds for the array. - unsafe { - values.value_unchecked(idx) - }); - - Ok(Some(values_iter.is_sorted())) - } - } - } - - fn is_strict_sorted(&self, array: &BoolArray) -> VortexResult> { - match array.validity_mask()? { - Mask::AllFalse(_) => Ok(Some(false)), - Mask::AllTrue(_) => Ok(Some(array.to_bit_buffer().iter().is_strict_sorted())), - Mask::Values(mask_values) => { - let validity_buffer = mask_values.bit_buffer(); - let values = array.to_bit_buffer(); - - Ok(Some( - validity_buffer - .iter() - .zip(values.iter()) - .map(|(is_valid, value)| is_valid.then_some(value)) - .is_strict_sorted(), - )) - } - } - } -} - -register_kernel!(IsSortedKernelAdapter(Bool).lift()); diff --git a/vortex-array/src/arrays/bool/compute/mod.rs b/vortex-array/src/arrays/bool/compute/mod.rs index 622430fb2ec..9649bd31d6c 100644 --- a/vortex-array/src/arrays/bool/compute/mod.rs +++ b/vortex-array/src/arrays/bool/compute/mod.rs @@ -4,7 +4,6 @@ mod cast; mod fill_null; pub(crate) mod filter; -mod is_sorted; mod mask; pub mod rules; mod slice; diff --git a/vortex-array/src/arrays/chunked/compute/is_sorted.rs b/vortex-array/src/arrays/chunked/compute/is_sorted.rs deleted file mode 100644 index 19d1b170434..00000000000 --- a/vortex-array/src/arrays/chunked/compute/is_sorted.rs +++ /dev/null @@ -1,68 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: Copyright the Vortex contributors - -use vortex_error::VortexResult; - -use crate::ArrayRef; -use crate::DynArray; -use crate::arrays::Chunked; -use crate::arrays::ChunkedArray; -use crate::compute::IsSortedKernel; -use crate::compute::IsSortedKernelAdapter; -use crate::compute::is_sorted; -use crate::compute::is_strict_sorted; -use crate::register_kernel; - -impl IsSortedKernel for Chunked { - fn is_sorted(&self, array: &ChunkedArray) -> VortexResult> { - is_sorted_impl(array, false, is_sorted) - } - - fn is_strict_sorted(&self, array: &ChunkedArray) -> VortexResult> { - is_sorted_impl(array, true, is_strict_sorted) - } -} - -register_kernel!(IsSortedKernelAdapter(Chunked).lift()); - -fn is_sorted_impl( - array: &ChunkedArray, - strict: bool, - reentry_fn: impl Fn(&ArrayRef) -> VortexResult>, -) -> VortexResult> { - let mut first_last = Vec::default(); - - for chunk in array.chunks() { - if chunk.is_empty() { - continue; - } - - let first = chunk.scalar_at(0)?; - let last = chunk.scalar_at(chunk.len() - 1)?; - - first_last.push((first, last)); - } - - let chunk_sorted = first_last - .iter() - .is_sorted_by(|a, b| if strict { a.1 < b.0 } else { a.1 <= b.0 }); - - if !chunk_sorted { - return Ok(Some(false)); - } - - for chunk in array.chunks() { - match reentry_fn(chunk)? { - None => { - return Ok(None); - } - Some(v) => { - if !v { - return Ok(Some(false)); - } - } - } - } - - Ok(Some(true)) -} diff --git a/vortex-array/src/arrays/chunked/compute/mod.rs b/vortex-array/src/arrays/chunked/compute/mod.rs index 8018a577516..bbc9029657a 100644 --- a/vortex-array/src/arrays/chunked/compute/mod.rs +++ b/vortex-array/src/arrays/chunked/compute/mod.rs @@ -5,7 +5,6 @@ pub(crate) mod aggregate; mod cast; mod fill_null; mod filter; -mod is_sorted; pub(crate) mod kernel; mod mask; pub(crate) mod rules; diff --git a/vortex-array/src/arrays/decimal/compute/is_sorted.rs b/vortex-array/src/arrays/decimal/compute/is_sorted.rs deleted file mode 100644 index 9688c454930..00000000000 --- a/vortex-array/src/arrays/decimal/compute/is_sorted.rs +++ /dev/null @@ -1,128 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: Copyright the Vortex contributors - -use itertools::Itertools; -use vortex_error::VortexResult; -use vortex_mask::Mask; - -use crate::arrays::Decimal; -use crate::arrays::DecimalArray; -use crate::compute::IsSortedIteratorExt; -use crate::compute::IsSortedKernel; -use crate::compute::IsSortedKernelAdapter; -use crate::dtype::NativeDecimalType; -use crate::match_each_decimal_value_type; -use crate::register_kernel; - -impl IsSortedKernel for Decimal { - fn is_sorted(&self, array: &DecimalArray) -> VortexResult> { - is_decimal_sorted(array, false) - } - - fn is_strict_sorted(&self, array: &DecimalArray) -> VortexResult> { - is_decimal_sorted(array, true) - } -} - -register_kernel!(IsSortedKernelAdapter(Decimal).lift()); - -fn is_decimal_sorted(array: &DecimalArray, strict: bool) -> VortexResult> { - match_each_decimal_value_type!(array.values_type, |S| { - compute_is_sorted::(array, strict).map(Some) - }) -} - -fn compute_is_sorted(array: &DecimalArray, strict: bool) -> VortexResult -where - dyn Iterator: IsSortedIteratorExt, -{ - match array.validity_mask()? { - Mask::AllFalse(_) => Ok(!strict), - Mask::AllTrue(_) => { - let buf = array.buffer::(); - let iter = buf.iter().copied(); - - Ok(if strict { - IsSortedIteratorExt::is_strict_sorted(iter) - } else { - iter.is_sorted() - }) - } - Mask::Values(mask_values) => { - let values = array.buffer::(); - let iter = mask_values - .bit_buffer() - .iter() - .zip_eq(values) - .map(|(is_valid, v)| is_valid.then_some(v)); - - Ok(if strict { - IsSortedIteratorExt::is_strict_sorted(iter) - } else { - iter.is_sorted() - }) - } - } -} - -#[cfg(test)] -mod tests { - use arrow_array::types::Decimal128Type; - use arrow_cast::parse::parse_decimal; - use vortex_buffer::buffer; - - use crate::IntoArray; - use crate::arrays::DecimalArray; - use crate::compute::is_sorted; - use crate::compute::is_strict_sorted; - use crate::dtype::DecimalDType; - use crate::validity::Validity; - - #[test] - fn test_is_sorted() { - let dtype = DecimalDType::new(19, 2); - let i100 = - parse_decimal::("100.00", dtype.precision(), dtype.scale()).unwrap(); - let i200 = - parse_decimal::("200.00", dtype.precision(), dtype.scale()).unwrap(); - - let sorted = buffer![i100, i200, i200]; - let unsorted = buffer![i200, i100, i200]; - - let sorted_array = DecimalArray::new(sorted, dtype, Validity::NonNullable); - let unsorted_array = DecimalArray::new(unsorted, dtype, Validity::NonNullable); - - assert!(is_sorted(&sorted_array.into_array()).unwrap().unwrap()); - assert!(!is_sorted(&unsorted_array.into_array()).unwrap().unwrap()); - } - - #[test] - fn test_is_strict_sorted() { - let dtype = DecimalDType::new(19, 2); - let i100 = - parse_decimal::("100.00", dtype.precision(), dtype.scale()).unwrap(); - let i200 = - parse_decimal::("200.00", dtype.precision(), dtype.scale()).unwrap(); - let i300 = - parse_decimal::("300.00", dtype.precision(), dtype.scale()).unwrap(); - - let strict_sorted = buffer![i100, i200, i300]; - let sorted = buffer![i100, i200, i200]; - - let dtype = DecimalDType::new(19, 2); - - let strict_sorted_array = DecimalArray::new(strict_sorted, dtype, Validity::NonNullable); - let sorted_array = DecimalArray::new(sorted, dtype, Validity::NonNullable); - - assert!( - is_strict_sorted(&strict_sorted_array.into_array()) - .unwrap() - .unwrap() - ); - assert!( - !is_strict_sorted(&sorted_array.into_array()) - .unwrap() - .unwrap() - ); - } -} diff --git a/vortex-array/src/arrays/decimal/compute/mod.rs b/vortex-array/src/arrays/decimal/compute/mod.rs index 3b2d687b6bf..09faba913c0 100644 --- a/vortex-array/src/arrays/decimal/compute/mod.rs +++ b/vortex-array/src/arrays/decimal/compute/mod.rs @@ -4,7 +4,6 @@ mod between; mod cast; mod fill_null; -mod is_sorted; mod mask; pub mod rules; mod take; diff --git a/vortex-array/src/arrays/dict/compute/is_sorted.rs b/vortex-array/src/arrays/dict/compute/is_sorted.rs index d23a74b2ec3..6787e6213ed 100644 --- a/vortex-array/src/arrays/dict/compute/is_sorted.rs +++ b/vortex-array/src/arrays/dict/compute/is_sorted.rs @@ -3,30 +3,51 @@ use vortex_error::VortexResult; -use super::Dict; -use super::DictArray; -use crate::compute::IsSortedKernel; -use crate::compute::IsSortedKernelAdapter; -use crate::compute::is_sorted; -use crate::compute::is_strict_sorted; -use crate::register_kernel; - -impl IsSortedKernel for Dict { - fn is_sorted(&self, array: &DictArray) -> VortexResult> { - if Some((true, true)) == is_sorted(array.values())?.zip(is_sorted(array.codes())?) { - return Ok(Some(true)); - } - Ok(None) - } +use crate::ArrayRef; +use crate::ExecutionCtx; +use crate::aggregate_fn::AggregateFnRef; +use crate::aggregate_fn::fns::is_sorted::IsSorted; +use crate::aggregate_fn::fns::is_sorted::is_sorted; +use crate::aggregate_fn::fns::is_sorted::is_strict_sorted; +use crate::aggregate_fn::kernels::DynAggregateKernel; +use crate::arrays::Dict; +use crate::scalar::Scalar; + +/// Dict-specific is_sorted kernel. +/// +/// If both values and codes are sorted (with the same strictness), then the dict array is sorted. +#[derive(Debug)] +pub(crate) struct DictIsSortedKernel; + +impl DynAggregateKernel for DictIsSortedKernel { + fn aggregate( + &self, + aggregate_fn: &AggregateFnRef, + batch: &ArrayRef, + ctx: &mut ExecutionCtx, + ) -> VortexResult> { + let Some(options) = aggregate_fn.as_opt::() else { + return Ok(None); + }; - fn is_strict_sorted(&self, array: &DictArray) -> VortexResult> { - if Some((true, true)) - == is_strict_sorted(array.values())?.zip(is_strict_sorted(array.codes())?) - { - return Ok(Some(true)); + let Some(dict) = batch.as_opt::() else { + return Ok(None); + }; + + let strict = options.strict; + + let result = if strict { + is_strict_sorted(dict.values(), ctx)? && is_strict_sorted(dict.codes(), ctx)? + } else { + is_sorted(dict.values(), ctx)? && is_sorted(dict.codes(), ctx)? + }; + + if result { + Ok(Some(IsSorted::make_partial(batch, true, strict)?)) + } else { + // We can't definitively say it's NOT sorted without canonicalizing, + // so return None to let the accumulator handle it. + Ok(None) } - Ok(None) } } - -register_kernel!(IsSortedKernelAdapter(Dict).lift()); diff --git a/vortex-array/src/arrays/dict/compute/mod.rs b/vortex-array/src/arrays/dict/compute/mod.rs index 3c2861a28f7..0aa1586d29f 100644 --- a/vortex-array/src/arrays/dict/compute/mod.rs +++ b/vortex-array/src/arrays/dict/compute/mod.rs @@ -5,7 +5,7 @@ mod cast; mod compare; mod fill_null; pub(crate) mod is_constant; -mod is_sorted; +pub(crate) mod is_sorted; mod like; mod mask; pub(crate) mod min_max; diff --git a/vortex-array/src/arrays/extension/compute/is_sorted.rs b/vortex-array/src/arrays/extension/compute/is_sorted.rs deleted file mode 100644 index 1ad2425675b..00000000000 --- a/vortex-array/src/arrays/extension/compute/is_sorted.rs +++ /dev/null @@ -1,23 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: Copyright the Vortex contributors - -use vortex_error::VortexResult; - -use crate::arrays::Extension; -use crate::arrays::ExtensionArray; -use crate::compute::IsSortedKernel; -use crate::compute::IsSortedKernelAdapter; -use crate::compute::{self}; -use crate::register_kernel; - -impl IsSortedKernel for Extension { - fn is_sorted(&self, array: &ExtensionArray) -> VortexResult> { - compute::is_sorted(array.storage_array()) - } - - fn is_strict_sorted(&self, array: &ExtensionArray) -> VortexResult> { - compute::is_strict_sorted(array.storage_array()) - } -} - -register_kernel!(IsSortedKernelAdapter(Extension).lift()); diff --git a/vortex-array/src/arrays/extension/compute/mod.rs b/vortex-array/src/arrays/extension/compute/mod.rs index 7020ceb66a3..ce25ab2c0ea 100644 --- a/vortex-array/src/arrays/extension/compute/mod.rs +++ b/vortex-array/src/arrays/extension/compute/mod.rs @@ -4,7 +4,6 @@ mod cast; mod compare; mod filter; -mod is_sorted; mod mask; pub(crate) mod rules; mod slice; diff --git a/vortex-array/src/arrays/fixed_size_list/compute/is_sorted.rs b/vortex-array/src/arrays/fixed_size_list/compute/is_sorted.rs deleted file mode 100644 index 65d643a5217..00000000000 --- a/vortex-array/src/arrays/fixed_size_list/compute/is_sorted.rs +++ /dev/null @@ -1,25 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: Copyright the Vortex contributors - -use vortex_error::VortexResult; - -use crate::arrays::FixedSizeList; -use crate::arrays::FixedSizeListArray; -use crate::compute::IsSortedKernel; -use crate::compute::IsSortedKernelAdapter; -use crate::register_kernel; - -/// IsSorted implementation for [`FixedSizeListArray`]. -impl IsSortedKernel for FixedSizeList { - fn is_sorted(&self, _array: &FixedSizeListArray) -> VortexResult> { - // This would require comparing lists lexicographically. - Ok(None) - } - - fn is_strict_sorted(&self, _array: &FixedSizeListArray) -> VortexResult> { - // This would require comparing lists lexicographically without duplicates. - Ok(None) - } -} - -register_kernel!(IsSortedKernelAdapter(FixedSizeList).lift()); diff --git a/vortex-array/src/arrays/fixed_size_list/compute/mod.rs b/vortex-array/src/arrays/fixed_size_list/compute/mod.rs index 72d2f8d64c3..9a43503c4b5 100644 --- a/vortex-array/src/arrays/fixed_size_list/compute/mod.rs +++ b/vortex-array/src/arrays/fixed_size_list/compute/mod.rs @@ -2,7 +2,6 @@ // SPDX-FileCopyrightText: Copyright the Vortex contributors mod cast; -mod is_sorted; mod mask; pub(crate) mod rules; mod slice; diff --git a/vortex-array/src/arrays/list/compute/is_sorted.rs b/vortex-array/src/arrays/list/compute/is_sorted.rs deleted file mode 100644 index 90a9d35a1bc..00000000000 --- a/vortex-array/src/arrays/list/compute/is_sorted.rs +++ /dev/null @@ -1,24 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: Copyright the Vortex contributors - -use vortex_error::VortexResult; - -use crate::arrays::List; -use crate::arrays::ListArray; -use crate::compute::IsSortedKernel; -use crate::compute::IsSortedKernelAdapter; -use crate::register_kernel; - -impl IsSortedKernel for List { - fn is_sorted(&self, _array: &ListArray) -> VortexResult> { - // This would require comparing lists lexicographically. - Ok(None) - } - - fn is_strict_sorted(&self, _array: &ListArray) -> VortexResult> { - // This would require comparing lists lexicographically without duplicates. - Ok(None) - } -} - -register_kernel!(IsSortedKernelAdapter(List).lift()); diff --git a/vortex-array/src/arrays/list/compute/mod.rs b/vortex-array/src/arrays/list/compute/mod.rs index 255ae96b744..65bacbebdf5 100644 --- a/vortex-array/src/arrays/list/compute/mod.rs +++ b/vortex-array/src/arrays/list/compute/mod.rs @@ -3,7 +3,6 @@ mod cast; mod filter; -mod is_sorted; mod kernels; mod mask; pub(crate) mod rules; diff --git a/vortex-array/src/arrays/listview/compute/is_sorted.rs b/vortex-array/src/arrays/listview/compute/is_sorted.rs deleted file mode 100644 index 1d1c0398f85..00000000000 --- a/vortex-array/src/arrays/listview/compute/is_sorted.rs +++ /dev/null @@ -1,24 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: Copyright the Vortex contributors - -use vortex_error::VortexResult; - -use crate::arrays::ListView; -use crate::arrays::ListViewArray; -use crate::compute::IsSortedKernel; -use crate::compute::IsSortedKernelAdapter; -use crate::register_kernel; - -impl IsSortedKernel for ListView { - fn is_sorted(&self, _array: &ListViewArray) -> VortexResult> { - // This would require comparing lists lexicographically. - Ok(None) - } - - fn is_strict_sorted(&self, _array: &ListViewArray) -> VortexResult> { - // This would require comparing lists lexicographically without duplicates. - Ok(None) - } -} - -register_kernel!(IsSortedKernelAdapter(ListView).lift()); diff --git a/vortex-array/src/arrays/listview/compute/mod.rs b/vortex-array/src/arrays/listview/compute/mod.rs index 72d2f8d64c3..9a43503c4b5 100644 --- a/vortex-array/src/arrays/listview/compute/mod.rs +++ b/vortex-array/src/arrays/listview/compute/mod.rs @@ -2,7 +2,6 @@ // SPDX-FileCopyrightText: Copyright the Vortex contributors mod cast; -mod is_sorted; mod mask; pub(crate) mod rules; mod slice; diff --git a/vortex-array/src/arrays/primitive/compute/is_sorted.rs b/vortex-array/src/arrays/primitive/compute/is_sorted.rs deleted file mode 100644 index a6c1409c28f..00000000000 --- a/vortex-array/src/arrays/primitive/compute/is_sorted.rs +++ /dev/null @@ -1,127 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: Copyright the Vortex contributors - -use itertools::Itertools; -use vortex_error::VortexResult; -use vortex_mask::Mask; - -use crate::arrays::Primitive; -use crate::arrays::PrimitiveArray; -use crate::compute::IsSortedIteratorExt; -use crate::compute::IsSortedKernel; -use crate::compute::IsSortedKernelAdapter; -use crate::dtype::NativePType; -use crate::match_each_native_ptype; -use crate::register_kernel; - -impl IsSortedKernel for Primitive { - fn is_sorted(&self, array: &PrimitiveArray) -> VortexResult> { - match_each_native_ptype!(array.ptype(), |P| { - compute_is_sorted::

(array, false).map(Some) - }) - } - - fn is_strict_sorted(&self, array: &PrimitiveArray) -> VortexResult> { - match_each_native_ptype!(array.ptype(), |P| { - compute_is_sorted::

(array, true).map(Some) - }) - } -} - -register_kernel!(IsSortedKernelAdapter(Primitive).lift()); - -#[derive(Copy, Clone)] -struct ComparablePrimitive(T); - -impl From<&T> for ComparablePrimitive -where - T: NativePType, -{ - fn from(value: &T) -> Self { - Self(*value) - } -} - -impl PartialOrd for ComparablePrimitive -where - T: NativePType, -{ - fn partial_cmp(&self, other: &Self) -> Option { - Some(self.0.total_compare(other.0)) - } -} - -impl PartialEq for ComparablePrimitive -where - T: NativePType, -{ - fn eq(&self, other: &Self) -> bool { - self.0.is_eq(other.0) - } -} - -fn compute_is_sorted(array: &PrimitiveArray, strict: bool) -> VortexResult { - match array.validity_mask()? { - Mask::AllFalse(_) => Ok(!strict), - Mask::AllTrue(_) => { - let slice = array.as_slice::(); - let iter = slice.iter().map(ComparablePrimitive::from); - - Ok(if strict { - iter.is_strict_sorted() - } else { - iter.is_sorted() - }) - } - Mask::Values(mask_values) => { - let iter = mask_values - .bit_buffer() - .iter() - .zip_eq(array.as_slice::()) - .map(|(is_valid, value)| is_valid.then_some(ComparablePrimitive::from(value))); - - Ok(if strict { - iter.is_strict_sorted() - } else { - iter.is_sorted() - }) - } - } -} - -#[cfg(test)] -mod tests { - use rstest::rstest; - use vortex_error::VortexExpect; - - use super::*; - use crate::IntoArray; - use crate::compute::is_sorted; - use crate::compute::is_strict_sorted; - - #[rstest] - #[case(PrimitiveArray::from_iter([1, 2, 3, 4, 5]), true)] - #[case(PrimitiveArray::from_iter([1, 1, 2, 3, 4, 5]), true)] - #[case(PrimitiveArray::from_option_iter([None, None, Some(1i32), Some(2)]), true)] - #[case(PrimitiveArray::from_option_iter([None, None, Some(1i32), Some(1)]), true)] - #[case(PrimitiveArray::from_option_iter([None, Some(5_u8), None]), false)] - fn test_primitive_is_sorted(#[case] array: PrimitiveArray, #[case] expected: bool) { - assert_eq!( - is_sorted(&array.into_array()).vortex_expect("operation should succeed in test"), - Some(expected) - ); - } - - #[rstest] - #[case(PrimitiveArray::from_iter([1, 2, 3, 4, 5]), true)] - #[case(PrimitiveArray::from_iter([1, 1, 2, 3, 4, 5]), false)] - #[case(PrimitiveArray::from_option_iter([None, None, Some(1i32), Some(2), None]), false)] - #[case(PrimitiveArray::from_option_iter([None, None, Some(1i32), Some(1), None]), false)] - #[case(PrimitiveArray::from_option_iter([None, Some(5_u8), None]), false)] - fn test_primitive_is_strict_sorted(#[case] array: PrimitiveArray, #[case] expected: bool) { - assert_eq!( - is_strict_sorted(&array.into_array()).vortex_expect("operation should succeed in test"), - Some(expected) - ); - } -} diff --git a/vortex-array/src/arrays/primitive/compute/mod.rs b/vortex-array/src/arrays/primitive/compute/mod.rs index e6a1542acde..867ddf69d03 100644 --- a/vortex-array/src/arrays/primitive/compute/mod.rs +++ b/vortex-array/src/arrays/primitive/compute/mod.rs @@ -4,7 +4,6 @@ mod between; mod cast; mod fill_null; -mod is_sorted; mod mask; pub(crate) mod rules; mod slice; diff --git a/vortex-array/src/arrays/varbin/compute/is_sorted.rs b/vortex-array/src/arrays/varbin/compute/is_sorted.rs deleted file mode 100644 index 945dd9f54b9..00000000000 --- a/vortex-array/src/arrays/varbin/compute/is_sorted.rs +++ /dev/null @@ -1,28 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: Copyright the Vortex contributors - -use vortex_error::VortexResult; - -use crate::accessor::ArrayAccessor; -use crate::arrays::VarBin; -use crate::arrays::VarBinArray; -use crate::compute::IsSortedIteratorExt; -use crate::compute::IsSortedKernel; -use crate::compute::IsSortedKernelAdapter; -use crate::register_kernel; - -impl IsSortedKernel for VarBin { - fn is_sorted(&self, array: &VarBinArray) -> VortexResult> { - Ok(Some( - array.with_iterator(|bytes_iter| bytes_iter.is_sorted()), - )) - } - - fn is_strict_sorted(&self, array: &VarBinArray) -> VortexResult> { - Ok(Some( - array.with_iterator(|bytes_iter| bytes_iter.is_strict_sorted()), - )) - } -} - -register_kernel!(IsSortedKernelAdapter(VarBin).lift()); diff --git a/vortex-array/src/arrays/varbin/compute/mod.rs b/vortex-array/src/arrays/varbin/compute/mod.rs index 0abd02252be..ab2de942138 100644 --- a/vortex-array/src/arrays/varbin/compute/mod.rs +++ b/vortex-array/src/arrays/varbin/compute/mod.rs @@ -7,7 +7,6 @@ mod slice; mod cast; mod compare; mod filter; -mod is_sorted; mod mask; mod take; diff --git a/vortex-array/src/arrays/varbinview/compute/is_sorted.rs b/vortex-array/src/arrays/varbinview/compute/is_sorted.rs deleted file mode 100644 index 52767ef5732..00000000000 --- a/vortex-array/src/arrays/varbinview/compute/is_sorted.rs +++ /dev/null @@ -1,28 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: Copyright the Vortex contributors - -use vortex_error::VortexResult; - -use crate::accessor::ArrayAccessor; -use crate::arrays::VarBinView; -use crate::arrays::VarBinViewArray; -use crate::compute::IsSortedIteratorExt; -use crate::compute::IsSortedKernel; -use crate::compute::IsSortedKernelAdapter; -use crate::register_kernel; - -impl IsSortedKernel for VarBinView { - fn is_sorted(&self, array: &VarBinViewArray) -> VortexResult> { - Ok(Some( - array.with_iterator(|bytes_iter| bytes_iter.is_sorted()), - )) - } - - fn is_strict_sorted(&self, array: &VarBinViewArray) -> VortexResult> { - Ok(Some( - array.with_iterator(|bytes_iter| bytes_iter.is_strict_sorted()), - )) - } -} - -register_kernel!(IsSortedKernelAdapter(VarBinView).lift()); diff --git a/vortex-array/src/arrays/varbinview/compute/mod.rs b/vortex-array/src/arrays/varbinview/compute/mod.rs index 5fe39e3d309..5e107f6beae 100644 --- a/vortex-array/src/arrays/varbinview/compute/mod.rs +++ b/vortex-array/src/arrays/varbinview/compute/mod.rs @@ -2,7 +2,6 @@ // SPDX-FileCopyrightText: Copyright the Vortex contributors mod cast; -mod is_sorted; mod mask; pub(crate) mod rules; mod slice; diff --git a/vortex-array/src/compute/is_sorted.rs b/vortex-array/src/compute/is_sorted.rs index c9adc1bd5e3..b47537a28d7 100644 --- a/vortex-array/src/compute/is_sorted.rs +++ b/vortex-array/src/compute/is_sorted.rs @@ -1,379 +1,30 @@ // SPDX-License-Identifier: Apache-2.0 // SPDX-FileCopyrightText: Copyright the Vortex contributors -use std::any::Any; -use std::sync::LazyLock; - -use arcref::ArcRef; -use vortex_error::VortexError; use vortex_error::VortexResult; -use vortex_error::vortex_bail; -use vortex_error::vortex_err; use crate::ArrayRef; -use crate::DynArray; -use crate::IntoArray as _; -use crate::arrays::Constant; -use crate::arrays::Null; -use crate::compute::ComputeFn; -use crate::compute::ComputeFnVTable; -use crate::compute::InvocationArgs; -use crate::compute::Kernel; -use crate::compute::Options; -use crate::compute::Output; -use crate::dtype::DType; -use crate::dtype::Nullability; -use crate::expr::stats::Precision; -use crate::expr::stats::Stat; -use crate::expr::stats::StatsProviderExt; -use crate::scalar::Scalar; -use crate::vtable::VTable; - -static IS_SORTED_FN: LazyLock = LazyLock::new(|| { - let compute = ComputeFn::new("is_sorted".into(), ArcRef::new_ref(&IsSorted)); - for kernel in inventory::iter:: { - compute.register_kernel(kernel.0.clone()); - } - compute -}); - -pub(crate) fn warm_up_vtable() -> usize { - IS_SORTED_FN.kernels().len() -} +use crate::LEGACY_SESSION; +use crate::VortexSessionExecute; +/// Computes whether an array is sorted in non-decreasing order. +/// +/// **Deprecated**: Use [`crate::aggregate_fn::fns::is_sorted::is_sorted`] instead. +#[deprecated(note = "Use crate::aggregate_fn::fns::is_sorted::is_sorted instead")] pub fn is_sorted(array: &ArrayRef) -> VortexResult> { - is_sorted_opts(array, false) + let mut ctx = LEGACY_SESSION.create_execution_ctx(); + Ok(Some(crate::aggregate_fn::fns::is_sorted::is_sorted( + array, &mut ctx, + )?)) } +/// Computes whether an array is strictly sorted in increasing order. +/// +/// **Deprecated**: Use [`crate::aggregate_fn::fns::is_sorted::is_strict_sorted`] instead. +#[deprecated(note = "Use crate::aggregate_fn::fns::is_sorted::is_strict_sorted instead")] pub fn is_strict_sorted(array: &ArrayRef) -> VortexResult> { - is_sorted_opts(array, true) -} - -pub fn is_sorted_opts(array: &ArrayRef, strict: bool) -> VortexResult> { - Ok(IS_SORTED_FN - .invoke(&InvocationArgs { - inputs: &[array.into()], - options: &IsSortedOptions { strict }, - })? - .unwrap_scalar()? - .as_bool() - .value()) -} - -struct IsSorted; -impl ComputeFnVTable for IsSorted { - fn invoke( - &self, - args: &InvocationArgs, - kernels: &[ArcRef], - ) -> VortexResult { - let IsSortedArgs { array, strict } = IsSortedArgs::try_from(args)?; - let array = array.to_array(); - - // We currently don't support sorting struct arrays. - if array.dtype().is_struct() { - let scalar: Scalar = Some(false).into(); - return Ok(scalar.into()); - } - - let is_sorted = if strict { - if let Some(Precision::Exact(value)) = - array.statistics().get_as::(Stat::IsStrictSorted) - { - let scalar: Scalar = Some(value).into(); - return Ok(scalar.into()); - } - - let is_strict_sorted = is_sorted_impl(&array, kernels, true)?; - let array_stats = array.statistics(); - - if is_strict_sorted.is_some() { - if is_strict_sorted.unwrap_or(false) { - array_stats.set(Stat::IsSorted, Precision::Exact(true.into())); - array_stats.set(Stat::IsStrictSorted, Precision::Exact(true.into())); - } else { - array_stats.set(Stat::IsStrictSorted, Precision::Exact(false.into())); - } - } - - is_strict_sorted - } else { - if let Some(Precision::Exact(value)) = array.statistics().get_as::(Stat::IsSorted) - { - let scalar: Scalar = Some(value).into(); - return Ok(scalar.into()); - } - - let is_sorted = is_sorted_impl(&array, kernels, false)?; - let array_stats = array.statistics(); - - if is_sorted.is_some() { - if is_sorted.unwrap_or(false) { - array_stats.set(Stat::IsSorted, Precision::Exact(true.into())); - } else { - array_stats.set(Stat::IsSorted, Precision::Exact(false.into())); - array_stats.set(Stat::IsStrictSorted, Precision::Exact(false.into())); - } - } - - is_sorted - }; - - let scalar: Scalar = is_sorted.into(); - Ok(scalar.into()) - } - - fn return_dtype(&self, _args: &InvocationArgs) -> VortexResult { - // We always return a nullable boolean where `null` indicates we couldn't determine - // whether the array is constant. - Ok(DType::Bool(Nullability::Nullable)) - } - - fn return_len(&self, _args: &InvocationArgs) -> VortexResult { - Ok(1) - } - - fn is_elementwise(&self) -> bool { - true - } -} - -struct IsSortedArgs<'a> { - array: &'a dyn DynArray, - strict: bool, -} - -impl<'a> TryFrom<&InvocationArgs<'a>> for IsSortedArgs<'a> { - type Error = VortexError; - - fn try_from(value: &InvocationArgs<'a>) -> Result { - if value.inputs.len() != 1 { - vortex_bail!( - "IsSorted function requires exactly one argument, got {}", - value.inputs.len() - ); - } - let array = value.inputs[0] - .array() - .ok_or_else(|| vortex_err!("Invalid argument type for is sorted function"))?; - let options = *value - .options - .as_any() - .downcast_ref::() - .ok_or_else(|| vortex_err!("Invalid options type for is sorted function"))?; - - Ok(IsSortedArgs { - array, - strict: options.strict, - }) - } -} - -#[derive(Clone, Copy)] -struct IsSortedOptions { - strict: bool, -} - -impl Options for IsSortedOptions { - fn as_any(&self) -> &dyn Any { - self - } -} - -pub struct IsSortedKernelRef(ArcRef); -inventory::collect!(IsSortedKernelRef); - -#[derive(Debug)] -pub struct IsSortedKernelAdapter(pub V); - -impl IsSortedKernelAdapter { - pub const fn lift(&'static self) -> IsSortedKernelRef { - IsSortedKernelRef(ArcRef::new_ref(self)) - } -} - -impl Kernel for IsSortedKernelAdapter { - fn invoke(&self, args: &InvocationArgs) -> VortexResult> { - let IsSortedArgs { array, strict } = IsSortedArgs::try_from(args)?; - let Some(array) = array.as_opt::() else { - return Ok(None); - }; - - let is_sorted = if strict { - V::is_strict_sorted(&self.0, array)? - } else { - V::is_sorted(&self.0, array)? - }; - - let scalar: Scalar = is_sorted.into(); - Ok(Some(scalar.into())) - } -} - -pub trait IsSortedKernel: VTable { - /// # Preconditions - /// - The array's length is > 1. - /// - The array is not encoded as `NullArray` or `ConstantArray`. - /// - If doing a `strict` check, if the array is nullable, it'll have at most 1 null element - /// as the first item in the array. - fn is_sorted(&self, array: &Self::Array) -> VortexResult>; - - fn is_strict_sorted(&self, array: &Self::Array) -> VortexResult>; -} - -#[expect( - clippy::wrong_self_convention, - reason = "is_* naming follows Iterator::is_sorted convention" -)] -/// Helper methods to check sortedness with strictness -pub trait IsSortedIteratorExt: Iterator -where - ::Item: PartialOrd, -{ - fn is_strict_sorted(self) -> bool - where - Self: Sized, - Self::Item: PartialOrd, - { - self.is_sorted_by(|a, b| a < b) - } -} - -impl IsSortedIteratorExt for T -where - T: Iterator + ?Sized, - T::Item: PartialOrd, -{ -} - -fn is_sorted_impl( - array: &ArrayRef, - kernels: &[ArcRef], - strict: bool, -) -> VortexResult> { - // Arrays with 0 or 1 elements are strict sorted. - if array.len() <= 1 { - return Ok(Some(true)); - } - - // Constant and null arrays are always sorted, but not strict sorted. - if array.is::() || array.is::() { - return Ok(Some(!strict)); - } - - // Enforce strictness before we even try to check if the array is sorted. - if strict { - let invalid_count = array.invalid_count()?; - match invalid_count { - // We can keep going - 0 => {} - // If we have a potential null value - it has to be the first one. - 1 => { - if !array.is_invalid(0)? { - return Ok(Some(false)); - } - } - _ => return Ok(Some(false)), - } - } - - let args = InvocationArgs { - inputs: &[array.into()], - options: &IsSortedOptions { strict }, - }; - - for kernel in kernels { - if let Some(output) = kernel.invoke(&args)? { - return Ok(output.unwrap_scalar()?.as_bool().value()); - } - } - - if !array.is_canonical() { - tracing::debug!( - "No is_sorted implementation found for {}", - array.encoding_id() - ); - - // Recurse to canonical implementation - let array = array.to_canonical()?.into_array(); - - return if strict { - is_strict_sorted(&array) - } else { - is_sorted(&array) - }; - } - - vortex_bail!( - "No is_sorted function for canonical array: {}", - array.encoding_id(), - ) -} - -#[cfg(test)] -mod tests { - use vortex_buffer::buffer; - - use crate::IntoArray; - use crate::arrays::BoolArray; - use crate::arrays::PrimitiveArray; - use crate::compute::is_sorted; - use crate::compute::is_strict_sorted; - use crate::validity::Validity; - #[test] - fn test_is_sorted() { - let arr = PrimitiveArray::new(buffer!(0, 1, 2, 3), Validity::AllValid).into_array(); - assert!(is_sorted(&arr).unwrap().unwrap()); - - let arr = PrimitiveArray::new( - buffer!(0, 1, 2, 3), - Validity::Array(BoolArray::from_iter([false, true, true, true]).into_array()), - ) - .into_array(); - assert!(is_sorted(&arr).unwrap().unwrap()); - - let arr = PrimitiveArray::new( - buffer!(0, 1, 2, 3), - Validity::Array(BoolArray::from_iter([true, false, true, true]).into_array()), - ) - .into_array(); - assert!(!is_sorted(&arr).unwrap().unwrap()); - - let arr = PrimitiveArray::new(buffer!(0, 1, 3, 2), Validity::AllValid).into_array(); - assert!(!is_sorted(&arr).unwrap().unwrap()); - - let arr = PrimitiveArray::new( - buffer!(0, 1, 3, 2), - Validity::Array(BoolArray::from_iter([false, true, true, true]).into_array()), - ) - .into_array(); - assert!(!is_sorted(&arr).unwrap().unwrap()); - } - - #[test] - fn test_is_strict_sorted() { - let arr = PrimitiveArray::new(buffer!(0, 1, 2, 3), Validity::AllValid).into_array(); - assert!(is_strict_sorted(&arr).unwrap().unwrap()); - - let arr = PrimitiveArray::new( - buffer!(0, 1, 2, 3), - Validity::Array(BoolArray::from_iter([false, true, true, true]).into_array()), - ) - .into_array(); - assert!(is_strict_sorted(&arr).unwrap().unwrap()); - - let arr = PrimitiveArray::new( - buffer!(0, 1, 2, 3), - Validity::Array(BoolArray::from_iter([true, false, true, true]).into_array()), - ) - .into_array(); - assert!(!is_strict_sorted(&arr).unwrap().unwrap()); - - let arr = PrimitiveArray::new( - buffer!(0, 1, 3, 2), - Validity::Array(BoolArray::from_iter([false, true, true, true]).into_array()), - ) - .into_array(); - assert!(!is_strict_sorted(&arr).unwrap().unwrap()); - } + let mut ctx = LEGACY_SESSION.create_execution_ctx(); + Ok(Some(crate::aggregate_fn::fns::is_sorted::is_strict_sorted( + array, &mut ctx, + )?)) } diff --git a/vortex-array/src/compute/mod.rs b/vortex-array/src/compute/mod.rs index 7c1fedfca0d..421c2372bef 100644 --- a/vortex-array/src/compute/mod.rs +++ b/vortex-array/src/compute/mod.rs @@ -52,14 +52,6 @@ pub struct ComputeFn { kernels: RwLock>>, } -/// Force all the default [`ComputeFn`] vtables to register all available compute kernels. -/// -/// Mostly useful for small benchmarks where the overhead might cause noise depending on the order of benchmarks. -pub fn warm_up_vtables() { - warm_up_vtable(); - // min_max, nan_count, and is_constant have been migrated to aggregate_fn -} - impl ComputeFn { /// Create a new compute function from the given [`ComputeFnVTable`]. pub fn new(id: ArcRef, vtable: ArcRef) -> Self { diff --git a/vortex-array/src/patches.rs b/vortex-array/src/patches.rs index dda5aa1e7c9..e57ec9c64ec 100644 --- a/vortex-array/src/patches.rs +++ b/vortex-array/src/patches.rs @@ -30,7 +30,6 @@ use crate::ToCanonical; use crate::arrays::BoolArray; use crate::arrays::PrimitiveArray; use crate::builtins::ArrayBuiltins; -use crate::compute::is_sorted; use crate::dtype::DType; use crate::dtype::IntegerPType; use crate::dtype::NativePType; @@ -187,10 +186,16 @@ impl Patches { "Patch indices {max:?}, offset {offset} are longer than the array length {array_len}" ); - debug_assert!( - is_sorted(&indices).unwrap_or(Some(false)).unwrap_or(false), - "Patch indices must be sorted" - ); + #[cfg(debug_assertions)] + { + use crate::VortexSessionExecute; + let mut ctx = crate::LEGACY_SESSION.create_execution_ctx(); + assert!( + crate::aggregate_fn::fns::is_sorted::is_sorted(&indices, &mut ctx) + .unwrap_or(false), + "Patch indices must be sorted" + ); + } } Ok(Self { diff --git a/vortex-array/src/scalar/typed_view/struct_.rs b/vortex-array/src/scalar/typed_view/struct_.rs index 9591d1af0db..93b796f055f 100644 --- a/vortex-array/src/scalar/typed_view/struct_.rs +++ b/vortex-array/src/scalar/typed_view/struct_.rs @@ -323,8 +323,7 @@ impl Scalar { children: impl IntoIterator, ) -> Self { let value_children: Vec<_> = children.into_iter().map(|s| s.into_value()).collect(); - Self::try_new(dtype, Some(ScalarValue::List(value_children))) - .vortex_expect("unable to construct a struct `Scalar`") + unsafe { Self::new_unchecked(dtype, Some(ScalarValue::List(value_children))) } } } diff --git a/vortex-array/src/stats/array.rs b/vortex-array/src/stats/array.rs index 3f018f64b35..863d6a94531 100644 --- a/vortex-array/src/stats/array.rs +++ b/vortex-array/src/stats/array.rs @@ -18,13 +18,13 @@ use crate::DynArray; use crate::LEGACY_SESSION; use crate::VortexSessionExecute; use crate::aggregate_fn::fns::is_constant::is_constant; +use crate::aggregate_fn::fns::is_sorted::is_sorted; +use crate::aggregate_fn::fns::is_sorted::is_strict_sorted; use crate::aggregate_fn::fns::min_max::MinMaxResult; use crate::aggregate_fn::fns::min_max::min_max; use crate::aggregate_fn::fns::nan_count::nan_count; use crate::aggregate_fn::fns::sum::sum; use crate::builders::builder_with_capacity; -use crate::compute::is_sorted; -use crate::compute::is_strict_sorted; use crate::expr::stats::Precision; use crate::expr::stats::Stat; use crate::expr::stats::StatsProvider; @@ -173,8 +173,8 @@ impl StatsSetRef<'_> { Some(is_constant(&array_ref, &mut ctx)?.into()) } } - Stat::IsSorted => is_sorted(&array_ref)?.map(|v| v.into()), - Stat::IsStrictSorted => is_strict_sorted(&array_ref)?.map(|v| v.into()), + Stat::IsSorted => Some(is_sorted(&array_ref, &mut ctx)?.into()), + Stat::IsStrictSorted => Some(is_strict_sorted(&array_ref, &mut ctx)?.into()), Stat::UncompressedSizeInBytes => { let mut builder = builder_with_capacity(self.dyn_array_ref.dtype(), self.dyn_array_ref.len());