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