Path: blob/main/crates/polars-core/src/series/implementations/duration.rs
8424 views
use polars_compute::rolling::QuantileMethod;12use super::*;3use crate::chunked_array::comparison::*;4#[cfg(feature = "algorithm_group_by")]5use crate::frame::group_by::*;6use crate::prelude::*;78unsafe impl IntoSeries for DurationChunked {9fn into_series(self) -> Series {10Series(Arc::new(SeriesWrap(self)))11}12}1314impl private::PrivateSeriesNumeric for SeriesWrap<DurationChunked> {15fn bit_repr(&self) -> Option<BitRepr> {16Some(self.0.physical().to_bit_repr())17}18}1920impl private::PrivateSeries for SeriesWrap<DurationChunked> {21fn compute_len(&mut self) {22self.0.physical_mut().compute_len()23}24fn _field(&self) -> Cow<'_, Field> {25Cow::Owned(self.0.field())26}27fn _dtype(&self) -> &DataType {28self.0.dtype()29}3031fn _set_flags(&mut self, flags: StatisticsFlags) {32self.0.physical_mut().set_flags(flags)33}3435fn _get_flags(&self) -> StatisticsFlags {36self.0.physical().get_flags()37}3839unsafe fn equal_element(&self, idx_self: usize, idx_other: usize, other: &Series) -> bool {40self.0.physical().equal_element(idx_self, idx_other, other)41}4243#[cfg(feature = "zip_with")]44fn zip_with_same_type(&self, mask: &BooleanChunked, other: &Series) -> PolarsResult<Series> {45let other = other.to_physical_repr().into_owned();46self.047.physical()48.zip_with(mask, other.as_ref().as_ref())49.map(|ca| ca.into_duration(self.0.time_unit()).into_series())50}5152fn into_total_eq_inner<'a>(&'a self) -> Box<dyn TotalEqInner + 'a> {53self.0.physical().into_total_eq_inner()54}55fn into_total_ord_inner<'a>(&'a self) -> Box<dyn TotalOrdInner + 'a> {56self.0.physical().into_total_ord_inner()57}5859fn vec_hash(60&self,61random_state: PlSeedableRandomStateQuality,62buf: &mut Vec<u64>,63) -> PolarsResult<()> {64self.0.physical().vec_hash(random_state, buf)?;65Ok(())66}6768fn vec_hash_combine(69&self,70build_hasher: PlSeedableRandomStateQuality,71hashes: &mut [u64],72) -> PolarsResult<()> {73self.0.physical().vec_hash_combine(build_hasher, hashes)?;74Ok(())75}7677#[cfg(feature = "algorithm_group_by")]78unsafe fn agg_min(&self, groups: &GroupsType) -> Series {79self.080.physical()81.agg_min(groups)82.into_duration(self.0.time_unit())83.into_series()84}8586#[cfg(feature = "algorithm_group_by")]87unsafe fn agg_max(&self, groups: &GroupsType) -> Series {88self.089.physical()90.agg_max(groups)91.into_duration(self.0.time_unit())92.into_series()93}9495#[cfg(feature = "algorithm_group_by")]96unsafe fn agg_arg_min(&self, groups: &GroupsType) -> Series {97self.0.physical().agg_arg_min(groups)98}99100#[cfg(feature = "algorithm_group_by")]101unsafe fn agg_arg_max(&self, groups: &GroupsType) -> Series {102self.0.physical().agg_arg_max(groups)103}104105#[cfg(feature = "algorithm_group_by")]106unsafe fn agg_sum(&self, groups: &GroupsType) -> Series {107self.0108.physical()109.agg_sum(groups)110.into_duration(self.0.time_unit())111.into_series()112}113114#[cfg(feature = "algorithm_group_by")]115unsafe fn agg_std(&self, groups: &GroupsType, ddof: u8) -> Series {116self.0117.physical()118.agg_std(groups, ddof)119// cast f64 back to physical type120.cast(&DataType::Int64)121.unwrap()122.into_duration(self.0.time_unit())123.into_series()124}125126#[cfg(feature = "algorithm_group_by")]127unsafe fn agg_var(&self, groups: &GroupsType, ddof: u8) -> Series {128self.0129.physical()130.agg_var(groups, ddof)131// cast f64 back to physical type132.cast(&DataType::Int64)133.unwrap()134.into_duration(self.0.time_unit())135.into_series()136}137138#[cfg(feature = "algorithm_group_by")]139unsafe fn agg_list(&self, groups: &GroupsType) -> Series {140// we cannot cast and dispatch as the inner type of the list would be incorrect141self.0142.physical()143.agg_list(groups)144.cast(&DataType::List(Box::new(self.dtype().clone())))145.unwrap()146}147148fn subtract(&self, rhs: &Series) -> PolarsResult<Series> {149match (self.dtype(), rhs.dtype()) {150(DataType::Duration(tu), DataType::Duration(tur)) => {151polars_ensure!(tu == tur, InvalidOperation: "units are different");152let lhs = self.cast(&DataType::Int64, CastOptions::NonStrict).unwrap();153let rhs = rhs.cast(&DataType::Int64).unwrap();154Ok(lhs.subtract(&rhs)?.into_duration(*tu).into_series())155},156(dtl, dtr) => polars_bail!(opq = sub, dtl, dtr),157}158}159fn add_to(&self, rhs: &Series) -> PolarsResult<Series> {160match (self.dtype(), rhs.dtype()) {161(DataType::Duration(tu), DataType::Duration(tur)) => {162polars_ensure!(tu == tur, InvalidOperation: "units are different");163let lhs = self.cast(&DataType::Int64, CastOptions::NonStrict).unwrap();164let rhs = rhs.cast(&DataType::Int64).unwrap();165Ok(lhs.add_to(&rhs)?.into_duration(*tu).into_series())166},167(DataType::Duration(tu), DataType::Date) => {168let one_day_in_tu: i64 = match tu {169TimeUnit::Milliseconds => 86_400_000,170TimeUnit::Microseconds => 86_400_000_000,171TimeUnit::Nanoseconds => 86_400_000_000_000,172};173let lhs =174self.cast(&DataType::Int64, CastOptions::NonStrict).unwrap() / one_day_in_tu;175let rhs = rhs176.cast(&DataType::Int32)177.unwrap()178.cast(&DataType::Int64)179.unwrap();180Ok(lhs181.add_to(&rhs)?182.cast(&DataType::Int32)?183.into_date()184.into_series())185},186(DataType::Duration(tu), DataType::Datetime(tur, tz)) => {187polars_ensure!(tu == tur, InvalidOperation: "units are different");188let lhs = self.cast(&DataType::Int64, CastOptions::NonStrict).unwrap();189let rhs = rhs.cast(&DataType::Int64).unwrap();190Ok(lhs191.add_to(&rhs)?192.into_datetime(*tu, tz.clone())193.into_series())194},195(dtl, dtr) => polars_bail!(opq = add, dtl, dtr),196}197}198fn multiply(&self, rhs: &Series) -> PolarsResult<Series> {199let tul = self.0.time_unit();200match rhs.dtype() {201DataType::Int64 => Ok((&self.0.phys * rhs.i64().unwrap())202.into_duration(tul)203.into_series()),204dt if dt.is_integer() => {205let rhs = rhs.cast(&DataType::Int64)?;206self.multiply(&rhs)207},208dt if dt.is_float() => {209let phys = &self.0.phys;210let phys_float = phys.cast(dt).unwrap();211let out = std::ops::Mul::mul(&phys_float, rhs)?212.cast(&DataType::Int64)213.unwrap();214let phys = out.i64().unwrap().clone();215Ok(phys.into_duration(tul).into_series())216},217_ => {218polars_bail!(opq = mul, self.dtype(), rhs.dtype());219},220}221}222fn divide(&self, rhs: &Series) -> PolarsResult<Series> {223let tul = self.0.time_unit();224match rhs.dtype() {225DataType::Duration(tur) => {226if tul == *tur {227// Returns a constant as f64.228Ok(std::ops::Div::div(229&self.0.phys.cast(&DataType::Float64).unwrap(),230&rhs.duration()231.unwrap()232.phys233.cast(&DataType::Float64)234.unwrap(),235)?236.into_series())237} else {238let rhs = rhs.cast(self.dtype())?;239self.divide(&rhs)240}241},242DataType::Int64 => Ok((&self.0.phys / rhs.i64().unwrap())243.into_duration(tul)244.into_series()),245dt if dt.is_integer() => {246let rhs = rhs.cast(&DataType::Int64)?;247self.divide(&rhs)248},249dt if dt.is_float() => {250let phys = &self.0.phys;251let phys_float = phys.cast(dt).unwrap();252let out = std::ops::Div::div(&phys_float, rhs)?253.cast(&DataType::Int64)254.unwrap();255let phys = out.i64().unwrap().clone();256Ok(phys.into_duration(tul).into_series())257},258_ => {259polars_bail!(opq = div, self.dtype(), rhs.dtype());260},261}262}263fn remainder(&self, rhs: &Series) -> PolarsResult<Series> {264polars_ensure!(self.dtype() == rhs.dtype(), InvalidOperation: "dtypes and units must be equal in duration arithmetic");265let lhs = self.cast(&DataType::Int64, CastOptions::NonStrict).unwrap();266let rhs = rhs.cast(&DataType::Int64).unwrap();267Ok(lhs268.remainder(&rhs)?269.into_duration(self.0.time_unit())270.into_series())271}272#[cfg(feature = "algorithm_group_by")]273fn group_tuples(&self, multithreaded: bool, sorted: bool) -> PolarsResult<GroupsType> {274self.0.physical().group_tuples(multithreaded, sorted)275}276277fn arg_sort_multiple(278&self,279by: &[Column],280options: &SortMultipleOptions,281) -> PolarsResult<IdxCa> {282self.0.physical().arg_sort_multiple(by, options)283}284}285286impl SeriesTrait for SeriesWrap<DurationChunked> {287fn rename(&mut self, name: PlSmallStr) {288self.0.rename(name);289}290291fn chunk_lengths(&self) -> ChunkLenIter<'_> {292self.0.physical().chunk_lengths()293}294fn name(&self) -> &PlSmallStr {295self.0.name()296}297298fn chunks(&self) -> &Vec<ArrayRef> {299self.0.physical().chunks()300}301unsafe fn chunks_mut(&mut self) -> &mut Vec<ArrayRef> {302self.0.physical_mut().chunks_mut()303}304305fn shrink_to_fit(&mut self) {306self.0.physical_mut().shrink_to_fit()307}308309fn slice(&self, offset: i64, length: usize) -> Series {310self.0.slice(offset, length).into_series()311}312313fn split_at(&self, offset: i64) -> (Series, Series) {314let (a, b) = self.0.split_at(offset);315(a.into_series(), b.into_series())316}317318fn _sum_as_f64(&self) -> f64 {319self.0.physical()._sum_as_f64()320}321322fn mean(&self) -> Option<f64> {323self.0.physical().mean()324}325326fn median(&self) -> Option<f64> {327self.0.physical().median()328}329330fn std(&self, ddof: u8) -> Option<f64> {331self.0.physical().std(ddof)332}333334fn var(&self, ddof: u8) -> Option<f64> {335self.0.physical().var(ddof)336}337338fn append(&mut self, other: &Series) -> PolarsResult<()> {339polars_ensure!(self.0.dtype() == other.dtype(), append);340let mut other = other.to_physical_repr().into_owned();341self.0342.physical_mut()343.append_owned(std::mem::take(other._get_inner_mut().as_mut()))344}345fn append_owned(&mut self, mut other: Series) -> PolarsResult<()> {346polars_ensure!(self.0.dtype() == other.dtype(), append);347self.0.physical_mut().append_owned(std::mem::take(348&mut other349._get_inner_mut()350.as_any_mut()351.downcast_mut::<DurationChunked>()352.unwrap()353.phys,354))355}356357fn extend(&mut self, other: &Series) -> PolarsResult<()> {358polars_ensure!(self.0.dtype() == other.dtype(), extend);359let other = other.to_physical_repr();360self.0361.physical_mut()362.extend(other.as_ref().as_ref().as_ref())?;363Ok(())364}365366fn filter(&self, filter: &BooleanChunked) -> PolarsResult<Series> {367self.0368.physical()369.filter(filter)370.map(|ca| ca.into_duration(self.0.time_unit()).into_series())371}372373fn take(&self, indices: &IdxCa) -> PolarsResult<Series> {374Ok(self375.0376.physical()377.take(indices)?378.into_duration(self.0.time_unit())379.into_series())380}381382unsafe fn take_unchecked(&self, indices: &IdxCa) -> Series {383self.0384.physical()385.take_unchecked(indices)386.into_duration(self.0.time_unit())387.into_series()388}389390fn take_slice(&self, indices: &[IdxSize]) -> PolarsResult<Series> {391Ok(self392.0393.physical()394.take(indices)?395.into_duration(self.0.time_unit())396.into_series())397}398399unsafe fn take_slice_unchecked(&self, indices: &[IdxSize]) -> Series {400self.0401.physical()402.take_unchecked(indices)403.into_duration(self.0.time_unit())404.into_series()405}406407fn deposit(&self, validity: &Bitmap) -> Series {408self.0409.physical()410.deposit(validity)411.into_duration(self.0.time_unit())412.into_series()413}414415fn len(&self) -> usize {416self.0.len()417}418419fn rechunk(&self) -> Series {420self.0421.physical()422.rechunk()423.into_owned()424.into_duration(self.0.time_unit())425.into_series()426}427428fn new_from_index(&self, index: usize, length: usize) -> Series {429self.0430.physical()431.new_from_index(index, length)432.into_duration(self.0.time_unit())433.into_series()434}435436fn cast(&self, dtype: &DataType, cast_options: CastOptions) -> PolarsResult<Series> {437self.0.cast_with_options(dtype, cast_options)438}439440#[inline]441unsafe fn get_unchecked(&self, index: usize) -> AnyValue<'_> {442self.0.get_any_value_unchecked(index)443}444445fn sort_with(&self, options: SortOptions) -> PolarsResult<Series> {446Ok(self447.0448.physical()449.sort_with(options)450.into_duration(self.0.time_unit())451.into_series())452}453454fn arg_sort(&self, options: SortOptions) -> IdxCa {455self.0.physical().arg_sort(options)456}457458fn null_count(&self) -> usize {459self.0.null_count()460}461462fn has_nulls(&self) -> bool {463self.0.has_nulls()464}465466#[cfg(feature = "algorithm_group_by")]467fn unique(&self) -> PolarsResult<Series> {468self.0469.physical()470.unique()471.map(|ca| ca.into_duration(self.0.time_unit()).into_series())472}473474#[cfg(feature = "algorithm_group_by")]475fn n_unique(&self) -> PolarsResult<usize> {476self.0.physical().n_unique()477}478479fn unique_id(&self) -> PolarsResult<(IdxSize, Vec<IdxSize>)> {480ChunkUnique::unique_id(self.0.physical())481}482483#[cfg(feature = "algorithm_group_by")]484fn arg_unique(&self) -> PolarsResult<IdxCa> {485self.0.physical().arg_unique()486}487488fn is_null(&self) -> BooleanChunked {489self.0.is_null()490}491492fn is_not_null(&self) -> BooleanChunked {493self.0.is_not_null()494}495496fn reverse(&self) -> Series {497self.0498.physical()499.reverse()500.into_duration(self.0.time_unit())501.into_series()502}503504fn as_single_ptr(&mut self) -> PolarsResult<usize> {505self.0.physical_mut().as_single_ptr()506}507508fn shift(&self, periods: i64) -> Series {509self.0510.physical()511.shift(periods)512.into_duration(self.0.time_unit())513.into_series()514}515516fn sum_reduce(&self) -> PolarsResult<Scalar> {517let sc = self.0.physical().sum_reduce();518let v = sc.value().as_duration(self.0.time_unit());519Ok(Scalar::new(self.dtype().clone(), v))520}521522fn max_reduce(&self) -> PolarsResult<Scalar> {523let sc = self.0.physical().max_reduce();524let v = sc.value().as_duration(self.0.time_unit());525Ok(Scalar::new(self.dtype().clone(), v))526}527fn min_reduce(&self) -> PolarsResult<Scalar> {528let sc = self.0.physical().min_reduce();529let v = sc.value().as_duration(self.0.time_unit());530Ok(Scalar::new(self.dtype().clone(), v))531}532fn std_reduce(&self, ddof: u8) -> PolarsResult<Scalar> {533let sc = self.0.physical().std_reduce(ddof);534let to = self.dtype().to_physical();535let v = sc.value().cast(&to);536Ok(Scalar::new(537self.dtype().clone(),538v.as_duration(self.0.time_unit()),539))540}541542fn mean_reduce(&self) -> PolarsResult<Scalar> {543let mean = self.mean().map(|v| v as i64);544let av = AnyValue::from(mean).as_duration(self.0.time_unit());545Ok(Scalar::new(self.dtype().clone(), av))546}547548fn median_reduce(&self) -> PolarsResult<Scalar> {549let mean = self.median().map(|v| v as i64);550let av = AnyValue::from(mean).as_duration(self.0.time_unit());551Ok(Scalar::new(self.dtype().clone(), av))552}553554fn quantile_reduce(&self, quantile: f64, method: QuantileMethod) -> PolarsResult<Scalar> {555let v = self.0.physical().quantile_reduce(quantile, method)?;556let v = v.value().cast(&DataType::Int64);557Ok(Scalar::new(558self.dtype().clone(),559v.as_duration(self.0.time_unit()),560))561}562563fn quantiles_reduce(&self, quantiles: &[f64], method: QuantileMethod) -> PolarsResult<Scalar> {564let result = self.0.physical().quantiles_reduce(quantiles, method)?;565if let AnyValue::List(float_s) = result.value() {566let float_ca = float_s.f64().unwrap();567let int_s = float_ca568.iter()569.map(|v: Option<f64>| v.map(|f| f as i64))570.collect::<Int64Chunked>()571.into_duration(self.0.time_unit())572.into_series();573Ok(Scalar::new(574DataType::List(Box::new(self.dtype().clone())),575AnyValue::List(int_s),576))577} else {578polars_bail!(ComputeError: "expected list scalar from quantiles_reduce")579}580}581582#[cfg(feature = "approx_unique")]583fn approx_n_unique(&self) -> PolarsResult<IdxSize> {584Ok(ChunkApproxNUnique::approx_n_unique(self.0.physical()))585}586587fn clone_inner(&self) -> Arc<dyn SeriesTrait> {588Arc::new(SeriesWrap(Clone::clone(&self.0)))589}590591fn find_validity_mismatch(&self, other: &Series, idxs: &mut Vec<IdxSize>) {592self.0.physical().find_validity_mismatch(other, idxs)593}594595fn as_any(&self) -> &dyn Any {596&self.0597}598599fn as_any_mut(&mut self) -> &mut dyn Any {600&mut self.0601}602603fn as_phys_any(&self) -> &dyn Any {604self.0.physical()605}606607fn as_arc_any(self: Arc<Self>) -> Arc<dyn Any + Send + Sync> {608self as _609}610}611612613