vortex_array/optimizer/
mod.rs1use smallvec::SmallVec;
19use vortex_error::VortexResult;
20use vortex_error::vortex_bail;
21use vortex_session::SessionExt;
22use vortex_session::VortexSession;
23
24use crate::ArrayRef;
25use crate::optimizer::kernels::ArrayKernels;
26
27pub mod kernels;
28pub mod rules;
29
30pub trait ArrayOptimizer {
32 fn optimize(&self) -> VortexResult<ArrayRef>;
37
38 fn optimize_ctx(&self, session: &VortexSession) -> VortexResult<ArrayRef>;
44
45 fn optimize_recursive(&self, session: &VortexSession) -> VortexResult<ArrayRef>;
50}
51
52impl ArrayOptimizer for ArrayRef {
53 fn optimize(&self) -> VortexResult<ArrayRef> {
54 Ok(try_optimize(self, None)?.unwrap_or_else(|| self.clone()))
55 }
56
57 fn optimize_ctx(&self, session: &VortexSession) -> VortexResult<ArrayRef> {
58 Ok(try_optimize(self, Some(session))?.unwrap_or_else(|| self.clone()))
59 }
60
61 fn optimize_recursive(&self, session: &VortexSession) -> VortexResult<ArrayRef> {
62 Ok(try_optimize_recursive(self, session)?.unwrap_or_else(|| self.clone()))
63 }
64}
65
66fn try_optimize(
67 array: &ArrayRef,
68 session: Option<&VortexSession>,
69) -> VortexResult<Option<ArrayRef>> {
70 let mut current_array = array.clone();
71 let mut any_optimizations = false;
72 let array_ref = session.and_then(|s| s.get_opt::<ArrayKernels>());
73
74 let mut loop_counter = 0;
76 'outer: loop {
77 if loop_counter > 100 {
78 vortex_bail!("Exceeded maximum optimization iterations (possible infinite loop)");
79 }
80 loop_counter += 1;
81
82 if let Some(new_array) = current_array.reduce()? {
83 current_array = new_array;
84 any_optimizations = true;
85 continue;
86 }
87
88 for (slot_idx, slot) in current_array.slots().iter().enumerate() {
91 let Some(child) = slot else { continue };
92
93 if let Some(array_ref) = &array_ref
95 && let Some(plugins) =
96 array_ref.find_reduce_parent(current_array.encoding_id(), child.encoding_id())
97 {
98 for plugin in plugins.as_ref() {
99 if let Some(new_array) = plugin(child, ¤t_array, slot_idx)? {
100 current_array = new_array;
101 any_optimizations = true;
102 continue 'outer;
103 }
104 }
105 }
106
107 if let Some(new_array) = child.reduce_parent(¤t_array, slot_idx)? {
108 current_array = new_array;
110 any_optimizations = true;
111
112 continue 'outer;
114 }
115 }
116
117 break;
119 }
120
121 if any_optimizations {
122 Ok(Some(current_array))
123 } else {
124 Ok(None)
125 }
126}
127
128fn try_optimize_recursive(
129 array: &ArrayRef,
130 session: &VortexSession,
131) -> VortexResult<Option<ArrayRef>> {
132 let mut current_array = array.clone();
133 let mut any_optimizations = false;
134
135 if let Some(new_array) = try_optimize(¤t_array, Some(session))? {
136 current_array = new_array;
137 any_optimizations = true;
138 }
139
140 let mut new_slots = SmallVec::with_capacity(current_array.slots().len());
141 let mut any_slot_optimized = false;
142 for slot in current_array.slots() {
143 match slot {
144 Some(child) => {
145 if let Some(new_child) = try_optimize_recursive(child, session)? {
146 new_slots.push(Some(new_child));
147 any_slot_optimized = true;
148 } else {
149 new_slots.push(Some(child.clone()));
150 }
151 }
152 None => new_slots.push(None),
153 }
154 }
155
156 if any_slot_optimized {
157 current_array = current_array.with_slots(new_slots)?;
158 any_optimizations = true;
159 }
160
161 if any_optimizations {
162 Ok(Some(current_array))
163 } else {
164 Ok(None)
165 }
166}