Skip to main content

RSTSR for NumPy Users

MATLAB® and NumPy have a lot in common, but NumPy was created to work with Python, not to be a MATLAB clone. This guide will help MATLAB users get started with NumPy.

--- NumPy user guide: NumPy for MATLAB users

From its inception, one of RSTSR's key design goals was to provide a programming experience somewhat similar to NumPy within the native Rust environment.

RSTSR shares many similarities with NumPy in Python. However, RSTSR was developed based on the Rust ecosystem, primarily to assist REST electronic structure programs. While it has not yet achieved (but aspires to) full feature parity as a NumPy clone, it strives to make advancements. This guide will help NumPy users quickly understand and adapt to RSTSR.

Additionally, both the ndarray library in Rust and RSTSR are nn-D tensor libraries. RSTSR has drawn many concepts from ndarray, particularly regarding lifetimes.

1. Similarities with NumPy

RSTSR shares many similarities with NumPy:

  • It is a dynamic nn-D tensor library where basic indexing (including slicing) does not involve data movement or copying (i.e., no computational cost).
  • It follows the same broadcasting rules, applied to element-wise operations, matrix multiplication, and other operations.
  • Iteration starts at 0 instead of 1, which is a commonality between Python and Rust.
  • For implemented functionalities, RSTSR strives to maintain consistent function names and parameter signatures with NumPy.
  • With certain backends, both RSTSR and NumPy can leverage external high-performance libraries for linear algebra computations.

2. Key Differences and Comparisons with NumPy

This topic also relates to other documents: Why Choose RSTSR and Why Not Use RSTSR.

DifferenceNumPyRSTSR
REPLPython is an interactive language, making debugging easier.Rust is a compiled language, making debugging more challenging but offering better performance.
LifetimesNumPy generally does not expose lifetimes in high-level APIs for user convenience.
However, in low-level APIs, the attribute np.ndarray.flags indicates whether the tensor owns its data, is writable, etc.
This is not strictly equivalent but serves a similar purpose to lifetimes.
RSTSR tensors are instances of TensorBase (or its type alias TensorAny).
In practice, RSTSR requires explicit lifetime and borrowing rules through multiple types:
  • Tensor as an owning tensor
  • TensorView as a tensor view (referencing another tensor's data but owning dimension and layout information like contiguity)
  • TensorMut as a mutable tensor view
  • TensorCow as an owning or view type (commonly used in reshape operations)
This approach is nearly identical to the Rust ndarray library.
Backend DevicesNumPy does not support multiple devices (though when installed via conda, it can be configured to use MKL or OpenBLAS).RSTSR supports multiple devices and allows limited conversions between them.
Currently implemented devices include DeviceFaer and DeviceOpenBLAS (as well as the reference DeviceCpuSerial).
Different backends offer varying implementations for matrix multiplication, linear algebra, and parallelism.
Dynamic DimensionsNumPy tensors always have dynamic dimensions.RSTSR supports static dimensions (like the ndarray library) but recommends using dynamic dimensions.
For basic indexing, RSTSR always returns tensors with dynamic dimensions.
Users needing static dimensions should consider the into_dim function.
For improved iteration performance with static dimensions, enable the cargo feature dispatch_dim_layout_iter.
Syntactic SugarNumPy allows the @ symbol for matrix multiplication.RSTSR allows the % symbol for matrix multiplication.
For modulo operations, use the rt::rem function.
OverloadingPython allows overloading based on parameter names.
For example, in scipy.linalg.eigh:
  • eigh(a) performs standard diagonalization Ax=λx\mathbf{A} \bm{x} = \lambda \bm{x}
  • eigh(a, b) performs generalized diagonalization Ax=λBx\mathbf{A} \bm{x} = \lambda \mathbf{B} \bm{x}
  • eigh(a, lower=False) specifies using the upper triangle of A\mathbf{A}
  • eigh(a, overwrite_a=True) writes eigenvectors back to a
Rust allows overloading based on traits.
For example, in rt::linalg::eigh:
  • eigh(&a) performs standard diagonalization Ax=λx\mathbf{A} \bm{x} = \lambda \bm{x}
  • eigh((&a, &b)) performs generalized diagonalization Ax=λBx\mathbf{A} \bm{x} = \lambda \mathbf{B} \bm{x}1
  • eigh((&a, Upper)) specifies using the upper triangle of A\mathbf{A}
  • eigh(a.view_mut()) writes eigenvectors back to a2
Row/Column MajorNumPy is row-major.By default, RSTSR is row-major.
The default can be adjusted via cargo features to row- or column-major.
RSTSR also supports dynamically changing row/column-major by modifying the device.

Footnotes

  1. Currently, RSTSR only implements generalized diagonalization for BLAS devices. For Faer devices (DeviceFaer), standard diagonalization is supported.

  2. Currently, RSTSR only supports writing eigenvectors back to the input matrix for BLAS devices. Note that this may not actually reduce memory usage during diagonalization, as LAPACK's default divide-and-conquer method requires significant cache space, and transposing to f-prefer may create temporary memory.