def _reorder_kronecker_product(hi, mat, acting_on) -> Tuple[Array, Tuple]: """ Reorders the matrix resulting from a kronecker product of several operators in such a way to sort acting_on. A conceptual example is the following: if `mat = Â ⊗ B̂ ⊗ Ĉ` and `acting_on = [[2],[1],[3]` you will get `result = B̂ ⊗ Â ⊗ Ĉ, [[1], [2], [3]]. However, essentially, A,B,C represent some operators acting on thei sub-space acting_on[1], [2] and [3] of the hilbert space. This function also handles any possible set of values in acting_on. The inner logic uses the Fock.all_states(), number_to_state and state_to_number to perform the re-ordering. """ acting_on_sorted = np.sort(acting_on) if np.array_equal(acting_on_sorted, acting_on): return mat, acting_on # could write custom binary <-> int logic instead of using Fock... # Since i need to work with bit-strings (where instead of bits i # have integers, in order to support arbitrary size spaces) this # is exactly what hilbert.to_number() and viceversa do. # target ordering binary representation hi_subspace = Fock(hi.shape[acting_on_sorted[0]] - 1) for site in acting_on_sorted[1:]: hi_subspace = hi_subspace * Fock(hi.shape[site] - 1) hi_unsorted_subspace = Fock(hi.shape[acting_on[0]] - 1) for site in acting_on[1:]: hi_unsorted_subspace = hi_unsorted_subspace * Fock(hi.shape[site] - 1) # find how to map target ordering back to unordered acting_on_unsorted_ids = np.zeros(len(acting_on), dtype=np.intp) for (i, site) in enumerate(acting_on): acting_on_unsorted_ids[i] = np.argmax(site == acting_on_sorted) # now it is valid that # acting_on_sorted == acting_on[acting_on_unsorted_ids] # generate n-bit strings in the target ordering v = hi_subspace.all_states() # convert them to origin (unordered) ordering v_unsorted = v[:, acting_on_unsorted_ids] # convert the unordered bit-strings to numbers in the target space. n_unsorted = hi_unsorted_subspace.states_to_numbers(v_unsorted) # reorder the matrix mat_sorted = mat[n_unsorted, :][:, n_unsorted] return mat_sorted, tuple(acting_on_sorted)
def _reorder_matrix(hi, mat, acting_on): acting_on_sorted = np.sort(acting_on) if np.all(acting_on_sorted == acting_on): return mat, acting_on acting_on_sorted_ids = np.argsort(acting_on) # could write custom binary <-> int logic instead of using Fock... # Since i need to work with bit-strings (where instead of bits i # have integers, in order to support arbitrary size spaces) this # is exactly what hilbert.to_number() and viceversa do. # target ordering binary representation hi_subspace = Fock(hi.shape[acting_on_sorted[0]] - 1) for site in acting_on_sorted[1:]: hi_subspace = Fock(hi.shape[site] - 1) * hi_subspace # find how to map target ordering back to unordered acting_on_unsorted_ids = np.zeros(len(acting_on), dtype=np.intp) for (i, site) in enumerate(acting_on): acting_on_unsorted_ids[i] = np.argmax(site == acting_on_sorted) # now it is valid that # acting_on_sorted == acting_on[acting_on_unsorted_ids] # generate n-bit strings in the target ordering v = hi_subspace.all_states() # convert them to origin (unordered) ordering v_unsorted = v[:, acting_on_unsorted_ids] # convert the unordered bit-strings to numbers in the target space. n_unsorted = hi_subspace.states_to_numbers(v_unsorted) # reorder the matrix mat_sorted = mat[n_unsorted, :][:, n_unsorted] return mat_sorted, acting_on_sorted