コード例 #1
0
 def test_sum(self, num_qubits, num_ops):
     """Test sum method for {num_qubits} qubits with {num_ops} operators."""
     ops = [self.random_spp_op(num_qubits, 2 ** num_qubits) for _ in range(num_ops)]
     sum_op = SparsePauliOp.sum(ops)
     value = Operator(sum_op)
     target_operator = sum((Operator(op) for op in ops[1:]), Operator(ops[0]))
     self.assertEqual(value, target_operator)
     target_spp_op = sum((op for op in ops[1:]), ops[0])
     self.assertEqual(sum_op, target_spp_op)
     np.testing.assert_array_equal(sum_op.paulis.phase, np.zeros(sum_op.size))
コード例 #2
0
 def test_sum_error(self):
     """Test sum method with invalid cases."""
     with self.assertRaises(QiskitError):
         SparsePauliOp.sum([])
     with self.assertRaises(QiskitError):
         ops = [self.random_spp_op(num_qubits, 2 ** num_qubits) for num_qubits in [1, 2]]
         SparsePauliOp.sum(ops)
     with self.assertRaises(QiskitError):
         SparsePauliOp.sum([1, 2])
コード例 #3
0
    def mode_based_mapping(
            second_q_op: SecondQuantizedOp,
            pauli_table: List[Tuple[Pauli, Pauli]]) -> PauliSumOp:
        """Utility method to map a `SecondQuantizedOp` to a `PauliSumOp` using a pauli table.

        Args:
            second_q_op: the `SecondQuantizedOp` to be mapped.
            pauli_table: a table of paulis built according to the modes of the operator

        Returns:
            The `PauliSumOp` corresponding to the problem-Hamiltonian in the qubit space.

        Raises:
            QiskitNatureError: If number length of pauli table does not match the number
                of operator modes, or if the operator has unexpected label content
        """
        nmodes = len(pauli_table)
        if nmodes != second_q_op.register_length:
            raise QiskitNatureError(
                f"Pauli table len {nmodes} does not match"
                f"operator register length {second_q_op.register_length}")

        # 0. Some utilities

        times_creation_op = []
        times_annihilation_op = []
        times_occupation_number_op = []
        times_emptiness_number_op = []
        for paulis in pauli_table:
            real_part = SparsePauliOp(paulis[0], coeffs=[0.5])
            imag_part = SparsePauliOp(paulis[1], coeffs=[0.5j])

            # The creation operator is given by 0.5*(X - 1j*Y)
            creation_op = real_part - imag_part
            times_creation_op.append(creation_op)

            # The annihilation operator is given by 0.5*(X + 1j*Y)
            annihilation_op = real_part + imag_part
            times_annihilation_op.append(annihilation_op)

            # The occupation number operator N is given by `+-`.
            times_occupation_number_op.append(
                creation_op.compose(annihilation_op, front=True).simplify())

            # The `emptiness number` operator E is given by `-+` = (I - N).
            times_emptiness_number_op.append(
                annihilation_op.compose(creation_op, front=True).simplify())

        # make sure ret_op_list is not empty by including a zero op
        ret_op_list = [SparsePauliOp("I" * nmodes, coeffs=[0])]

        # TODO to_list() is not an attribute of SecondQuantizedOp. Change the former to have this or
        #   change the signature above to take FermionicOp?
        label_coeff_list = (second_q_op.to_list(
            display_format="dense") if isinstance(second_q_op, FermionicOp)
                            else second_q_op.to_list())
        for label, coeff in label_coeff_list:

            # 1. Initialize an operator list with the identity scaled by the `self.coeff`
            ret_op = SparsePauliOp("I" * nmodes, coeffs=[coeff])

            # Go through the label and replace the fermion operators by their qubit-equivalent, then
            # save the respective Pauli string in the pauli_str list.
            for position, char in enumerate(label):
                if char == "+":
                    ret_op = ret_op.compose(times_creation_op[position],
                                            front=True)
                elif char == "-":
                    ret_op = ret_op.compose(times_annihilation_op[position],
                                            front=True)
                elif char == "N":
                    ret_op = ret_op.compose(
                        times_occupation_number_op[position], front=True)
                elif char == "E":
                    ret_op = ret_op.compose(
                        times_emptiness_number_op[position], front=True)
                elif char == "I":
                    continue

                # catch any disallowed labels
                else:
                    raise QiskitNatureError(
                        f"FermionicOp label included '{char}'. Allowed characters: I, N, E, +, -"
                    )
            ret_op_list.append(ret_op)

        return PauliSumOp(SparsePauliOp.sum(ret_op_list).simplify())