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