def evolution_for_pauli(self, pauli_op: PauliOp) -> PrimitiveOp: r""" Compute evolution Operator for a single Pauli using a ``PauliBasisChange``. Args: pauli_op: The ``PauliOp`` to evolve. Returns: A ``PrimitiveOp``, either the evolution ``CircuitOp`` or a ``PauliOp`` equal to the identity if pauli_op is the identity. """ def replacement_fn(cob_instr_op, dest_pauli_op): z_evolution = dest_pauli_op.exp_i() # Remember, circuit composition order is mirrored operator composition order. return cob_instr_op.adjoint().compose(z_evolution).compose( cob_instr_op) # Note: PauliBasisChange will pad destination with identities # to produce correct CoB circuit sig_bits = np.logical_or(pauli_op.primitive.z, pauli_op.primitive.x) a_sig_bit = int( max(np.extract(sig_bits, np.arange(pauli_op.num_qubits)[::-1]))) destination = (I.tensorpower(a_sig_bit)) ^ (Z * pauli_op.coeff) cob = PauliBasisChange(destination_basis=destination, replacement_fn=replacement_fn) return cast(PrimitiveOp, cob.convert(pauli_op))
def convert(self, operator: OperatorBase) -> OperatorBase: """Accepts an Operator and returns a new Operator with the Pauli measurements replaced by diagonal Pauli post-rotation based measurements so they can be evaluated by sampling and averaging. Args: operator: The operator to convert. Returns: The converted operator. """ if isinstance(operator, ListOp): return operator.traverse(self.convert).reduce() if isinstance(operator, OperatorStateFn) and operator.is_measurement: # Change to Pauli representation if necessary if (isinstance(operator.primitive, (ListOp, PrimitiveOp)) and not isinstance(operator.primitive, PauliSumOp) and {"Pauli", "SparsePauliOp"} < operator.primitive_strings()): logger.warning( "Measured Observable 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 Observable with massive=True explicitly if they so choose. pauli_obsv = operator.primitive.to_pauli_op(massive=False) operator = StateFn(pauli_obsv, is_measurement=True, coeff=operator.coeff) if self._grouper and isinstance(operator.primitive, (ListOp, PauliSumOp)): grouped = self._grouper.convert(operator.primitive) operator = StateFn(grouped, is_measurement=True, coeff=operator.coeff) # Convert the measurement into diagonal basis (PauliBasisChange chooses # this basis by default). cob = PauliBasisChange( replacement_fn=PauliBasisChange.measurement_replacement_fn) return cob.convert(operator).reduce() return operator