Skip to content

Commit a1039fe

Browse files
committed
is-constant
Signed-off-by: Nicholas Gates <nick@nickgates.com>
1 parent 852ac32 commit a1039fe

7 files changed

Lines changed: 50 additions & 152 deletions

File tree

encodings/datetime-parts/src/compute/is_constant.rs

Lines changed: 1 addition & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,11 @@
22
// SPDX-FileCopyrightText: Copyright the Vortex contributors
33

44
use vortex_array::ArrayRef;
5-
use vortex_array::DynArray;
65
use vortex_array::ExecutionCtx;
76
use vortex_array::aggregate_fn::AggregateFnRef;
87
use vortex_array::aggregate_fn::fns::is_constant::IsConstant;
98
use vortex_array::aggregate_fn::fns::is_constant::is_constant;
10-
use vortex_array::aggregate_fn::fns::is_constant::make_is_constant_partial_dtype;
119
use vortex_array::aggregate_fn::kernels::DynAggregateKernel;
12-
use vortex_array::dtype::Nullability;
1310
use vortex_array::scalar::Scalar;
1411
use vortex_error::VortexResult;
1512

@@ -39,27 +36,6 @@ impl DynAggregateKernel for DateTimePartsIsConstantKernel {
3936
let result = is_constant(array.days(), ctx)?
4037
&& is_constant(array.seconds(), ctx)?
4138
&& is_constant(array.subseconds(), ctx)?;
42-
43-
let partial_dtype = make_is_constant_partial_dtype(batch.dtype());
44-
45-
if result {
46-
let first_value = if batch.is_empty() {
47-
return Ok(Some(Scalar::null(partial_dtype)));
48-
} else {
49-
batch.scalar_at(0)?.into_nullable()
50-
};
51-
Ok(Some(Scalar::struct_(
52-
partial_dtype,
53-
vec![Scalar::bool(true, Nullability::NonNullable), first_value],
54-
)))
55-
} else {
56-
Ok(Some(Scalar::struct_(
57-
partial_dtype,
58-
vec![
59-
Scalar::bool(false, Nullability::NonNullable),
60-
Scalar::null(batch.dtype().as_nullable()),
61-
],
62-
)))
63-
}
39+
Ok(Some(IsConstant::make_partial(batch, result)?))
6440
}
6541
}

encodings/decimal-byte-parts/src/decimal_byte_parts/compute/is_constant.rs

Lines changed: 1 addition & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,11 @@
22
// SPDX-FileCopyrightText: Copyright the Vortex contributors
33

44
use vortex_array::ArrayRef;
5-
use vortex_array::DynArray;
65
use vortex_array::ExecutionCtx;
76
use vortex_array::aggregate_fn::AggregateFnRef;
87
use vortex_array::aggregate_fn::fns::is_constant::IsConstant;
98
use vortex_array::aggregate_fn::fns::is_constant::is_constant;
10-
use vortex_array::aggregate_fn::fns::is_constant::make_is_constant_partial_dtype;
119
use vortex_array::aggregate_fn::kernels::DynAggregateKernel;
12-
use vortex_array::dtype::Nullability;
1310
use vortex_array::scalar::Scalar;
1411
use vortex_error::VortexResult;
1512

@@ -37,26 +34,6 @@ impl DynAggregateKernel for DecimalBytePartsIsConstantKernel {
3734
};
3835

3936
let result = is_constant(array.msp(), ctx)?;
40-
let partial_dtype = make_is_constant_partial_dtype(batch.dtype());
41-
42-
if result {
43-
let first_value = if batch.is_empty() {
44-
return Ok(Some(Scalar::null(partial_dtype)));
45-
} else {
46-
batch.scalar_at(0)?.into_nullable()
47-
};
48-
Ok(Some(Scalar::struct_(
49-
partial_dtype,
50-
vec![Scalar::bool(true, Nullability::NonNullable), first_value],
51-
)))
52-
} else {
53-
Ok(Some(Scalar::struct_(
54-
partial_dtype,
55-
vec![
56-
Scalar::bool(false, Nullability::NonNullable),
57-
Scalar::null(batch.dtype().as_nullable()),
58-
],
59-
)))
60-
}
37+
Ok(Some(IsConstant::make_partial(batch, result)?))
6138
}
6239
}

encodings/fastlanes/src/bitpacking/compute/is_constant.rs

