use numpy::{IntoPyArray, PyArray1, PyArrayMethods, PyUntypedArrayMethods};
use pyo3::prelude::*;
use pyo3::types::PyTuple;
use crate::csr::{check_index_capacity, CsrMatrix, CsrView};
use crate::index::Index;
use crate::scalar::Scalar;
pub(crate) fn borrow_csr_view<'py, V, I>(
data: &Bound<'py, PyAny>,
indptr: &Bound<'py, PyAny>,
indices: &Bound<'py, PyAny>,
nrows: usize,
ncols: usize,
) -> PyResult<CsrView<'py, V, I>>
where
V: Scalar + numpy::Element,
I: Index + numpy::Element,
{
let data_arr = data.downcast::<PyArray1<V>>()?.readonly();
let indptr_arr = indptr.downcast::<PyArray1<I>>()?.readonly();
let indices_arr = indices.downcast::<PyArray1<I>>()?.readonly();
let data_slice: &[V] = data_arr.as_slice()?;
let indptr_slice: &[I] = indptr_arr.as_slice()?;
let indices_slice: &[I] = indices_arr.as_slice()?;
let data_slice: &'py [V] = unsafe { std::mem::transmute(data_slice) };
let indptr_slice: &'py [I] = unsafe { std::mem::transmute(indptr_slice) };
let indices_slice: &'py [I] = unsafe { std::mem::transmute(indices_slice) };
CsrView::new(nrows, ncols, indptr_slice, indices_slice, data_slice)
.map_err(|e| pyo3::exceptions::PyValueError::new_err(e.to_string()))
}
pub(crate) fn indptr_nrows<I>(indptr: &Bound<'_, PyAny>) -> PyResult<usize>
where
I: Index + numpy::Element,
{
let arr = indptr.downcast::<PyArray1<I>>()?;
let len = arr.len();
if len == 0 {
return Err(pyo3::exceptions::PyValueError::new_err(
"indptr must have length >= 1",
));
}
Ok(len - 1)
}
pub(crate) fn csr_to_py_tuple<'py, V, I>(
py: Python<'py>,
m: CsrMatrix<V, I>,
) -> PyResult<Bound<'py, PyTuple>>
where
V: Scalar + numpy::Element,
I: Index + numpy::Element,
{
check_index_capacity::<I>(m.nnz(), m.ncols).map_err(|e| {
pyo3::exceptions::PyOverflowError::new_err(format!(
"{e}; pass idx_dtype=np.int64 or split the inputs"
))
})?;
let data = m.data.into_pyarray(py);
let indices = m.indices.into_pyarray(py);
let indptr = m.indptr.into_pyarray(py);
PyTuple::new(py, [data.into_any(), indices.into_any(), indptr.into_any()])
}