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