Lines changed: 1 addition & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -6,18 +6,15 @@ use std::ops::Range;
66
use itertools::Itertools;
77
use lending_iterator::LendingIterator;
88
use vortex_array::ArrayRef;
9-
use vortex_array::DynArray;
109
use vortex_array::ExecutionCtx;
1110
use vortex_array::ToCanonical;
1211
use vortex_array::aggregate_fn::AggregateFnRef;
1312
use vortex_array::aggregate_fn::fns::is_constant::IsConstant;
14-
use vortex_array::aggregate_fn::fns::is_constant::make_is_constant_partial_dtype;
1513
use vortex_array::aggregate_fn::fns::is_constant::primitive::IS_CONST_LANE_WIDTH;
1614
use vortex_array::aggregate_fn::fns::is_constant::primitive::compute_is_constant;
1715
use vortex_array::aggregate_fn::kernels::DynAggregateKernel;
1816
use vortex_array::arrays::PrimitiveArray;
1917
use vortex_array::dtype::IntegerPType;
20-
use vortex_array::dtype::Nullability;
2118
use vortex_array::match_each_integer_ptype;
2219
use vortex_array::match_each_unsigned_integer_ptype;
2320
use vortex_array::scalar::Scalar;
@@ -50,27 +47,7 @@ impl DynAggregateKernel for BitPackedIsConstantKernel {
5047
bitpacked_is_constant::<P, { IS_CONST_LANE_WIDTH / size_of::<P>() }>(array)?
5148
});
5249

53-
let partial_dtype = make_is_constant_partial_dtype(batch.dtype());
54-
55-
if result {
56-
let first_value = if batch.is_empty() {
57-
return Ok(Some(Scalar::null(partial_dtype)));
58-
} else {
59-
batch.scalar_at(0)?.into_nullable()
60-
};
61-
Ok(Some(Scalar::struct_(
62-
partial_dtype,
63-
vec![Scalar::bool(true, Nullability::NonNullable), first_value],
64-
)))
65-
} else {
66-
Ok(Some(Scalar::struct_(
67-
partial_dtype,
68-
vec![
69-
Scalar::bool(false, Nullability::NonNullable),
70-
Scalar::null(batch.dtype().as_nullable()),
71-
],
72-
)))
73-
}
50+
Ok(Some(IsConstant::make_partial(batch, result)?))
7451
}
7552
}
7653

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

Lines changed: 1 addition & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,11 @@
22
// SPDX-FileCopyrightText: Copyright the Vortex contributors
33

44
use vortex_array::ArrayRef;
5-
use vortex_array::DynArray;
65
use vortex_array::ExecutionCtx;
76
use vortex_array::aggregate_fn::AggregateFnRef;
87
use vortex_array::aggregate_fn::fns::is_constant::IsConstant;
98
use vortex_array::aggregate_fn::fns::is_constant::is_constant;
10-
use vortex_array::aggregate_fn::fns::is_constant::make_is_constant_partial_dtype;
119
use vortex_array::aggregate_fn::kernels::DynAggregateKernel;
12-
use vortex_array::dtype::Nullability;
1310
use vortex_array::scalar::Scalar;
1411
use vortex_error::VortexResult;
1512

@@ -37,26 +34,6 @@ impl DynAggregateKernel for FoRIsConstantKernel {
3734
};
3835

3936
let result = is_constant(array.encoded(), ctx)?;
40-
let partial_dtype = make_is_constant_partial_dtype(batch.dtype());
41-
42-
if result {
43-
let first_value = if batch.is_empty() {
44-
return Ok(Some(Scalar::null(partial_dtype)));
45-
} else {
46-
batch.scalar_at(0)?.into_nullable()
47-
};
48-
Ok(Some(Scalar::struct_(
49-
partial_dtype,
50-
vec![Scalar::bool(true, Nullability::NonNullable), first_value],
51-
)))
52-
} else {
53-
Ok(Some(Scalar::struct_(
54-
partial_dtype,
55-
vec![
56-
Scalar::bool(false, Nullability::NonNullable),
57-
Scalar::null(batch.dtype().as_nullable()),
58-
],
59-
)))
60-
}
37+
Ok(Some(IsConstant::make_partial(batch, result)?))
6138
}
6239
}

encodings/runend/src/compute/is_constant.rs

Lines changed: 1 addition & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,11 @@
22
// SPDX-FileCopyrightText: Copyright the Vortex contributors
33

44
use vortex_array::ArrayRef;
5-
use vortex_array::DynArray;
65
use vortex_array::ExecutionCtx;
76
use vortex_array::aggregate_fn::AggregateFnRef;
87
use vortex_array::aggregate_fn::fns::is_constant::IsConstant;
98
use vortex_array::aggregate_fn::fns::is_constant::is_constant;
10-
use vortex_array::aggregate_fn::fns::is_constant::make_is_constant_partial_dtype;
119
use vortex_array::aggregate_fn::kernels::DynAggregateKernel;
12-
use vortex_array::dtype::Nullability;
1310
use vortex_array::scalar::Scalar;
1411
use vortex_error::VortexResult;
1512

@@ -37,26 +34,6 @@ impl DynAggregateKernel for RunEndIsConstantKernel {
3734
};
3835

3936
let result = is_constant(array.values(), ctx)?;
40-
let partial_dtype = make_is_constant_partial_dtype(batch.dtype());
41-
42-
if result {
43-
let first_value = if batch.is_empty() {
44-
return Ok(Some(Scalar::null(partial_dtype)));
45-
} else {
46-
batch.scalar_at(0)?.into_nullable()
47-
};
48-
Ok(Some(Scalar::struct_(
49-
partial_dtype,
50-
vec![Scalar::bool(true, Nullability::NonNullable), first_value],
51-
)))
52-
} else {
53-
Ok(Some(Scalar::struct_(
54-
partial_dtype,
55-
vec![
56-
Scalar::bool(false, Nullability::NonNullable),
57-
Scalar::null(batch.dtype().as_nullable()),
58-
],
59-
)))
60-
}
37+
Ok(Some(IsConstant::make_partial(batch, result)?))
6138
}
6239
}

