Memory Order

tenferro dense tensors use column-major flat buffers. The leftmost dimension varies fastest in memory.

use tenferro::Tensor;

let tensor = Tensor::from_vec(vec![2, 3], vec![1.0_f64, 4.0, 2.0, 5.0, 3.0, 6.0]);
assert_eq!(tensor.shape(), &[2, 3]);
assert_eq!(
    tensor.as_slice::<f64>().unwrap(),
    &[1.0, 4.0, 2.0, 5.0, 3.0, 6.0]
);

The logical matrix is:

[[1, 2, 3],
 [4, 5, 6]]

Importing Row-Major Data

PyTorch, NumPy, and JAX examples often show row-major flat buffers. Convert those buffers to column-major before constructing a tenferro tensor.

use tenferro::Tensor;

fn row_major_to_column_major<T: Copy>(shape: &[usize], data: &[T]) -> Vec<T> {
    assert_eq!(shape.len(), 2);
    let rows = shape[0];
    let cols = shape[1];
    assert_eq!(data.len(), rows * cols);

    let mut out = Vec::with_capacity(data.len());
    for col in 0..cols {
        for row in 0..rows {
            out.push(data[row * cols + col]);
        }
    }
    out
}

let shape = vec![2, 3];
let row_major = vec![1.0_f64, 2.0, 3.0, 4.0, 5.0, 6.0];
let column_major = row_major_to_column_major(&shape, &row_major);
let tensor = Tensor::from_vec(shape, column_major);

assert_eq!(
    tensor.as_slice::<f64>().unwrap(),
    &[1.0, 4.0, 2.0, 5.0, 3.0, 6.0]
);

Owned Export

Owned export returns the column-major host buffer:

use tenferro::Tensor;

let tensor = Tensor::from_vec(vec![2, 2], vec![1.0_f64, 3.0, 2.0, 4.0]);
let (shape, data) = tensor.try_into_vec::<f64>().unwrap();

assert_eq!(shape, vec![2, 2]);
assert_eq!(data, vec![1.0, 3.0, 2.0, 4.0]);

Convert the exported buffer in your application if a consumer expects row-major data.