Skip to content

Commit 5d10e73

Browse files
authored
Optional fallback in new is_constant compute function (#2485)
1 parent 9c0681c commit 5d10e73

File tree

12 files changed

+54
-61
lines changed

12 files changed

+54
-61
lines changed

encodings/alp/src/alp/compute/mod.rs

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use std::fmt::Debug;
55
use vortex_array::arrays::ConstantArray;
66
use vortex_array::compute::{
77
between, filter, scalar_at, slice, take, BetweenFn, BetweenOptions, CompareFn, FilterFn,
8-
IsConstantFn, ScalarAtFn, SliceFn, StrictComparison, TakeFn,
8+
ScalarAtFn, SliceFn, StrictComparison, TakeFn,
99
};
1010
use vortex_array::variants::PrimitiveArrayTrait;
1111
use vortex_array::vtable::ComputeVTable;
@@ -30,10 +30,6 @@ impl ComputeVTable for ALPEncoding {
3030
Some(self)
3131
}
3232

33-
fn is_constant_fn(&self) -> Option<&dyn IsConstantFn<&dyn Array>> {
34-
Some(self)
35-
}
36-
3733
fn scalar_at_fn(&self) -> Option<&dyn ScalarAtFn<&dyn Array>> {
3834
Some(self)
3935
}
@@ -121,12 +117,6 @@ impl FilterFn<&ALPArray> for ALPEncoding {
121117
}
122118
}
123119

