#[cfg(feature = "scirs2")]
use crate::core::error::{Error, Result};
#[cfg(feature = "scirs2")]
use crate::dataframe::DataFrame;
#[cfg(feature = "scirs2")]
use crate::scirs2_integration::conversion::{array2_to_dataframe, dataframe_to_array2};
#[cfg(feature = "scirs2")]
use crate::series::Series;
#[cfg(feature = "scirs2")]
#[derive(Debug, Clone)]
pub struct EigResult {
pub values: Vec<f64>,
pub vectors: DataFrame,
}
#[cfg(feature = "scirs2")]
#[derive(Debug, Clone)]
pub struct SvdResult {
pub u: DataFrame,
pub s: Vec<f64>,
pub vt: DataFrame,
}
#[cfg(feature = "scirs2")]
pub struct SciRS2LinAlg;
#[cfg(feature = "scirs2")]
impl SciRS2LinAlg {
pub fn matmul(a: &DataFrame, b: &DataFrame) -> Result<DataFrame> {
let a_col_names = a.column_names();
let a_cols: Vec<&str> = a_col_names.iter().map(|s| s.as_str()).collect();
let b_col_names = b.column_names();
let b_cols: Vec<&str> = b_col_names.iter().map(|s| s.as_str()).collect();
let arr_a = dataframe_to_array2(a, &a_cols)?;
let arr_b = dataframe_to_array2(b, &b_cols)?;
let (m, k_a) = arr_a.dim();
let (k_b, n) = arr_b.dim();
if k_a != k_b {
return Err(Error::InvalidInput(format!(
"Matrix dimensions incompatible for multiplication: ({}, {}) x ({}, {})",
m, k_a, k_b, n
)));
}
let result = arr_a.dot(&arr_b);
let col_names: Vec<String> = (0..n).map(|i| format!("c{}", i)).collect();
array2_to_dataframe(&result, col_names)
}
pub fn eig(df: &DataFrame) -> Result<EigResult> {
use scirs2_linalg::eigh;
let cols: Vec<String> = df.column_names();
let col_refs: Vec<&str> = cols.iter().map(|s| s.as_str()).collect();
let arr = dataframe_to_array2(df, &col_refs)?;
let (n_rows, n_cols) = arr.dim();
if n_rows != n_cols {
return Err(Error::InvalidInput(format!(
"Eigendecomposition requires a square matrix, got ({}, {})",
n_rows, n_cols
)));
}
let (eigenvalues, eigenvectors) = eigh(&arr.view(), None)
.map_err(|e| Error::OperationFailed(format!("SciRS2 eigh failed: {}", e)))?;
let values: Vec<f64> = eigenvalues.iter().copied().collect();
let ev_col_names: Vec<String> = (0..n_cols).map(|i| format!("ev{}", i)).collect();
let vectors_df = array2_to_dataframe(&eigenvectors, ev_col_names)?;
Ok(EigResult {
values,
vectors: vectors_df,
})
}
pub fn svd(df: &DataFrame) -> Result<SvdResult> {
use scirs2_linalg::svd;
let cols: Vec<String> = df.column_names();
let col_refs: Vec<&str> = cols.iter().map(|s| s.as_str()).collect();
let arr = dataframe_to_array2(df, &col_refs)?;
let (m, n) = arr.dim();
let (u, s, vt) = svd(&arr.view(), false, None)
.map_err(|e| Error::OperationFailed(format!("SciRS2 svd failed: {}", e)))?;
let k = s.len();
let singular_values: Vec<f64> = s.iter().copied().collect();
let u_col_names: Vec<String> = (0..u.ncols()).map(|i| format!("u{}", i)).collect();
let vt_col_names: Vec<String> = (0..vt.ncols()).map(|i| format!("v{}", i)).collect();
let u_df = array2_to_dataframe(&u, u_col_names)?;
let vt_df = array2_to_dataframe(&vt, vt_col_names)?;
Ok(SvdResult {
u: u_df,
s: singular_values,
vt: vt_df,
})
}
pub fn solve(a: &DataFrame, b: &DataFrame) -> Result<DataFrame> {
use scirs2_linalg::solve_multiple;
let a_cols: Vec<String> = a.column_names();
let b_cols: Vec<String> = b.column_names();
let a_col_refs: Vec<&str> = a_cols.iter().map(|s| s.as_str()).collect();
let b_col_refs: Vec<&str> = b_cols.iter().map(|s| s.as_str()).collect();
let arr_a = dataframe_to_array2(a, &a_col_refs)?;
let arr_b = dataframe_to_array2(b, &b_col_refs)?;
let (n_rows, n_cols) = arr_a.dim();
if n_rows != n_cols {
return Err(Error::InvalidInput(format!(
"Coefficient matrix must be square, got ({}, {})",
n_rows, n_cols
)));
}
let x = solve_multiple(&arr_a.view(), &arr_b.view(), None)
.map_err(|e| Error::OperationFailed(format!("SciRS2 solve failed: {}", e)))?;
let k = x.ncols();
let x_col_names: Vec<String> = (0..k).map(|i| format!("x{}", i)).collect();
array2_to_dataframe(&x, x_col_names)
}
pub fn inv(df: &DataFrame) -> Result<DataFrame> {
use scirs2_linalg::inv;
let cols: Vec<String> = df.column_names();
let col_refs: Vec<&str> = cols.iter().map(|s| s.as_str()).collect();
let arr = dataframe_to_array2(df, &col_refs)?;
let (n_rows, n_cols) = arr.dim();
if n_rows != n_cols {
return Err(Error::InvalidInput(format!(
"Matrix inverse requires a square matrix, got ({}, {})",
n_rows, n_cols
)));
}
let inv_arr = inv(&arr.view(), None)
.map_err(|e| Error::OperationFailed(format!("SciRS2 inv failed: {}", e)))?;
array2_to_dataframe(&inv_arr, cols)
}
pub fn det(df: &DataFrame) -> Result<f64> {
use scirs2_linalg::det;
let cols: Vec<String> = df.column_names();
let col_refs: Vec<&str> = cols.iter().map(|s| s.as_str()).collect();
let arr = dataframe_to_array2(df, &col_refs)?;
let (n_rows, n_cols) = arr.dim();
if n_rows != n_cols {
return Err(Error::InvalidInput(format!(
"Determinant requires a square matrix, got ({}, {})",
n_rows, n_cols
)));
}
det(&arr.view(), None)
.map_err(|e| Error::OperationFailed(format!("SciRS2 det failed: {}", e)))
}
}