Hello,
I’m working on an opensource library for tensor network computations for quantum physics and other sciences. I’d be grateful for some feedback regarding the following architectural ideas.
One basic concept of the library is a tensor, a kind of generalized ndimensional matrix that can have various internal representations (dense, sparse, but there are also others).
One basic operations is contraction of two tensors, which is a generalization of matrix multiplication. It is important that contractions of different kinds of tensors are optimized, i.e. densedense, densesparse, sparsesparse, etc. I’m considering having methods that allow to probe capacities of tensors (i.e. whether it has a dense representation, whether it has a sparse representation). I might also define a hierarchy of traits and use that.
The other basic concept is a tensor network, that is a graph of interconnected tensors that offers various algorithms that transform the network while preserving some invariants. For example there would be various algorithms to contract a network into a single tensor.
I would like to employ Rust generics for performance reasons, but also not to overdo with generality.
For example the whole library could be made generic over the floating point type, but I think that this is not necessary. That’s why I’m leaning towards using cargo features for specifying the floating point type: by default all computations would be done in f32 (say), and if the cargo feature “f64” is activated, all computations and data will switch to f64
. Does this sound like a good idea?
Here are two cases where I think the use of generics is justified:

It is crucial that a network can hold a mixture of different tensor types. But in cases where the item type is fixed (all tensors in a network are dense, say), knowing this at compile time could save dynamic lookups of capabilities.

A network does not modify its tensors. It may no longer need some, or replace some. So tensors could be shared over networks within one thread or even across threads. But it feels overkill to use
Arc<dyn Tensor>
everywhere. After all quite often tensors will be created specifically for a given network and the network could own them.
In order to address both requirement I’m considering using Deref<T>
where T: Tensor
as the item type of the network. Then one optimized network could hold items of type Box<DenseTensor>
and another more general network could hold Arc<dyn Tensor>
.
Does this sound reasonable?
Is there a way to avoid using Box
for the case where the network owns the tensors? I think I could define something like PseudoBox<T>
that is simply a wrapper type and doesn’t put its payload on the heap. But is this even a good idea? Does something like this already exist, or is there a better way to achieve that?
Thanks!