124-
impl IsConstantFn<&ALPArray> for ALPEncoding {
125-
fn is_constant(&self, _array: &ALPArray) -> VortexResult<Option<bool>> {
126-
Ok(None)
127-
}
128-
}
129-
130120
impl BetweenFn<&ALPArray> for ALPEncoding {
131121
fn between(
132122
&self,

encodings/alp/src/alp_rd/compute/is_constant.rs

Lines changed: 0 additions & 10 deletions
This file was deleted.

encodings/alp/src/alp_rd/compute/mod.rs

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,16 @@
1-
use vortex_array::compute::{FilterFn, IsConstantFn, MaskFn, ScalarAtFn, SliceFn, TakeFn};
1+
use vortex_array::compute::{FilterFn, MaskFn, ScalarAtFn, SliceFn, TakeFn};
22
use vortex_array::vtable::ComputeVTable;
33
use vortex_array::Array;
44

55
use crate::ALPRDEncoding;
66

77
mod filter;
8-
mod is_constant;
98
mod mask;
109
mod scalar_at;
1110
mod slice;
1211
mod take;
1312

1413
impl ComputeVTable for ALPRDEncoding {
15-
fn is_constant_fn(&self) -> Option<&dyn IsConstantFn<&dyn Array>> {
16-
Some(self)
17-
}
18-
1914
fn filter_fn(&self) -> Option<&dyn FilterFn<&dyn Array>> {
2015
Some(self)
2116
}

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

Lines changed: 0 additions & 10 deletions
This file was deleted.

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

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
use vortex_array::compute::{
2-
between, BetweenFn, BetweenOptions, FilterFn, IsConstantFn, ScalarAtFn, SearchSortedFn,
3-
SliceFn, TakeFn,
2+
between, BetweenFn, BetweenOptions, FilterFn, ScalarAtFn, SearchSortedFn, SliceFn, TakeFn,
43
};
54
use vortex_array::vtable::ComputeVTable;
65
use vortex_array::{Array, ArrayRef, IntoArray};
@@ -9,7 +8,6 @@ use vortex_error::VortexResult;
98
use crate::{BitPackedArray, BitPackedEncoding};
109

1110
mod filter;
12-
mod is_constant;
1311
mod scalar_at;
1412
mod search_sorted;
1513
mod slice;
@@ -20,10 +18,6 @@ impl ComputeVTable for BitPackedEncoding {
2018
Some(self)
2119
}
2220

23-
fn is_constant_fn(&self) -> Option<&dyn IsConstantFn<&dyn Array>> {
24-
Some(self)
25-
}
26-
2721
fn scalar_at_fn(&self) -> Option<&dyn ScalarAtFn<&dyn Array>> {
2822
Some(self)
2923
}

vortex-array/src/array/statistics.rs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use std::sync::RwLock;
33
use vortex_error::{VortexExpect, VortexResult};
44
use vortex_scalar::{Scalar, ScalarValue};
55

6-
use crate::compute::{is_constant, min_max, scalar_at, sum, MinMaxResult};
6+
use crate::compute::{is_constant_opts, min_max, scalar_at, sum, IsConstantOpts, MinMaxResult};
77
use crate::stats::{Precision, Stat, Statistics, StatsSet};
88
use crate::{Array, ArrayImpl};
99

@@ -86,7 +86,15 @@ impl<A: Array + ArrayImpl> Statistics for A {
8686
if self.is_empty() {
8787
None
8888
} else {
89-
Some(is_constant(self)?.into())
89+
Some(
90+
is_constant_opts(
91+
self,
92+
&IsConstantOpts {
93+
fallback_to_canonicalize: true,
94+
},
95+
)?
96+
.into(),
97+
)
9098
}
9199
}
92100
_ => {

vortex-array/src/arrays/list/compute/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ impl MinMaxFn<&ListArray> for ListEncoding {
8484

8585
impl IsConstantFn<&ListArray> for ListEncoding {
8686
fn is_constant(&self, _array: &ListArray) -> VortexResult<Option<bool>> {
87+
// TODO(adam): Do we want to fallback to arrow here?
8788
Ok(None)
8889
}
8990
}

vortex-array/src/compute/boolean.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ use vortex_dtype::DType;
77
use vortex_error::{vortex_bail, VortexExpect, VortexResult};
88

99
use crate::arrow::{FromArrowArray, IntoArrowArray};
10+
use crate::compute::is_constant;
1011
use crate::encoding::Encoding;
1112
use crate::{Array, ArrayRef};
1213

@@ -85,13 +86,15 @@ pub fn binary_boolean(
8586
vortex_bail!("Boolean operations are only supported on boolean arrays")
8687
}
8788

89+
let rhs_is_constant = is_constant(rhs)?;
90+
8891
// If LHS is constant, then we make sure it's on the RHS.
89-
if lhs.is_constant() && !rhs.is_constant() {
92+
if is_constant(lhs)? && !rhs_is_constant {
9093
return binary_boolean(rhs, lhs, op);
9194
}
9295

9396
// If the RHS is constant and the LHS is Arrow, we can't do any better than arrow_compare.
94-
if lhs.is_arrow() && (rhs.is_arrow() || rhs.is_constant()) {
97+
if lhs.is_arrow() && (rhs.is_arrow() || rhs_is_constant) {
9598
return arrow_boolean(lhs.to_array(), rhs.to_array(), op);
9699
}
97100

vortex-array/src/compute/compare.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ use vortex_dtype::{DType, NativePType, Nullability};
77
use vortex_error::{vortex_bail, VortexExpect, VortexResult};
88
use vortex_scalar::Scalar;
99

10+
use super::is_constant;
1011
use crate::arrays::ConstantArray;
1112
use crate::arrow::{from_arrow_array_with_len, Datum};
1213
use crate::encoding::Encoding;
@@ -124,8 +125,11 @@ pub fn compare(left: &dyn Array, right: &dyn Array, operator: Operator) -> Vorte
124125
return Ok(ConstantArray::new(Scalar::null(result_dtype), left.len()).into_array());
125126
}
126127

128+
let left_is_constant = is_constant(left)?;
129+
let right_is_constant = is_constant(right)?;
130+
127131
// Always try to put constants on the right-hand side so encodings can optimise themselves.
128-
if left.is_constant() && !right.is_constant() {
132+
if left_is_constant && !right_is_constant {
129133
return compare(right, left, operator.swap());
130134
}
131135

@@ -151,7 +155,7 @@ pub fn compare(left: &dyn Array, right: &dyn Array, operator: Operator) -> Vorte
151155

152156
// Only log missing compare implementation if there's possibly better one than arrow,
153157
// i.e. lhs isn't arrow or rhs isn't arrow or constant
154-
if !(left.is_arrow() && (right.is_arrow() || right.is_constant())) {
158+
if !(left.is_arrow() && (right.is_arrow() || right_is_constant)) {
155159
log::debug!(
156160
"No compare implementation found for LHS {}, RHS {}, and operator {} (or inverse)",
157161
right.encoding(),

vortex-array/src/compute/is_constant.rs

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,16 @@ where
2727
}
2828
}
2929

30+
#[derive(Default, Clone)]
31+
pub struct IsConstantOpts {
32+
pub fallback_to_canonicalize: bool,
33+
}
34+
35+
pub fn is_constant(array: &dyn Array) -> VortexResult<bool> {
36+
let opts = IsConstantOpts::default();
37+
is_constant_opts(array, &opts)
38+
}
39+
3040
/// Computes whether an array has constant values.
3141
/// An array is constant IFF at least one of the following conditions apply:
3242
/// 1. It has one elements.
@@ -37,7 +47,7 @@ where
3747
///
3848
/// If the array has some null values but is not all null, it'll never be constant.
3949
/// **Please note:** Might return false negatives if a specific encoding couldn't make a determination.
40-
pub fn is_constant(array: &dyn Array) -> VortexResult<bool> {
50+
pub fn is_constant_opts(array: &dyn Array, opts: &IsConstantOpts) -> VortexResult<bool> {
4151
match array.len() {
4252
// Our current semantics are that we can always get a value out of a constant array. We might want to change that in the future.
4353
0 => return Ok(false),
@@ -96,15 +106,19 @@ pub fn is_constant(array: &dyn Array) -> VortexResult<bool> {
96106
array.encoding()
97107
);
98108

99-
let array = array.to_canonical()?;
100-
101-
if let Some(is_constant_fn) = array.as_ref().vtable().is_constant_fn() {
102-
is_constant_fn.is_constant(array.as_ref())?
109+
if opts.fallback_to_canonicalize {
110+
let array = array.to_canonical()?;
111+
112+
if let Some(is_constant_fn) = array.as_ref().vtable().is_constant_fn() {
113+
is_constant_fn.is_constant(array.as_ref())?
114+
} else {
115+
vortex_bail!(
116+
"No is_constant function for canonical array: {}",
117+
array.as_ref().encoding(),
118+
)
119+
}
103120
} else {
104-
vortex_bail!(
105-
"No is_constant function for canonical array: {}",
106-
array.as_ref().encoding(),
107-
)
121+
None
108122
}
109123
};
110124

0 commit comments

Comments
 (0)