A simulation I'm doing requires me to calculate the partial trace of a large density matrix. I am trying to calculate it using tools from numpy, but my code seems to be having some problems. For background, let me explain the arrays I am interested in a little more, and the way I'm defining the partial trace. Then, I will give the code I have and the errors I am getting.
First, the partial trace. If I have a tensor product of vector spaces
$$ V = \prod_i V_i$$
and a linear operator $T: V \to V$, then given a basis I can store all the information about $T$ as a multidimensional array $T_{out_1,..,out_n,in_1,..,in_n}$ where $T_{out_1,..,out_n,in_1,..,in_n}$ is the $v_{out_1} \otimes v_{out_2}\otimes \dots \otimes v_{out_n}$ component of $T(v_{in_1} \otimes \dots \otimes v_{in_n} )$. (Compare this to a matrix in a basis where $M_{ij}$ is the $i^{th}$ component of $M(v_j)$.)
The partial trace over some of these indices is a new operator given as a multidimensional array defined by $\widetilde{T}_{kept_{out},kept_{in}} = \sum_{traced} T_{keep_{out},traced, keep_{in},traced}$, where $kept_{in}$, $kept_{out}$, and $traced$ are all multi indices referring to a subset of basis states. The sum is taken over all combinations of indices in the traced set.
My code for computing this in numpy is:
def trace_index(array,i):
"""
Given an array and an index i, traces out the index.
"""
n = len(array.shape)
tot = list(range(n))
tot[n//2+i-1] = i-1
return np.einsum(array,list(tot))
def partial_trace(array,indices):
"""
Given an array and a list of indices to trace out, traces out the indices
"""
in_sorted = sorted(indices,reverse=True)
cur_trace = array
for i in in_sorted:
cur_trace = trace_index(cur_trace,i)
return cur_trace
I trace them in the descending order eg. 5,4,... because then I can apply trace_index to the indices one at a time. If I trace index 5 and then index 4, index 4 is still index 4 after tracing index 5. If I do it the other way, after I traced index 4, there is no index 5.
This code seems to work well for small cases, but for larger ones I
ValueError: invalid subscript '}' in einstein sum subscripts string, subscripts must be letters
So, my question is this: Is there a better way to do what I am trying to do than what I am doing?