1use std::collections::{BTreeMap, BTreeSet};
5use std::sync::Arc;
6use std::time::Duration;
7
8use arrow_array::cast::AsArray;
9use arrow_array::types::{Float16Type, Float32Type, Float64Type};
10use arrow_array::{
11 new_null_array, Array, ArrayRef, ArrowPrimitiveType, Decimal128Array, Float64Array,
12 RecordBatch, RecordBatchOptions, UInt64Array,
13};
14use arrow_schema::{DataType, Field, Schema};
15use arrow_select::interleave::interleave;
16
17use crate::bucket::{float_starts, whole_starts, Bucket};
18use crate::dictionary::dictionary_index;
19use crate::filter::{resolve, Filter, Predicate};
20use crate::sorted::{Entry, SortedRows};
21use crate::value::{canonical, prefix, unscale, Kind, Value, ValueFn};
22use crate::view::{entry, entry_order, Rows, SortColumn};
23use crate::window::Span;
24use crate::{DataError, RowId, RowRef};
25
26const DECIMAL_LIMIT: u128 = 10u128.pow(38);
28
29const fn power_of_two(exponent: i32) -> f64 {
31 f64::from_bits(((1023 + exponent) as u64) << 52)
32}
33
34const HUGE: f64 = power_of_two(960);
38const UNSCALE: f64 = power_of_two(-128);
39const SCALE: f64 = power_of_two(128);
40
41#[derive(Debug, Clone, PartialEq, Eq)]
43enum Function {
44 Count,
45 Sum(String),
46 Min(String),
47 Max(String),
48 Mean(String),
49}
50
51#[derive(Debug, Clone, PartialEq, Eq)]
54pub struct Aggregate {
55 function: Function,
56 name: Option<String>,
57}
58
59impl Aggregate {
60 #[must_use]
62 pub fn count() -> Self {
63 Self::of(Function::Count)
64 }
65
66 #[must_use]
72 pub fn sum(column: impl Into<String>) -> Self {
73 Self::of(Function::Sum(column.into()))
74 }
75
76 #[must_use]
79 pub fn min(column: impl Into<String>) -> Self {
80 Self::of(Function::Min(column.into()))
81 }
82
83 #[must_use]
86 pub fn max(column: impl Into<String>) -> Self {
87 Self::of(Function::Max(column.into()))
88 }
89
90 #[must_use]
93 pub fn mean(column: impl Into<String>) -> Self {
94 Self::of(Function::Mean(column.into()))
95 }
96
97 #[must_use]
99 pub fn named(mut self, name: impl Into<String>) -> Self {
100 self.name = Some(name.into());
101 self
102 }
103
104 fn of(function: Function) -> Self {
105 Self {
106 function,
107 name: None,
108 }
109 }
110
111 fn name(&self) -> String {
112 if let Some(name) = &self.name {
113 return name.clone();
114 }
115 let (function, column) = match &self.function {
116 Function::Count => return "count".to_owned(),
117 Function::Sum(column) => ("sum", column),
118 Function::Min(column) => ("min", column),
119 Function::Max(column) => ("max", column),
120 Function::Mean(column) => ("mean", column),
121 };
122 format!("{function}({column})")
123 }
124}
125
126#[derive(Debug, Clone, Default, PartialEq)]
156pub struct GroupSpec {
157 keys: Vec<KeySpec>,
158 aggregates: Vec<Aggregate>,
159 filter: Option<Filter>,
160}
161
162impl GroupSpec {
163 #[must_use]
166 pub fn new() -> Self {
167 Self::default()
168 }
169
170 #[must_use]
174 pub fn group_by(self, column: impl Into<String>) -> Self {
175 self.key(column, None)
176 }
177
178 #[must_use]
223 pub fn group_by_time(self, column: impl Into<String>, every: Duration) -> Self {
224 self.key(column, Some(Span::Duration(every)))
225 }
226
227 #[must_use]
245 pub fn group_by_step(self, column: impl Into<String>, step: f64) -> Self {
246 self.key(column, Some(Span::Value(step)))
247 }
248
249 fn key(mut self, column: impl Into<String>, bucket: Option<Span>) -> Self {
250 self.keys.push(KeySpec {
251 column: column.into(),
252 bucket,
253 });
254 self
255 }
256
257 #[must_use]
259 pub fn aggregate(mut self, aggregate: Aggregate) -> Self {
260 self.aggregates.push(aggregate);
261 self
262 }
263
264 #[must_use]
266 pub fn filter(mut self, filter: Filter) -> Self {
267 self.filter = Some(filter);
268 self
269 }
270}
271
272#[derive(Debug, Clone, PartialEq)]
274struct KeySpec {
275 column: String,
276 bucket: Option<Span>,
277}
278
279#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
282enum Part {
283 Bool(bool),
284 Int(i64),
285 UInt(u64),
286 Decimal(i128),
287 Float(u64),
289 Str(Box<str>),
290 Null,
291}
292
293impl Part {
294 fn of(value: Value<'_>) -> Self {
295 match value {
296 Value::Null => Self::Null,
297 Value::Bool(v) => Self::Bool(v),
298 Value::Int(v) => Self::Int(v),
299 Value::UInt(v) => Self::UInt(v),
300 Value::Decimal(v) => Self::Decimal(v),
301 Value::Float(_) => Self::Float(prefix(value, false)),
302 Value::Str(v) => Self::Str(v.into()),
303 }
304 }
305}
306
307fn from_prefix(bits: u64) -> f64 {
309 const SIGN: u64 = 1 << 63;
310 f64::from_bits(if bits & SIGN != 0 {
311 bits & !SIGN
312 } else {
313 !bits
314 })
315}
316
317#[derive(Debug, Clone)]
319struct Source {
320 column: usize,
321 read: ValueFn,
322 kind: Kind,
323 data_type: DataType,
324 name: String,
325}
326
327impl Source {
328 fn new(schema: &Schema, name: &str) -> Result<Self, DataError> {
329 let (column, kind, read) = resolve(schema, name)?;
330 Ok(Self {
331 column,
332 read,
333 kind,
334 data_type: schema.field(column).data_type().clone(),
335 name: name.to_owned(),
336 })
337 }
338
339 fn read<'a>(&self, batches: &'a [RecordBatch], at: RowRef) -> Value<'a> {
340 (self.read)(batches[at.batch].column(self.column).as_ref(), at.row)
341 }
342
343 fn output_type(&self) -> &DataType {
346 match &self.data_type {
347 DataType::Dictionary(_, values) => values,
348 other => other,
349 }
350 }
351}
352
353#[derive(Debug, Clone)]
355struct Key {
356 source: Source,
357 bucket: Option<Bucket>,
358}
359
360impl Key {
361 fn new(schema: &Schema, spec: &KeySpec) -> Result<Self, DataError> {
362 let source = Source::new(schema, &spec.column)?;
363 let bucket = spec
364 .bucket
365 .map(|width| {
366 Bucket::new(width, &source.data_type, source.kind)
367 .ok_or_else(|| DataError::BucketWidth(spec.column.clone()))
368 })
369 .transpose()?;
370 Ok(Self { source, bucket })
371 }
372
373 fn part(&self, batches: &[RecordBatch], at: RowRef) -> Part {
374 let value = self.source.read(batches, at);
375 Part::of(match &self.bucket {
376 Some(bucket) => bucket.start(value),
377 None => value,
378 })
379 }
380}
381
382#[derive(Debug, Clone, Copy, PartialEq, Eq)]
384enum Numeric {
385 Integer,
386 Decimal { scale: i8 },
387 Float,
388}
389
390impl Numeric {
391 fn of(data_type: &DataType) -> Option<Self> {
392 Some(match data_type {
393 DataType::Decimal128(_, scale) => Self::Decimal { scale: *scale },
394 t if t.is_integer() => Self::Integer,
395 t if t.is_floating() => Self::Float,
396 _ => return None,
397 })
398 }
399}
400
401#[derive(Debug, Clone)]
404enum Track {
405 Sum(Numeric),
406 Order(SortColumn),
407}
408
409#[derive(Debug, Clone)]
410struct Tracker {
411 source: Source,
412 track: Track,
413}
414
415impl Tracker {
416 fn apply(&self, state: &mut State, rows: Rows<'_>, id: RowId, at: RowRef, sign: i8) {
418 match (&self.track, state, self.source.read(rows.batches, at)) {
419 (_, _, Value::Null) => {}
420 (Track::Order(column), State::Ordered(sorted), _) => {
421 let sort = std::slice::from_ref(column);
422 let probe = entry(sort, rows.batches, id, at);
423 let order = |other: Entry| entry_order(sort, rows, other, probe, at);
424 if sign > 0 {
425 sorted.insert(probe, order);
426 } else {
427 let found = sorted.remove(id, order);
428 debug_assert!(found, "a counted value is among the sorted values");
429 }
430 }
431 (_, State::Exact(sum), Value::Int(v)) => sum.apply(i128::from(v), sign),
432 (_, State::Exact(sum), Value::UInt(v)) => sum.apply(i128::from(v), sign),
433 (_, State::Exact(sum), Value::Decimal(v)) => sum.apply(v, sign),
434 (_, State::Float(sum), Value::Float(v)) => sum.apply(v, sign),
435 _ => debug_assert!(false, "a tracker's state does not fit its column"),
436 }
437 }
438}
439
440fn step(count: u64, sign: i8) -> u64 {
442 if sign > 0 {
443 count + 1
444 } else {
445 count - 1
446 }
447}
448
449#[derive(Debug, Clone, Copy, Default)]
452struct ExactSum {
453 sum: i128,
454 carry: i64,
455 values: u64,
456}
457
458impl ExactSum {
459 fn apply(&mut self, value: i128, sign: i8) {
460 let (sum, wrapped) = if sign > 0 {
461 self.sum.overflowing_add(value)
462 } else {
463 self.sum.overflowing_sub(value)
464 };
465 if wrapped {
466 self.carry += if (sign > 0) == (value > 0) { 1 } else { -1 };
468 }
469 self.sum = sum;
470 self.values = step(self.values, sign);
471 }
472
473 fn total(&self) -> Option<i128> {
475 (self.values > 0 && self.carry == 0).then_some(self.sum)
476 }
477
478 fn mean(&self) -> Option<f64> {
479 let total = self.sum as f64 + self.carry as f64 * SCALE;
481 (self.values > 0).then(|| total / self.values as f64)
482 }
483}
484
485#[derive(Debug, Clone, Copy, Default)]
487struct Compensated {
488 sum: f64,
489 compensation: f64,
490 values: u64,
491}
492
493impl Compensated {
494 fn apply(&mut self, value: f64, sign: i8) {
495 self.values = step(self.values, sign);
496 if self.values == 0 {
497 *self = Self::default();
499 return;
500 }
501 let value = if sign > 0 { value } else { -value };
502 let total = self.sum + value;
503 if self.sum.abs() >= value.abs() {
504 self.compensation += (self.sum - total) + value;
505 } else {
506 self.compensation += (value - total) + self.sum;
507 }
508 self.sum = total;
509 }
510
511 fn total(&self) -> f64 {
512 self.sum + self.compensation
513 }
514}
515
516#[derive(Debug, Clone, Copy, Default)]
519struct FloatSum {
520 normal: Compensated,
521 huge: Compensated,
523 nan: u64,
524 infinity: u64,
525 negative_infinity: u64,
526}
527
528impl FloatSum {
529 fn apply(&mut self, value: f64, sign: i8) {
530 if value.is_nan() {
531 self.nan = step(self.nan, sign);
532 } else if value == f64::INFINITY {
533 self.infinity = step(self.infinity, sign);
534 } else if value == f64::NEG_INFINITY {
535 self.negative_infinity = step(self.negative_infinity, sign);
536 } else if value.abs() >= HUGE {
537 self.huge.apply(value * UNSCALE, sign);
538 } else {
539 self.normal.apply(value, sign);
540 }
541 }
542
543 fn values(&self) -> u64 {
544 self.normal.values + self.huge.values + self.nan + self.infinity + self.negative_infinity
545 }
546
547 fn sum(&self) -> Option<f64> {
548 (self.values() > 0).then(|| self.divided(1.0))
549 }
550
551 fn mean(&self) -> Option<f64> {
552 let values = self.values();
553 (values > 0).then(|| self.divided(values as f64))
554 }
555
556 fn divided(&self, divisor: f64) -> f64 {
558 if self.nan > 0 || (self.infinity > 0 && self.negative_infinity > 0) {
559 return f64::NAN;
560 }
561 if self.infinity > 0 {
562 return f64::INFINITY;
563 }
564 if self.negative_infinity > 0 {
565 return f64::NEG_INFINITY;
566 }
567 let normal = self.normal.total() / divisor;
568 let huge = self.huge.total() / divisor;
569 if huge == 0.0 {
570 normal
571 } else {
572 (huge + normal * UNSCALE) * SCALE
573 }
574 }
575}
576
577#[derive(Debug, Clone)]
579enum State {
580 Exact(ExactSum),
581 Float(FloatSum),
582 Ordered(SortedRows),
584}
585
586impl State {
587 fn new(track: &Track) -> Self {
588 match track {
589 Track::Sum(Numeric::Float) => Self::Float(FloatSum::default()),
590 Track::Sum(_) => Self::Exact(ExactSum::default()),
591 Track::Order(_) => Self::Ordered(SortedRows::default()),
592 }
593 }
594
595 fn exact(&self) -> Option<&ExactSum> {
596 match self {
597 Self::Exact(sum) => Some(sum),
598 _ => None,
599 }
600 }
601
602 fn float(&self) -> Option<&FloatSum> {
603 match self {
604 Self::Float(sum) => Some(sum),
605 _ => None,
606 }
607 }
608
609 fn extreme(&self, max: bool) -> Option<RowId> {
611 match self {
612 Self::Ordered(sorted) if max => sorted.last(),
613 Self::Ordered(sorted) => sorted.first(),
614 _ => None,
615 }
616 }
617}
618
619#[derive(Debug, Clone, Copy)]
621enum Output {
622 Count,
623 Sum(usize, Numeric),
624 Mean(usize, Numeric),
625 Min(usize),
626 Max(usize),
627}
628
629#[derive(Debug, Clone)]
631struct Compiled {
632 output: Output,
633 name: String,
634}
635
636#[derive(Debug, Clone)]
638struct Group {
639 rows: BTreeSet<RowId>,
640 states: Vec<State>,
641}
642
643impl Group {
644 fn new(trackers: &[Tracker]) -> Self {
645 Self {
646 rows: BTreeSet::new(),
647 states: trackers.iter().map(|t| State::new(&t.track)).collect(),
648 }
649 }
650}
651
652#[derive(Debug, Clone)]
654pub(crate) struct GroupState {
655 keys: Vec<Key>,
656 trackers: Vec<Tracker>,
657 aggregates: Vec<Compiled>,
658 filter: Option<Predicate>,
659 groups: BTreeMap<Vec<Part>, Group>,
660 member: Vec<bool>,
662 revision: u64,
663}
664
665impl GroupState {
666 pub(crate) fn compile(spec: &GroupSpec, schema: &Schema) -> Result<Self, DataError> {
667 let keys = spec
668 .keys
669 .iter()
670 .map(|k| Key::new(schema, k))
671 .collect::<Result<Vec<_>, _>>()?;
672 let mut trackers = Vec::new();
673 let aggregates = spec
674 .aggregates
675 .iter()
676 .map(|aggregate| {
677 let output = match &aggregate.function {
678 Function::Count => Output::Count,
679 Function::Sum(column) => {
680 let (index, numeric) = sum_tracker(&mut trackers, schema, column)?;
681 Output::Sum(index, numeric)
682 }
683 Function::Mean(column) => {
684 let (index, numeric) = sum_tracker(&mut trackers, schema, column)?;
685 Output::Mean(index, numeric)
686 }
687 Function::Min(column) => {
688 Output::Min(order_tracker(&mut trackers, schema, column)?)
689 }
690 Function::Max(column) => {
691 Output::Max(order_tracker(&mut trackers, schema, column)?)
692 }
693 };
694 Ok(Compiled {
695 output,
696 name: aggregate.name(),
697 })
698 })
699 .collect::<Result<Vec<_>, DataError>>()?;
700 let mut names = BTreeSet::new();
701 let all_names = keys
702 .iter()
703 .map(|k| &k.source.name)
704 .chain(aggregates.iter().map(|a| &a.name));
705 for name in all_names {
706 if !names.insert(name) {
707 return Err(DataError::DuplicateName(name.clone()));
708 }
709 }
710 let filter = spec
711 .filter
712 .as_ref()
713 .map(|f| Predicate::compile(f, schema))
714 .transpose()?;
715 let mut state = Self {
716 keys,
717 trackers,
718 aggregates,
719 filter,
720 groups: BTreeMap::new(),
721 member: Vec::new(),
722 revision: 0,
723 };
724 state.clear();
725 Ok(state)
726 }
727
728 fn clear(&mut self) {
730 self.groups.clear();
731 self.member.clear();
732 if self.keys.is_empty() {
733 self.groups.insert(Vec::new(), Group::new(&self.trackers));
734 }
735 }
736
737 fn passes(&self, batches: &[RecordBatch], at: RowRef) -> bool {
738 self.filter
739 .as_ref()
740 .is_none_or(|f| f.eval(&batches[at.batch], at.row) == Some(true))
741 }
742
743 fn key(&self, batches: &[RecordBatch], at: RowRef) -> Vec<Part> {
744 self.keys.iter().map(|k| k.part(batches, at)).collect()
745 }
746
747 fn count(&mut self, rows: Rows<'_>, id: RowId, at: RowRef, sorted: bool) -> bool {
750 if !self.passes(rows.batches, at) {
751 return false;
752 }
753 let key = self.key(rows.batches, at);
754 let trackers = &self.trackers;
755 let group = self
756 .groups
757 .entry(key)
758 .or_insert_with(|| Group::new(trackers));
759 group.rows.insert(id);
760 for (tracker, state) in trackers.iter().zip(&mut group.states) {
761 if sorted || !matches!(tracker.track, Track::Order(_)) {
762 tracker.apply(state, rows, id, at, 1);
763 }
764 }
765 if self.member.len() <= id as usize {
766 self.member.resize(id as usize + 1, false);
767 }
768 self.member[id as usize] = true;
769 true
770 }
771
772 pub(crate) fn insert(&mut self, rows: Rows<'_>, id: RowId, at: RowRef) {
774 if self.count(rows, id, at, true) {
775 self.revision += 1;
776 }
777 }
778
779 pub(crate) fn remove(&mut self, rows: Rows<'_>, id: RowId, at: RowRef) {
781 if !self.member.get(id as usize).copied().unwrap_or(false) {
782 return;
783 }
784 let key = self.key(rows.batches, at);
785 let Some(group) = self.groups.get_mut(&key) else {
786 debug_assert!(false, "a counted row's group exists");
787 return;
788 };
789 group.rows.remove(&id);
790 for (tracker, state) in self.trackers.iter().zip(&mut group.states) {
791 tracker.apply(state, rows, id, at, -1);
792 }
793 if group.rows.is_empty() && !self.keys.is_empty() {
795 self.groups.remove(&key);
796 }
797 self.member[id as usize] = false;
798 self.revision += 1;
799 }
800
801 pub(crate) fn rebuild(&mut self, rows: Rows<'_>) {
803 let had_rows = self.groups.values().any(|g| !g.rows.is_empty());
804 self.clear();
805 let mut counted = false;
806 for (id, slot) in rows.slots.iter().enumerate() {
807 if let (Ok(id), Some(slot)) = (RowId::try_from(id), slot) {
808 counted |= self.count(rows, id, slot.row_ref(), false);
809 }
810 }
811 self.sort_values(rows);
812 if had_rows || counted {
813 self.revision += 1;
814 }
815 }
816
817 fn sort_values(&mut self, rows: Rows<'_>) {
820 for (index, tracker) in self.trackers.iter().enumerate() {
821 let Track::Order(column) = &tracker.track else {
822 continue;
823 };
824 let sort = std::slice::from_ref(column);
825 for group in self.groups.values_mut() {
826 let mut entries: Vec<Entry> = group
827 .rows
828 .iter()
829 .map(|&id| (id, rows.at(id)))
830 .filter(|&(_, at)| tracker.source.read(rows.batches, at) != Value::Null)
831 .map(|(id, at)| entry(sort, rows.batches, id, at))
832 .collect();
833 entries.sort_unstable_by(|&a, &b| entry_order(sort, rows, a, b, rows.at(b.id)));
834 if let State::Ordered(sorted) = &mut group.states[index] {
835 sorted.rebuild(&entries);
836 }
837 }
838 }
839 }
840}
841
842fn sum_tracker(
844 trackers: &mut Vec<Tracker>,
845 schema: &Schema,
846 column: &str,
847) -> Result<(usize, Numeric), DataError> {
848 let source = Source::new(schema, column)?;
849 let numeric =
850 Numeric::of(&source.data_type).ok_or_else(|| DataError::NotNumeric(column.to_owned()))?;
851 Ok((tracker(trackers, source, Track::Sum(numeric)), numeric))
852}
853
854fn order_tracker(
856 trackers: &mut Vec<Tracker>,
857 schema: &Schema,
858 column: &str,
859) -> Result<usize, DataError> {
860 let source = Source::new(schema, column)?;
861 let sort = SortColumn::ascending(source.column, source.read);
862 Ok(tracker(trackers, source, Track::Order(sort)))
863}
864
865fn tracker(trackers: &mut Vec<Tracker>, source: Source, track: Track) -> usize {
868 let same = |t: &Tracker| {
869 t.source.column == source.column
870 && std::mem::discriminant(&t.track) == std::mem::discriminant(&track)
871 };
872 if let Some(index) = trackers.iter().position(same) {
873 return index;
874 }
875 trackers.push(Tracker { source, track });
876 trackers.len() - 1
877}
878
879#[derive(Debug, Clone, Copy)]
915pub struct Groups<'a> {
916 pub(crate) state: &'a GroupState,
917 pub(crate) rows: Rows<'a>,
918}
919
920impl Groups<'_> {
921 pub fn len(&self) -> usize {
924 self.state.groups.len()
925 }
926
927 pub fn is_empty(&self) -> bool {
929 self.len() == 0
930 }
931
932 pub fn revision(&self) -> u64 {
935 self.state.revision
936 }
937
938 pub fn to_batch(&self) -> Result<RecordBatch, DataError> {
950 let groups: Vec<&Group> = self.state.groups.values().collect();
951 let mut fields = Vec::new();
952 let mut columns = Vec::new();
953 for (index, key) in self.state.keys.iter().enumerate() {
954 let source = &key.source;
955 columns.push(match key.bucket {
956 Some(_) => self.starts(index, source),
957 None => {
958 let rows = groups.iter().map(|g| g.rows.first().copied());
959 self.gather(source, rows)?
960 }
961 });
962 fields.push(Field::new(&source.name, source.output_type().clone(), true));
963 }
964 for aggregate in &self.state.aggregates {
965 let (column, data_type) = self.column(aggregate.output, &groups)?;
966 let nullable = !matches!(aggregate.output, Output::Count);
967 fields.push(Field::new(&aggregate.name, data_type, nullable));
968 columns.push(column);
969 }
970 let schema = Arc::new(Schema::new(fields));
971 let options = RecordBatchOptions::new().with_row_count(Some(groups.len()));
972 RecordBatch::try_new_with_options(schema, columns, &options).map_err(DataError::arrow)
973 }
974
975 fn column(&self, output: Output, groups: &[&Group]) -> Result<(ArrayRef, DataType), DataError> {
976 Ok(match output {
977 Output::Count => {
978 let counts: UInt64Array =
980 groups.iter().map(|g| Some(g.rows.len() as u64)).collect();
981 (Arc::new(counts), DataType::UInt64)
982 }
983 Output::Sum(index, numeric) => sums(numeric, groups.iter().map(|g| &g.states[index]))?,
984 Output::Mean(index, numeric) => {
985 let means: Float64Array = groups
986 .iter()
987 .map(|g| mean(&g.states[index], numeric))
988 .collect();
989 (Arc::new(means), DataType::Float64)
990 }
991 Output::Min(index) | Output::Max(index) => {
992 let max = matches!(output, Output::Max(_));
993 let rows = groups.iter().map(|g| g.states[index].extreme(max));
994 let source = &self.state.trackers[index].source;
995 (self.gather(source, rows)?, source.output_type().clone())
996 }
997 })
998 }
999
1000 fn starts(&self, index: usize, source: &Source) -> ArrayRef {
1002 let parts = self.state.groups.keys().map(|key| &key[index]);
1003 if source.kind == Kind::Float {
1004 let starts: Vec<Option<f64>> = parts
1005 .map(|part| match part {
1006 Part::Float(bits) => Some(from_prefix(*bits)),
1007 _ => None,
1008 })
1009 .collect();
1010 return float_starts(&source.data_type, &starts);
1011 }
1012 let starts: Vec<Option<i128>> = parts
1013 .map(|part| match part {
1014 Part::Decimal(start) => Some(*start),
1015 _ => None,
1016 })
1017 .collect();
1018 whole_starts(&source.data_type, &starts)
1019 }
1020
1021 fn gather(
1024 &self,
1025 source: &Source,
1026 ids: impl Iterator<Item = Option<RowId>>,
1027 ) -> Result<ArrayRef, DataError> {
1028 let batches = self.rows.batches;
1029 let column = |batch: usize| batches[batch].column(source.column).as_ref();
1030 let decode = matches!(source.data_type, DataType::Dictionary(..));
1031 let null = new_null_array(source.output_type(), 1);
1032 let mut arrays: Vec<&dyn Array> = (0..batches.len())
1033 .map(|batch| {
1034 let array = column(batch);
1035 match array.as_any_dictionary_opt() {
1036 Some(dictionary) if decode => dictionary.values().as_ref(),
1037 _ => array,
1038 }
1039 })
1040 .collect();
1041 arrays.push(null.as_ref());
1042 let null_at = (arrays.len() - 1, 0);
1043 let indices: Vec<(usize, usize)> = ids
1044 .map(|id| {
1045 let place = id.and_then(|id| {
1046 let at = self.rows.at(id);
1047 let row = if decode {
1048 dictionary_index(column(at.batch), at.row)?
1049 } else {
1050 at.row
1051 };
1052 Some((at.batch, row))
1053 });
1054 place.unwrap_or(null_at)
1055 })
1056 .collect();
1057 let array = interleave(&arrays, &indices).map_err(DataError::arrow)?;
1058 Ok(if source.kind == Kind::Float {
1059 canonical_floats(&array)
1060 } else {
1061 array
1062 })
1063 }
1064}
1065
1066fn canonical_floats(array: &ArrayRef) -> ArrayRef {
1068 type F16 = <Float16Type as ArrowPrimitiveType>::Native;
1069 if let Some(a) = array.as_primitive_opt::<Float64Type>() {
1070 Arc::new(a.unary::<_, Float64Type>(canonical))
1071 } else if let Some(a) = array.as_primitive_opt::<Float32Type>() {
1072 Arc::new(a.unary::<_, Float32Type>(|v| canonical(f64::from(v)) as f32))
1074 } else if let Some(a) = array.as_primitive_opt::<Float16Type>() {
1075 Arc::new(a.unary::<_, Float16Type>(|v| F16::from_f64(canonical(v.into()))))
1076 } else {
1077 Arc::clone(array)
1078 }
1079}
1080
1081fn mean(state: &State, numeric: Numeric) -> Option<f64> {
1082 match (state, numeric) {
1083 (State::Float(sum), _) => sum.mean(),
1084 (State::Exact(sum), Numeric::Decimal { scale }) => sum.mean().map(|m| unscale(m, scale)),
1085 (State::Exact(sum), _) => sum.mean(),
1086 (State::Ordered(_), _) => None,
1087 }
1088}
1089
1090fn sums<'g>(
1092 numeric: Numeric,
1093 states: impl Iterator<Item = &'g State>,
1094) -> Result<(ArrayRef, DataType), DataError> {
1095 let scale = match numeric {
1096 Numeric::Float => {
1097 let sums: Float64Array = states.map(|s| s.float().and_then(FloatSum::sum)).collect();
1098 return Ok((Arc::new(sums), DataType::Float64));
1099 }
1100 Numeric::Integer => 0,
1102 Numeric::Decimal { scale } => scale,
1103 };
1104 let sums: Decimal128Array = states
1105 .map(|s| {
1106 let sum = s.exact().and_then(ExactSum::total);
1107 sum.filter(|v| v.unsigned_abs() < DECIMAL_LIMIT)
1108 })
1109 .collect();
1110 let sums = sums
1111 .with_precision_and_scale(38, scale)
1112 .map_err(DataError::arrow)?;
1113 Ok((Arc::new(sums), DataType::Decimal128(38, scale)))
1114}
1115
1116#[cfg(test)]
1117mod tests {
1118 use super::*;
1119
1120 #[test]
1121 fn a_compensated_sum_keeps_what_a_plain_sum_loses() {
1122 for (first, second) in [(1e16, 1.0), (1.0, 1e16)] {
1124 let mut sum = FloatSum::default();
1125 sum.apply(first, 1);
1126 sum.apply(second, 1);
1127 sum.apply(1e16, -1);
1128 assert_eq!(sum.sum(), Some(1.0), "{first} then {second}");
1129 }
1130 }
1131
1132 #[test]
1133 fn a_float_sum_forgets_its_rounding_once_its_values_are_gone() {
1134 let huge = [1.7e308, 1.3e308, 0.9e308, 1.1e308];
1135 let mut sum = FloatSum::default();
1136 sum.apply(1.0, 1);
1137 for v in huge {
1138 sum.apply(v, 1);
1139 }
1140 for v in huge.iter().rev() {
1141 sum.apply(*v, -1);
1142 }
1143 assert_eq!(sum.sum(), Some(1.0));
1144 let mut sum = FloatSum::default();
1145 for v in [0.1, 0.2, 0.3] {
1146 sum.apply(v, 1);
1147 }
1148 for v in [0.2, 0.1, 0.3] {
1149 sum.apply(v, -1);
1150 }
1151 sum.apply(1e-30, 1);
1152 assert_eq!(sum.sum(), Some(1e-30));
1153 }
1154
1155 #[test]
1156 fn nan_and_infinities_leave_a_float_sum_with_their_values() {
1157 let mut sum = FloatSum::default();
1158 for _ in 0..100 {
1159 sum.apply(1.0, 1);
1160 }
1161 sum.apply(f64::NAN, 1);
1162 assert!(sum.sum().is_some_and(f64::is_nan));
1163 sum.apply(f64::NAN, -1);
1164 assert_eq!(sum.sum(), Some(100.0));
1165 sum.apply(f64::INFINITY, 1);
1166 assert_eq!(sum.sum(), Some(f64::INFINITY));
1167 sum.apply(f64::NEG_INFINITY, 1);
1168 assert!(sum.sum().is_some_and(f64::is_nan), "inf + -inf");
1169 sum.apply(f64::INFINITY, -1);
1170 assert_eq!(sum.sum(), Some(f64::NEG_INFINITY));
1171 sum.apply(f64::NEG_INFINITY, -1);
1172 assert_eq!(sum.sum(), Some(100.0));
1173 assert_eq!(sum.mean(), Some(1.0));
1174 }
1175
1176 #[test]
1177 fn huge_floats_sum_past_f64_and_back() {
1178 let mut sum = FloatSum::default();
1179 sum.apply(1.0, 1);
1180 sum.apply(f64::MAX, 1);
1181 sum.apply(f64::MAX, 1);
1182 assert_eq!(sum.sum(), Some(f64::INFINITY));
1183 let mean = sum.mean().unwrap();
1184 let expected = f64::MAX / 3.0 * 2.0;
1185 assert!(
1186 (mean - expected).abs() <= expected * 1e-15,
1187 "{mean} vs {expected}"
1188 );
1189 sum.apply(f64::MAX, -1);
1190 assert_eq!(sum.sum(), Some(f64::MAX), "f64::MAX + 1");
1191 sum.apply(f64::MAX, -1);
1192 assert_eq!(sum.sum(), Some(1.0));
1193 }
1194
1195 #[test]
1196 fn a_sum_just_below_overflow_does_not_round_to_infinity() {
1197 let mut sum = FloatSum::default();
1198 sum.apply(power_of_two(1023), 1);
1199 sum.apply(power_of_two(1023), 1);
1200 for _ in 0..4_096 {
1201 sum.apply(-power_of_two(959), 1);
1202 }
1203 assert_eq!(sum.sum(), Some(f64::MAX));
1205 }
1206
1207 #[test]
1208 fn huge_values_keep_their_rounding_too() {
1209 let (a, b, c) = (f64::MAX, 1e308, -1.5e308);
1211 let mut sum = FloatSum::default();
1212 for v in [a, b, c] {
1213 sum.apply(v, 1);
1214 }
1215 assert_eq!(sum.sum(), Some((a + c) + b));
1217 }
1218
1219 #[test]
1220 fn an_exact_sum_past_i128_comes_back_when_the_values_leave() {
1221 for big in [i128::MAX, i128::MIN] {
1222 let mut sum = ExactSum::default();
1223 sum.apply(7, 1);
1224 sum.apply(big, 1);
1225 sum.apply(big, 1);
1226 assert_eq!(sum.total(), None, "7 + 2 * {big}");
1227 let mean = sum.mean().unwrap();
1228 assert!((mean - big as f64 * 2.0 / 3.0).abs() <= 1e25, "{mean}");
1229 sum.apply(big, -1);
1230 assert_eq!(sum.total(), big.checked_add(7));
1231 sum.apply(big, -1);
1232 assert_eq!(sum.total(), Some(7));
1233 }
1234 }
1235}