use crate::column::{ColumnTrait, Float64Column, Int64Column};
use crate::core::error::{Error, Result};
use crate::optimized::jit::simd_column_ops::{
simd_abs_f64, simd_abs_i64, simd_add_f64, simd_add_i64, simd_add_scalar_f64,
simd_add_scalar_i64, simd_compare_f64, simd_compare_i64, simd_divide_f64, simd_multiply_f64,
simd_multiply_i64, simd_multiply_scalar_f64, simd_sqrt_f64, simd_subtract_f64,
simd_subtract_i64, ComparisonOp,
};
pub trait SIMDFloat64Ops {
fn simd_add(&self, other: &Float64Column) -> Result<Float64Column>;
fn simd_subtract(&self, other: &Float64Column) -> Result<Float64Column>;
fn simd_multiply(&self, other: &Float64Column) -> Result<Float64Column>;
fn simd_divide(&self, other: &Float64Column) -> Result<Float64Column>;
fn simd_add_scalar(&self, scalar: f64) -> Result<Float64Column>;
fn simd_multiply_scalar(&self, scalar: f64) -> Result<Float64Column>;
fn simd_abs(&self) -> Result<Float64Column>;
fn simd_sqrt(&self) -> Result<Float64Column>;
fn simd_compare(&self, other: &Float64Column, op: ComparisonOp) -> Result<Vec<bool>>;
fn simd_compare_scalar(&self, scalar: f64, op: ComparisonOp) -> Result<Vec<bool>>;
}
pub trait SIMDInt64Ops {
fn simd_add(&self, other: &Int64Column) -> Result<Int64Column>;
fn simd_subtract(&self, other: &Int64Column) -> Result<Int64Column>;
fn simd_multiply(&self, other: &Int64Column) -> Result<Int64Column>;
fn simd_add_scalar(&self, scalar: i64) -> Result<Int64Column>;
fn simd_abs(&self) -> Result<Int64Column>;
fn simd_compare(&self, other: &Int64Column, op: ComparisonOp) -> Result<Vec<bool>>;
fn simd_compare_scalar(&self, scalar: i64, op: ComparisonOp) -> Result<Vec<bool>>;
fn to_float64_simd(&self) -> Result<Float64Column>;
}
impl SIMDFloat64Ops for Float64Column {
fn simd_add(&self, other: &Float64Column) -> Result<Float64Column> {
if self.len() != other.len() {
return Err(Error::InconsistentRowCount {
expected: self.len(),
found: other.len(),
});
}
let mut result_data = vec![0.0; self.len()];
simd_add_f64(&self.data, &other.data, &mut result_data)?;
let null_mask = combine_null_masks(&self.null_mask, &other.null_mask, self.len())?;
Ok(Float64Column {
data: result_data.into(),
null_mask,
name: None,
})
}
fn simd_subtract(&self, other: &Float64Column) -> Result<Float64Column> {
if self.len() != other.len() {
return Err(Error::InconsistentRowCount {
expected: self.len(),
found: other.len(),
});
}
let mut result_data = vec![0.0; self.len()];
simd_subtract_f64(&self.data, &other.data, &mut result_data)?;
let null_mask = combine_null_masks(&self.null_mask, &other.null_mask, self.len())?;
Ok(Float64Column {
data: result_data.into(),
null_mask,
name: None,
})
}
fn simd_multiply(&self, other: &Float64Column) -> Result<Float64Column> {
if self.len() != other.len() {
return Err(Error::InconsistentRowCount {
expected: self.len(),
found: other.len(),
});
}
let mut result_data = vec![0.0; self.len()];
simd_multiply_f64(&self.data, &other.data, &mut result_data)?;
let null_mask = combine_null_masks(&self.null_mask, &other.null_mask, self.len())?;
Ok(Float64Column {
data: result_data.into(),
null_mask,
name: None,
})
}
fn simd_divide(&self, other: &Float64Column) -> Result<Float64Column> {
if self.len() != other.len() {
return Err(Error::InconsistentRowCount {
expected: self.len(),
found: other.len(),
});
}
let mut result_data = vec![0.0; self.len()];
simd_divide_f64(&self.data, &other.data, &mut result_data)?;
let null_mask = combine_null_masks(&self.null_mask, &other.null_mask, self.len())?;
Ok(Float64Column {
data: result_data.into(),
null_mask,
name: None,
})
}
fn simd_add_scalar(&self, scalar: f64) -> Result<Float64Column> {
let mut result_data = vec![0.0; self.len()];
simd_add_scalar_f64(&self.data, scalar, &mut result_data)?;
Ok(Float64Column {
data: result_data.into(),
null_mask: self.null_mask.clone(),
name: None,
})
}
fn simd_multiply_scalar(&self, scalar: f64) -> Result<Float64Column> {
let mut result_data = vec![0.0; self.len()];
simd_multiply_scalar_f64(&self.data, scalar, &mut result_data)?;
Ok(Float64Column {
data: result_data.into(),
null_mask: self.null_mask.clone(),
name: None,
})
}
fn simd_abs(&self) -> Result<Float64Column> {
let mut result_data = vec![0.0; self.len()];
simd_abs_f64(&self.data, &mut result_data)?;
Ok(Float64Column {
data: result_data.into(),
null_mask: self.null_mask.clone(),
name: None,
})
}
fn simd_sqrt(&self) -> Result<Float64Column> {
let mut result_data = vec![0.0; self.len()];
simd_sqrt_f64(&self.data, &mut result_data)?;
Ok(Float64Column {
data: result_data.into(),
null_mask: self.null_mask.clone(),
name: None,
})
}
fn simd_compare(&self, other: &Float64Column, op: ComparisonOp) -> Result<Vec<bool>> {
if self.len() != other.len() {
return Err(Error::InconsistentRowCount {
expected: self.len(),
found: other.len(),
});
}
let mut result = vec![false; self.len()];
simd_compare_f64(&self.data, &other.data, op, &mut result)?;
apply_null_mask_to_comparison(&mut result, &self.null_mask, &other.null_mask);
Ok(result)
}
fn simd_compare_scalar(&self, scalar: f64, op: ComparisonOp) -> Result<Vec<bool>> {
let scalar_vec = vec![scalar; self.len()];
let mut result = vec![false; self.len()];
simd_compare_f64(&self.data, &scalar_vec, op, &mut result)?;
apply_null_mask_to_comparison(&mut result, &self.null_mask, &None);
Ok(result)
}
}
impl SIMDInt64Ops for Int64Column {
fn simd_add(&self, other: &Int64Column) -> Result<Int64Column> {
if self.len() != other.len() {
return Err(Error::InconsistentRowCount {
expected: self.len(),
found: other.len(),
});
}
let mut result_data = vec![0i64; self.len()];
simd_add_i64(&self.data, &other.data, &mut result_data)?;
let null_mask = combine_null_masks(&self.null_mask, &other.null_mask, self.len())?;
Ok(Int64Column {
data: result_data.into(),
null_mask,
name: None,
})
}
fn simd_subtract(&self, other: &Int64Column) -> Result<Int64Column> {
if self.len() != other.len() {
return Err(Error::InconsistentRowCount {
expected: self.len(),
found: other.len(),
});
}
let mut result_data = vec![0i64; self.len()];
simd_subtract_i64(&self.data, &other.data, &mut result_data)?;
let null_mask = combine_null_masks(&self.null_mask, &other.null_mask, self.len())?;
Ok(Int64Column {
data: result_data.into(),
null_mask,
name: None,
})
}
fn simd_multiply(&self, other: &Int64Column) -> Result<Int64Column> {
if self.len() != other.len() {
return Err(Error::InconsistentRowCount {
expected: self.len(),
found: other.len(),
});
}
let mut result_data = vec![0i64; self.len()];
simd_multiply_i64(&self.data, &other.data, &mut result_data)?;
let null_mask = combine_null_masks(&self.null_mask, &other.null_mask, self.len())?;
Ok(Int64Column {
data: result_data.into(),
null_mask,
name: None,
})
}
fn simd_add_scalar(&self, scalar: i64) -> Result<Int64Column> {
let mut result_data = vec![0i64; self.len()];
simd_add_scalar_i64(&self.data, scalar, &mut result_data)?;
Ok(Int64Column {
data: result_data.into(),
null_mask: self.null_mask.clone(),
name: None,
})
}
fn simd_abs(&self) -> Result<Int64Column> {
let mut result_data = vec![0i64; self.len()];
simd_abs_i64(&self.data, &mut result_data)?;
Ok(Int64Column {
data: result_data.into(),
null_mask: self.null_mask.clone(),
name: None,
})
}
fn simd_compare(&self, other: &Int64Column, op: ComparisonOp) -> Result<Vec<bool>> {
if self.len() != other.len() {
return Err(Error::InconsistentRowCount {
expected: self.len(),
found: other.len(),
});
}
let mut result = vec![false; self.len()];
simd_compare_i64(&self.data, &other.data, op, &mut result)?;
apply_null_mask_to_comparison(&mut result, &self.null_mask, &other.null_mask);
Ok(result)
}
fn simd_compare_scalar(&self, scalar: i64, op: ComparisonOp) -> Result<Vec<bool>> {
let scalar_vec = vec![scalar; self.len()];
let mut result = vec![false; self.len()];
simd_compare_i64(&self.data, &scalar_vec, op, &mut result)?;
apply_null_mask_to_comparison(&mut result, &self.null_mask, &None);
Ok(result)
}
fn to_float64_simd(&self) -> Result<Float64Column> {
let float_data: Vec<f64> = self.data.iter().map(|&x| x as f64).collect();
Ok(Float64Column {
data: float_data.into(),
null_mask: self.null_mask.clone(),
name: None,
})
}
}
fn combine_null_masks(
mask1: &Option<std::sync::Arc<[u8]>>,
mask2: &Option<std::sync::Arc<[u8]>>,
len: usize,
) -> Result<Option<std::sync::Arc<[u8]>>> {
match (mask1, mask2) {
(Some(m1), Some(m2)) => {
let bytes_needed = (len + 7) / 8;
let mut combined = vec![0u8; bytes_needed];
for i in 0..bytes_needed.min(m1.len()).min(m2.len()) {
combined[i] = m1[i] | m2[i];
}
Ok(Some(combined.into()))
}
(Some(m), None) | (None, Some(m)) => Ok(Some(m.clone())),
(None, None) => Ok(None),
}
}
fn apply_null_mask_to_comparison(
result: &mut [bool],
mask1: &Option<std::sync::Arc<[u8]>>,
mask2: &Option<std::sync::Arc<[u8]>>,
) {
for i in 0..result.len() {
let is_null = is_null_at_index(mask1, i) || is_null_at_index(mask2, i);
if is_null {
result[i] = false;
}
}
}
fn is_null_at_index(mask: &Option<std::sync::Arc<[u8]>>, index: usize) -> bool {
if let Some(m) = mask {
let byte_idx = index / 8;
let bit_idx = index % 8;
if byte_idx < m.len() {
(m[byte_idx] & (1 << bit_idx)) != 0
} else {
false
}
} else {
false
}
}
pub struct SIMDColumnArithmetic;
impl SIMDColumnArithmetic {
pub fn add_columns(
left: &crate::column::Column,
right: &crate::column::Column,
) -> Result<crate::column::Column> {
use crate::column::Column;
match (left, right) {
(Column::Float64(l), Column::Float64(r)) => Ok(Column::Float64(l.simd_add(r)?)),
(Column::Int64(l), Column::Int64(r)) => Ok(Column::Int64(l.simd_add(r)?)),
(Column::Float64(l), Column::Int64(r)) => {
let r_float = r.to_float64_simd()?;
Ok(Column::Float64(l.simd_add(&r_float)?))
}
(Column::Int64(l), Column::Float64(r)) => {
let l_float = l.to_float64_simd()?;
Ok(Column::Float64(l_float.simd_add(r)?))
}
_ => Err(Error::InvalidOperation(
"SIMD addition not supported for these column types".to_string(),
)),
}
}
pub fn multiply_columns(
left: &crate::column::Column,
right: &crate::column::Column,
) -> Result<crate::column::Column> {
use crate::column::Column;
match (left, right) {
(Column::Float64(l), Column::Float64(r)) => Ok(Column::Float64(l.simd_multiply(r)?)),
(Column::Int64(l), Column::Int64(r)) => Ok(Column::Int64(l.simd_multiply(r)?)),
(Column::Float64(l), Column::Int64(r)) => {
let r_float = r.to_float64_simd()?;
Ok(Column::Float64(l.simd_multiply(&r_float)?))
}
(Column::Int64(l), Column::Float64(r)) => {
let l_float = l.to_float64_simd()?;
Ok(Column::Float64(l_float.simd_multiply(r)?))
}
_ => Err(Error::InvalidOperation(
"SIMD multiplication not supported for these column types".to_string(),
)),
}
}
pub fn multiply_scalar(
column: &crate::column::Column,
scalar: f64,
) -> Result<crate::column::Column> {
use crate::column::Column;
match column {
Column::Float64(col) => Ok(Column::Float64(col.simd_multiply_scalar(scalar)?)),
Column::Int64(col) => {
let float_col = col.to_float64_simd()?;
Ok(Column::Float64(float_col.simd_multiply_scalar(scalar)?))
}
_ => Err(Error::InvalidOperation(
"SIMD scalar multiplication not supported for this column type".to_string(),
)),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::column::{Float64Column, Int64Column};
#[test]
fn test_simd_float64_add() {
let col1 = Float64Column::new(vec![1.0, 2.0, 3.0, 4.0]);
let col2 = Float64Column::new(vec![1.0, 1.0, 1.0, 1.0]);
let result = col1.simd_add(&col2).expect("operation should succeed");
assert_eq!(result.data(), vec![2.0, 3.0, 4.0, 5.0]);
}
#[test]
fn test_simd_float64_scalar_multiply() {
let col = Float64Column::new(vec![1.0, 2.0, 3.0, 4.0]);
let result = col
.simd_multiply_scalar(2.0)
.expect("operation should succeed");
assert_eq!(result.data(), vec![2.0, 4.0, 6.0, 8.0]);
}
#[test]
fn test_simd_float64_abs() {
let col = Float64Column::new(vec![-1.0, 2.0, -3.0, 4.0]);
let result = col.simd_abs().expect("operation should succeed");
assert_eq!(result.data(), vec![1.0, 2.0, 3.0, 4.0]);
}
#[test]
fn test_simd_float64_compare() {
let col1 = Float64Column::new(vec![1.0, 2.0, 3.0, 4.0]);
let col2 = Float64Column::new(vec![1.0, 1.0, 4.0, 4.0]);
let result = col1
.simd_compare(&col2, ComparisonOp::GreaterThan)
.expect("operation should succeed");
assert_eq!(result, vec![false, true, false, false]);
}
#[test]
fn test_simd_int64_add() {
let col1 = Int64Column::new(vec![1, 2, 3, 4]);
let col2 = Int64Column::new(vec![1, 1, 1, 1]);
let result = col1.simd_add(&col2).expect("operation should succeed");
assert_eq!(result.data(), vec![2, 3, 4, 5]);
}
#[test]
fn test_simd_int64_to_float64() {
let col = Int64Column::new(vec![1, 2, 3, 4]);
let result = col.to_float64_simd().expect("operation should succeed");
assert_eq!(result.data(), vec![1.0, 2.0, 3.0, 4.0]);
}
#[test]
fn test_mixed_column_arithmetic() {
use crate::column::Column;
let col1 = Column::Float64(Float64Column::new(vec![1.0, 2.0, 3.0]));
let col2 = Column::Int64(Int64Column::new(vec![1, 2, 3]));
let result =
SIMDColumnArithmetic::add_columns(&col1, &col2).expect("operation should succeed");
if let Column::Float64(float_result) = result {
assert_eq!(float_result.data(), vec![2.0, 4.0, 6.0]);
} else {
panic!("Expected Float64 column result");
}
}
#[test]
fn test_length_mismatch_error() {
let col1 = Float64Column::new(vec![1.0, 2.0]);
let col2 = Float64Column::new(vec![1.0]);
let result = col1.simd_add(&col2);
assert!(result.is_err());
}
}