Skip to content

Commit 03e62d2

Browse files
committed
IsSortedKernel
Signed-off-by: Nicholas Gates <nick@nickgates.com>
1 parent 8baeaca commit 03e62d2

41 files changed

Lines changed: 355 additions & 1267 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

encodings/fastlanes/public-api.lock

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -420,12 +420,6 @@ impl vortex_array::arrays::slice::SliceReduce for vortex_fastlanes::FoR
420420

421421
pub fn vortex_fastlanes::FoR::slice(array: &Self::Array, range: core::ops::range::Range<usize>) -> vortex_error::VortexResult<core::option::Option<vortex_array::array::ArrayRef>>
422422

423-
impl vortex_array::compute::is_sorted::IsSortedKernel for vortex_fastlanes::FoR
424-
425-
pub fn vortex_fastlanes::FoR::is_sorted(&self, array: &vortex_fastlanes::FoRArray) -> vortex_error::VortexResult<core::option::Option<bool>>
426-
427-
pub fn vortex_fastlanes::FoR::is_strict_sorted(&self, array: &vortex_fastlanes::FoRArray) -> vortex_error::VortexResult<core::option::Option<bool>>
428-
429423
impl vortex_array::scalar_fn::fns::binary::compare::CompareKernel for vortex_fastlanes::FoR
430424

431425
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<core::option::Option<vortex_array::array::ArrayRef>>

encodings/fastlanes/src/for/compute/is_sorted.rs

Lines changed: 48 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,19 @@
11
// SPDX-License-Identifier: Apache-2.0
22
// SPDX-FileCopyrightText: Copyright the Vortex contributors
33

4+
use vortex_array::ArrayRef;
5+
use vortex_array::ExecutionCtx;
46
use vortex_array::IntoArray;
57
use vortex_array::ToCanonical;
6-
use vortex_array::compute::IsSortedKernel;
7-
use vortex_array::compute::IsSortedKernelAdapter;
8-
use vortex_array::compute::is_sorted;
9-
use vortex_array::compute::is_strict_sorted;
10-
use vortex_array::register_kernel;
8+
use vortex_array::aggregate_fn::AggregateFnRef;
9+
use vortex_array::aggregate_fn::fns::is_sorted::IsSorted;
10+
use vortex_array::aggregate_fn::fns::is_sorted::is_sorted;
11+
use vortex_array::aggregate_fn::fns::is_sorted::is_strict_sorted;
12+
use vortex_array::aggregate_fn::kernels::DynAggregateKernel;
13+
use vortex_array::scalar::Scalar;
1114
use vortex_error::VortexResult;
1215

1316
use crate::FoR;
14-
use crate::FoRArray;
1517

