def _get_diagonal_component_polynomial_tensor(polynomial_tensor): """Get the component of an interaction operator that is diagonal in the computational basis under Jordan-Wigner transformation (i.e., the terms that can be expressed as products of number operators). Args: interaction_operator (openfermion.ops.InteractionOperator): the operator Returns: tuple: two openfermion.ops.InteractionOperator objects. The first is the diagonal component, and the second is the remainder. """ n_modes = count_qubits(polynomial_tensor) remainder_tensors = {} diagonal_tensors = {} diagonal_tensors[()] = polynomial_tensor.constant for key in polynomial_tensor.n_body_tensors: if key == (): continue remainder_tensors[key] = np.zeros((n_modes,) * len(key), complex) diagonal_tensors[key] = np.zeros((n_modes,) * len(key), complex) for indices in itertools.product(range(n_modes), repeat=len(key)): creation_counts = {} annihilation_counts = {} for meta_index, index in enumerate(indices): if key[meta_index] == 0: if annihilation_counts.get(index) is None: annihilation_counts[index] = 1 else: annihilation_counts[index] += 1 elif key[meta_index] == 1: if creation_counts.get(index) is None: creation_counts[index] = 1 else: creation_counts[index] += 1 term_is_diagonal = True for index in creation_counts: if creation_counts[index] != annihilation_counts.get(index): term_is_diagonal = False break if term_is_diagonal: for index in annihilation_counts: if annihilation_counts[index] != creation_counts.get(index): term_is_diagonal = False break if term_is_diagonal: diagonal_tensors[key][indices] = polynomial_tensor.n_body_tensors[key][ indices ] else: remainder_tensors[key][indices] = polynomial_tensor.n_body_tensors[key][ indices ] return PolynomialTensor(diagonal_tensors), PolynomialTensor(remainder_tensors)
def get_polynomial_tensor(fermion_operator, n_qubits=None): r"""Convert a fermionic operator to a Polynomial Tensor. Args: fermion_operator (openferion.ops.FermionOperator): The operator. n_qubits (int): The number of qubits to be included in the PolynomialTensor. Must be at least equal to the number of qubits that are acted on by fermion_operator. If None, then the number of qubits is inferred from fermion_operator. Returns: openfermion.ops.PolynomialTensor: The tensor representation of the operator. """ if not isinstance(fermion_operator, FermionOperator): raise TypeError("Input must be a FermionOperator.") if n_qubits is None: n_qubits = count_qubits(fermion_operator) if n_qubits < count_qubits(fermion_operator): raise ValueError("Invalid number of qubits specified.") # Normal order the terms and initialize. fermion_operator = normal_ordered(fermion_operator) tensor_dict = {} # Loop through terms and assign to matrix. for term in fermion_operator.terms: coefficient = fermion_operator.terms[term] # Handle constant shift. if len(term) == 0: tensor_dict[()] = coefficient else: key = tuple([operator[1] for operator in term]) if tensor_dict.get(key) is None: tensor_dict[key] = np.zeros((n_qubits,) * len(key), complex) indices = tuple([operator[0] for operator in term]) tensor_dict[key][indices] = coefficient return PolynomialTensor(tensor_dict)