vortex-array/src/aggregate_fn/fns/is_constant/mod.rs

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,35 @@ pub fn is_constant(array: &ArrayRef, ctx: &mut ExecutionCtx) -> VortexResult<boo
180180
#[derive(Clone, Debug)]
181181
pub struct IsConstant;
182182

183+
impl IsConstant {
184+
/// Build a partial scalar from a kernel's `is_constant` result.
185+
///
186+
/// Kernels that compute `is_constant` by delegating to child arrays can call this
187+
/// to package the boolean result into the partial struct format expected by the
188+
/// accumulator, avoiding duplicated boilerplate.
189+
pub fn make_partial(batch: &ArrayRef, is_constant: bool) -> VortexResult<Scalar> {
190+
let partial_dtype = make_is_constant_partial_dtype(batch.dtype());
191+
if is_constant {
192+
if batch.is_empty() {
193+
return Ok(Scalar::null(partial_dtype));
194+
}
195+
let first_value = batch.scalar_at(0)?.into_nullable();
196+
Ok(Scalar::struct_(
197+
partial_dtype,
198+
vec![Scalar::bool(true, Nullability::NonNullable), first_value],
199+
))
200+
} else {
201+
Ok(Scalar::struct_(
202+
partial_dtype,
203+
vec![
204+
Scalar::bool(false, Nullability::NonNullable),
205+
Scalar::null(batch.dtype().as_nullable()),
206+
],
207+
))
208+
}
209+
}
210+
}
211+
183212
/// Partial accumulator state for is_constant.
184213
pub struct IsConstantPartial {
185214
is_constant: bool,

vortex-array/src/arrays/dict/compute/is_constant.rs

Lines changed: 16 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@
22
// SPDX-FileCopyrightText: Copyright the Vortex contributors
33

44
use vortex_error::VortexResult;
5+
use vortex_mask::Mask;
56

67
use crate::ArrayRef;
7-
use crate::DynArray;
88
use crate::ExecutionCtx;
99
use crate::aggregate_fn::AggregateFnRef;
1010
use crate::aggregate_fn::fns::is_constant::IsConstant;
@@ -16,7 +16,8 @@ use crate::scalar::Scalar;
1616
/// Dict-specific is_constant kernel.
1717
///
1818
/// If codes are constant, the whole array is constant.
19-
/// Otherwise, check the values array.
19+
/// When all dictionary values are referenced, is_constant can be computed directly on the values
20+
/// array. Otherwise, unreferenced values are filtered out first.
2021
#[derive(Debug)]
2122
pub(crate) struct DictIsConstantKernel;
2223

@@ -35,37 +36,21 @@ impl DynAggregateKernel for DictIsConstantKernel {
3536
return Ok(None);
3637
};
3738

38-
let result = if is_constant(dict.codes(), ctx)? {
39-
true
40-
} else {
39+
// If codes are constant, only one dictionary value is referenced → constant.
40+
if is_constant(dict.codes(), ctx)? {
41+
return Ok(Some(IsConstant::make_partial(batch, true)?));
42+
}
43+
44+
// Otherwise, check the values array. Filter to only referenced values if needed.
45+
let result = if dict.has_all_values_referenced() {
4146
is_constant(dict.values(), ctx)?
47+
} else {
48+
let referenced_mask = dict.compute_referenced_values_mask(true)?;
49+
let mask = Mask::from(referenced_mask);
50+
let filtered_values = dict.values().filter(mask)?;
51+
is_constant(&filtered_values, ctx)?
4252
};
4353

44-
// Return in the partial dtype format: struct {is_constant, value}
45-
// We use the first scalar as the representative value.
46-
let partial_dtype =
47-
crate::aggregate_fn::fns::is_constant::make_is_constant_partial_dtype(batch.dtype());
48-
if result {
49-
let first_value = if batch.is_empty() {
50-
return Ok(Some(Scalar::null(partial_dtype)));
51-
} else {
52-
batch.scalar_at(0)?.into_nullable()
53-
};
54-
Ok(Some(Scalar::struct_(
55-
partial_dtype,
56-
vec![
57-
Scalar::bool(true, crate::dtype::Nullability::NonNullable),
58-
first_value,
59-
],
60-
)))
61-
} else {
62-
Ok(Some(Scalar::struct_(
63-
partial_dtype,
64-
vec![
65-
Scalar::bool(false, crate::dtype::Nullability::NonNullable),
66-
Scalar::null(batch.dtype().as_nullable()),
67-
],
68-
)))
69-
}
54+
Ok(Some(IsConstant::make_partial(batch, result)?))
7055
}
7156
}

0 commit comments

Comments
 (0)