vortex_alp/alp/compute/
cast.rs1use vortex_array::ArrayRef;
5use vortex_array::ArrayView;
6use vortex_array::IntoArray;
7use vortex_array::builtins::ArrayBuiltins;
8use vortex_array::dtype::DType;
9use vortex_array::scalar_fn::fns::cast::CastReduce;
10use vortex_error::VortexResult;
11
12use crate::ALPArrayExt;
13use crate::ALPArraySlotsExt;
14use crate::alp::ALP;
15
16impl CastReduce for ALP {
17 fn cast(array: ArrayView<'_, Self>, dtype: &DType) -> VortexResult<Option<ArrayRef>> {
18 if !array.dtype().eq_ignore_nullability(dtype) {
20 return Ok(None);
21 }
22
23 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 unsafe {
39 Ok(Some(
40 ALP::new_unchecked(new_encoded, array.exponents(), new_patches).into_array(),
41 ))
42 }
43 }
44}
45
46#[cfg(test)]
47mod tests {
48 use std::sync::LazyLock;
49
50 use rstest::rstest;
51 use vortex_array::IntoArray;
52 use vortex_array::VortexSessionExecute;
53 use vortex_array::arrays::PrimitiveArray;
54 use vortex_array::assert_arrays_eq;
55 use vortex_array::builtins::ArrayBuiltins;
56 use vortex_array::compute::conformance::cast::test_cast_conformance;
57 use vortex_array::dtype::DType;
58 use vortex_array::dtype::Nullability;
59 use vortex_array::dtype::PType;
60 use vortex_buffer::buffer;
61 use vortex_error::VortexExpect;
62 use vortex_error::VortexResult;
63 use vortex_session::VortexSession;
64
65 use crate::alp::array::ALPArrayExt;
66 use crate::alp_encode;
67
68 static SESSION: LazyLock<VortexSession> = LazyLock::new(|| {
69 let session = vortex_array::array_session();
70 crate::initialize(&session);
71 session
72 });
73
74 #[test]
75 fn issue_5766_test_cast_alp_with_patches_to_nullable() -> VortexResult<()> {
76 let mut ctx = SESSION.create_execution_ctx();
77 let values = buffer![1.234f32, f32::NAN, 2.345, f32::INFINITY, 3.456].into_array();
78 let values_primitive = values.clone().execute::<PrimitiveArray>(&mut ctx)?;
79 let alp = alp_encode(values_primitive.as_view(), None, &mut ctx)?;
80
81 assert!(
82 alp.patches().is_some(),
83 "Test requires ALP array with patches"
84 );
85
86 let nullable_dtype = DType::Primitive(PType::F32, Nullability::Nullable);
87 let casted = alp.into_array().cast(nullable_dtype.clone())?;
88
89 let expected = values.cast(nullable_dtype)?;
90
91 assert_arrays_eq!(casted, expected, &mut ctx);
92
93 Ok(())
94 }
95
96 #[test]
97 fn test_cast_alp_f32_to_f64() -> VortexResult<()> {
98 let mut ctx = SESSION.create_execution_ctx();
99 let values = buffer![1.5f32, 2.5, 3.5, 4.5].into_array();
100 let values_primitive = values.execute::<PrimitiveArray>(&mut ctx)?;
101 let alp = alp_encode(values_primitive.as_view(), None, &mut ctx)?;
102
103 let casted = alp
104 .into_array()
105 .cast(DType::Primitive(PType::F64, Nullability::NonNullable))?;
106 assert_eq!(
107 casted.dtype(),
108 &DType::Primitive(PType::F64, Nullability::NonNullable)
109 );
110
111 assert_arrays_eq!(
112 casted,
113 PrimitiveArray::from_iter([1.5f64, 2.5, 3.5, 4.5]),
114 &mut ctx
115 );
116
117 Ok(())
118 }
119
120 #[test]
121 fn test_cast_alp_to_int() -> VortexResult<()> {
122 let mut ctx = SESSION.create_execution_ctx();
123 let values = buffer![1.0f32, 2.0, 3.0, 4.0].into_array();
124 let values_primitive = values.execute::<PrimitiveArray>(&mut ctx)?;
125 let alp = alp_encode(values_primitive.as_view(), None, &mut ctx)?;
126
127 let casted = alp
128 .into_array()
129 .cast(DType::Primitive(PType::I32, Nullability::NonNullable))?;
130 assert_eq!(
131 casted.dtype(),
132 &DType::Primitive(PType::I32, Nullability::NonNullable)
133 );
134
135 assert_arrays_eq!(casted, PrimitiveArray::from_iter([1i32, 2, 3, 4]), &mut ctx);
136
137 Ok(())
138 }
139
140 #[rstest]
141 #[case(buffer![1.23f32, 4.56, 7.89, 10.11, 12.13].into_array())]
142 #[case(buffer![100.1f64, 200.2, 300.3, 400.4, 500.5].into_array())]
143 #[case(PrimitiveArray::from_option_iter([Some(1.1f32), None, Some(2.2), Some(3.3), None]).into_array())]
144 #[case(buffer![42.42f64].into_array())]
145 #[case(buffer![0.0f32, -1.5, 2.5, -3.5, 4.5].into_array())]
146 fn test_cast_alp_conformance(#[case] array: vortex_array::ArrayRef) -> VortexResult<()> {
147 let mut ctx = SESSION.create_execution_ctx();
148 let array_primitive = array.execute::<PrimitiveArray>(&mut ctx)?;
149 let alp =
150 alp_encode(array_primitive.as_view(), None, &mut ctx).vortex_expect("cannot fail");
151 test_cast_conformance(&alp.into_array(), &mut ctx);
152
153 Ok(())
154 }
155}