Skip to main content

Crate cart_lin

Crate cart_lin 

Source
Expand description

§cart_lin

A lightweight library for converting between linear and cartesian indices for any number of dimensions.

This library offers the following functions for conversion between linear and cartesian indices for any number of dimensions:

Additionally, CartesianIndices provides an iterator over cartesian indices which can be seen as the multidimensional equivalent of the Range iterator.

This library has no dependencies besides the Rust stdlib and is therefore very lightweight.

The full API documentation is available at https://docs.rs/cart_lin/0.2.1/cart_lin/.

§Cartesian to linear conversion

Let’s use the following 2x3 matrix (two rows, three columns) as an example:

0 1 2
3 4 5

The cartesian index of element 0 is [0, 0], that of 1 is [0, 1], that of 5 is [1, 2] and so on. cart_to_lin (as well as all other functions of this library) uses row-major order (= last index changes fastest).

use cart_lin::cart_to_lin;

// Rows, columns
let dim_size = [2, 3];

assert_eq!(cart_to_lin(&[0, 0], &dim_size).unwrap(), 0);
assert_eq!(cart_to_lin(&[0, 1], &dim_size).unwrap(), 1);
assert_eq!(cart_to_lin(&[0, 2], &dim_size).unwrap(), 2);
assert_eq!(cart_to_lin(&[1, 0], &dim_size).unwrap(), 3);
assert_eq!(cart_to_lin(&[1, 1], &dim_size).unwrap(), 4);
assert_eq!(cart_to_lin(&[1, 2], &dim_size).unwrap(), 5);

For higher-dimensional matrices, it works in the same way (using the example of a matrix with 4 rows, 3 columns and 2 pages):

use cart_lin::cart_to_lin;

// Rows, columns, pages
let dim_size = [4, 3, 2];

assert_eq!(cart_to_lin(&[0, 0, 0], &dim_size).unwrap(), 0);
assert_eq!(cart_to_lin(&[0, 0, 1], &dim_size).unwrap(), 1);
assert_eq!(cart_to_lin(&[0, 1, 0], &dim_size).unwrap(), 2);
assert_eq!(cart_to_lin(&[0, 1, 1], &dim_size).unwrap(), 3);
assert_eq!(cart_to_lin(&[0, 2, 0], &dim_size).unwrap(), 4);
assert_eq!(cart_to_lin(&[0, 2, 1], &dim_size).unwrap(), 5);
assert_eq!(cart_to_lin(&[1, 0, 0], &dim_size).unwrap(), 6);

cart_to_lin checks whether the given cartesian index is valid for the specified number of dimensions. In order to avoid this check, use cart_to_lin_unchecked (which is not unsafe, but might return invalid indices).

§Linear to cartesian conversion

The inverse of cart_to_lin is lin_to_cart:

use cart_lin::lin_to_cart;

// Rows, columns
let dim_size = [2, 3];

assert_eq!(lin_to_cart(0, &dim_size).unwrap(), [0, 0]);
assert_eq!(lin_to_cart(1, &dim_size).unwrap(), [0, 1]);
assert_eq!(lin_to_cart(2, &dim_size).unwrap(), [0, 2]);
assert_eq!(lin_to_cart(3, &dim_size).unwrap(), [1, 0]);
assert_eq!(lin_to_cart(4, &dim_size).unwrap(), [1, 1]);
assert_eq!(lin_to_cart(5, &dim_size).unwrap(), [1, 2]);

§Iterate over cartesian indices

use cart_lin::CartesianIndices;

// Two dimensions (2 x 3 matrix)
let mut cartiter = CartesianIndices::new([2, 3]);
assert_eq!(cartiter.next(), Some([0, 0]));
assert_eq!(cartiter.next(), Some([0, 1]));
assert_eq!(cartiter.next(), Some([0, 2]));
assert_eq!(cartiter.next(), Some([1, 0]));
assert_eq!(cartiter.next(), Some([1, 1]));
assert_eq!(cartiter.next(), Some([1, 2]));
assert_eq!(cartiter.next(), None);

// Four dimensions (2 x 2 x 2 x 2 matrix)
let mut cartiter = CartesianIndices::new([2, 2, 2, 2]);
assert_eq!(cartiter.next(), Some([0, 0, 0, 0]));
assert_eq!(cartiter.next(), Some([0, 0, 0, 1]));
assert_eq!(cartiter.next(), Some([0, 0, 1, 0]));
assert_eq!(cartiter.next(), Some([0, 0, 1, 1]));
assert_eq!(cartiter.next(), Some([0, 1, 0, 0]));
assert_eq!(cartiter.next(), Some([0, 1, 0, 1]));
assert_eq!(cartiter.next(), Some([0, 1, 1, 0]));
assert_eq!(cartiter.next(), Some([0, 1, 1, 1]));
assert_eq!(cartiter.next(), Some([1, 0, 0, 0]));
// ...

CartesianIndices can also be constructed by defining lower and upper bounds for each axis. The following example is functionally equivalent to the previous one:

use cart_lin::CartesianIndices;

let mut cartiter = CartesianIndices::from_bounds([[0, 2], [0, 3]]).expect("bounds must be strictly monotonic increasing");
assert_eq!(cartiter.next(), Some([0, 0]));
assert_eq!(cartiter.next(), Some([0, 1]));
assert_eq!(cartiter.next(), Some([0, 2]));
assert_eq!(cartiter.next(), Some([1, 0]));
assert_eq!(cartiter.next(), Some([1, 1]));
assert_eq!(cartiter.next(), Some([1, 2]));
assert_eq!(cartiter.next(), None);

But it is also possible to add offsets via the lower bounds:

use cart_lin::CartesianIndices;

let mut cartiter = CartesianIndices::from_bounds([[1, 3], [2, 5]]).expect("bounds must be strictly monotonic increasing");
assert_eq!(cartiter.next(), Some([1, 2]));
assert_eq!(cartiter.next(), Some([1, 3]));
assert_eq!(cartiter.next(), Some([1, 4]));
assert_eq!(cartiter.next(), Some([2, 2]));
assert_eq!(cartiter.next(), Some([2, 3]));
assert_eq!(cartiter.next(), Some([2, 4]));
assert_eq!(cartiter.next(), None);

§Usage with matrix libraries

The tests directory contains examples on how to use this library together with nalgebra and ndarray. However, neither of those libraries is a dependency of cart_lin.

Structs§

CartesianIndices
An iterator over all cartesian indices within the input dimension sizes.

Functions§

cart_to_lin
Convert a cartesian index into a linear index (row-major).
cart_to_lin_unchecked
Like cart_to_lin, but without the checks.
lin_to_cart
Convert a linear index to a cartesian index (row-major).
lin_to_cart_dyn
Like lin_to_cart, but mutates cart_indices in place instead of returning a new array.
lin_to_cart_dyn_unchecked
Like lin_to_cart_dyn, but without the checks.
lin_to_cart_unchecked
Like lin_to_cart, but without the checks.