1618
/// FoR can express sortedness directly on its encoded form.
1719
///
@@ -71,92 +73,107 @@ use crate::FoRArray;
7173
/// Addition is order-preserving, so all the wrapped values preserve their order and they're all
7274
/// represented as unsigned values larger than 127 so they also preserve their order with the
7375
/// unwrapped values.
74-
impl IsSortedKernel for FoR {
75-
fn is_sorted(&self, array: &FoRArray) -> VortexResult<Option<bool>> {
76-
let encoded = array.encoded().to_primitive();
77-
is_sorted(
78-
&encoded
79-
.reinterpret_cast(encoded.ptype().to_unsigned())
80-
.into_array(),
81-
)
82-
}
76+
#[derive(Debug)]
77+
pub(crate) struct FoRIsSortedKernel;
78+
79+
impl DynAggregateKernel for FoRIsSortedKernel {
80+
fn aggregate(
81+
&self,
82+
aggregate_fn: &AggregateFnRef,
83+
batch: &ArrayRef,
84+
ctx: &mut ExecutionCtx,
85+
) -> VortexResult<Option<Scalar>> {
86+
let Some(options) = aggregate_fn.as_opt::<IsSorted>() else {
87+
return Ok(None);
88+
};
89+
90+
let Some(array) = batch.as_opt::<FoR>() else {
91+
return Ok(None);
92+
};
8393

84-
fn is_strict_sorted(&self, array: &FoRArray) -> VortexResult<Option<bool>> {
8594
let encoded = array.encoded().to_primitive();
86-
is_strict_sorted(
87-
&encoded
88-
.reinterpret_cast(encoded.ptype().to_unsigned())
89-
.into_array(),
90-
)
95+
let unsigned_array = encoded
96+
.reinterpret_cast(encoded.ptype().to_unsigned())
97+
.into_array();
98+
99+
let result = if options.strict {
100+
is_strict_sorted(&unsigned_array, ctx)?
101+
} else {
102+
is_sorted(&unsigned_array, ctx)?
103+
};
104+
105+
Ok(Some(IsSorted::make_partial(batch, result, options.strict)?))
91106
}
92107
}
93108

94-
register_kernel!(IsSortedKernelAdapter(FoR).lift());
95-
96109
#[cfg(test)]
97110
mod test {
98111
use vortex_array::IntoArray;
112+
use vortex_array::LEGACY_SESSION;
113+
use vortex_array::VortexSessionExecute;
114+
use vortex_array::aggregate_fn::fns::is_sorted::is_sorted;
99115
use vortex_array::arrays::PrimitiveArray;
100-
use vortex_array::compute::is_sorted;
101116
use vortex_array::validity::Validity;
102117
use vortex_buffer::buffer;
103118

104119
use crate::FoRArray;
105120

106121
#[test]
107122
fn test_sorted() {
123+
let mut ctx = LEGACY_SESSION.create_execution_ctx();
124+
108125
let a = PrimitiveArray::new(buffer![-1, 0, i8::MAX], Validity::NonNullable);
109126
let b = FoRArray::encode(a).unwrap();
110127
assert!(
111-
is_sorted(&b.clone().into_array()).unwrap().unwrap(),
128+
is_sorted(&b.clone().into_array(), &mut ctx).unwrap(),
112129
"{}",
113130
b.encoded().display_values()
114131
);
115132

116133
let a = PrimitiveArray::new(buffer![i8::MIN, 0, i8::MAX], Validity::NonNullable);
117134
let b = FoRArray::encode(a).unwrap();
118135
assert!(
119-
is_sorted(&b.clone().into_array()).unwrap().unwrap(),
136+
is_sorted(&b.clone().into_array(), &mut ctx).unwrap(),
120137
"{}",
121138
b.encoded().display_values()
122139
);
123140

124141
let a = PrimitiveArray::new(buffer![i8::MIN, 0, 30, 127], Validity::NonNullable);
125142
let b = FoRArray::encode(a).unwrap();
126143
assert!(
127-
is_sorted(&b.clone().into_array()).unwrap().unwrap(),
144+
is_sorted(&b.clone().into_array(), &mut ctx).unwrap(),
128145
"{}",
129146
b.encoded().display_values()
130147
);
131148

132149
let a = PrimitiveArray::new(buffer![i8::MIN, -3, -1], Validity::NonNullable);
133150
let b = FoRArray::encode(a).unwrap();
134151
assert!(
135-
is_sorted(&b.clone().into_array()).unwrap().unwrap(),
152+
is_sorted(&b.clone().into_array(), &mut ctx).unwrap(),
136153
"{}",
137154
b.encoded().display_values()
138155
);
139156

140157
let a = PrimitiveArray::new(buffer![-10, -3, -1], Validity::NonNullable);
141158
let b = FoRArray::encode(a).unwrap();
142159
assert!(
143-
is_sorted(&b.clone().into_array()).unwrap().unwrap(),
160+
is_sorted(&b.clone().into_array(), &mut ctx).unwrap(),
144161
"{}",
145162
b.encoded().display_values()
146163
);
147164

148165
let a = PrimitiveArray::new(buffer![-10, -11, -1], Validity::NonNullable);
149166
let b = FoRArray::encode(a).unwrap();
150167
assert!(
151-
!is_sorted(&b.clone().into_array()).unwrap().unwrap(),
168+
!is_sorted(&b.clone().into_array(), &mut ctx).unwrap(),
152169
"{}",
153170
b.encoded().display_values()
154171
);
155172

156173
let a = PrimitiveArray::new(buffer![-10, i8::MIN, -1], Validity::NonNullable);
157174
let b = FoRArray::encode(a).unwrap();
158175
assert!(
159-
!is_sorted(&b.clone().into_array()).unwrap().unwrap(),
176+
!is_sorted(&b.clone().into_array(), &mut ctx).unwrap(),
160177
"{}",
161178
b.encoded().display_values()
162179
);

encodings/fastlanes/src/for/compute/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
mod cast;
55
mod compare;
66
pub(crate) mod is_constant;
7-
mod is_sorted;
7+
pub(crate) mod is_sorted;
88

99
use vortex_array::ArrayRef;
1010
use vortex_array::DynArray;

encodings/fastlanes/src/lib.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,10 @@ pub(crate) const FL_CHUNK_SIZE: usize = 1024;
1818

1919
use bitpacking::compute::is_constant::BitPackedIsConstantKernel;
2020
use r#for::compute::is_constant::FoRIsConstantKernel;
21+
use r#for::compute::is_sorted::FoRIsSortedKernel;
2122
use vortex_array::aggregate_fn::AggregateFnVTable;
2223
use vortex_array::aggregate_fn::fns::is_constant::IsConstant;
24+
use vortex_array::aggregate_fn::fns::is_sorted::IsSorted;
2325
use vortex_array::aggregate_fn::session::AggregateFnSessionExt;
2426
use vortex_array::session::ArraySessionExt;
2527
use vortex_session::VortexSession;
@@ -42,6 +44,11 @@ pub fn initialize(session: &mut VortexSession) {
4244
Some(IsConstant.id()),
4345
&FoRIsConstantKernel,
4446
);
47+
session.aggregate_fns().register_aggregate_kernel(
48+
FoR::ID,
49+
Some(IsSorted.id()),
50+
&FoRIsSortedKernel,
51+
);
4552
}
4653

4754
#[cfg(test)]

encodings/runend/public-api.lock

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -34,12 +34,6 @@ impl vortex_array::arrays::filter::kernel::FilterKernel for vortex_runend::RunEn
3434

3535
pub fn vortex_runend::RunEnd::filter(array: &vortex_runend::RunEndArray, mask: &vortex_mask::Mask, ctx: &mut vortex_array::executor::ExecutionCtx) -> vortex_error::VortexResult<core::option::Option<vortex_array::array::ArrayRef>>
3636

37-
impl vortex_array::compute::is_sorted::IsSortedKernel for vortex_runend::RunEnd
38-
39-
pub fn vortex_runend::RunEnd::is_sorted(&self, array: &vortex_runend::RunEndArray) -> vortex_error::VortexResult<core::option::Option<bool>>
40-
41-
pub fn vortex_runend::RunEnd::is_strict_sorted(&self, array: &vortex_runend::RunEndArray) -> vortex_error::VortexResult<core::option::Option<bool>>
42-
4337
impl vortex_array::scalar_fn::fns::binary::compare::CompareKernel for vortex_runend::RunEnd
4438

4539
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<core::option::Option<vortex_array::array::ArrayRef>>

encodings/runend/src/compute/is_sorted.rs

Lines changed: 38 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,49 @@
11
// SPDX-License-Identifier: Apache-2.0
22
// SPDX-FileCopyrightText: Copyright the Vortex contributors
33

4+
use vortex_array::ArrayRef;
5+
use vortex_array::ExecutionCtx;
46
use vortex_array::IntoArray as _;
5-
use vortex_array::compute::IsSortedKernel;
6-
use vortex_array::compute::IsSortedKernelAdapter;
7-
use vortex_array::compute::is_sorted;
8-
use vortex_array::compute::is_strict_sorted;
9-
use vortex_array::register_kernel;
7+
use vortex_array::aggregate_fn::AggregateFnRef;
8+
use vortex_array::aggregate_fn::fns::is_sorted::IsSorted;
9+
use vortex_array::aggregate_fn::fns::is_sorted::is_sorted;
10+
use vortex_array::aggregate_fn::fns::is_sorted::is_strict_sorted;
11+
use vortex_array::aggregate_fn::kernels::DynAggregateKernel;
12+
use vortex_array::scalar::Scalar;
1013
use vortex_error::VortexResult;
1114

1215
use crate::RunEnd;
13-
use crate::RunEndArray;
1416

15-
impl IsSortedKernel for RunEnd {
16-
fn is_sorted(&self, array: &RunEndArray) -> VortexResult<Option<bool>> {
17-
is_sorted(array.values())
18-
}
17+
/// RunEnd-specific is_sorted kernel.
18+
///
19+
/// Non-strict: values array sorted implies the run-end array is sorted.
20+
/// Strict: must canonicalize since runs repeat values.
21+
#[derive(Debug)]
22+
pub(crate) struct RunEndIsSortedKernel;
23+
24+
impl DynAggregateKernel for RunEndIsSortedKernel {
25+
fn aggregate(
26+
&self,
27+
aggregate_fn: &AggregateFnRef,
28+
batch: &ArrayRef,
29+
ctx: &mut ExecutionCtx,
30+
) -> VortexResult<Option<Scalar>> {
31+
let Some(options) = aggregate_fn.as_opt::<IsSorted>() else {
32+
return Ok(None);
33+
};
34+
35+
let Some(array) = batch.as_opt::<RunEnd>() else {
36+
return Ok(None);
37+
};
1938

20-
fn is_strict_sorted(&self, array: &RunEndArray) -> VortexResult<Option<bool>> {
21-
is_strict_sorted(&array.to_canonical()?.into_array())
39+
let result = if options.strict {
40+
// Strict sort with run-end encoding means we need to canonicalize
41+
// since run-end encoding repeats values.
42+
is_strict_sorted(&array.to_canonical()?.into_array(), ctx)?
43+
} else {
44+
is_sorted(array.values(), ctx)?
45+
};
46+
47+
Ok(Some(IsSorted::make_partial(batch, result, options.strict)?))
2248
}
2349
}
24-
25-
register_kernel!(IsSortedKernelAdapter(RunEnd).lift());

encodings/runend/src/compute/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ mod compare;
66
mod fill_null;
77
pub(crate) mod filter;
88
pub(crate) mod is_constant;
9-
mod is_sorted;
9+
pub(crate) mod is_sorted;
1010
pub(crate) mod min_max;
1111
pub(crate) mod take;
1212
pub(crate) mod take_from;

encodings/runend/src/lib.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ pub mod _benchmarking {
2828

2929
use vortex_array::aggregate_fn::AggregateFnVTable;
3030
use vortex_array::aggregate_fn::fns::is_constant::IsConstant;
31+
use vortex_array::aggregate_fn::fns::is_sorted::IsSorted;
3132
use vortex_array::aggregate_fn::fns::min_max::MinMax;
3233
use vortex_array::aggregate_fn::session::AggregateFnSessionExt;
3334
use vortex_array::session::ArraySessionExt;
@@ -48,6 +49,11 @@ pub fn initialize(session: &mut VortexSession) {
4849
Some(IsConstant.id()),
4950
&compute::is_constant::RunEndIsConstantKernel,
5051
);
52+
session.aggregate_fns().register_aggregate_kernel(
53+
RunEnd::ID,
54+
Some(IsSorted.id()),
55+
&compute::is_sorted::RunEndIsSortedKernel,
56+
);
5157
}
5258

5359
#[cfg(test)]

encodings/sequence/public-api.lock

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,6 @@ impl vortex_array::arrays::slice::SliceReduce for vortex_sequence::Sequence
2222

2323
pub fn vortex_sequence::Sequence::slice(array: &Self::Array, range: core::ops::range::Range<usize>) -> vortex_error::VortexResult<core::option::Option<vortex_array::array::ArrayRef>>
2424

25-
impl vortex_array::compute::is_sorted::IsSortedKernel for vortex_sequence::Sequence
26-
27-
pub fn vortex_sequence::Sequence::is_sorted(&self, array: &vortex_sequence::SequenceArray) -> vortex_error::VortexResult<core::option::Option<bool>>
28-
29-
pub fn vortex_sequence::Sequence::is_strict_sorted(&self, array: &vortex_sequence::SequenceArray) -> vortex_error::VortexResult<core::option::Option<bool>>
30-
3125
impl vortex_array::scalar_fn::fns::binary::compare::CompareKernel for vortex_sequence::Sequence
3226

3327
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<core::option::Option<vortex_array::array::ArrayRef>>

encodings/sequence/src/compute/is_sorted.rs

Lines changed: 39 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2,29 +2,51 @@
22
// SPDX-FileCopyrightText: Copyright the Vortex contributors
33

44
use num_traits::zero;
5-
use vortex_array::compute::IsSortedKernel;
6-
use vortex_array::compute::IsSortedKernelAdapter;
5+
use vortex_array::ArrayRef;
6+
use vortex_array::ExecutionCtx;
7+
use vortex_array::aggregate_fn::AggregateFnRef;
8+
use vortex_array::aggregate_fn::fns::is_sorted::IsSorted;
9+
use vortex_array::aggregate_fn::kernels::DynAggregateKernel;
710
use vortex_array::match_each_native_ptype;
8-
use vortex_array::register_kernel;
11+
use vortex_array::scalar::Scalar;
912
use vortex_error::VortexResult;
1013

1114
use crate::Sequence;
12-
use crate::SequenceArray;
1315

14-
impl IsSortedKernel for Sequence {
15-
fn is_sorted(&self, array: &SequenceArray) -> VortexResult<Option<bool>> {
16-
let m = array.multiplier();
17-
match_each_native_ptype!(m.ptype(), |P| {
18-
m.cast::<P>().map(|x| Some(x >= zero::<P>()))
19-
})
20-
}
16+
/// Sequence-specific is_sorted kernel.
17+
///
18+
/// A sequence `A[i] = base + i * multiplier` is sorted iff multiplier >= 0,
19+
/// and strict sorted iff multiplier > 0.
20+
#[derive(Debug)]
21+
pub(crate) struct SequenceIsSortedKernel;
22+
23+
impl DynAggregateKernel for SequenceIsSortedKernel {
24+
fn aggregate(
25+
&self,
26+
aggregate_fn: &AggregateFnRef,
27+
batch: &ArrayRef,
28+
ctx: &mut ExecutionCtx,
29+
) -> VortexResult<Option<Scalar>> {
30+
let _ = ctx;
31+
let Some(options) = aggregate_fn.as_opt::<IsSorted>() else {
32+
return Ok(None);
33+
};
34+
35+
let Some(array) = batch.as_opt::<Sequence>() else {
36+
return Ok(None);
37+
};
2138

22-
fn is_strict_sorted(&self, array: &SequenceArray) -> VortexResult<Option<bool>> {
2339
let m = array.multiplier();
24-
match_each_native_ptype!(m.ptype(), |P| {
25-
m.cast::<P>().map(|x| Some(x > zero::<P>()))
26-
})
40+
let result = match_each_native_ptype!(m.ptype(), |P| {
41+
m.cast::<P>().map(|x| {
42+
if options.strict {
43+
x > zero::<P>()
44+
} else {
45+
x >= zero::<P>()
46+
}
47+
})
48+
})?;
49+
50+
Ok(Some(IsSorted::make_partial(batch, result, options.strict)?))
2751
}
2852
}
29-
30-
register_kernel!(IsSortedKernelAdapter(Sequence).lift());

0 commit comments

Comments
 (0)