Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
pola-rs
GitHub Repository: pola-rs/polars
Path: blob/main/crates/polars-plan/src/plans/optimizer/slice_pushdown_expr.rs
8416 views
1
use std::borrow::BorrowMut;
2
3
use super::*;
4
5
/// Returns whether slice was pushed
6
fn pushdown<T>(inputs: &mut [T], offset: Node, length: Node, arena: &mut Arena<AExpr>) -> bool
7
where
8
T: BorrowMut<Node>,
9
{
10
if inputs.is_empty() {
11
return false;
12
}
13
14
let mut has_column_height_projection = false;
15
16
macro_rules! is_column_height {
17
($node:expr) => {{
18
let node = $node;
19
is_length_preserving_ae(node, arena)
20
&& aexpr_to_leaf_names_iter(node, arena).next().is_some()
21
}};
22
}
23
24
for node in inputs.iter().map(|x| x.borrow()).copied() {
25
if is_scalar_ae(node, arena) {
26
continue;
27
}
28
29
let column_height = is_column_height!(node);
30
31
if column_height {
32
has_column_height_projection = true;
33
} else {
34
// Unknown non-scalar height
35
// TODO: Can technically still push slices with offset >=0.
36
return false;
37
}
38
}
39
40
if !has_column_height_projection {
41
return false;
42
}
43
44
for node in inputs {
45
let n = *node.borrow();
46
47
if is_scalar_ae(n, arena) {
48
continue;
49
}
50
51
if is_column_height!(n) {
52
*node.borrow_mut() = arena.add(AExpr::Slice {
53
input: n,
54
offset,
55
length,
56
})
57
}
58
}
59
60
true
61
}
62
63
impl OptimizationRule for SlicePushDown {
64
fn optimize_expr(
65
&mut self,
66
expr_arena: &mut Arena<AExpr>,
67
expr_node: Node,
68
_schema: &Schema,
69
_ctx: OptimizeExprContext,
70
) -> PolarsResult<Option<AExpr>> {
71
if let AExpr::Slice {
72
input,
73
offset,
74
length,
75
} = expr_arena.get(expr_node)
76
{
77
let offset = *offset;
78
let length = *length;
79
80
use AExpr::*;
81
let out = match expr_arena.get(*input) {
82
ae @ Cast { .. } => {
83
let ae = ae.clone();
84
let scratch = self.empty_nodes_scratch_mut();
85
86
ae.inputs_rev(scratch);
87
assert_eq!(scratch.len(), 1);
88
89
pushdown(scratch, offset, length, expr_arena)
90
.then(|| ae.replace_inputs(scratch))
91
},
92
BinaryExpr { left, right, op } => {
93
let left = *left;
94
let right = *right;
95
let op = *op;
96
97
let mut inputs = [left, right];
98
99
pushdown(&mut inputs[..], offset, length, expr_arena).then(|| BinaryExpr {
100
left: inputs[0],
101
op,
102
right: inputs[1],
103
})
104
},
105
Ternary {
106
truthy,
107
falsy,
108
predicate,
109
} => {
110
let mut inputs = [*truthy, *falsy, *predicate];
111
112
pushdown(&mut inputs[..], offset, length, expr_arena).then(|| Ternary {
113
truthy: inputs[0],
114
falsy: inputs[1],
115
predicate: inputs[2],
116
})
117
},
118
m @ AnonymousFunction { options, .. } if options.is_elementwise() => {
119
if let AnonymousFunction {
120
mut input,
121
function,
122
options,
123
fmt_str,
124
} = m.clone()
125
{
126
pushdown(input.as_mut_slice(), offset, length, expr_arena).then(|| {
127
AnonymousFunction {
128
input,
129
function,
130
options,
131
fmt_str,
132
}
133
})
134
} else {
135
unreachable!()
136
}
137
},
138
m @ Function { options, .. } if options.is_elementwise() => {
139
if let Function {
140
mut input,
141
function,
142
options,
143
} = m.clone()
144
{
145
pushdown(input.as_mut_slice(), offset, length, expr_arena).then(|| {
146
Function {
147
input,
148
function,
149
options,
150
}
151
})
152
} else {
153
unreachable!()
154
}
155
},
156
_ => None,
157
};
158
Ok(out)
159
} else {
160
Ok(None)
161
}
162
}
163
}
164
165