1mod simplify_functions;
2
3use polars_utils::floor_divmod::FloorDivMod;
4use polars_utils::total_ord::ToTotalOrd;
5use simplify_functions::optimize_functions;
6
7use crate::plans::*;
8
9fn new_null_count(input: &[ExprIR]) -> AExpr {
10 AExpr::Function {
11 input: input.to_vec(),
12 function: FunctionExpr::NullCount,
13 options: FunctionOptions {
14 collect_groups: ApplyOptions::GroupWise,
15 flags: FunctionFlags::ALLOW_GROUP_AWARE | FunctionFlags::RETURNS_SCALAR,
16 ..Default::default()
17 },
18 }
19}
20
21macro_rules! eval_binary_same_type {
22 ($lhs:expr, $rhs:expr, |$l: ident, $r: ident| $ret: expr) => {{
23 if let (AExpr::Literal(lit_left), AExpr::Literal(lit_right)) = ($lhs, $rhs) {
24 match (lit_left, lit_right) {
25 (LiteralValue::Float32($l), LiteralValue::Float32($r)) => {
26 Some(AExpr::Literal(LiteralValue::Float32($ret)))
27 },
28 (LiteralValue::Float64($l), LiteralValue::Float64($r)) => {
29 Some(AExpr::Literal(LiteralValue::Float64($ret)))
30 },
31 #[cfg(feature = "dtype-i8")]
32 (LiteralValue::Int8($l), LiteralValue::Int8($r)) => {
33 Some(AExpr::Literal(LiteralValue::Int8($ret)))
34 },
35 #[cfg(feature = "dtype-i16")]
36 (LiteralValue::Int16($l), LiteralValue::Int16($r)) => {
37 Some(AExpr::Literal(LiteralValue::Int16($ret)))
38 },
39 (LiteralValue::Int32($l), LiteralValue::Int32($r)) => {
40 Some(AExpr::Literal(LiteralValue::Int32($ret)))
41 },
42 (LiteralValue::Int64($l), LiteralValue::Int64($r)) => {
43 Some(AExpr::Literal(LiteralValue::Int64($ret)))
44 },
45 #[cfg(feature = "dtype-u8")]
46 (LiteralValue::UInt8($l), LiteralValue::UInt8($r)) => {
47 Some(AExpr::Literal(LiteralValue::UInt8($ret)))
48 },
49 #[cfg(feature = "dtype-u16")]
50 (LiteralValue::UInt16($l), LiteralValue::UInt16($r)) => {
51 Some(AExpr::Literal(LiteralValue::UInt16($ret)))
52 },
53 (LiteralValue::UInt32($l), LiteralValue::UInt32($r)) => {
54 Some(AExpr::Literal(LiteralValue::UInt32($ret)))
55 },
56 (LiteralValue::UInt64($l), LiteralValue::UInt64($r)) => {
57 Some(AExpr::Literal(LiteralValue::UInt64($ret)))
58 },
59 (LiteralValue::Float($l), LiteralValue::Float($r)) => {
60 Some(AExpr::Literal(LiteralValue::Float($ret)))
61 },
62 (LiteralValue::Int($l), LiteralValue::Int($r)) => {
63 Some(AExpr::Literal(LiteralValue::Int($ret)))
64 },
65 _ => None,
66 }
67 } else {
68 None
69 }
70 }};
71}
72
73macro_rules! eval_binary_cmp_same_type {
74 ($lhs:expr, $operand: tt, $rhs:expr) => {{
75 if let (AExpr::Literal(lit_left), AExpr::Literal(lit_right)) = ($lhs, $rhs) {
76 match (lit_left, lit_right) {
77 (LiteralValue::Float32(x), LiteralValue::Float32(y)) => {
78 Some(AExpr::Literal(LiteralValue::Boolean(x.to_total_ord() $operand y.to_total_ord())))
79 }
80 (LiteralValue::Float64(x), LiteralValue::Float64(y)) => {
81 Some(AExpr::Literal(LiteralValue::Boolean(x.to_total_ord() $operand y.to_total_ord())))
82 }
83 #[cfg(feature = "dtype-i8")]
84 (LiteralValue::Int8(x), LiteralValue::Int8(y)) => {
85 Some(AExpr::Literal(LiteralValue::Boolean(x $operand y)))
86 }
87 #[cfg(feature = "dtype-i16")]
88 (LiteralValue::Int16(x), LiteralValue::Int16(y)) => {
89 Some(AExpr::Literal(LiteralValue::Boolean(x $operand y)))
90 }
91 (LiteralValue::Int32(x), LiteralValue::Int32(y)) => {
92 Some(AExpr::Literal(LiteralValue::Boolean(x $operand y)))
93 }
94 (LiteralValue::Int64(x), LiteralValue::Int64(y)) => {
95 Some(AExpr::Literal(LiteralValue::Boolean(x $operand y)))
96 }
97 #[cfg(feature = "dtype-u8")]
98 (LiteralValue::UInt8(x), LiteralValue::UInt8(y)) => {
99 Some(AExpr::Literal(LiteralValue::Boolean(x $operand y)))
100 }
101 #[cfg(feature = "dtype-u16")]
102 (LiteralValue::UInt16(x), LiteralValue::UInt16(y)) => {
103 Some(AExpr::Literal(LiteralValue::Boolean(x $operand y)))
104 }
105 (LiteralValue::UInt32(x), LiteralValue::UInt32(y)) => {
106 Some(AExpr::Literal(LiteralValue::Boolean(x $operand y)))
107 }
108 (LiteralValue::UInt64(x), LiteralValue::UInt64(y)) => {
109 Some(AExpr::Literal(LiteralValue::Boolean(x $operand y)))
110 }
111 (LiteralValue::Boolean(x), LiteralValue::Boolean(y)) => {
112 Some(AExpr::Literal(LiteralValue::Boolean(x $operand y)))
113 },
114 (LiteralValue::Int(x), LiteralValue::Int(y)) => {
115 Some(AExpr::Literal(LiteralValue::Boolean(x $operand y)))
116 }
117 (LiteralValue::Float(x), LiteralValue::Float(y)) => {
118 Some(AExpr::Literal(LiteralValue::Boolean(x $operand y)))
119 }
120 _ => None,
121 }
122 } else {
123 None
124 }
125
126 }}
127}
128
129pub struct SimplifyBooleanRule {}
130
131impl OptimizationRule for SimplifyBooleanRule {
132 fn optimize_expr(
133 &mut self,
134 expr_arena: &mut Arena<AExpr>,
135 expr_node: Node,
136 lp_arena: &Arena<IR>,
137 lp_node: Node,
138 ) -> PolarsResult<Option<AExpr>> {
139 let expr = expr_arena.get(expr_node);
140 let in_filter = matches!(lp_arena.get(lp_node), IR::Filter { .. });
141
142 let out = match expr {
143 AExpr::BinaryExpr {
145 left,
146 op: Operator::And,
147 right,
148 } if matches!(
149 expr_arena.get(*left),
150 AExpr::Literal(LiteralValue::Boolean(true))
151 ) && in_filter =>
152 {
153 return Ok(Some(expr_arena.get(*right).clone()));
156 },
157 AExpr::BinaryExpr {
159 left,
160 op: Operator::And,
161 right,
162 } if matches!(
163 expr_arena.get(*right),
164 AExpr::Literal(LiteralValue::Boolean(true))
165 ) =>
166 {
167 Some(expr_arena.get(*left).clone())
168 },
169
170 AExpr::BinaryExpr {
174 left,
175 op: Operator::And,
176 right,
177 } if matches!(expr_arena.get(*left), AExpr::Literal(_))
178 && matches!(
179 expr_arena.get(*right),
180 AExpr::Literal(LiteralValue::Boolean(false))
181 ) =>
182 {
183 Some(AExpr::Literal(LiteralValue::Boolean(false)))
184 },
185
186 AExpr::BinaryExpr {
190 left,
191 op: Operator::And,
192 right,
193 } if matches!(
194 expr_arena.get(*left),
195 AExpr::Literal(LiteralValue::Boolean(false))
196 ) && matches!(expr_arena.get(*right), AExpr::Literal(_)) =>
197 {
198 Some(AExpr::Literal(LiteralValue::Boolean(false)))
199 },
200
201 AExpr::BinaryExpr {
203 left,
204 op: Operator::Or,
205 right,
206 } if matches!(
207 expr_arena.get(*left),
208 AExpr::Literal(LiteralValue::Boolean(false))
209 ) && in_filter =>
210 {
211 return Ok(Some(expr_arena.get(*right).clone()));
214 },
215 AExpr::BinaryExpr {
217 left,
218 op: Operator::Or,
219 right,
220 ..
221 } if matches!(
222 expr_arena.get(*right),
223 AExpr::Literal(LiteralValue::Boolean(false))
224 ) =>
225 {
226 Some(expr_arena.get(*left).clone())
227 },
228
229 AExpr::BinaryExpr {
233 left,
234 op: Operator::Or,
235 right,
236 } if matches!(expr_arena.get(*left), AExpr::Literal(_))
237 && matches!(
238 expr_arena.get(*right),
239 AExpr::Literal(LiteralValue::Boolean(true))
240 ) =>
241 {
242 Some(AExpr::Literal(LiteralValue::Boolean(true)))
243 },
244
245 AExpr::BinaryExpr {
249 left,
250 op: Operator::Or,
251 right,
252 } if matches!(
253 expr_arena.get(*left),
254 AExpr::Literal(LiteralValue::Boolean(true))
255 ) && matches!(expr_arena.get(*right), AExpr::Literal(_)) =>
256 {
257 Some(AExpr::Literal(LiteralValue::Boolean(true)))
258 },
259 AExpr::Function {
260 input,
261 function: FunctionExpr::Negate,
262 ..
263 } if input.len() == 1 => {
264 let input = &input[0];
265 let ae = expr_arena.get(input.node());
266 eval_negate(ae)
267 },
268 _ => None,
269 };
270 Ok(out)
271 }
272}
273
274fn eval_negate(ae: &AExpr) -> Option<AExpr> {
275 let out = match ae {
276 AExpr::Literal(lv) => match lv {
277 #[cfg(feature = "dtype-i8")]
278 LiteralValue::Int8(v) => LiteralValue::Int8(-*v),
279 #[cfg(feature = "dtype-i16")]
280 LiteralValue::Int16(v) => LiteralValue::Int16(-*v),
281 LiteralValue::Int32(v) => LiteralValue::Int32(-*v),
282 LiteralValue::Int64(v) => LiteralValue::Int64(-*v),
283 LiteralValue::Float32(v) => LiteralValue::Float32(-*v),
284 LiteralValue::Float64(v) => LiteralValue::Float64(-*v),
285 LiteralValue::Float(v) => LiteralValue::Float(-*v),
286 LiteralValue::Int(v) => LiteralValue::Int(-*v),
287 _ => return None,
288 },
289 _ => return None,
290 };
291 Some(AExpr::Literal(out))
292}
293
294fn eval_bitwise<F>(left: &AExpr, right: &AExpr, operation: F) -> Option<AExpr>
295where
296 F: Fn(bool, bool) -> bool,
297{
298 if let (AExpr::Literal(lit_left), AExpr::Literal(lit_right)) = (left, right) {
299 return match (lit_left, lit_right) {
300 (LiteralValue::Boolean(x), LiteralValue::Boolean(y)) => {
301 Some(AExpr::Literal(LiteralValue::Boolean(operation(*x, *y))))
302 },
303 _ => None,
304 };
305 }
306 None
307}
308
309#[cfg(all(feature = "strings", feature = "concat_str"))]
310fn string_addition_to_linear_concat(
311 lp_arena: &Arena<IR>,
312 lp_node: Node,
313 expr_arena: &Arena<AExpr>,
314 left_node: Node,
315 right_node: Node,
316 left_aexpr: &AExpr,
317 right_aexpr: &AExpr,
318) -> Option<AExpr> {
319 {
320 let lp = lp_arena.get(lp_node);
321 let input = lp.get_input()?;
322 let schema = lp_arena.get(input).schema(lp_arena);
323 let left_e = ExprIR::from_node(left_node, expr_arena);
324 let right_e = ExprIR::from_node(right_node, expr_arena);
325
326 let get_type = |ae: &AExpr| ae.get_type(&schema, Context::Default, expr_arena).ok();
327 let type_a = get_type(left_aexpr).or_else(|| get_type(right_aexpr))?;
328 let type_b = get_type(right_aexpr).or_else(|| get_type(right_aexpr))?;
329
330 if type_a != type_b {
331 return None;
332 }
333
334 if type_a.is_string() {
335 match (left_aexpr, right_aexpr) {
336 (
338 AExpr::Function {
339 input: input_left,
340 function:
341 ref fun_l @ FunctionExpr::StringExpr(StringFunction::ConcatHorizontal {
342 delimiter: sep_l,
343 ignore_nulls: ignore_nulls_l,
344 }),
345 options,
346 },
347 AExpr::Function {
348 input: input_right,
349 function:
350 FunctionExpr::StringExpr(StringFunction::ConcatHorizontal {
351 delimiter: sep_r,
352 ignore_nulls: ignore_nulls_r,
353 }),
354 ..
355 },
356 ) => {
357 if sep_l.is_empty() && sep_r.is_empty() && ignore_nulls_l == ignore_nulls_r {
358 let mut input = Vec::with_capacity(input_left.len() + input_right.len());
359 input.extend_from_slice(input_left);
360 input.extend_from_slice(input_right);
361 Some(AExpr::Function {
362 input,
363 function: fun_l.clone(),
364 options: *options,
365 })
366 } else {
367 None
368 }
369 },
370 (
372 AExpr::Function {
373 input,
374 function:
375 ref fun @ FunctionExpr::StringExpr(StringFunction::ConcatHorizontal {
376 delimiter: sep,
377 ignore_nulls,
378 }),
379 options,
380 },
381 _,
382 ) => {
383 if sep.is_empty() && !ignore_nulls {
384 let mut input = input.clone();
385 input.push(right_e);
386 Some(AExpr::Function {
387 input,
388 function: fun.clone(),
389 options: *options,
390 })
391 } else {
392 None
393 }
394 },
395 (
397 _,
398 AExpr::Function {
399 input: input_right,
400 function:
401 ref fun @ FunctionExpr::StringExpr(StringFunction::ConcatHorizontal {
402 delimiter: sep,
403 ignore_nulls,
404 }),
405 options,
406 },
407 ) => {
408 if sep.is_empty() && !ignore_nulls {
409 let mut input = Vec::with_capacity(1 + input_right.len());
410 input.push(left_e);
411 input.extend_from_slice(input_right);
412 Some(AExpr::Function {
413 input,
414 function: fun.clone(),
415 options: *options,
416 })
417 } else {
418 None
419 }
420 },
421 _ => Some(AExpr::Function {
422 input: vec![left_e, right_e],
423 function: StringFunction::ConcatHorizontal {
424 delimiter: "".into(),
425 ignore_nulls: false,
426 }
427 .into(),
428 options: FunctionOptions {
429 collect_groups: ApplyOptions::ElementWise,
430 flags: FunctionFlags::default()
431 | FunctionFlags::INPUT_WILDCARD_EXPANSION
432 & !FunctionFlags::RETURNS_SCALAR,
433 ..Default::default()
434 },
435 }),
436 }
437 } else {
438 None
439 }
440 }
441}
442
443pub struct SimplifyExprRule {}
444
445impl OptimizationRule for SimplifyExprRule {
446 #[allow(clippy::float_cmp)]
447 fn optimize_expr(
448 &mut self,
449 expr_arena: &mut Arena<AExpr>,
450 expr_node: Node,
451 lp_arena: &Arena<IR>,
452 lp_node: Node,
453 ) -> PolarsResult<Option<AExpr>> {
454 let expr = expr_arena.get(expr_node).clone();
455
456 let out = match &expr {
457 AExpr::Agg(IRAggExpr::Count(input, _)) => {
460 let input_expr = expr_arena.get(*input);
461 match input_expr {
462 AExpr::Function {
463 input,
464 function: FunctionExpr::DropNulls,
465 options: _,
466 } => {
467 if input.len() == 1 {
470 let drop_nulls_input_node = input[0].node();
471 match expr_arena.get(drop_nulls_input_node) {
472 AExpr::Column(_) => Some(AExpr::BinaryExpr {
473 op: Operator::Minus,
474 right: expr_arena.add(new_null_count(input)),
475 left: expr_arena.add(AExpr::Agg(IRAggExpr::Count(
476 drop_nulls_input_node,
477 true,
478 ))),
479 }),
480 _ => None,
481 }
482 } else {
483 None
484 }
485 },
486 _ => None,
487 }
488 },
489 AExpr::Agg(IRAggExpr::Sum(input)) => {
492 let input_expr = expr_arena.get(*input);
493 match input_expr {
494 AExpr::Function {
495 input,
496 function: FunctionExpr::Boolean(BooleanFunction::IsNull),
497 options: _,
498 } => Some(new_null_count(input)),
499 AExpr::Function {
500 input,
501 function: FunctionExpr::Boolean(BooleanFunction::IsNotNull),
502 options: _,
503 } => {
504 if input.len() == 1 {
507 let is_not_null_input_node = input[0].node();
508 match expr_arena.get(is_not_null_input_node) {
509 AExpr::Column(_) => Some(AExpr::BinaryExpr {
510 op: Operator::Minus,
511 right: expr_arena.add(new_null_count(input)),
512 left: expr_arena.add(AExpr::Agg(IRAggExpr::Count(
513 is_not_null_input_node,
514 true,
515 ))),
516 }),
517 _ => None,
518 }
519 } else {
520 None
521 }
522 },
523 _ => None,
524 }
525 },
526 AExpr::BinaryExpr { left, op, right } => {
529 let left_aexpr = expr_arena.get(*left);
530 let right_aexpr = expr_arena.get(*right);
531
532 use Operator::*;
534 #[allow(clippy::manual_map)]
535 let out = match op {
536 Plus => {
537 match eval_binary_same_type!(left_aexpr, right_aexpr, |l, r| l + r) {
538 Some(new) => Some(new),
539 None => {
540 #[cfg(all(feature = "strings", feature = "concat_str"))]
542 {
543 string_addition_to_linear_concat(
544 lp_arena,
545 lp_node,
546 expr_arena,
547 *left,
548 *right,
549 left_aexpr,
550 right_aexpr,
551 )
552 }
553 #[cfg(not(all(feature = "strings", feature = "concat_str")))]
554 {
555 None
556 }
557 },
558 }
559 },
560 Minus => eval_binary_same_type!(left_aexpr, right_aexpr, |l, r| l - r),
561 Multiply => eval_binary_same_type!(left_aexpr, right_aexpr, |l, r| l * r),
562 Divide => {
563 if let (AExpr::Literal(lit_left), AExpr::Literal(lit_right)) =
564 (left_aexpr, right_aexpr)
565 {
566 match (lit_left, lit_right) {
567 (LiteralValue::Float32(x), LiteralValue::Float32(y)) => {
568 Some(AExpr::Literal(LiteralValue::Float32(x / y)))
569 },
570 (LiteralValue::Float64(x), LiteralValue::Float64(y)) => {
571 Some(AExpr::Literal(LiteralValue::Float64(x / y)))
572 },
573 (LiteralValue::Float(x), LiteralValue::Float(y)) => {
574 Some(AExpr::Literal(LiteralValue::Float64(x / y)))
575 },
576 #[cfg(feature = "dtype-i8")]
577 (LiteralValue::Int8(x), LiteralValue::Int8(y)) => {
578 Some(AExpr::Literal(LiteralValue::Int8(
579 x.wrapping_floor_div_mod(*y).0,
580 )))
581 },
582 #[cfg(feature = "dtype-i16")]
583 (LiteralValue::Int16(x), LiteralValue::Int16(y)) => {
584 Some(AExpr::Literal(LiteralValue::Int16(
585 x.wrapping_floor_div_mod(*y).0,
586 )))
587 },
588 (LiteralValue::Int32(x), LiteralValue::Int32(y)) => {
589 Some(AExpr::Literal(LiteralValue::Int32(
590 x.wrapping_floor_div_mod(*y).0,
591 )))
592 },
593 (LiteralValue::Int64(x), LiteralValue::Int64(y)) => {
594 Some(AExpr::Literal(LiteralValue::Int64(
595 x.wrapping_floor_div_mod(*y).0,
596 )))
597 },
598 (LiteralValue::Int(x), LiteralValue::Int(y)) => {
599 Some(AExpr::Literal(LiteralValue::Int(
600 x.wrapping_floor_div_mod(*y).0,
601 )))
602 },
603 #[cfg(feature = "dtype-u8")]
604 (LiteralValue::UInt8(x), LiteralValue::UInt8(y)) => {
605 Some(AExpr::Literal(LiteralValue::UInt8(x / y)))
606 },
607 #[cfg(feature = "dtype-u16")]
608 (LiteralValue::UInt16(x), LiteralValue::UInt16(y)) => {
609 Some(AExpr::Literal(LiteralValue::UInt16(x / y)))
610 },
611 (LiteralValue::UInt32(x), LiteralValue::UInt32(y)) => {
612 Some(AExpr::Literal(LiteralValue::UInt32(x / y)))
613 },
614 (LiteralValue::UInt64(x), LiteralValue::UInt64(y)) => {
615 Some(AExpr::Literal(LiteralValue::UInt64(x / y)))
616 },
617 _ => None,
618 }
619 } else {
620 None
621 }
622 },
623 TrueDivide => {
624 if let (AExpr::Literal(lit_left), AExpr::Literal(lit_right)) =
625 (left_aexpr, right_aexpr)
626 {
627 match (lit_left, lit_right) {
628 (LiteralValue::Float32(x), LiteralValue::Float32(y)) => {
629 Some(AExpr::Literal(LiteralValue::Float32(x / y)))
630 },
631 (LiteralValue::Float64(x), LiteralValue::Float64(y)) => {
632 Some(AExpr::Literal(LiteralValue::Float64(x / y)))
633 },
634 (LiteralValue::Float(x), LiteralValue::Float(y)) => {
635 Some(AExpr::Literal(LiteralValue::Float(x / y)))
636 },
637 #[cfg(feature = "dtype-i8")]
638 (LiteralValue::Int8(x), LiteralValue::Int8(y)) => Some(
639 AExpr::Literal(LiteralValue::Float64(*x as f64 / *y as f64)),
640 ),
641 #[cfg(feature = "dtype-i16")]
642 (LiteralValue::Int16(x), LiteralValue::Int16(y)) => Some(
643 AExpr::Literal(LiteralValue::Float64(*x as f64 / *y as f64)),
644 ),
645 (LiteralValue::Int32(x), LiteralValue::Int32(y)) => Some(
646 AExpr::Literal(LiteralValue::Float64(*x as f64 / *y as f64)),
647 ),
648 (LiteralValue::Int64(x), LiteralValue::Int64(y)) => Some(
649 AExpr::Literal(LiteralValue::Float64(*x as f64 / *y as f64)),
650 ),
651 #[cfg(feature = "dtype-u8")]
652 (LiteralValue::UInt8(x), LiteralValue::UInt8(y)) => Some(
653 AExpr::Literal(LiteralValue::Float64(*x as f64 / *y as f64)),
654 ),
655 #[cfg(feature = "dtype-u16")]
656 (LiteralValue::UInt16(x), LiteralValue::UInt16(y)) => Some(
657 AExpr::Literal(LiteralValue::Float64(*x as f64 / *y as f64)),
658 ),
659 (LiteralValue::UInt32(x), LiteralValue::UInt32(y)) => Some(
660 AExpr::Literal(LiteralValue::Float64(*x as f64 / *y as f64)),
661 ),
662 (LiteralValue::UInt64(x), LiteralValue::UInt64(y)) => Some(
663 AExpr::Literal(LiteralValue::Float64(*x as f64 / *y as f64)),
664 ),
665 (LiteralValue::Int(x), LiteralValue::Int(y)) => {
666 Some(AExpr::Literal(LiteralValue::Float(*x as f64 / *y as f64)))
667 },
668 _ => None,
669 }
670 } else {
671 None
672 }
673 },
674 Modulus => eval_binary_same_type!(left_aexpr, right_aexpr, |l, r| l
675 .wrapping_floor_div_mod(*r)
676 .1),
677 Lt => eval_binary_cmp_same_type!(left_aexpr, <, right_aexpr),
678 Gt => eval_binary_cmp_same_type!(left_aexpr, >, right_aexpr),
679 Eq | EqValidity => eval_binary_cmp_same_type!(left_aexpr, ==, right_aexpr),
680 NotEq | NotEqValidity => {
681 eval_binary_cmp_same_type!(left_aexpr, !=, right_aexpr)
682 },
683 GtEq => eval_binary_cmp_same_type!(left_aexpr, >=, right_aexpr),
684 LtEq => eval_binary_cmp_same_type!(left_aexpr, <=, right_aexpr),
685 And | LogicalAnd => eval_bitwise(left_aexpr, right_aexpr, |l, r| l & r),
686 Or | LogicalOr => eval_bitwise(left_aexpr, right_aexpr, |l, r| l | r),
687 Xor => eval_bitwise(left_aexpr, right_aexpr, |l, r| l ^ r),
688 FloorDivide => eval_binary_same_type!(left_aexpr, right_aexpr, |l, r| l
689 .wrapping_floor_div_mod(*r)
690 .0),
691 };
692 if out.is_some() {
693 return Ok(out);
694 }
695
696 None
697 },
698 AExpr::Function {
699 input,
700 function,
701 options,
702 ..
703 } => return optimize_functions(input, function, options, expr_arena),
704 _ => None,
705 };
706 Ok(out)
707 }
708}
709
710#[test]
711#[cfg(feature = "dtype-i8")]
712fn test_expr_to_aexp() {
713 use super::*;
714
715 let expr = Expr::Literal(LiteralValue::Int8(0));
716 let mut arena = Arena::new();
717 let aexpr = to_aexpr(expr, &mut arena).unwrap();
718 assert_eq!(aexpr, Node(0));
719 assert!(matches!(
720 arena.get(aexpr),
721 AExpr::Literal(LiteralValue::Int8(0))
722 ))
723}