matamorph 0.2.0

Seamless conversions between Rust’s major matrix libraries: ndarray, faer, nalgebra, and mdarray.
Documentation
#![doc(
    html_logo_url = "https://gitlab.com/starcluster/matamorph/-/raw/master/logo.png",
    // Credit goes to https://commons.wikimedia.org/wiki/User:Meul for the drawing
    html_favicon_url = "https://gitlab.com/starcluster/matamorph/-/raw/master/logo.png"
)]
//! # Matamorph
//!
//! Seamless conversions between Rust's major matrix libraries: [ndarray], [faer], [nalgebra], and [mdarray].
//!
//! ## Overview
//!
//! Matamorph provides a unified interface for converting 2D matrices between the four main Rust crates
//! for matrix manipulation.
//!
//! The crate provides three types of conversions:
//! - **Owned conversions** : Create a new matrix with copied data
//! - **Immutable reference conversions** : Zero-copy read-only views
//! - **Mutable reference conversions** : Zero-copy read-write views
//!
//! ## Memory Layout Considerations
//!
//! Different crates use different memory layouts:
//! - **Row-major**: [ndarray], [mdarray]
//! - **Column-major**: [faer], [nalgebra]
//!
//! Additionally, [nalgebra] requires data to be contiguous along the first dimension and doesn't support
//! arbitrary strides. This constraint affects certain conversions:
//!
//! ### Conversion Compatibility Matrix
//!
//! | From ↓ \ To → | [ndarray] | [faer] | [nalgebra] | [mdarray] |
//! |---------------|-----------|--------|------------|-----------|
//! | **owned**     | ✓         | ✓      | ✓          | ✓         |
//! | **ref**       | ✓         | ✓      | ✓ᵀ         | ✓         |
//! | **mut**       | ✓         | ✓      | ✓ᵀ         | ✓         |
//!
//! - ✓ = Conversion preserves layout
//! - ✓ᵀ = Conversion returns a transposed view (only when converting from row-major [ndarray]/[mdarray]
//!   references to column-major [nalgebra])
//!
//! **Note**: Owned conversions always copy data and ensure correct layout for the target crate.
//! Reference conversions (`ref` and `mut`) are zero-copy operations.
//!
//! ## Example
//!
//! ### Basic Usage
//!
//! ```
//! use matamorph::own::MataConvertOwn;
//! use matamorph::ref_::MataConvertRef;
//! use matamorph::mut_::MataConvertMut;
//!
//! // Owned conversion (copies data): ndarray → nalgebra
//! let a = ndarray::array![[1.0, 2.0], [3.0, 4.0]];
//! let b = a.to_nalgebra();
//! assert_eq!(b[(0, 1)], 2.0);
//!
//! // Reference conversion (zero-copy): mdarray → faer
//! let c = mdarray::tensor![[5.0, 6.0], [7.0, 8.0]];
//! let d = c.view(.., ..).to_faer();
//! assert_eq!(d[(1, 0)], 7.0);
//!
//! // Mutable reference conversion (zero-copy): ndarray → faer
//! let mut e = ndarray::array![[9.0, 10.0], [11.0, 12.0]];
//! let mut f = e.view_mut().to_faer();
//! f[(0, 0)] = 0.0;
//! assert_eq!(e[[0, 0]], 0.0);  // Original is modified
//! ```
//! ### Memory Layout Considerations (nalgebra)
//!
//! ```
//! use matamorph::ref_::MataConvertRef;
//! // ⚠️ Warning: conversions to nalgebra from row-major references are transposed!
//! let g = ndarray::array![[1.0, 2.0], [3.0, 4.0]];
//! let h = g.view().to_nalgebra();
//! assert_eq!(h[(1, 0)], 2.0);  // h is transposed: h[(row, col)] = g[(col, row)]
//!
//! // But conversions FROM nalgebra preserve layout (no transposition)
//! let i = nalgebra::dmatrix![1.0, 2.0; 3.0, 4.0];
//! let i_view = i.view((0,0), (2,2));
//! let j = i_view.to_ndarray();
//! assert_eq!(j[[0, 1]], 2.0);  // No transposition
//! assert_eq!(i[(0, 1)], 2.0);  // Same element accessed
//!
//! // Similarly, conversions between column-major crates (faer ↔ nalgebra) preserve layout
//! let k = faer::mat![[1.0, 2.0], [3.0, 4.0]];
//! let l = k.as_ref().to_nalgebra();
//! assert_eq!(l[(1, 0)], 3.0);  // No transposition
//! assert_eq!(k[(1, 0)], 3.0);  // Same element accessed
//! ```
//!
//!
//! [ndarray]: https://docs.rs/ndarray
//! [faer]: https://docs.rs/faer
//! [nalgebra]: https://docs.rs/nalgebra
//! [mdarray]: https://docs.rs/mdarray

pub mod mut_;
pub mod own;
pub mod ref_;

#[allow(dead_code)]
fn compute_len(shape: (usize, usize), strides: (isize, isize)) -> usize {
    let (rows, cols) = shape;

    if rows == 0 || cols == 0 {
        0
    } else {
        (rows - 1) * strides.0 as usize + (cols - 1) * strides.1 as usize + 1
    }
}