vortex_array/optimizer/
mod.rs1use std::sync::Arc;
5
6use vortex_error::VortexResult;
7use vortex_utils::aliases::hash_map::HashMap;
8
9use crate::Array;
10use crate::ArrayVisitor;
11use crate::array::ArrayRef;
12use crate::optimizer::rules::AnyArray;
13use crate::optimizer::rules::ArrayParentReduceRule;
14use crate::optimizer::rules::ArrayReduceRule;
15use crate::optimizer::rules::DynArrayParentReduceRule;
16use crate::optimizer::rules::DynArrayReduceRule;
17use crate::optimizer::rules::MatchKey;
18use crate::optimizer::rules::Matcher;
19use crate::optimizer::rules::ParentReduceRuleAdapter;
20use crate::optimizer::rules::ReduceRuleAdapter;
21
22pub mod rules;
23
24#[cfg(test)]
25mod tests;
26
27#[derive(Default, Debug, Clone)]
32pub struct ArrayOptimizer {
33 reduce_rules: HashMap<MatchKey, Vec<Arc<dyn DynArrayReduceRule>>>,
35 parent_rules: HashMap<(MatchKey, MatchKey), Vec<Arc<dyn DynArrayParentReduceRule>>>,
37}
38
39impl ArrayOptimizer {
40 pub fn optimize_array(&self, array: ArrayRef) -> VortexResult<ArrayRef> {
46 let array = self.apply_parent_rules(array)?;
48
49 let array = self.apply_reduce_rules(array)?;
51
52 Ok(array)
53 }
54
55 fn apply_parent_rules(&self, array: ArrayRef) -> VortexResult<ArrayRef> {
60 let children = array.children();
62 if children.is_empty() {
63 return Ok(array);
64 }
65
66 let mut optimized_children = Vec::with_capacity(children.len());
67 let mut children_changed = false;
68
69 for child in children.iter() {
70 let optimized_child = self.apply_parent_rules(child.clone())?;
71 children_changed |= !Arc::ptr_eq(&optimized_child, child);
72 optimized_children.push(optimized_child);
73 }
74
75 let array = if children_changed {
77 array.with_children(&optimized_children)?
78 } else {
79 array
80 };
81
82 for (idx, child) in optimized_children.iter().enumerate() {
87 let result = self.with_parent_rules(
88 child,
89 Some(&array),
90 |rules| -> VortexResult<Option<ArrayRef>> {
91 for rule in rules {
92 if let Some(new_array) = rule.reduce_parent(child, &array, idx)? {
93 return Ok(Some(new_array));
94 }
95 }
96 Ok(None)
97 },
98 )?;
99
100 if let Some(transformed) = result {
101 return Ok(transformed);
102 }
103 }
104
105 Ok(array)
107 }
108
109 fn apply_reduce_rules(&self, array: ArrayRef) -> VortexResult<ArrayRef> {
114 let children = array.children();
116 if !children.is_empty() {
117 let mut new_children = Vec::with_capacity(children.len());
118 let mut changed = false;
119
120 for child in children.iter() {
121 let optimized_child = self.apply_reduce_rules(child.clone())?;
122 changed |= !Arc::ptr_eq(&optimized_child, child);
123 new_children.push(optimized_child);
124 }
125
126 let array = if changed {
128 array.with_children(&new_children)?
129 } else {
130 array
131 };
132
133 self.try_reduce(array)
135 } else {
136 self.try_reduce(array)
138 }
139 }
140
141 fn try_reduce(&self, array: ArrayRef) -> VortexResult<ArrayRef> {
143 let result = self.with_reduce_rules(&array, |rules| -> VortexResult<Option<ArrayRef>> {
144 for rule in rules {
145 if let Some(new_array) = rule.reduce(&array)? {
146 return Ok(Some(new_array));
147 }
148 }
149 Ok(None)
150 })?;
151
152 if let Some(transformed) = result {
153 Ok(transformed)
156 } else {
157 Ok(array)
158 }
159 }
160
161 pub fn register_reduce_rule<M, R>(&mut self, rule: R)
163 where
164 M: Matcher,
165 R: ArrayReduceRule<M> + 'static,
166 {
167 let key = rule.matcher().key();
168 let adapter = ReduceRuleAdapter::new(rule);
169 self.reduce_rules
170 .entry(key)
171 .or_default()
172 .push(Arc::new(adapter));
173 }
174
175 pub fn register_parent_rule<Child, Parent, R>(&mut self, rule: R)
177 where
178 Child: Matcher,
179 Parent: Matcher,
180 R: ArrayParentReduceRule<Child, Parent> + 'static,
181 {
182 let key = (rule.child().key(), rule.parent().key());
183 let adapter = ParentReduceRuleAdapter::new(rule);
184 self.parent_rules
185 .entry(key)
186 .or_default()
187 .push(Arc::new(adapter));
188 }
189
190 pub fn register_any_parent_rule<Child, R>(&mut self, rule: R)
192 where
193 Child: Matcher,
194 R: ArrayParentReduceRule<Child, AnyArray> + 'static,
195 {
196 let key = (rule.child().key(), MatchKey::Any);
197 let adapter = ParentReduceRuleAdapter::new(rule);
198 self.parent_rules
199 .entry(key)
200 .or_default()
201 .push(Arc::new(adapter));
202 }
203
204 pub(crate) fn with_reduce_rules<F, R>(&self, array: &ArrayRef, f: F) -> R
206 where
207 F: FnOnce(&mut dyn Iterator<Item = &dyn DynArrayReduceRule>) -> R,
208 {
209 let exact = self.reduce_rules.get(&MatchKey::Array(array.encoding_id()));
210 let any = self.reduce_rules.get(&MatchKey::Any);
211 f(&mut exact
212 .iter()
213 .chain(any.iter())
214 .flat_map(|v| v.iter())
215 .map(|v| v.as_ref()))
216 }
217
218 pub(crate) fn with_parent_rules<F, R>(
222 &self,
223 child: &ArrayRef,
224 parent: Option<&ArrayRef>,
225 f: F,
226 ) -> R
227 where
228 F: FnOnce(&mut dyn Iterator<Item = &dyn DynArrayParentReduceRule>) -> R,
229 {
230 let exact = parent.and_then(|parent| {
231 self.parent_rules.get(&(
232 MatchKey::Array(child.encoding_id()),
233 MatchKey::Array(parent.encoding_id()),
234 ))
235 });
236 let any = self
237 .parent_rules
238 .get(&(MatchKey::Array(child.encoding_id()), MatchKey::Any));
239
240 f(&mut exact
241 .iter()
242 .chain(any.iter())
243 .flat_map(|v| v.iter())
244 .map(|arc| arc.as_ref()))
245 }
246}