quantrs2-core 0.1.3

Core types and traits for the QuantRS2 quantum computing framework
Documentation
//! Linear algebra utilities using SciRS2-Linalg
//! Compliant with SciRS2 POLICY - uses scirs2_linalg for all operations

use crate::error::QuantRS2Result;
use scirs2_core::ndarray::{Array1, Array2, ArrayView2};
use scirs2_core::Complex64;

/// Sparse CSR matrix stub
#[derive(Debug, Clone)]
pub struct CsrMatrix<T> {
    pub data: Vec<T>,
    pub indices: Vec<usize>,
    pub indptr: Vec<usize>,
    pub shape: (usize, usize),
}

impl<T: Clone + Default> CsrMatrix<T> {
    pub fn zeros(shape: (usize, usize)) -> Self {
        Self {
            data: Vec::new(),
            indices: Vec::new(),
            indptr: vec![0; shape.0 + 1],
            shape,
        }
    }

    pub const fn new(
        data: Vec<T>,
        indices: Vec<usize>,
        indptr: Vec<usize>,
        shape: (usize, usize),
    ) -> Result<Self, String> {
        Ok(Self {
            data,
            indices,
            indptr,
            shape,
        })
    }

    pub const fn shape(&self) -> (usize, usize) {
        self.shape
    }

    pub fn nnz(&self) -> usize {
        self.data.len()
    }
}

impl CsrMatrix<Complex64> {
    pub fn to_dense(&self) -> Array2<Complex64> {
        let (rows, cols) = self.shape;
        let mut dense = Array2::zeros((rows, cols));

        for row in 0..rows {
            let start = self.indptr[row];
            let end = self.indptr[row + 1];

            for idx in start..end {
                let col = self.indices[idx];
                let val = self.data[idx];
                dense[(row, col)] = val;
            }
        }

        dense
    }
}

/// SVD result
pub struct SvdResult {
    pub u: Array2<f64>,
    pub s: Array1<f64>,
    pub vt: Array2<f64>,
}

/// Compute SVD using SciRS2-Linalg (SciRS2 POLICY compliant)
pub fn svd(
    matrix: &ArrayView2<f64>,
    full_matrices: bool,
    compute_uv: Option<bool>,
) -> QuantRS2Result<(Array2<f64>, Array1<f64>, Array2<f64>)> {
    // Use scirs2_linalg for SVD computation (SciRS2 POLICY)
    // svd returns (u, singular_values, vt) tuple
    let (u, s, vt) = scirs2_linalg::svd(matrix, true, None)
        .map_err(|e| crate::error::QuantRS2Error::ComputationError(format!("SVD failed: {e:?}")))?;

    Ok((u, s, vt))
}

/// Compute SVD (simplified version)
pub fn svd_simple(matrix: &Array2<f64>) -> QuantRS2Result<SvdResult> {
    let (u, s, vt) = svd(&matrix.view(), true, Some(true))?;
    Ok(SvdResult { u, s, vt })
}

/// Compute randomized SVD
pub fn randomized_svd(
    matrix: &ArrayView2<f64>,
    rank: usize,
    oversampling: Option<usize>,
    n_iter: Option<usize>,
    random_state: Option<u64>,
) -> QuantRS2Result<(Array2<f64>, Array1<f64>, Array2<f64>)> {
    // Stub implementation - just call regular SVD and truncate
    let (u, s, vt) = svd(matrix, false, Some(true))?;
    let k = rank.min(s.len());

    Ok((
        u.slice(scirs2_core::ndarray::s![.., ..k]).to_owned(),
        s.slice(scirs2_core::ndarray::s![..k]).to_owned(),
        vt.slice(scirs2_core::ndarray::s![..k, ..]).to_owned(),
    ))
}

/// Compute truncated SVD
pub fn truncated_svd(
    matrix: &ArrayView2<f64>,
    rank: usize,
    random_state: Option<u64>,
) -> QuantRS2Result<(Array2<f64>, Array1<f64>, Array2<f64>)> {
    randomized_svd(matrix, rank, Some(10), Some(2), random_state)
}