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::patches::Patches;
10use vortex_array::scalar_fn::fns::cast::CastReduce;
11use vortex_error::VortexResult;
12
13use crate::ALPArrayExt;
14use crate::ALPArraySlotsExt;
15use crate::alp::ALP;
16
17impl CastReduce for ALP {
18 fn cast(array: ArrayView<'_, Self>, dtype: &DType) -> VortexResult<Option<ArrayRef>> {
19 if array.dtype().eq_ignore_nullability(dtype) {
21 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 unsafe {
49 Ok(Some(
50 ALP::new_unchecked(new_encoded, array.exponents(), new_patches).into_array(),
51 ))
52 }
53 } else {
54 Ok(None)
55 }
56 }
57}
58
59#[cfg(test)]
60mod tests {
61 use rstest::rstest;
62 use vortex_array::IntoArray;
63 use vortex_array::ToCanonical;
64 use vortex_array::arrays::PrimitiveArray;
65 use vortex_array::assert_arrays_eq;
66 use vortex_array::builtins::ArrayBuiltins;
67 use vortex_array::compute::conformance::cast::test_cast_conformance;
68 use vortex_array::dtype::DType;
69 use vortex_array::dtype::Nullability;
70 use vortex_array::dtype::PType;
71 use vortex_buffer::buffer;
72 use vortex_error::VortexExpect;
73 use vortex_error::VortexResult;
74
75 use crate::alp::array::ALPArrayExt;
76 use crate::alp_encode;
77
78 #[test]
79 fn issue_5766_test_cast_alp_with_patches_to_nullable() -> VortexResult<()> {
80 let values = buffer![1.234f32, f32::NAN, 2.345, f32::INFINITY, 3.456].into_array();
81 let alp = alp_encode(&values.to_primitive(), None)?;
82
83 assert!(
84 alp.patches().is_some(),
85 "Test requires ALP array with patches"
86 );
87
88 let nullable_dtype = DType::Primitive(PType::F32, Nullability::Nullable);
89 let casted = alp.into_array().cast(nullable_dtype.clone())?;
90
91 let expected = values.cast(nullable_dtype)?;
92
93 assert_arrays_eq!(casted.to_canonical()?.into_primitive(), expected);
94
95 Ok(())
96 }
97
98 #[test]
99 fn test_cast_alp_f32_to_f64() -> VortexResult<()> {
100 let values = buffer![1.5f32, 2.5, 3.5, 4.5].into_array();
101 let alp = alp_encode(&values.to_primitive(), None)?;
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 let decoded = casted.to_canonical()?.into_primitive();
112 let values = decoded.as_slice::<f64>();
113 assert_eq!(values.len(), 4);
114 assert!((values[0] - 1.5).abs() < f64::EPSILON);
115 assert!((values[1] - 2.5).abs() < f64::EPSILON);
116
117 Ok(())
118 }
119
120 #[test]
121 fn test_cast_alp_to_int() -> VortexResult<()> {
122 let values = buffer![1.0f32, 2.0, 3.0, 4.0].into_array();
123 let alp = alp_encode(&values.to_primitive(), None)?;
124
125 let casted = alp
126 .into_array()
127 .cast(DType::Primitive(PType::I32, Nullability::NonNullable))?;
128 assert_eq!(
129 casted.dtype(),
130 &DType::Primitive(PType::I32, Nullability::NonNullable)
131 );
132
133 let decoded = casted.to_canonical()?.into_primitive();
134 assert_arrays_eq!(decoded, PrimitiveArray::from_iter([1i32, 2, 3, 4]));
135
136 Ok(())
137 }
138
139 #[rstest]
140 #[case(buffer![1.23f32, 4.56, 7.89, 10.11, 12.13].into_array())]
141 #[case(buffer![100.1f64, 200.2, 300.3, 400.4, 500.5].into_array())]
142 #[case(PrimitiveArray::from_option_iter([Some(1.1f32), None, Some(2.2), Some(3.3), None]).into_array())]
143 #[case(buffer![42.42f64].into_array())]
144 #[case(buffer![0.0f32, -1.5, 2.5, -3.5, 4.5].into_array())]
145 fn test_cast_alp_conformance(#[case] array: vortex_array::ArrayRef) -> VortexResult<()> {
146 let alp = alp_encode(&array.to_primitive(), None).vortex_expect("cannot fail");
147 test_cast_conformance(&alp.into_array());
148
149 Ok(())
150 }
151}