def _recursive_convert(self, operator: OperatorBase) -> OperatorBase: if isinstance(operator, EvolvedOp): if isinstance(operator.primitive, PauliSumOp): operator = EvolvedOp(operator.primitive.to_pauli_op(), coeff=operator.coeff) if not {"Pauli"} == operator.primitive_strings(): logger.warning( "Evolved Hamiltonian is not composed of only Paulis, converting to " "Pauli representation, which can be expensive.") # Setting massive=False because this conversion is implicit. User can perform this # action on the Hamiltonian with massive=True explicitly if they so choose. # TODO explore performance to see whether we should avoid doing this repeatedly pauli_ham = operator.primitive.to_pauli_op(massive=False) operator = EvolvedOp(pauli_ham, coeff=operator.coeff) if isinstance(operator.primitive, SummedOp): # TODO uncomment when we implement Abelian grouped evolution. # if operator.primitive.abelian: # return self.evolution_for_abelian_paulisum(operator.primitive) # else: # Collect terms that are not the identity. oplist = [ x for x in operator.primitive if not isinstance(x, PauliOp) or sum(x.primitive.x + x.primitive.z) != 0 ] # Collect the coefficients of any identity terms, # which become global phases when exponentiated. identity_phases = [ x.coeff for x in operator.primitive if isinstance(x, PauliOp) and sum(x.primitive.x + x.primitive.z) == 0 ] # Construct sum without the identity operators. new_primitive = SummedOp(oplist, coeff=operator.primitive.coeff) trotterized = self.trotter.convert(new_primitive) circuit_no_identities = self._recursive_convert(trotterized) # Set the global phase of the QuantumCircuit to account for removed identity terms. global_phase = -sum(identity_phases) * operator.primitive.coeff circuit_no_identities.primitive.global_phase = global_phase return circuit_no_identities elif isinstance(operator.primitive, PauliOp): return self.evolution_for_pauli(operator.primitive) # Covers ListOp, ComposedOp, TensoredOp elif isinstance(operator.primitive, ListOp): converted_ops = [ self._recursive_convert(op) for op in operator.primitive.oplist ] return operator.primitive.__class__(converted_ops, coeff=operator.coeff) elif isinstance(operator, ListOp): return operator.traverse(self.convert).reduce() return operator
def convert(self, operator: OperatorBase) -> OperatorBase: """Check if operator is a SummedOp, in which case covert it into a sum of mutually commuting sums, or if the Operator contains sub-Operators and ``traverse`` is True, attempt to convert any sub-Operators. Args: operator: The Operator to attempt to convert. Returns: The converted Operator. """ if isinstance(operator, PauliSumOp): return self.group_subops(operator) if isinstance(operator, ListOp): if isinstance(operator, SummedOp) and all( isinstance(op, PauliOp) for op in operator.oplist): # For now, we only support graphs over Paulis. return self.group_subops(operator) elif self._traverse: return operator.traverse(self.convert) elif isinstance(operator, OperatorStateFn) and self._traverse: return OperatorStateFn( self.convert(operator.primitive), is_measurement=operator.is_measurement, coeff=operator.coeff, ) elif isinstance(operator, EvolvedOp) and self._traverse: return EvolvedOp(self.convert(operator.primitive), coeff=operator.coeff) return operator
def convert(self, operator: OperatorBase) -> OperatorBase: r""" Traverse the operator, replacing ``EvolvedOps`` with ``CircuitOps`` containing ``UnitaryGates`` or ``HamiltonianGates`` (if self.coeff is a ``ParameterExpression``) equalling the exponentiation of -i * operator. This is done by converting the ``EvolvedOp.primitive`` to a ``MatrixOp`` and simply calling ``.exp_i()`` on that. Args: operator: The Operator to convert. Returns: The converted operator. """ if isinstance(operator, EvolvedOp): if not {"Matrix"} == operator.primitive_strings(): logger.warning( "Evolved Hamiltonian is not composed of only MatrixOps, converting " "to Matrix representation, which can be expensive.") # Setting massive=False because this conversion is implicit. User can perform this # action on the Hamiltonian with massive=True explicitly if they so choose. # TODO explore performance to see whether we should avoid doing this repeatedly matrix_ham = operator.primitive.to_matrix_op(massive=False) operator = EvolvedOp(matrix_ham, coeff=operator.coeff) if isinstance(operator.primitive, ListOp): return operator.primitive.exp_i() * operator.coeff elif isinstance(operator.primitive, (MatrixOp, PauliOp)): return operator.primitive.exp_i() elif isinstance(operator, ListOp): return operator.traverse(self.convert).reduce() return operator