I'm working on a module that wraps a C machine learning library, but keep going back and forth between a few options in the API design.
Main thing I'm undecided on is how to pass/return matrices to/from functions. Under the hood, they all get passed to C as a flat array plus the number of rows/columns they contain, but there seem to be a bunch of different approaches that I could take on the Rust side of things.
One obvious option would be to use ndarray
, e.g.:
fn transform(matrix: ndarray::Array2<f32>) -> ndarray::Array2<f32> { ... }
It's very convenient to use, has lots of support for common array/matrix operations (and nice slicing macros etc.).
Main worry is that it forces users to use ndarray
, and I know there are several alternatives out there (nalgebra
, rulinalg
, etc.) which might be preferred.
Another alternative would be to stick to the Rust standard libraries, e.g.:
fn transform(data: &[u32], num_rows: usize, num_cols: usize) -> (Vec<f32>, usize, usize) { ... }
Which has the advantage of not tying users to a particular 3rd party linalg module, is closer to how the underlying C library takes/returns matrices, and might be easier to use for those not familiar with ndarray
.
A 3rd alternative I'd considered was to define my own matrix structs (in a similar way to e.g. rusty_machine does things), which might look like e.g.:
fn transform(matrix: &MyMatrix) -> MyMatrix { ... }
One upside of this approach is that is that the same struct could be used to represent both dense/sparse matrices (ndarray
doesn't have sparse support), and would be easy enough to construct from a variety of sources.
Downside is that it's yet another thing for users to learn.
Any suggestions on which approach might be preferred? Any alternatives I've not considered?