1mod scalar;
2
3#[cfg(feature = "dtype-categorical")]
4mod categorical;
5
6use std::ops::{BitAnd, BitOr, Not};
7
8use arrow::array::BooleanArray;
9use arrow::bitmap::{Bitmap, BitmapBuilder};
10use num_traits::{NumCast, ToPrimitive};
11use polars_compute::comparisons::{TotalEqKernel, TotalOrdKernel};
12
13use crate::prelude::*;
14use crate::series::IsSorted;
15use crate::series::implementations::null::NullChunked;
16use crate::utils::align_chunks_binary;
17
18impl<T> ChunkCompareEq<&ChunkedArray<T>> for ChunkedArray<T>
19where
20 T: PolarsNumericType,
21 T::Array: TotalOrdKernel<Scalar = T::Native> + TotalEqKernel<Scalar = T::Native>,
22{
23 type Item = BooleanChunked;
24
25 fn equal(&self, rhs: &ChunkedArray<T>) -> BooleanChunked {
26 match (self.len(), rhs.len()) {
28 (_, 1) => {
29 if let Some(value) = rhs.get(0) {
30 self.equal(value)
31 } else {
32 BooleanChunked::full_null(PlSmallStr::EMPTY, self.len())
33 }
34 },
35 (1, _) => {
36 if let Some(value) = self.get(0) {
37 rhs.equal(value)
38 } else {
39 BooleanChunked::full_null(PlSmallStr::EMPTY, rhs.len())
40 }
41 },
42 _ => arity::binary_mut_values(
43 self,
44 rhs,
45 |a, b| a.tot_eq_kernel(b).into(),
46 PlSmallStr::EMPTY,
47 ),
48 }
49 }
50
51 fn equal_missing(&self, rhs: &ChunkedArray<T>) -> BooleanChunked {
52 match (self.len(), rhs.len()) {
54 (_, 1) => {
55 if let Some(value) = rhs.get(0) {
56 self.equal_missing(value)
57 } else {
58 self.is_null()
59 }
60 },
61 (1, _) => {
62 if let Some(value) = self.get(0) {
63 rhs.equal_missing(value)
64 } else {
65 rhs.is_null()
66 }
67 },
68 _ => arity::binary_mut_with_options(
69 self,
70 rhs,
71 |a, b| a.tot_eq_missing_kernel(b).into(),
72 PlSmallStr::EMPTY,
73 ),
74 }
75 }
76
77 fn not_equal(&self, rhs: &ChunkedArray<T>) -> BooleanChunked {
78 match (self.len(), rhs.len()) {
80 (_, 1) => {
81 if let Some(value) = rhs.get(0) {
82 self.not_equal(value)
83 } else {
84 BooleanChunked::full_null(PlSmallStr::EMPTY, self.len())
85 }
86 },
87 (1, _) => {
88 if let Some(value) = self.get(0) {
89 rhs.not_equal(value)
90 } else {
91 BooleanChunked::full_null(PlSmallStr::EMPTY, rhs.len())
92 }
93 },
94 _ => arity::binary_mut_values(
95 self,
96 rhs,
97 |a, b| a.tot_ne_kernel(b).into(),
98 PlSmallStr::EMPTY,
99 ),
100 }
101 }
102
103 fn not_equal_missing(&self, rhs: &ChunkedArray<T>) -> BooleanChunked {
104 match (self.len(), rhs.len()) {
106 (_, 1) => {
107 if let Some(value) = rhs.get(0) {
108 self.not_equal_missing(value)
109 } else {
110 self.is_not_null()
111 }
112 },
113 (1, _) => {
114 if let Some(value) = self.get(0) {
115 rhs.not_equal_missing(value)
116 } else {
117 rhs.is_not_null()
118 }
119 },
120 _ => arity::binary_mut_with_options(
121 self,
122 rhs,
123 |a, b| a.tot_ne_missing_kernel(b).into(),
124 PlSmallStr::EMPTY,
125 ),
126 }
127 }
128}
129
130impl<T> ChunkCompareIneq<&ChunkedArray<T>> for ChunkedArray<T>
131where
132 T: PolarsNumericType,
133 T::Array: TotalOrdKernel<Scalar = T::Native> + TotalEqKernel<Scalar = T::Native>,
134{
135 type Item = BooleanChunked;
136
137 fn lt(&self, rhs: &ChunkedArray<T>) -> BooleanChunked {
138 match (self.len(), rhs.len()) {
140 (_, 1) => {
141 if let Some(value) = rhs.get(0) {
142 self.lt(value)
143 } else {
144 BooleanChunked::full_null(PlSmallStr::EMPTY, self.len())
145 }
146 },
147 (1, _) => {
148 if let Some(value) = self.get(0) {
149 rhs.gt(value)
150 } else {
151 BooleanChunked::full_null(PlSmallStr::EMPTY, rhs.len())
152 }
153 },
154 _ => arity::binary_mut_values(
155 self,
156 rhs,
157 |a, b| a.tot_lt_kernel(b).into(),
158 PlSmallStr::EMPTY,
159 ),
160 }
161 }
162
163 fn lt_eq(&self, rhs: &ChunkedArray<T>) -> BooleanChunked {
164 match (self.len(), rhs.len()) {
166 (_, 1) => {
167 if let Some(value) = rhs.get(0) {
168 self.lt_eq(value)
169 } else {
170 BooleanChunked::full_null(PlSmallStr::EMPTY, self.len())
171 }
172 },
173 (1, _) => {
174 if let Some(value) = self.get(0) {
175 rhs.gt_eq(value)
176 } else {
177 BooleanChunked::full_null(PlSmallStr::EMPTY, rhs.len())
178 }
179 },
180 _ => arity::binary_mut_values(
181 self,
182 rhs,
183 |a, b| a.tot_le_kernel(b).into(),
184 PlSmallStr::EMPTY,
185 ),
186 }
187 }
188
189 fn gt(&self, rhs: &Self) -> BooleanChunked {
190 rhs.lt(self)
191 }
192
193 fn gt_eq(&self, rhs: &Self) -> BooleanChunked {
194 rhs.lt_eq(self)
195 }
196}
197
198impl ChunkCompareEq<&NullChunked> for NullChunked {
199 type Item = BooleanChunked;
200
201 fn equal(&self, rhs: &NullChunked) -> Self::Item {
202 BooleanChunked::full_null(self.name().clone(), get_broadcast_length(self, rhs))
203 }
204
205 fn equal_missing(&self, rhs: &NullChunked) -> Self::Item {
206 BooleanChunked::full(self.name().clone(), true, get_broadcast_length(self, rhs))
207 }
208
209 fn not_equal(&self, rhs: &NullChunked) -> Self::Item {
210 BooleanChunked::full_null(self.name().clone(), get_broadcast_length(self, rhs))
211 }
212
213 fn not_equal_missing(&self, rhs: &NullChunked) -> Self::Item {
214 BooleanChunked::full(self.name().clone(), false, get_broadcast_length(self, rhs))
215 }
216}
217
218impl ChunkCompareIneq<&NullChunked> for NullChunked {
219 type Item = BooleanChunked;
220
221 fn gt(&self, rhs: &NullChunked) -> Self::Item {
222 BooleanChunked::full_null(self.name().clone(), get_broadcast_length(self, rhs))
223 }
224
225 fn gt_eq(&self, rhs: &NullChunked) -> Self::Item {
226 BooleanChunked::full_null(self.name().clone(), get_broadcast_length(self, rhs))
227 }
228
229 fn lt(&self, rhs: &NullChunked) -> Self::Item {
230 BooleanChunked::full_null(self.name().clone(), get_broadcast_length(self, rhs))
231 }
232
233 fn lt_eq(&self, rhs: &NullChunked) -> Self::Item {
234 BooleanChunked::full_null(self.name().clone(), get_broadcast_length(self, rhs))
235 }
236}
237
238#[inline]
239fn get_broadcast_length(lhs: &NullChunked, rhs: &NullChunked) -> usize {
240 match (lhs.len(), rhs.len()) {
241 (1, len_r) => len_r,
242 (len_l, 1) => len_l,
243 (len_l, len_r) if len_l == len_r => len_l,
244 _ => panic!("Cannot compare two series of different lengths."),
245 }
246}
247
248impl ChunkCompareEq<&BooleanChunked> for BooleanChunked {
249 type Item = BooleanChunked;
250
251 fn equal(&self, rhs: &BooleanChunked) -> BooleanChunked {
252 match (self.len(), rhs.len()) {
254 (_, 1) => {
255 if let Some(value) = rhs.get(0) {
256 arity::unary_mut_values(self, |arr| arr.tot_eq_kernel_broadcast(&value).into())
257 } else {
258 BooleanChunked::full_null(PlSmallStr::EMPTY, self.len())
259 }
260 },
261 (1, _) => {
262 if let Some(value) = self.get(0) {
263 arity::unary_mut_values(rhs, |arr| arr.tot_eq_kernel_broadcast(&value).into())
264 } else {
265 BooleanChunked::full_null(PlSmallStr::EMPTY, rhs.len())
266 }
267 },
268 _ => arity::binary_mut_values(
269 self,
270 rhs,
271 |a, b| a.tot_eq_kernel(b).into(),
272 PlSmallStr::EMPTY,
273 ),
274 }
275 }
276
277 fn equal_missing(&self, rhs: &BooleanChunked) -> BooleanChunked {
278 match (self.len(), rhs.len()) {
280 (_, 1) => {
281 if let Some(value) = rhs.get(0) {
282 arity::unary_mut_with_options(self, |arr| {
283 arr.tot_eq_missing_kernel_broadcast(&value).into()
284 })
285 } else {
286 self.is_null()
287 }
288 },
289 (1, _) => {
290 if let Some(value) = self.get(0) {
291 arity::unary_mut_with_options(rhs, |arr| {
292 arr.tot_eq_missing_kernel_broadcast(&value).into()
293 })
294 } else {
295 rhs.is_null()
296 }
297 },
298 _ => arity::binary_mut_with_options(
299 self,
300 rhs,
301 |a, b| a.tot_eq_missing_kernel(b).into(),
302 PlSmallStr::EMPTY,
303 ),
304 }
305 }
306
307 fn not_equal(&self, rhs: &BooleanChunked) -> BooleanChunked {
308 match (self.len(), rhs.len()) {
310 (_, 1) => {
311 if let Some(value) = rhs.get(0) {
312 arity::unary_mut_values(self, |arr| arr.tot_ne_kernel_broadcast(&value).into())
313 } else {
314 BooleanChunked::full_null(PlSmallStr::EMPTY, self.len())
315 }
316 },
317 (1, _) => {
318 if let Some(value) = self.get(0) {
319 arity::unary_mut_values(rhs, |arr| arr.tot_ne_kernel_broadcast(&value).into())
320 } else {
321 BooleanChunked::full_null(PlSmallStr::EMPTY, rhs.len())
322 }
323 },
324 _ => arity::binary_mut_values(
325 self,
326 rhs,
327 |a, b| a.tot_ne_kernel(b).into(),
328 PlSmallStr::EMPTY,
329 ),
330 }
331 }
332
333 fn not_equal_missing(&self, rhs: &BooleanChunked) -> BooleanChunked {
334 match (self.len(), rhs.len()) {
336 (_, 1) => {
337 if let Some(value) = rhs.get(0) {
338 arity::unary_mut_with_options(self, |arr| {
339 arr.tot_ne_missing_kernel_broadcast(&value).into()
340 })
341 } else {
342 self.is_not_null()
343 }
344 },
345 (1, _) => {
346 if let Some(value) = self.get(0) {
347 arity::unary_mut_with_options(rhs, |arr| {
348 arr.tot_ne_missing_kernel_broadcast(&value).into()
349 })
350 } else {
351 rhs.is_not_null()
352 }
353 },
354 _ => arity::binary_mut_with_options(
355 self,
356 rhs,
357 |a, b| a.tot_ne_missing_kernel(b).into(),
358 PlSmallStr::EMPTY,
359 ),
360 }
361 }
362}
363
364impl ChunkCompareIneq<&BooleanChunked> for BooleanChunked {
365 type Item = BooleanChunked;
366
367 fn lt(&self, rhs: &BooleanChunked) -> BooleanChunked {
368 match (self.len(), rhs.len()) {
370 (_, 1) => {
371 if let Some(value) = rhs.get(0) {
372 arity::unary_mut_values(self, |arr| arr.tot_lt_kernel_broadcast(&value).into())
373 } else {
374 BooleanChunked::full_null(PlSmallStr::EMPTY, self.len())
375 }
376 },
377 (1, _) => {
378 if let Some(value) = self.get(0) {
379 arity::unary_mut_values(rhs, |arr| arr.tot_gt_kernel_broadcast(&value).into())
380 } else {
381 BooleanChunked::full_null(PlSmallStr::EMPTY, rhs.len())
382 }
383 },
384 _ => arity::binary_mut_values(
385 self,
386 rhs,
387 |a, b| a.tot_lt_kernel(b).into(),
388 PlSmallStr::EMPTY,
389 ),
390 }
391 }
392
393 fn lt_eq(&self, rhs: &BooleanChunked) -> BooleanChunked {
394 match (self.len(), rhs.len()) {
396 (_, 1) => {
397 if let Some(value) = rhs.get(0) {
398 arity::unary_mut_values(self, |arr| arr.tot_le_kernel_broadcast(&value).into())
399 } else {
400 BooleanChunked::full_null(PlSmallStr::EMPTY, self.len())
401 }
402 },
403 (1, _) => {
404 if let Some(value) = self.get(0) {
405 arity::unary_mut_values(rhs, |arr| arr.tot_ge_kernel_broadcast(&value).into())
406 } else {
407 BooleanChunked::full_null(PlSmallStr::EMPTY, rhs.len())
408 }
409 },
410 _ => arity::binary_mut_values(
411 self,
412 rhs,
413 |a, b| a.tot_le_kernel(b).into(),
414 PlSmallStr::EMPTY,
415 ),
416 }
417 }
418
419 fn gt(&self, rhs: &Self) -> BooleanChunked {
420 rhs.lt(self)
421 }
422
423 fn gt_eq(&self, rhs: &Self) -> BooleanChunked {
424 rhs.lt_eq(self)
425 }
426}
427
428impl ChunkCompareEq<&StringChunked> for StringChunked {
429 type Item = BooleanChunked;
430
431 fn equal(&self, rhs: &StringChunked) -> BooleanChunked {
432 self.as_binary().equal(&rhs.as_binary())
433 }
434
435 fn equal_missing(&self, rhs: &StringChunked) -> BooleanChunked {
436 self.as_binary().equal_missing(&rhs.as_binary())
437 }
438
439 fn not_equal(&self, rhs: &StringChunked) -> BooleanChunked {
440 self.as_binary().not_equal(&rhs.as_binary())
441 }
442
443 fn not_equal_missing(&self, rhs: &StringChunked) -> BooleanChunked {
444 self.as_binary().not_equal_missing(&rhs.as_binary())
445 }
446}
447
448impl ChunkCompareIneq<&StringChunked> for StringChunked {
449 type Item = BooleanChunked;
450
451 fn gt(&self, rhs: &StringChunked) -> BooleanChunked {
452 self.as_binary().gt(&rhs.as_binary())
453 }
454
455 fn gt_eq(&self, rhs: &StringChunked) -> BooleanChunked {
456 self.as_binary().gt_eq(&rhs.as_binary())
457 }
458
459 fn lt(&self, rhs: &StringChunked) -> BooleanChunked {
460 self.as_binary().lt(&rhs.as_binary())
461 }
462
463 fn lt_eq(&self, rhs: &StringChunked) -> BooleanChunked {
464 self.as_binary().lt_eq(&rhs.as_binary())
465 }
466}
467
468macro_rules! binary_eq_ineq_impl {
469 ($($ca:ident),+) => {
470 $(
471 impl ChunkCompareEq<&$ca> for $ca {
472 type Item = BooleanChunked;
473
474 fn equal(&self, rhs: &$ca) -> BooleanChunked {
475 match (self.len(), rhs.len()) {
477 (_, 1) => {
478 if let Some(value) = rhs.get(0) {
479 self.equal(value)
480 } else {
481 BooleanChunked::full_null(PlSmallStr::EMPTY, self.len())
482 }
483 },
484 (1, _) => {
485 if let Some(value) = self.get(0) {
486 rhs.equal(value)
487 } else {
488 BooleanChunked::full_null(PlSmallStr::EMPTY, rhs.len())
489 }
490 },
491 _ => arity::binary_mut_values(
492 self,
493 rhs,
494 |a, b| a.tot_eq_kernel(b).into(),
495 PlSmallStr::EMPTY,
496 ),
497 }
498 }
499
500 fn equal_missing(&self, rhs: &$ca) -> BooleanChunked {
501 match (self.len(), rhs.len()) {
503 (_, 1) => {
504 if let Some(value) = rhs.get(0) {
505 self.equal_missing(value)
506 } else {
507 self.is_null()
508 }
509 },
510 (1, _) => {
511 if let Some(value) = self.get(0) {
512 rhs.equal_missing(value)
513 } else {
514 rhs.is_null()
515 }
516 },
517 _ => arity::binary_mut_with_options(
518 self,
519 rhs,
520 |a, b| a.tot_eq_missing_kernel(b).into(),
521 PlSmallStr::EMPTY,
522 ),
523 }
524 }
525
526 fn not_equal(&self, rhs: &$ca) -> BooleanChunked {
527 match (self.len(), rhs.len()) {
529 (_, 1) => {
530 if let Some(value) = rhs.get(0) {
531 self.not_equal(value)
532 } else {
533 BooleanChunked::full_null(PlSmallStr::EMPTY, self.len())
534 }
535 },
536 (1, _) => {
537 if let Some(value) = self.get(0) {
538 rhs.not_equal(value)
539 } else {
540 BooleanChunked::full_null(PlSmallStr::EMPTY, rhs.len())
541 }
542 },
543 _ => arity::binary_mut_values(
544 self,
545 rhs,
546 |a, b| a.tot_ne_kernel(b).into(),
547 PlSmallStr::EMPTY,
548 ),
549 }
550 }
551
552 fn not_equal_missing(&self, rhs: &$ca) -> BooleanChunked {
553 match (self.len(), rhs.len()) {
555 (_, 1) => {
556 if let Some(value) = rhs.get(0) {
557 self.not_equal_missing(value)
558 } else {
559 self.is_not_null()
560 }
561 },
562 (1, _) => {
563 if let Some(value) = self.get(0) {
564 rhs.not_equal_missing(value)
565 } else {
566 rhs.is_not_null()
567 }
568 },
569 _ => arity::binary_mut_with_options(
570 self,
571 rhs,
572 |a, b| a.tot_ne_missing_kernel(b).into(),
573 PlSmallStr::EMPTY,
574 ),
575 }
576 }
577 }
578
579 impl ChunkCompareIneq<&$ca> for $ca {
580 type Item = BooleanChunked;
581
582 fn lt(&self, rhs: &$ca) -> BooleanChunked {
583 match (self.len(), rhs.len()) {
585 (_, 1) => {
586 if let Some(value) = rhs.get(0) {
587 self.lt(value)
588 } else {
589 BooleanChunked::full_null(PlSmallStr::EMPTY, self.len())
590 }
591 },
592 (1, _) => {
593 if let Some(value) = self.get(0) {
594 rhs.gt(value)
595 } else {
596 BooleanChunked::full_null(PlSmallStr::EMPTY, rhs.len())
597 }
598 },
599 _ => arity::binary_mut_values(
600 self,
601 rhs,
602 |a, b| a.tot_lt_kernel(b).into(),
603 PlSmallStr::EMPTY,
604 ),
605 }
606 }
607
608 fn lt_eq(&self, rhs: &$ca) -> BooleanChunked {
609 match (self.len(), rhs.len()) {
611 (_, 1) => {
612 if let Some(value) = rhs.get(0) {
613 self.lt_eq(value)
614 } else {
615 BooleanChunked::full_null(PlSmallStr::EMPTY, self.len())
616 }
617 },
618 (1, _) => {
619 if let Some(value) = self.get(0) {
620 rhs.gt_eq(value)
621 } else {
622 BooleanChunked::full_null(PlSmallStr::EMPTY, rhs.len())
623 }
624 },
625 _ => arity::binary_mut_values(
626 self,
627 rhs,
628 |a, b| a.tot_le_kernel(b).into(),
629 PlSmallStr::EMPTY,
630 ),
631 }
632 }
633
634 fn gt(&self, rhs: &Self) -> BooleanChunked {
635 rhs.lt(self)
636 }
637
638 fn gt_eq(&self, rhs: &Self) -> BooleanChunked {
639 rhs.lt_eq(self)
640 }
641 }
642 )+
643 };
644}
645
646binary_eq_ineq_impl!(BinaryChunked, BinaryOffsetChunked);
647
648fn _list_comparison_helper<F, B>(
649 lhs: &ListChunked,
650 rhs: &ListChunked,
651 op: F,
652 broadcast_op: B,
653 missing: bool,
654 is_ne: bool,
655) -> BooleanChunked
656where
657 F: Fn(&ListArray<i64>, &ListArray<i64>) -> Bitmap,
658 B: Fn(&ListArray<i64>, &Box<dyn Array>) -> Bitmap,
659{
660 match (lhs.len(), rhs.len()) {
661 (_, 1) => {
662 let right = rhs
663 .downcast_iter()
664 .find(|x| !x.is_empty())
665 .unwrap()
666 .as_any()
667 .downcast_ref::<ListArray<i64>>()
668 .unwrap();
669
670 if !right.validity().is_none_or(|v| v.get(0).unwrap()) {
671 if missing {
672 if is_ne {
673 return lhs.is_not_null();
674 } else {
675 return lhs.is_null();
676 }
677 } else {
678 return BooleanChunked::full_null(PlSmallStr::EMPTY, lhs.len());
679 }
680 }
681
682 let values = right.values().sliced(
683 (*right.offsets().first()).try_into().unwrap(),
684 right.offsets().range().try_into().unwrap(),
685 );
686
687 if missing {
688 arity::unary_mut_with_options(lhs, |a| broadcast_op(a, &values).into())
689 } else {
690 arity::unary_mut_values(lhs, |a| broadcast_op(a, &values).into())
691 }
692 },
693 (1, _) => {
694 let left = lhs
695 .downcast_iter()
696 .find(|x| !x.is_empty())
697 .unwrap()
698 .as_any()
699 .downcast_ref::<ListArray<i64>>()
700 .unwrap();
701
702 if !left.validity().is_none_or(|v| v.get(0).unwrap()) {
703 if missing {
704 if is_ne {
705 return rhs.is_not_null();
706 } else {
707 return rhs.is_null();
708 }
709 } else {
710 return BooleanChunked::full_null(PlSmallStr::EMPTY, rhs.len());
711 }
712 }
713
714 let values = left.values().sliced(
715 (*left.offsets().first()).try_into().unwrap(),
716 left.offsets().range().try_into().unwrap(),
717 );
718
719 if missing {
720 arity::unary_mut_with_options(rhs, |a| broadcast_op(a, &values).into())
721 } else {
722 arity::unary_mut_values(rhs, |a| broadcast_op(a, &values).into())
723 }
724 },
725 _ => {
726 if missing {
727 arity::binary_mut_with_options(lhs, rhs, |a, b| op(a, b).into(), PlSmallStr::EMPTY)
728 } else {
729 arity::binary_mut_values(lhs, rhs, |a, b| op(a, b).into(), PlSmallStr::EMPTY)
730 }
731 },
732 }
733}
734
735impl ChunkCompareEq<&ListChunked> for ListChunked {
736 type Item = BooleanChunked;
737 fn equal(&self, rhs: &ListChunked) -> BooleanChunked {
738 _list_comparison_helper(
739 self,
740 rhs,
741 TotalEqKernel::tot_eq_kernel,
742 TotalEqKernel::tot_eq_kernel_broadcast,
743 false,
744 false,
745 )
746 }
747
748 fn equal_missing(&self, rhs: &ListChunked) -> BooleanChunked {
749 _list_comparison_helper(
750 self,
751 rhs,
752 TotalEqKernel::tot_eq_missing_kernel,
753 TotalEqKernel::tot_eq_missing_kernel_broadcast,
754 true,
755 false,
756 )
757 }
758
759 fn not_equal(&self, rhs: &ListChunked) -> BooleanChunked {
760 _list_comparison_helper(
761 self,
762 rhs,
763 TotalEqKernel::tot_ne_kernel,
764 TotalEqKernel::tot_ne_kernel_broadcast,
765 false,
766 true,
767 )
768 }
769
770 fn not_equal_missing(&self, rhs: &ListChunked) -> BooleanChunked {
771 _list_comparison_helper(
772 self,
773 rhs,
774 TotalEqKernel::tot_ne_missing_kernel,
775 TotalEqKernel::tot_ne_missing_kernel_broadcast,
776 true,
777 true,
778 )
779 }
780}
781
782#[cfg(feature = "dtype-struct")]
783fn struct_helper<F, R>(
784 a: &StructChunked,
785 b: &StructChunked,
786 op: F,
787 reduce: R,
788 op_is_ne: bool,
789 is_missing: bool,
790) -> BooleanChunked
791where
792 F: Fn(&Series, &Series) -> BooleanChunked,
793 R: Fn(BooleanChunked, BooleanChunked) -> BooleanChunked,
794{
795 let len_a = a.len();
796 let len_b = b.len();
797 let broadcasts = len_a == 1 || len_b == 1;
798 if (a.len() != b.len() && !broadcasts) || a.struct_fields().len() != b.struct_fields().len() {
799 BooleanChunked::full(PlSmallStr::EMPTY, op_is_ne, a.len())
800 } else {
801 let (a, b) = align_chunks_binary(a, b);
802
803 let mut out = a
804 .fields_as_series()
805 .iter()
806 .zip(b.fields_as_series().iter())
807 .map(|(l, r)| op(l, r))
808 .reduce(&reduce)
809 .unwrap_or_else(|| BooleanChunked::full(PlSmallStr::EMPTY, !op_is_ne, a.len()));
810
811 if is_missing && (a.has_nulls() || b.has_nulls()) {
812 let default =
815 || BooleanChunked::with_chunk(PlSmallStr::EMPTY, BooleanArray::from_slice([true]));
816 let validity_to_ca = |x| unsafe {
817 BooleanChunked::with_chunk(
818 PlSmallStr::EMPTY,
819 BooleanArray::from_inner_unchecked(ArrowDataType::Boolean, x, None),
820 )
821 };
822
823 let a_s = a.rechunk_validity().map_or_else(default, validity_to_ca);
824 let b_s = b.rechunk_validity().map_or_else(default, validity_to_ca);
825
826 let shared_validity = (&a_s).bitand(&b_s);
827 let valid_nested = if op_is_ne {
828 (shared_validity).bitand(out)
829 } else {
830 (!shared_validity).bitor(out)
831 };
832 out = reduce(op(&a_s.into_series(), &b_s.into_series()), valid_nested);
833 }
834
835 if !is_missing && (a.has_nulls() || b.has_nulls()) {
836 let mut a = a;
837 let mut b = b;
838
839 if broadcasts {
840 if a.len() == 1 {
841 a = std::borrow::Cow::Owned(a.new_from_index(0, b.len()));
842 }
843 if b.len() == 1 {
844 b = std::borrow::Cow::Owned(b.new_from_index(0, a.len()));
845 }
846 }
847
848 let mut a = a.into_owned();
849 a.zip_outer_validity(&b);
850 unsafe {
851 let mut new_null_count = 0;
852 for (arr, a) in out.downcast_iter_mut().zip(a.downcast_iter()) {
853 arr.set_validity(a.validity().cloned());
854 new_null_count += arr.null_count();
855 }
856 out.set_null_count(new_null_count);
857 }
858 }
859
860 out
861 }
862}
863
864#[cfg(feature = "dtype-struct")]
865impl ChunkCompareEq<&StructChunked> for StructChunked {
866 type Item = BooleanChunked;
867 fn equal(&self, rhs: &StructChunked) -> BooleanChunked {
868 struct_helper(
869 self,
870 rhs,
871 |l, r| l.equal_missing(r).unwrap(),
872 |a, b| a.bitand(b),
873 false,
874 false,
875 )
876 }
877
878 fn equal_missing(&self, rhs: &StructChunked) -> BooleanChunked {
879 struct_helper(
880 self,
881 rhs,
882 |l, r| l.equal_missing(r).unwrap(),
883 |a, b| a.bitand(b),
884 false,
885 true,
886 )
887 }
888
889 fn not_equal(&self, rhs: &StructChunked) -> BooleanChunked {
890 struct_helper(
891 self,
892 rhs,
893 |l, r| l.not_equal_missing(r).unwrap(),
894 |a, b| a.bitor(b),
895 true,
896 false,
897 )
898 }
899
900 fn not_equal_missing(&self, rhs: &StructChunked) -> BooleanChunked {
901 struct_helper(
902 self,
903 rhs,
904 |l, r| l.not_equal_missing(r).unwrap(),
905 |a, b| a.bitor(b),
906 true,
907 true,
908 )
909 }
910}
911
912#[cfg(feature = "dtype-array")]
913fn _array_comparison_helper<F, B>(
914 lhs: &ArrayChunked,
915 rhs: &ArrayChunked,
916 op: F,
917 broadcast_op: B,
918 missing: bool,
919 is_ne: bool,
920) -> BooleanChunked
921where
922 F: Fn(&FixedSizeListArray, &FixedSizeListArray) -> Bitmap,
923 B: Fn(&FixedSizeListArray, &Box<dyn Array>) -> Bitmap,
924{
925 match (lhs.len(), rhs.len()) {
926 (_, 1) => {
927 let right = rhs
928 .downcast_iter()
929 .find(|x| !x.is_empty())
930 .unwrap()
931 .as_any()
932 .downcast_ref::<FixedSizeListArray>()
933 .unwrap();
934
935 if !right.validity().is_none_or(|v| v.get(0).unwrap()) {
936 if missing {
937 if is_ne {
938 return lhs.is_not_null();
939 } else {
940 return lhs.is_null();
941 }
942 } else {
943 return BooleanChunked::full_null(PlSmallStr::EMPTY, lhs.len());
944 }
945 }
946
947 if missing {
948 arity::unary_mut_with_options(lhs, |a| broadcast_op(a, right.values()).into())
949 } else {
950 arity::unary_mut_values(lhs, |a| broadcast_op(a, right.values()).into())
951 }
952 },
953 (1, _) => {
954 let left = lhs
955 .downcast_iter()
956 .find(|x| !x.is_empty())
957 .unwrap()
958 .as_any()
959 .downcast_ref::<FixedSizeListArray>()
960 .unwrap();
961
962 if !left.validity().is_none_or(|v| v.get(0).unwrap()) {
963 if missing {
964 if is_ne {
965 return rhs.is_not_null();
966 } else {
967 return rhs.is_null();
968 }
969 } else {
970 return BooleanChunked::full_null(PlSmallStr::EMPTY, rhs.len());
971 }
972 }
973
974 if missing {
975 arity::unary_mut_with_options(rhs, |a| broadcast_op(a, left.values()).into())
976 } else {
977 arity::unary_mut_values(rhs, |a| broadcast_op(a, left.values()).into())
978 }
979 },
980 _ => {
981 if missing {
982 arity::binary_mut_with_options(lhs, rhs, |a, b| op(a, b).into(), PlSmallStr::EMPTY)
983 } else {
984 arity::binary_mut_values(lhs, rhs, |a, b| op(a, b).into(), PlSmallStr::EMPTY)
985 }
986 },
987 }
988}
989
990#[cfg(feature = "dtype-array")]
991impl ChunkCompareEq<&ArrayChunked> for ArrayChunked {
992 type Item = BooleanChunked;
993 fn equal(&self, rhs: &ArrayChunked) -> BooleanChunked {
994 _array_comparison_helper(
995 self,
996 rhs,
997 TotalEqKernel::tot_eq_kernel,
998 TotalEqKernel::tot_eq_kernel_broadcast,
999 false,
1000 false,
1001 )
1002 }
1003
1004 fn equal_missing(&self, rhs: &ArrayChunked) -> BooleanChunked {
1005 _array_comparison_helper(
1006 self,
1007 rhs,
1008 TotalEqKernel::tot_eq_missing_kernel,
1009 TotalEqKernel::tot_eq_missing_kernel_broadcast,
1010 true,
1011 false,
1012 )
1013 }
1014
1015 fn not_equal(&self, rhs: &ArrayChunked) -> BooleanChunked {
1016 _array_comparison_helper(
1017 self,
1018 rhs,
1019 TotalEqKernel::tot_ne_kernel,
1020 TotalEqKernel::tot_ne_kernel_broadcast,
1021 false,
1022 true,
1023 )
1024 }
1025
1026 fn not_equal_missing(&self, rhs: &ArrayChunked) -> Self::Item {
1027 _array_comparison_helper(
1028 self,
1029 rhs,
1030 TotalEqKernel::tot_ne_missing_kernel,
1031 TotalEqKernel::tot_ne_missing_kernel_broadcast,
1032 true,
1033 true,
1034 )
1035 }
1036}
1037
1038impl Not for &BooleanChunked {
1039 type Output = BooleanChunked;
1040
1041 fn not(self) -> Self::Output {
1042 let chunks = self.downcast_iter().map(polars_compute::boolean::not);
1043 ChunkedArray::from_chunk_iter(self.name().clone(), chunks)
1044 }
1045}
1046
1047impl Not for BooleanChunked {
1048 type Output = BooleanChunked;
1049
1050 fn not(self) -> Self::Output {
1051 (&self).not()
1052 }
1053}
1054
1055impl BooleanChunked {
1056 pub fn any(&self) -> bool {
1060 self.downcast_iter()
1061 .any(|a| polars_compute::boolean::any(a).unwrap_or(false))
1062 }
1063
1064 pub fn all(&self) -> bool {
1068 self.downcast_iter()
1069 .all(|a| polars_compute::boolean::all(a).unwrap_or(true))
1070 }
1071
1072 pub fn any_kleene(&self) -> Option<bool> {
1077 for arr in self.downcast_iter() {
1078 if let Some(true) = polars_compute::boolean::any(arr) {
1079 return Some(true);
1080 }
1081 }
1082 if self.has_nulls() { None } else { Some(false) }
1083 }
1084
1085 pub fn all_kleene(&self) -> Option<bool> {
1090 for arr in self.downcast_iter() {
1091 if let Some(false) = polars_compute::boolean::all(arr) {
1092 return Some(false);
1093 }
1094 }
1095 if self.has_nulls() { None } else { Some(true) }
1096 }
1097}
1098
1099pub(crate) trait ChunkEqualElement {
1101 unsafe fn equal_element(&self, _idx_self: usize, _idx_other: usize, _other: &Series) -> bool {
1108 unimplemented!()
1109 }
1110}
1111
1112impl<T> ChunkEqualElement for ChunkedArray<T>
1113where
1114 T: PolarsNumericType,
1115{
1116 unsafe fn equal_element(&self, idx_self: usize, idx_other: usize, other: &Series) -> bool {
1117 let ca_other = other.as_ref().as_ref();
1118 debug_assert!(self.dtype() == other.dtype());
1119 let ca_other = &*(ca_other as *const ChunkedArray<T>);
1120 self.get_unchecked(idx_self)
1122 .tot_eq(&ca_other.get_unchecked(idx_other))
1123 }
1124}
1125
1126impl ChunkEqualElement for BooleanChunked {
1127 unsafe fn equal_element(&self, idx_self: usize, idx_other: usize, other: &Series) -> bool {
1128 let ca_other = other.as_ref().as_ref();
1129 debug_assert!(self.dtype() == other.dtype());
1130 let ca_other = &*(ca_other as *const BooleanChunked);
1131 self.get_unchecked(idx_self) == ca_other.get_unchecked(idx_other)
1132 }
1133}
1134
1135impl ChunkEqualElement for StringChunked {
1136 unsafe fn equal_element(&self, idx_self: usize, idx_other: usize, other: &Series) -> bool {
1137 let ca_other = other.as_ref().as_ref();
1138 debug_assert!(self.dtype() == other.dtype());
1139 let ca_other = &*(ca_other as *const StringChunked);
1140 self.get_unchecked(idx_self) == ca_other.get_unchecked(idx_other)
1141 }
1142}
1143
1144impl ChunkEqualElement for BinaryChunked {
1145 unsafe fn equal_element(&self, idx_self: usize, idx_other: usize, other: &Series) -> bool {
1146 let ca_other = other.as_ref().as_ref();
1147 debug_assert!(self.dtype() == other.dtype());
1148 let ca_other = &*(ca_other as *const BinaryChunked);
1149 self.get_unchecked(idx_self) == ca_other.get_unchecked(idx_other)
1150 }
1151}
1152
1153impl ChunkEqualElement for BinaryOffsetChunked {
1154 unsafe fn equal_element(&self, idx_self: usize, idx_other: usize, other: &Series) -> bool {
1155 let ca_other = other.as_ref().as_ref();
1156 debug_assert!(self.dtype() == other.dtype());
1157 let ca_other = &*(ca_other as *const BinaryOffsetChunked);
1158 self.get_unchecked(idx_self) == ca_other.get_unchecked(idx_other)
1159 }
1160}
1161
1162impl ChunkEqualElement for ListChunked {}
1163#[cfg(feature = "dtype-array")]
1164impl ChunkEqualElement for ArrayChunked {}
1165
1166#[cfg(test)]
1167#[cfg_attr(feature = "nightly", allow(clippy::manual_repeat_n))] mod test {
1169 use std::iter::repeat_n;
1170
1171 use super::super::test::get_chunked_array;
1172 use crate::prelude::*;
1173
1174 pub(crate) fn create_two_chunked() -> (Int32Chunked, Int32Chunked) {
1175 let mut a1 = Int32Chunked::new(PlSmallStr::from_static("a"), &[1, 2, 3]);
1176 let a2 = Int32Chunked::new(PlSmallStr::from_static("a"), &[4, 5, 6]);
1177 let a3 = Int32Chunked::new(PlSmallStr::from_static("a"), &[1, 2, 3, 4, 5, 6]);
1178 a1.append(&a2).unwrap();
1179 (a1, a3)
1180 }
1181
1182 #[test]
1183 fn test_bitwise_ops() {
1184 let a = BooleanChunked::new(PlSmallStr::from_static("a"), &[true, false, false]);
1185 let b = BooleanChunked::new(
1186 PlSmallStr::from_static("b"),
1187 &[Some(true), Some(true), None],
1188 );
1189 assert_eq!(Vec::from(&a | &b), &[Some(true), Some(true), None]);
1190 assert_eq!(Vec::from(&a & &b), &[Some(true), Some(false), Some(false)]);
1191 assert_eq!(Vec::from(!b), &[Some(false), Some(false), None]);
1192 }
1193
1194 #[test]
1195 fn test_compare_chunk_diff() {
1196 let (a1, a2) = create_two_chunked();
1197
1198 assert_eq!(
1199 a1.equal(&a2).into_iter().collect::<Vec<_>>(),
1200 repeat_n(Some(true), 6).collect::<Vec<_>>()
1201 );
1202 assert_eq!(
1203 a2.equal(&a1).into_iter().collect::<Vec<_>>(),
1204 repeat_n(Some(true), 6).collect::<Vec<_>>()
1205 );
1206 assert_eq!(
1207 a1.not_equal(&a2).into_iter().collect::<Vec<_>>(),
1208 repeat_n(Some(false), 6).collect::<Vec<_>>()
1209 );
1210 assert_eq!(
1211 a2.not_equal(&a1).into_iter().collect::<Vec<_>>(),
1212 repeat_n(Some(false), 6).collect::<Vec<_>>()
1213 );
1214 assert_eq!(
1215 a1.gt(&a2).into_iter().collect::<Vec<_>>(),
1216 repeat_n(Some(false), 6).collect::<Vec<_>>()
1217 );
1218 assert_eq!(
1219 a2.gt(&a1).into_iter().collect::<Vec<_>>(),
1220 repeat_n(Some(false), 6).collect::<Vec<_>>()
1221 );
1222 assert_eq!(
1223 a1.gt_eq(&a2).into_iter().collect::<Vec<_>>(),
1224 repeat_n(Some(true), 6).collect::<Vec<_>>()
1225 );
1226 assert_eq!(
1227 a2.gt_eq(&a1).into_iter().collect::<Vec<_>>(),
1228 repeat_n(Some(true), 6).collect::<Vec<_>>()
1229 );
1230 assert_eq!(
1231 a1.lt_eq(&a2).into_iter().collect::<Vec<_>>(),
1232 repeat_n(Some(true), 6).collect::<Vec<_>>()
1233 );
1234 assert_eq!(
1235 a2.lt_eq(&a1).into_iter().collect::<Vec<_>>(),
1236 repeat_n(Some(true), 6).collect::<Vec<_>>()
1237 );
1238 assert_eq!(
1239 a1.lt(&a2).into_iter().collect::<Vec<_>>(),
1240 repeat_n(Some(false), 6).collect::<Vec<_>>()
1241 );
1242 assert_eq!(
1243 a2.lt(&a1).into_iter().collect::<Vec<_>>(),
1244 repeat_n(Some(false), 6).collect::<Vec<_>>()
1245 );
1246 }
1247
1248 #[test]
1249 fn test_equal_chunks() {
1250 let a1 = get_chunked_array();
1251 let a2 = get_chunked_array();
1252
1253 assert_eq!(
1254 a1.equal(&a2).into_iter().collect::<Vec<_>>(),
1255 repeat_n(Some(true), 3).collect::<Vec<_>>()
1256 );
1257 assert_eq!(
1258 a2.equal(&a1).into_iter().collect::<Vec<_>>(),
1259 repeat_n(Some(true), 3).collect::<Vec<_>>()
1260 );
1261 assert_eq!(
1262 a1.not_equal(&a2).into_iter().collect::<Vec<_>>(),
1263 repeat_n(Some(false), 3).collect::<Vec<_>>()
1264 );
1265 assert_eq!(
1266 a2.not_equal(&a1).into_iter().collect::<Vec<_>>(),
1267 repeat_n(Some(false), 3).collect::<Vec<_>>()
1268 );
1269 assert_eq!(
1270 a1.gt(&a2).into_iter().collect::<Vec<_>>(),
1271 repeat_n(Some(false), 3).collect::<Vec<_>>()
1272 );
1273 assert_eq!(
1274 a2.gt(&a1).into_iter().collect::<Vec<_>>(),
1275 repeat_n(Some(false), 3).collect::<Vec<_>>()
1276 );
1277 assert_eq!(
1278 a1.gt_eq(&a2).into_iter().collect::<Vec<_>>(),
1279 repeat_n(Some(true), 3).collect::<Vec<_>>()
1280 );
1281 assert_eq!(
1282 a2.gt_eq(&a1).into_iter().collect::<Vec<_>>(),
1283 repeat_n(Some(true), 3).collect::<Vec<_>>()
1284 );
1285 assert_eq!(
1286 a1.lt_eq(&a2).into_iter().collect::<Vec<_>>(),
1287 repeat_n(Some(true), 3).collect::<Vec<_>>()
1288 );
1289 assert_eq!(
1290 a2.lt_eq(&a1).into_iter().collect::<Vec<_>>(),
1291 repeat_n(Some(true), 3).collect::<Vec<_>>()
1292 );
1293 assert_eq!(
1294 a1.lt(&a2).into_iter().collect::<Vec<_>>(),
1295 repeat_n(Some(false), 3).collect::<Vec<_>>()
1296 );
1297 assert_eq!(
1298 a2.lt(&a1).into_iter().collect::<Vec<_>>(),
1299 repeat_n(Some(false), 3).collect::<Vec<_>>()
1300 );
1301 }
1302
1303 #[test]
1304 fn test_null_handling() {
1305 let a1: Int32Chunked = [Some(1), None, Some(3)].iter().copied().collect();
1311 let a2: Int32Chunked = [Some(1), Some(2), Some(3)].iter().copied().collect();
1312
1313 let mut a2_2chunks: Int32Chunked = [Some(1), Some(2)].iter().copied().collect();
1314 a2_2chunks
1315 .append(&[Some(3)].iter().copied().collect())
1316 .unwrap();
1317
1318 assert_eq!(
1319 a1.equal(&a2).into_iter().collect::<Vec<_>>(),
1320 a1.equal(&a2_2chunks).into_iter().collect::<Vec<_>>()
1321 );
1322
1323 assert_eq!(
1324 a1.not_equal(&a2).into_iter().collect::<Vec<_>>(),
1325 a1.not_equal(&a2_2chunks).into_iter().collect::<Vec<_>>()
1326 );
1327 assert_eq!(
1328 a1.not_equal(&a2).into_iter().collect::<Vec<_>>(),
1329 a2_2chunks.not_equal(&a1).into_iter().collect::<Vec<_>>()
1330 );
1331
1332 assert_eq!(
1333 a1.gt(&a2).into_iter().collect::<Vec<_>>(),
1334 a1.gt(&a2_2chunks).into_iter().collect::<Vec<_>>()
1335 );
1336 assert_eq!(
1337 a1.gt(&a2).into_iter().collect::<Vec<_>>(),
1338 a2_2chunks.gt(&a1).into_iter().collect::<Vec<_>>()
1339 );
1340
1341 assert_eq!(
1342 a1.gt_eq(&a2).into_iter().collect::<Vec<_>>(),
1343 a1.gt_eq(&a2_2chunks).into_iter().collect::<Vec<_>>()
1344 );
1345 assert_eq!(
1346 a1.gt_eq(&a2).into_iter().collect::<Vec<_>>(),
1347 a2_2chunks.gt_eq(&a1).into_iter().collect::<Vec<_>>()
1348 );
1349
1350 assert_eq!(
1351 a1.lt_eq(&a2).into_iter().collect::<Vec<_>>(),
1352 a1.lt_eq(&a2_2chunks).into_iter().collect::<Vec<_>>()
1353 );
1354 assert_eq!(
1355 a1.lt_eq(&a2).into_iter().collect::<Vec<_>>(),
1356 a2_2chunks.lt_eq(&a1).into_iter().collect::<Vec<_>>()
1357 );
1358
1359 assert_eq!(
1360 a1.lt(&a2).into_iter().collect::<Vec<_>>(),
1361 a1.lt(&a2_2chunks).into_iter().collect::<Vec<_>>()
1362 );
1363 assert_eq!(
1364 a1.lt(&a2).into_iter().collect::<Vec<_>>(),
1365 a2_2chunks.lt(&a1).into_iter().collect::<Vec<_>>()
1366 );
1367 }
1368
1369 #[test]
1370 fn test_left_right() {
1371 let a1: Int32Chunked = [Some(1), Some(2)].iter().copied().collect();
1374 let a1 = a1.slice(1, 1);
1375 let a2: Int32Chunked = [Some(2)].iter().copied().collect();
1376 assert_eq!(a1.equal(&a2).sum(), a2.equal(&a1).sum());
1377 assert_eq!(a1.not_equal(&a2).sum(), a2.not_equal(&a1).sum());
1378 assert_eq!(a1.gt(&a2).sum(), a2.gt(&a1).sum());
1379 assert_eq!(a1.lt(&a2).sum(), a2.lt(&a1).sum());
1380 assert_eq!(a1.lt_eq(&a2).sum(), a2.lt_eq(&a1).sum());
1381 assert_eq!(a1.gt_eq(&a2).sum(), a2.gt_eq(&a1).sum());
1382
1383 let a1: StringChunked = ["a", "b"].iter().copied().collect();
1384 let a1 = a1.slice(1, 1);
1385 let a2: StringChunked = ["b"].iter().copied().collect();
1386 assert_eq!(a1.equal(&a2).sum(), a2.equal(&a1).sum());
1387 assert_eq!(a1.not_equal(&a2).sum(), a2.not_equal(&a1).sum());
1388 assert_eq!(a1.gt(&a2).sum(), a2.gt(&a1).sum());
1389 assert_eq!(a1.lt(&a2).sum(), a2.lt(&a1).sum());
1390 assert_eq!(a1.lt_eq(&a2).sum(), a2.lt_eq(&a1).sum());
1391 assert_eq!(a1.gt_eq(&a2).sum(), a2.gt_eq(&a1).sum());
1392 }
1393
1394 #[test]
1395 fn test_kleene() {
1396 let a = BooleanChunked::new(PlSmallStr::EMPTY, &[Some(true), Some(false), None]);
1397 let trues = BooleanChunked::from_slice(PlSmallStr::EMPTY, &[true, true, true]);
1398 let falses = BooleanChunked::from_slice(PlSmallStr::EMPTY, &[false, false, false]);
1399
1400 let c = &a | &trues;
1401 assert_eq!(Vec::from(&c), &[Some(true), Some(true), Some(true)]);
1402
1403 let c = &a | &falses;
1404 assert_eq!(Vec::from(&c), &[Some(true), Some(false), None])
1405 }
1406
1407 #[test]
1408 fn list_broadcasting_lists() {
1409 let s_el = Series::new(PlSmallStr::EMPTY, &[1, 2, 3]);
1410 let s_lhs = Series::new(PlSmallStr::EMPTY, &[s_el.clone(), s_el.clone()]);
1411 let s_rhs = Series::new(PlSmallStr::EMPTY, std::slice::from_ref(&s_el));
1412
1413 let result = s_lhs.list().unwrap().equal(s_rhs.list().unwrap());
1414 assert_eq!(result.len(), 2);
1415 assert!(result.all());
1416 }
1417
1418 #[test]
1419 fn test_broadcasting_bools() {
1420 let a = BooleanChunked::from_slice(PlSmallStr::EMPTY, &[true, false, true]);
1421 let true_ = BooleanChunked::from_slice(PlSmallStr::EMPTY, &[true]);
1422 let false_ = BooleanChunked::from_slice(PlSmallStr::EMPTY, &[false]);
1423
1424 let out = a.equal(&true_);
1425 assert_eq!(Vec::from(&out), &[Some(true), Some(false), Some(true)]);
1426 let out = true_.equal(&a);
1427 assert_eq!(Vec::from(&out), &[Some(true), Some(false), Some(true)]);
1428 let out = a.equal(&false_);
1429 assert_eq!(Vec::from(&out), &[Some(false), Some(true), Some(false)]);
1430 let out = false_.equal(&a);
1431 assert_eq!(Vec::from(&out), &[Some(false), Some(true), Some(false)]);
1432
1433 let out = a.not_equal(&true_);
1434 assert_eq!(Vec::from(&out), &[Some(false), Some(true), Some(false)]);
1435 let out = true_.not_equal(&a);
1436 assert_eq!(Vec::from(&out), &[Some(false), Some(true), Some(false)]);
1437 let out = a.not_equal(&false_);
1438 assert_eq!(Vec::from(&out), &[Some(true), Some(false), Some(true)]);
1439 let out = false_.not_equal(&a);
1440 assert_eq!(Vec::from(&out), &[Some(true), Some(false), Some(true)]);
1441
1442 let out = a.gt(&true_);
1443 assert_eq!(Vec::from(&out), &[Some(false), Some(false), Some(false)]);
1444 let out = true_.gt(&a);
1445 assert_eq!(Vec::from(&out), &[Some(false), Some(true), Some(false)]);
1446 let out = a.gt(&false_);
1447 assert_eq!(Vec::from(&out), &[Some(true), Some(false), Some(true)]);
1448 let out = false_.gt(&a);
1449 assert_eq!(Vec::from(&out), &[Some(false), Some(false), Some(false)]);
1450
1451 let out = a.gt_eq(&true_);
1452 assert_eq!(Vec::from(&out), &[Some(true), Some(false), Some(true)]);
1453 let out = true_.gt_eq(&a);
1454 assert_eq!(Vec::from(&out), &[Some(true), Some(true), Some(true)]);
1455 let out = a.gt_eq(&false_);
1456 assert_eq!(Vec::from(&out), &[Some(true), Some(true), Some(true)]);
1457 let out = false_.gt_eq(&a);
1458 assert_eq!(Vec::from(&out), &[Some(false), Some(true), Some(false)]);
1459
1460 let out = a.lt(&true_);
1461 assert_eq!(Vec::from(&out), &[Some(false), Some(true), Some(false)]);
1462 let out = true_.lt(&a);
1463 assert_eq!(Vec::from(&out), &[Some(false), Some(false), Some(false)]);
1464 let out = a.lt(&false_);
1465 assert_eq!(Vec::from(&out), &[Some(false), Some(false), Some(false)]);
1466 let out = false_.lt(&a);
1467 assert_eq!(Vec::from(&out), &[Some(true), Some(false), Some(true)]);
1468
1469 let out = a.lt_eq(&true_);
1470 assert_eq!(Vec::from(&out), &[Some(true), Some(true), Some(true)]);
1471 let out = true_.lt_eq(&a);
1472 assert_eq!(Vec::from(&out), &[Some(true), Some(false), Some(true)]);
1473 let out = a.lt_eq(&false_);
1474 assert_eq!(Vec::from(&out), &[Some(false), Some(true), Some(false)]);
1475 let out = false_.lt_eq(&a);
1476 assert_eq!(Vec::from(&out), &[Some(true), Some(true), Some(true)]);
1477
1478 let a =
1479 BooleanChunked::from_slice_options(PlSmallStr::EMPTY, &[Some(true), Some(false), None]);
1480 let all_true = BooleanChunked::from_slice(PlSmallStr::EMPTY, &[true, true, true]);
1481 let all_false = BooleanChunked::from_slice(PlSmallStr::EMPTY, &[false, false, false]);
1482 let out = a.equal(&true_);
1483 assert_eq!(Vec::from(&out), &[Some(true), Some(false), None]);
1484 let out = a.not_equal(&true_);
1485 assert_eq!(Vec::from(&out), &[Some(false), Some(true), None]);
1486
1487 let out = a.equal(&all_true);
1488 assert_eq!(Vec::from(&out), &[Some(true), Some(false), None]);
1489 let out = a.not_equal(&all_true);
1490 assert_eq!(Vec::from(&out), &[Some(false), Some(true), None]);
1491 let out = a.equal(&false_);
1492 assert_eq!(Vec::from(&out), &[Some(false), Some(true), None]);
1493 let out = a.not_equal(&false_);
1494 assert_eq!(Vec::from(&out), &[Some(true), Some(false), None]);
1495 let out = a.equal(&all_false);
1496 assert_eq!(Vec::from(&out), &[Some(false), Some(true), None]);
1497 let out = a.not_equal(&all_false);
1498 assert_eq!(Vec::from(&out), &[Some(true), Some(false), None]);
1499 }
1500
1501 #[test]
1502 fn test_broadcasting_numeric() {
1503 let a = Int32Chunked::from_slice(PlSmallStr::EMPTY, &[1, 2, 3]);
1504 let one = Int32Chunked::from_slice(PlSmallStr::EMPTY, &[1]);
1505 let three = Int32Chunked::from_slice(PlSmallStr::EMPTY, &[3]);
1506
1507 let out = a.equal(&one);
1508 assert_eq!(Vec::from(&out), &[Some(true), Some(false), Some(false)]);
1509 let out = one.equal(&a);
1510 assert_eq!(Vec::from(&out), &[Some(true), Some(false), Some(false)]);
1511 let out = a.equal(&three);
1512 assert_eq!(Vec::from(&out), &[Some(false), Some(false), Some(true)]);
1513 let out = three.equal(&a);
1514 assert_eq!(Vec::from(&out), &[Some(false), Some(false), Some(true)]);
1515
1516 let out = a.not_equal(&one);
1517 assert_eq!(Vec::from(&out), &[Some(false), Some(true), Some(true)]);
1518 let out = one.not_equal(&a);
1519 assert_eq!(Vec::from(&out), &[Some(false), Some(true), Some(true)]);
1520 let out = a.not_equal(&three);
1521 assert_eq!(Vec::from(&out), &[Some(true), Some(true), Some(false)]);
1522 let out = three.not_equal(&a);
1523 assert_eq!(Vec::from(&out), &[Some(true), Some(true), Some(false)]);
1524
1525 let out = a.gt(&one);
1526 assert_eq!(Vec::from(&out), &[Some(false), Some(true), Some(true)]);
1527 let out = one.gt(&a);
1528 assert_eq!(Vec::from(&out), &[Some(false), Some(false), Some(false)]);
1529 let out = a.gt(&three);
1530 assert_eq!(Vec::from(&out), &[Some(false), Some(false), Some(false)]);
1531 let out = three.gt(&a);
1532 assert_eq!(Vec::from(&out), &[Some(true), Some(true), Some(false)]);
1533
1534 let out = a.lt(&one);
1535 assert_eq!(Vec::from(&out), &[Some(false), Some(false), Some(false)]);
1536 let out = one.lt(&a);
1537 assert_eq!(Vec::from(&out), &[Some(false), Some(true), Some(true)]);
1538 let out = a.lt(&three);
1539 assert_eq!(Vec::from(&out), &[Some(true), Some(true), Some(false)]);
1540 let out = three.lt(&a);
1541 assert_eq!(Vec::from(&out), &[Some(false), Some(false), Some(false)]);
1542
1543 let out = a.gt_eq(&one);
1544 assert_eq!(Vec::from(&out), &[Some(true), Some(true), Some(true)]);
1545 let out = one.gt_eq(&a);
1546 assert_eq!(Vec::from(&out), &[Some(true), Some(false), Some(false)]);
1547 let out = a.gt_eq(&three);
1548 assert_eq!(Vec::from(&out), &[Some(false), Some(false), Some(true)]);
1549 let out = three.gt_eq(&a);
1550 assert_eq!(Vec::from(&out), &[Some(true), Some(true), Some(true)]);
1551
1552 let out = a.lt_eq(&one);
1553 assert_eq!(Vec::from(&out), &[Some(true), Some(false), Some(false)]);
1554 let out = one.lt_eq(&a);
1555 assert_eq!(Vec::from(&out), &[Some(true), Some(true), Some(true)]);
1556 let out = a.lt_eq(&three);
1557 assert_eq!(Vec::from(&out), &[Some(true), Some(true), Some(true)]);
1558 let out = three.lt_eq(&a);
1559 assert_eq!(Vec::from(&out), &[Some(false), Some(false), Some(true)]);
1560 }
1561}