Skip to content

Commit 65fb0bf

Browse files
committed
Merge remote-tracking branch 'origin/develop' into ji/remove-param-names-public-lock
Signed-off-by: Joe Isaacs <joe.isaacs@live.co.uk> # Conflicts: # encodings/fsst/public-api.lock # encodings/runend/public-api.lock # vortex-array/public-api.lock # vortex-tensor/public-api.lock
2 parents b5a043c + 128ce5f commit 65fb0bf

93 files changed

Lines changed: 9895 additions & 5908 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.

AGENTS.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,11 +64,14 @@ Examples:
6464
cargo nextest run -p vortex-array
6565
make -C docs doctest
6666
uv run --all-packages pytest vortex-python/test
67+
cargo test --doc
6768
```
6869

6970
Run docs doctests from the docs directory with `make -C docs doctest` so the correct Sphinx
7071
Makefile target is used.
7172

73+
If you touch documentation run doc tests via `cargo test --doc`.
74+
7275
## Linting, Formatting, and Generated Files
7376

7477
Run verification that matches the files changed. Do not run expensive Rust checks for changes that

encodings/alp/src/alp/compute/cast.rs

Lines changed: 23 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ use vortex_array::ArrayView;
66
use vortex_array::IntoArray;
77
use vortex_array::builtins::ArrayBuiltins;
88
use vortex_array::dtype::DType;
9-
use vortex_array::patches::Patches;
109
use vortex_array::scalar_fn::fns::cast::CastReduce;
1110
use vortex_error::VortexResult;
1211

@@ -17,41 +16,29 @@ use crate::alp::ALP;
1716
impl CastReduce for ALP {
1817
fn cast(array: ArrayView<'_, Self>, dtype: &DType) -> VortexResult<Option<ArrayRef>> {
1918
// Check if this is just a nullability change
20-
if array.dtype().eq_ignore_nullability(dtype) {
21-
// For nullability-only changes, we can avoid decoding
22-
// Cast the encoded array (integers) to handle nullability
23-
let new_encoded = array.encoded().cast(
24-
array
25-
.encoded()
26-
.dtype()
27-
.with_nullability(dtype.nullability()),
28-
)?;
29-
30-
let new_patches = array
31-
.patches()
32-
.map(|p| {
33-
if p.values().dtype() == dtype {
34-
Ok(p)
35-
} else {
36-
Patches::new(
37-
p.array_len(),
38-
p.offset(),
39-
p.indices().clone(),
40-
p.values().cast(dtype.clone())?,
41-
p.chunk_offsets().clone(),
42-
)
43-
}
44-
})
45-
.transpose()?;
46-
47-
// SAFETY: casting nullability doesn't alter the invariants
48-
unsafe {
49-
Ok(Some(
50-
ALP::new_unchecked(new_encoded, array.exponents(), new_patches).into_array(),
51-
))
52-
}
53-
} else {
54-
Ok(None)
19+
if !array.dtype().eq_ignore_nullability(dtype) {
20+
return Ok(None);
21+
}
22+
23+
// For nullability-only changes, we can avoid decoding
24+
// Cast the encoded array (integers) to handle nullability
25+
let new_encoded = array.encoded().cast(
26+
array
27+
.encoded()
28+
.dtype()
29+
.with_nullability(dtype.nullability()),
30+
)?;
31+
32+
let new_patches = array
33+
.patches()
34+
.map(|p| p.map_values(|v| v.cast(dtype.clone())))
35+
.transpose()?;
36+
37+
// SAFETY: casting nullability doesn't alter the invariants
38+
unsafe {
39+
Ok(Some(
40+
ALP::new_unchecked(new_encoded, array.exponents(), new_patches).into_array(),
41+
))
5542
}
5643
}
5744
}

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

Lines changed: 29 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,6 @@
44
use vortex_array::ArrayRef;
55
use vortex_array::ArrayView;
66
use vortex_array::IntoArray;
7-
use vortex_array::LEGACY_SESSION;
8-
use vortex_array::VortexSessionExecute;
97
use vortex_array::builtins::ArrayBuiltins;
108
use vortex_array::dtype::DType;
119
use vortex_array::scalar_fn::fns::cast::CastReduce;
@@ -16,38 +14,35 @@ use crate::alp_rd::ALPRD;
1614

1715
impl CastReduce for ALPRD {
1816
fn cast(array: ArrayView<'_, Self>, dtype: &DType) -> VortexResult<Option<ArrayRef>> {
19-
// ALPRDArray stores floating-point values, so only cast between float types
20-
// or if just changing nullability
21-
2217
// Check if this is just a nullability change
23-
if array.dtype().eq_ignore_nullability(dtype) {
24-
// For nullability-only changes, we need to cast the left_parts array
25-
// since it carries the validity information
26-
let new_left_parts = array.left_parts().cast(
27-
array
28-
.left_parts()
29-
.dtype()
30-
.with_nullability(dtype.nullability()),
31-
)?;
18+
if !array.dtype().eq_ignore_nullability(dtype) {
19+
return Ok(None);
20+
}
21+
22+
// For nullability-only changes, we need to cast the left_parts array
23+
// since it carries the validity information
24+
let new_left_parts = array.left_parts().cast(
25+
array
26+
.left_parts()
27+
.dtype()
28+
.with_nullability(dtype.nullability()),
29+
)?;
3230

33-
// NOTE: `CastReduce::cast` has a fixed trait signature without `ExecutionCtx`, so we
34-
// construct a legacy ctx locally at this trait boundary.
35-
return Ok(Some(
36-
ALPRD::try_new(
31+
// NOTE: `CastReduce::cast` has a fixed trait signature without `ExecutionCtx`, so we
32+
// construct a legacy ctx locally at this trait boundary.
33+
Ok(Some(
34+
unsafe {
35+
ALPRD::new_unchecked(
3736
dtype.clone(),
3837
new_left_parts,
3938
array.left_parts_dictionary().clone(),
4039
array.right_parts().clone(),
4140
array.right_bit_width(),
4241
array.left_parts_patches(),
43-
&mut LEGACY_SESSION.create_execution_ctx(),
44-
)?
45-
.into_array(),
46-
));
47-
}
48-
49-
// For other casts (e.g., f32 to f64), decode to canonical and let PrimitiveArray handle it
50-
Ok(None)
42+
)
43+
}
44+
.into_array(),
45+
))
5146
}
5247
}
5348

@@ -99,12 +94,17 @@ mod tests {
9994
let encoder = RDEncoder::new(&values);
10095
let alprd = encoder.encode(arr.as_view(), &mut ctx);
10196

102-
// Cast to NonNullable should fail since we have nulls
97+
// Cast to NonNullable should fail since we have nulls. The failure surfaces during
98+
// execution since the reduce path defers when the validity stat is not cached.
10399
let result = alprd
104100
.clone()
105101
.into_array()
106-
.cast(DType::Primitive(PType::F64, Nullability::NonNullable));
107-
assert!(result.is_err());
102+
.cast(DType::Primitive(PType::F64, Nullability::NonNullable))
103+
.and_then(|a| {
104+
a.execute::<PrimitiveArray>(&mut ctx)
105+
.map(|p| p.into_array())
106+
});
107+
assert!(result.is_err(), "Expected error, got: {result:?}");
108108

109109
// Cast to same type with Nullable should succeed
110110
let casted = alprd

encodings/bytebool/public-api.lock

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,10 @@ impl vortex_array::arrays::slice::SliceReduce for vortex_bytebool::ByteBool
6464

6565
pub fn vortex_bytebool::ByteBool::slice(vortex_array::array::view::ArrayView<'_, Self>, core::ops::range::Range<usize>) -> vortex_error::VortexResult<core::option::Option<vortex_array::array::erased::ArrayRef>>
6666

67+
impl vortex_array::scalar_fn::fns::cast::kernel::CastKernel for vortex_bytebool::ByteBool
68+
69+
pub fn vortex_bytebool::ByteBool::cast(array: vortex_array::array::view::ArrayView<'_, Self>, dtype: &vortex_array::dtype::DType, ctx: &mut vortex_array::executor::ExecutionCtx) -> vortex_error::VortexResult<core::option::Option<vortex_array::array::erased::ArrayRef>>
70+
6771
impl vortex_array::scalar_fn::fns::cast::kernel::CastReduce for vortex_bytebool::ByteBool
6872

6973
pub fn vortex_bytebool::ByteBool::cast(vortex_array::array::view::ArrayView<'_, Self>, &vortex_array::dtype::DType) -> vortex_error::VortexResult<core::option::Option<vortex_array::array::erased::ArrayRef>>

encodings/bytebool/src/compute.rs

Lines changed: 34 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ use vortex_array::arrays::dict::TakeExecute;
1111
use vortex_array::buffer::BufferHandle;
1212
use vortex_array::dtype::DType;
1313
use vortex_array::match_each_integer_ptype;
14+
use vortex_array::scalar_fn::fns::cast::CastKernel;
1415
use vortex_array::scalar_fn::fns::cast::CastReduce;
1516
use vortex_array::scalar_fn::fns::mask::MaskReduce;
1617
use vortex_array::validity::Validity;
@@ -24,20 +25,43 @@ impl CastReduce for ByteBool {
2425
// ByteBool is essentially a bool array stored as bytes
2526
// The main difference from BoolArray is the storage format
2627
// For casting, we can decode to canonical (BoolArray) and let it handle the cast
27-
2828
// If just changing nullability, we can optimize
29-
if array.dtype().eq_ignore_nullability(dtype) {
30-
let new_validity = array
31-
.validity()?
32-
.cast_nullability(dtype.nullability(), array.len())?;
29+
if !dtype.is_boolean() {
30+
return Ok(None);
31+
}
32+
33+
let Some(new_validity) = array
34+
.validity()?
35+
.trivial_cast_nullability(dtype.nullability(), array.len())?
36+
else {
37+
return Ok(None);
38+
};
39+
40+
Ok(Some(
41+
ByteBool::new(array.buffer().clone(), new_validity).into_array(),
42+
))
43+
}
44+
}
3345

34-
return Ok(Some(
35-
ByteBool::new(array.buffer().clone(), new_validity).into_array(),
36-
));
46+
impl CastKernel for ByteBool {
47+
fn cast(
48+
array: ArrayView<'_, Self>,
49+
dtype: &DType,
50+
ctx: &mut ExecutionCtx,
51+
) -> VortexResult<Option<ArrayRef>> {
52+
// Only handle nullability changes here; non-bool targets fall through to canonicalization.
53+
if !dtype.is_boolean() {
54+
return Ok(None);
3755
}
3856

39-
// For other casts, decode to canonical and let BoolArray handle it
40-
Ok(None)
57+
let new_validity =
58+
array
59+
.validity()?
60+
.cast_nullability(dtype.nullability(), array.len(), ctx)?;
61+
62+
Ok(Some(
63+
ByteBool::new(array.buffer().clone(), new_validity).into_array(),
64+
))
4165
}
4266
}
4367

encodings/bytebool/src/kernel.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,11 @@
33

44
use vortex_array::arrays::dict::TakeExecuteAdaptor;
55
use vortex_array::kernel::ParentKernelSet;
6+
use vortex_array::scalar_fn::fns::cast::CastExecuteAdaptor;
67

78
use crate::ByteBool;
89

9-
pub(crate) const PARENT_KERNELS: ParentKernelSet<ByteBool> =
10-
ParentKernelSet::new(&[ParentKernelSet::lift(&TakeExecuteAdaptor(ByteBool))]);
10+
pub(crate) const PARENT_KERNELS: ParentKernelSet<ByteBool> = ParentKernelSet::new(&[
11+
ParentKernelSet::lift(&CastExecuteAdaptor(ByteBool)),
12+
ParentKernelSet::lift(&TakeExecuteAdaptor(ByteBool)),
13+
]);

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

Lines changed: 12 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -7,39 +7,31 @@ use vortex_array::IntoArray;
77
use vortex_array::builtins::ArrayBuiltins;
88
use vortex_array::dtype::DType;
99
use vortex_array::scalar_fn::fns::cast::CastReduce;
10-
use vortex_error::VortexExpect;
1110
use vortex_error::VortexResult;
1211

1312
use crate::DecimalByteParts;
1413
use crate::decimal_byte_parts::DecimalBytePartsArrayExt;
14+
1515
impl CastReduce for DecimalByteParts {
1616
fn cast(array: ArrayView<'_, Self>, dtype: &DType) -> VortexResult<Option<ArrayRef>> {
17+
// Check if this is just a nullability change
18+
if !dtype.eq_ignore_nullability(array.dtype()) {
19+
return Ok(None);
20+
}
1721
// DecimalBytePartsArray can only have Decimal dtype, so we only handle decimal-to-decimal casts
1822
let DType::Decimal(target_decimal, target_nullability) = dtype else {
1923
// Cannot cast decimal to non-decimal types - delegate to canonical form
2024
return Ok(None);
2125
};
2226

23-
// Check if this is just a nullability change
24-
if array
25-
.dtype()
26-
.as_decimal_opt()
27-
.vortex_expect("must be a decimal dtype")
28-
== target_decimal
29-
&& array.dtype().nullability() != *target_nullability
30-
{
31-
// Cast the msp array to handle nullability change
32-
let new_msp = array
33-
.msp()
34-
.cast(array.msp().dtype().with_nullability(*target_nullability))?;
35-
36-
return Ok(Some(
37-
DecimalByteParts::try_new(new_msp, *target_decimal)?.into_array(),
38-
));
39-
}
27+
// Cast the msp array to handle nullability change
28+
let new_msp = array
29+
.msp()
30+
.cast(array.msp().dtype().with_nullability(*target_nullability))?;
4031

41-
// For precision/scale changes, decode to canonical and let DecimalArray handle it
42-
Ok(None)
32+
Ok(Some(
33+
DecimalByteParts::try_new(new_msp, *target_decimal)?.into_array(),
34+
))
4335
}
4436
}
4537

encodings/fastlanes/public-api.lock

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,10 @@ impl vortex_array::arrays::slice::SliceReduce for vortex_fastlanes::BitPacked
186186

187187
pub fn vortex_fastlanes::BitPacked::slice(vortex_array::array::view::ArrayView<'_, Self>, core::ops::range::Range<usize>) -> vortex_error::VortexResult<core::option::Option<vortex_array::array::erased::ArrayRef>>
188188

189+
impl vortex_array::scalar_fn::fns::cast::kernel::CastKernel for vortex_fastlanes::BitPacked
190+
191+
pub fn vortex_fastlanes::BitPacked::cast(array: vortex_array::array::view::ArrayView<'_, Self>, dtype: &vortex_array::dtype::DType, ctx: &mut vortex_array::executor::ExecutionCtx) -> vortex_error::VortexResult<core::option::Option<vortex_array::array::erased::ArrayRef>>
192+
189193
impl vortex_array::scalar_fn::fns::cast::kernel::CastReduce for vortex_fastlanes::BitPacked
190194

191195
pub fn vortex_fastlanes::BitPacked::cast(vortex_array::array::view::ArrayView<'_, Self>, &vortex_array::dtype::DType) -> vortex_error::VortexResult<core::option::Option<vortex_array::array::erased::ArrayRef>>

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

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -334,19 +334,25 @@ impl<T: TypedArrayRef<crate::BitPacked>> BitPackedArrayExt for T {}
334334

335335
#[cfg(test)]
336336
mod test {
337+
use std::sync::LazyLock;
338+
337339
use vortex_array::IntoArray;
338-
use vortex_array::LEGACY_SESSION;
339340
use vortex_array::VortexSessionExecute;
340341
use vortex_array::arrays::PrimitiveArray;
341342
use vortex_array::assert_arrays_eq;
343+
use vortex_array::session::ArraySession;
342344
use vortex_buffer::Buffer;
345+
use vortex_session::VortexSession;
343346

344347
use crate::BitPackedData;
345348
use crate::bitpacking::array::BitPackedArrayExt;
346349

350+
static SESSION: LazyLock<VortexSession> =
351+
LazyLock::new(|| VortexSession::empty().with::<ArraySession>());
352+
347353
#[test]
348354
fn test_encode() {
349-
let mut ctx = LEGACY_SESSION.create_execution_ctx();
355+
let mut ctx = SESSION.create_execution_ctx();
350356
let values = [
351357
Some(1u64),
352358
None,
@@ -369,7 +375,7 @@ mod test {
369375

370376
#[test]
371377
fn test_encode_too_wide() {
372-
let mut ctx = LEGACY_SESSION.create_execution_ctx();
378+
let mut ctx = SESSION.create_execution_ctx();
373379
let values = [Some(1u8), None, Some(1), None, Some(1), None];
374380
let uncompressed = PrimitiveArray::from_option_iter(values);
375381
let _packed = BitPackedData::encode(&uncompressed.clone().into_array(), 8, &mut ctx)
@@ -380,7 +386,7 @@ mod test {
380386

381387
#[test]
382388
fn signed_with_patches() {
383-
let mut ctx = LEGACY_SESSION.create_execution_ctx();
389+
let mut ctx = SESSION.create_execution_ctx();
384390
let values: Buffer<i32> = (0i32..=512).collect();
385391
let parray = values.clone().into_array();
386392

0 commit comments

Comments
 (0)