I am trying to use Rust to perform sequential kronecker product to multiple matrices, i.e. I want to do
In python, I know I can do
import numpy as np
from functools import reduce
X = np.array([[0, 1], [1, 0])
matrices = [X for _ in range(8)]
product = reduce(np.kron, matrices)
and get the desired result. How to do the same in Rust?
My Rust code look like the following for now:
use ndarray::{array, ArrayBase, OwnedRepr, Dim};
use ndarray::linalg::kron;
use num::complex::Complex64 as Complex;
fn X() -> ArrayBase<OwnedRepr<Complex>, Dim<[usize; 2]>> {
array![
[Complex::new(0.0, 0.0), Complex::new(1.0, 0.0)],
[Complex::new(1.0, 0.0), Complex::new(0.0, 0.0)]
]
}
fn main() {
let mut matrices = Vec::new();
for _ in 0..8 {
matrices.push(X());
}
let product = matrices
.iter()
.reduce(|g1, g2| kron(g1, g2));
}
Here's the error matrix I got:
Here's the things I don't understand:
OwnedRepr
: I'm not sure what this is for exactly, but this is what the rust-analyzer suggested me to doHow can I achieve this?
Unlike Python, in Rust you are required to think about ownership.
ndarray
includes multiple version of arrays: Array
, ArrayView
, ArrayViewMut
, ArcArray
and CowArray
. They are analogous to the many ways one can view a data in Rust: owned (T
or Box<T>
) - this is Array
which is an alias of ArrayBase<OwnedRepr>
, shared reference (&T
) - ArrayView
, mutable reference (&mut T
) - ArrayViewMut
, shared ownership (Rc<T>
and Arc<T>
) - ArcArray
, and copy-on-write (Cow<T>
) - CowArray
.
iter()
gives you an iterator over references to the elements, that is, &Array
, while kron()
returns owned arrays - Array
. But reduce()
requires both the inputs and the output to be of the same type, because the output becomes the input of the next item. So you need to unify them.
There are multiple ways you can do that. For example, by using into_iter()
instead of iter()
:
let product = matrices.into_iter().reduce(|g1, g2| kron(&g1, &g2));
Or by cloning the first matrix and using fold()
:
fn kron_many(matrices: &[Array2<Complex>]) -> Option<Array2<Complex>> {
let (first, rest) = matrices.split_first()?;
let first = first.clone();
Some(rest.iter().fold(first, |g1, g2| kron(&g1, g2)))
}
fn main() {
let mut matrices = Vec::new();
for _ in 0..8 {
matrices.push(X());
}
let product = kron_many(&matrices);
}
Or without cloning, by using CowArray
to represent a maybe-owned array:
let product = matrices
.iter()
.map(|matrix| CowArray::from(matrix))
.reduce(|g1, g2| kron(&g1, &g2).into());