Repository: pola-rs/polars
File: crates/polars-ops/src/series/ops/log.rs (Rust)

Code before:
use polars_core::{with_match_physical_float_polars_type, with_match_physical_integer_polars_type};

use crate::series::ops::SeriesSealed;

fn log1p<T: PolarsNumericType>(ca: &ChunkedArray<T>) -> Float64Chunked {
    ca.cast_and_apply_in_place(|v: f64| v.ln_1p())
}

fn exp<T: PolarsNumericType>(ca: &ChunkedArray<T>) -> Float64Chunked {
    ca.cast_and_apply_in_place(|v: f64| v.exp())
}

pub trait LogSeries: SeriesSealed {
    /// Compute the logarithm to a given base
    fn log(&self, base: &Series) -> Series {
        let s = self.as_series();

        use DataType::*;
        match (s.dtype(), base.dtype()) {
            (dt1, dt2) if dt1 == dt2 && dt1.is_float() => {
                let s = s.to_physical_repr();
                let base = base.to_physical_repr();
                with_match_physical_float_polars_type!(s.dtype(), |$T| {
                    let ca: &ChunkedArray<$T> = s.as_ref().as_ref().as_ref();
                    let base_ca: &ChunkedArray<$T> = base.as_ref().as_ref().as_ref();
                    let ca: ChunkedArray<$T> = apply_binary_kernel_broadcast(
                        ca,
                        base_ca,
                        |l, r| log_kernel_binary::<$T>(l, r)                        ,
                        |l, r| log_kernel_unary_left::<$T>(l, r),
                        |l, r| log_kernel_unary_right::<$T>(l, r),
                    );
                    ca.into_series()
                })
            },
            (_, Float64) => s.cast(&DataType::Float64).unwrap().log(base),
            (Float64, _) => s.log(&base.cast(&DataType::Float64).unwrap()),
            (_, _) => s
                .cast(&DataType::Float64)
                .unwrap()
                .log(&base.cast(&DataType::Float64).unwrap()),
        }
    }

    /// Compute the natural logarithm of all elements plus one in the input array
    fn log1p(&self) -> Series {
        let s = self.as_series();
        if s.dtype().is_decimal() {
            return s.cast(&DataType::Float64).unwrap().log1p();
        }


Review comment (suggestion):
I think you can avoid writing these kernel functions entirely if you use `broadcast_binary_elementwise`.

Code after:
fn log1p<T: PolarsNumericType>(ca: &ChunkedArray<T>) -> Float64Chunked {
    ca.cast_and_apply_in_place(|v: f64| v.ln_1p())
}

fn exp<T: PolarsNumericType>(ca: &ChunkedArray<T>) -> Float64Chunked {
    ca.cast_and_apply_in_place(|v: f64| v.exp())
}

pub trait LogSeries: SeriesSealed {
    /// Compute the logarithm to a given base
    fn log(&self, base: &Series) -> Series {
        let s = self.as_series();

        use DataType::*;
        match (s.dtype(), base.dtype()) {
            (dt1, dt2) if dt1 == dt2 && dt1.is_float() => {
                let s = s.to_physical_repr();
                let base = base.to_physical_repr();
                with_match_physical_float_polars_type!(s.dtype(), |$T| {
                    let ca: &ChunkedArray<$T> = s.as_ref().as_ref().as_ref();
                    let base_ca: &ChunkedArray<$T> = base.as_ref().as_ref().as_ref();
                    let out: ChunkedArray<$T> = broadcast_binary_elementwise_values(ca, base_ca,
                        |x, base| x.log(base)
                    );
                    out.into_series()
                })
            },
            (_, Float64) => s.cast(&DataType::Float64).unwrap().log(base),
            (Float64, _) => s.log(&base.cast(&DataType::Float64).unwrap()),
            (_, _) => s
                .cast(&DataType::Float64)
                .unwrap()
                .log(&base.cast(&DataType::Float64).unwrap()),
        }
    }

    /// Compute the natural logarithm of all elements plus one in the input array
    fn log1p(&self) -> Series {
        let s = self.as_series();
        if s.dtype().is_decimal() {
            return s.cast(&DataType::Float64).unwrap().log1p();
        }

        let s = s.to_physical_repr();
        let s = s.as_ref();

        use DataType::*;
        match s.dtype() {
            dt if dt.is_integer() => {
                with_match_physical_integer_polars_type!(s.dtype(), |$T| {
                    let ca: &ChunkedArray<$T> = s.as_ref().as_ref().as_ref();