def from_pauli_sum(cls, pauli_sum: SummedOp) -> 'PhaseEstimationScale':
        """Create a PhaseEstimationScale from a `SummedOp` representing a sum of Pauli Operators.

        It is assumed that the ``pauli_sum`` is the sum of ``PauliOp`` objects. The bound on
        the absolute value of the eigenvalues of the sum is obtained as the sum of the
        absolute values of the coefficients of the terms. This is the best bound available in
        the generic case. A ``PhaseEstimationScale`` object is instantiated using this bound.

        Args:
            pauli_sum: A ``SummedOp`` whose terms are ``PauliOp`` objects.

        Raises:
            ValueError: if ``pauli_sum`` is not a sum of Pauli operators.

        Returns:
            A ``PhaseEstimationScale`` object
        """
        if pauli_sum.primitive_strings() != {'Pauli'}:
            raise ValueError(
                '`pauli_sum` must be a sum of Pauli operators. Got primitives {}.'
                .format(pauli_sum.primitive_strings()))

        bound = sum(
            [abs(pauli_sum.coeff * pauli.coeff) for pauli in pauli_sum])
        return PhaseEstimationScale(bound)
예제 #2
0
    def test_group_subops(self, is_summed_op):
        """grouper subroutine test"""
        paulis = (I ^ X) + (2 * X ^ X) + (3 * Z ^ Y)
        if is_summed_op:
            paulis = paulis.to_pauli_op()
        grouped_sum = AbelianGrouper.group_subops(paulis)
        self.assertEqual(len(grouped_sum), 2)
        with self.subTest("test group subops 1"):
            if is_summed_op:
                expected = SummedOp(
                    [
                        SummedOp([I ^ X, 2.0 * X ^ X], abelian=True),
                        SummedOp([3.0 * Z ^ Y], abelian=True),
                    ]
                )
                self.assertEqual(grouped_sum, expected)
            else:
                self.assertSetEqual(
                    frozenset([frozenset(grouped_sum[i].primitive.to_list()) for i in range(2)]),
                    frozenset({frozenset({("ZY", 3)}), frozenset({("IX", 1), ("XX", 2)})}),
                )

        paulis = X + (2 * Y) + (3 * Z)
        if is_summed_op:
            paulis = paulis.to_pauli_op()
        grouped_sum = AbelianGrouper.group_subops(paulis)
        self.assertEqual(len(grouped_sum), 3)
        with self.subTest("test group subops 2"):
            if is_summed_op:
                self.assertEqual(grouped_sum, paulis)
            else:
                self.assertSetEqual(
                    frozenset(sum([grouped_sum[i].primitive.to_list() for i in range(3)], [])),
                    frozenset([("X", 1), ("Y", 2), ("Z", 3)]),
                )
    def test_permute_on_list_op(self):
        """Test if ListOp permute method is consistent with PrimitiveOps permute methods."""

        op1 = (X ^ Y ^ Z).to_circuit_op()
        op2 = Z ^ X ^ Y

        # ComposedOp
        indices = [1, 2, 0]
        primitive_op = op1 @ op2
        primitive_op_perm = primitive_op.permute(indices)  # CircuitOp.permute

        composed_op = ComposedOp([op1, op2])
        composed_op_perm = composed_op.permute(indices)

        # reduce the ListOp to PrimitiveOp
        to_primitive = composed_op_perm.oplist[0] @ composed_op_perm.oplist[1]
        # compare resulting PrimitiveOps
        equal = np.allclose(primitive_op_perm.to_matrix(),
                            to_primitive.to_matrix())
        self.assertTrue(equal)

        # TensoredOp
        indices = [3, 5, 4, 0, 2, 1]
        primitive_op = op1 ^ op2
        primitive_op_perm = primitive_op.permute(indices)

        tensored_op = TensoredOp([op1, op2])
        tensored_op_perm = tensored_op.permute(indices)

        # reduce the ListOp to PrimitiveOp
        composed_oplist = tensored_op_perm.oplist
        to_primitive = (composed_oplist[0] @ (composed_oplist[1].oplist[0]
                                              ^ composed_oplist[1].oplist[1])
                        @ composed_oplist[2])

        # compare resulting PrimitiveOps
        equal = np.allclose(primitive_op_perm.to_matrix(),
                            to_primitive.to_matrix())
        self.assertTrue(equal)

        # SummedOp
        primitive_op = X ^ Y ^ Z
        summed_op = SummedOp([primitive_op])

        indices = [1, 2, 0]
        primitive_op_perm = primitive_op.permute(indices)  # PauliOp.permute
        summed_op_perm = summed_op.permute(indices)

        # reduce the ListOp to PrimitiveOp
        to_primitive = summed_op_perm.oplist[
            0] @ primitive_op @ summed_op_perm.oplist[2]

        # compare resulting PrimitiveOps
        equal = np.allclose(primitive_op_perm.to_matrix(),
                            to_primitive.to_matrix())
        self.assertTrue(equal)
    def test_evals(self):
        """ evals test """
        # TODO: Think about eval names
        self.assertEqual(Z.eval('0').eval('0'), 1)
        self.assertEqual(Z.eval('1').eval('0'), 0)
        self.assertEqual(Z.eval('0').eval('1'), 0)
        self.assertEqual(Z.eval('1').eval('1'), -1)
        self.assertEqual(X.eval('0').eval('0'), 0)
        self.assertEqual(X.eval('1').eval('0'), 1)
        self.assertEqual(X.eval('0').eval('1'), 1)
        self.assertEqual(X.eval('1').eval('1'), 0)
        self.assertEqual(Y.eval('0').eval('0'), 0)
        self.assertEqual(Y.eval('1').eval('0'), -1j)
        self.assertEqual(Y.eval('0').eval('1'), 1j)
        self.assertEqual(Y.eval('1').eval('1'), 0)

        with self.assertRaises(ValueError):
            Y.eval('11')

        with self.assertRaises(ValueError):
            (X ^ Y).eval('1111')

        with self.assertRaises(ValueError):
            Y.eval((X ^ X).to_matrix_op())

        # Check that Pauli logic eval returns same as matrix logic
        self.assertEqual(PrimitiveOp(Z.to_matrix()).eval('0').eval('0'), 1)
        self.assertEqual(PrimitiveOp(Z.to_matrix()).eval('1').eval('0'), 0)
        self.assertEqual(PrimitiveOp(Z.to_matrix()).eval('0').eval('1'), 0)
        self.assertEqual(PrimitiveOp(Z.to_matrix()).eval('1').eval('1'), -1)
        self.assertEqual(PrimitiveOp(X.to_matrix()).eval('0').eval('0'), 0)
        self.assertEqual(PrimitiveOp(X.to_matrix()).eval('1').eval('0'), 1)
        self.assertEqual(PrimitiveOp(X.to_matrix()).eval('0').eval('1'), 1)
        self.assertEqual(PrimitiveOp(X.to_matrix()).eval('1').eval('1'), 0)
        self.assertEqual(PrimitiveOp(Y.to_matrix()).eval('0').eval('0'), 0)
        self.assertEqual(PrimitiveOp(Y.to_matrix()).eval('1').eval('0'), -1j)
        self.assertEqual(PrimitiveOp(Y.to_matrix()).eval('0').eval('1'), 1j)
        self.assertEqual(PrimitiveOp(Y.to_matrix()).eval('1').eval('1'), 0)

        pauli_op = Z ^ I ^ X ^ Y
        mat_op = PrimitiveOp(pauli_op.to_matrix())
        full_basis = list(map(''.join, itertools.product('01', repeat=pauli_op.num_qubits)))
        for bstr1, bstr2 in itertools.product(full_basis, full_basis):
            # print('{} {} {} {}'.format(bstr1, bstr2, pauli_op.eval(bstr1, bstr2),
            # mat_op.eval(bstr1, bstr2)))
            np.testing.assert_array_almost_equal(pauli_op.eval(bstr1).eval(bstr2),
                                                 mat_op.eval(bstr1).eval(bstr2))

        gnarly_op = SummedOp([(H ^ I ^ Y).compose(X ^ X ^ Z).tensor(Z),
                              PrimitiveOp(Operator.from_label('+r0I')),
                              3 * (X ^ CX ^ T)], coeff=3 + .2j)
        gnarly_mat_op = PrimitiveOp(gnarly_op.to_matrix())
        full_basis = list(map(''.join, itertools.product('01', repeat=gnarly_op.num_qubits)))
        for bstr1, bstr2 in itertools.product(full_basis, full_basis):
            np.testing.assert_array_almost_equal(gnarly_op.eval(bstr1).eval(bstr2),
                                                 gnarly_mat_op.eval(bstr1).eval(bstr2))
    def test_list_op_parameters(self):
        """Test that Parameters are stored correctly in a List Operator"""
        lam = Parameter('λ')
        phi = Parameter('φ')
        omega = Parameter('ω')

        mat_op = PrimitiveOp([[0, 1],
                              [1, 0]],
                             coeff=omega)

        qc = QuantumCircuit(1)
        qc.rx(phi, 0)
        qc_op = PrimitiveOp(qc)

        op1 = SummedOp([mat_op, qc_op])

        params = [phi, omega]
        self.assertEqual(op1.parameters, set(params))

        # check list nesting case
        op2 = PrimitiveOp([[1, 0],
                           [0, -1]],
                          coeff=lam)

        list_op = ListOp([op1, op2])

        params.append(lam)
        self.assertEqual(list_op.parameters, set(params))
예제 #6
0
    def test_coeffs(self):
        """ListOp.coeffs test"""
        sum1 = SummedOp(
            [(0 + 1j) * X, (1 / np.sqrt(2) + 1j / np.sqrt(2)) * Z], 0.5
        ).collapse_summands()
        self.assertAlmostEqual(sum1.coeffs[0], 0.5j)
        self.assertAlmostEqual(sum1.coeffs[1], (1 + 1j) / (2 * np.sqrt(2)))

        a_param = Parameter("a")
        b_param = Parameter("b")
        param_exp = ParameterExpression({a_param: 1, b_param: 0}, Symbol("a") ** 2 + Symbol("b"))
        sum2 = SummedOp([X, (1 / np.sqrt(2) - 1j / np.sqrt(2)) * Y], param_exp).collapse_summands()
        self.assertIsInstance(sum2.coeffs[0], ParameterExpression)
        self.assertIsInstance(sum2.coeffs[1], ParameterExpression)

        # Nested ListOp
        sum_nested = SummedOp([X, sum1])
        self.assertRaises(TypeError, lambda: sum_nested.coeffs)
    def test_expand_on_list_op(self):
        """ Test if expanded ListOp has expected num_qubits. """
        add_qubits = 3

        # ComposedOp
        composed_op = ComposedOp([(X ^ Y ^ Z), (H ^ T), (Z ^ X ^ Y ^ Z).to_matrix_op()])
        expanded = composed_op._expand_dim(add_qubits)
        self.assertEqual(composed_op.num_qubits + add_qubits, expanded.num_qubits)

        # TensoredOp
        tensored_op = TensoredOp([(X ^ Y), (Z ^ I)])
        expanded = tensored_op._expand_dim(add_qubits)
        self.assertEqual(tensored_op.num_qubits + add_qubits, expanded.num_qubits)

        # SummedOp
        summed_op = SummedOp([(X ^ Y), (Z ^ I ^ Z)])
        expanded = summed_op._expand_dim(add_qubits)
        self.assertEqual(summed_op.num_qubits + add_qubits, expanded.num_qubits)
예제 #8
0
    def test_add(self):
        """add test"""
        pauli_sum = 3 * X + Y
        self.assertIsInstance(pauli_sum, PauliSumOp)
        expected = PauliSumOp(3.0 * SparsePauliOp(Pauli("X")) + SparsePauliOp(Pauli("Y")))
        self.assertEqual(pauli_sum, expected)

        pauli_sum = X + Y
        summed_op = SummedOp([X, Y])
        self.assertEqual(pauli_sum, summed_op)

        a = Parameter("a")
        b = Parameter("b")
        actual = a * PauliSumOp.from_list([("X", 2)]) + b * PauliSumOp.from_list([("Y", 1)])
        expected = SummedOp(
            [PauliSumOp.from_list([("X", 2)], a), PauliSumOp.from_list([("Y", 1)], b)]
        )
        self.assertEqual(actual, expected)
예제 #9
0
    def test_bind_parameters_complex(self):
        """bind parameters with a complex value test"""
        th1 = Parameter("th1")
        th2 = Parameter("th2")

        operator = th1 * X + th2 * Y
        bound_operator = operator.bind_parameters({th1: 3j, th2: 2})

        expected_bound_operator = SummedOp([3j * X, (2 + 0j) * Y])
        self.assertEqual(bound_operator, expected_bound_operator)
    def test_trotter_qrte_qdrift(self, initial_state, expected_state):
        """Test for TrotterQRTE with QDrift."""
        operator = SummedOp([X, Z])
        time = 1
        evolution_problem = EvolutionProblem(operator, time, initial_state)

        algorithm_globals.random_seed = 0
        trotter_qrte = TrotterQRTE(product_formula=QDrift())
        evolution_result = trotter_qrte.evolve(evolution_problem)
        np.testing.assert_equal(evolution_result.evolved_state.eval(), expected_state)
예제 #11
0
    def test_add(self):
        """ add test """
        pauli_sum = 3 * X + Y
        self.assertIsInstance(pauli_sum, PauliSumOp)
        expected = PauliSumOp(3.0 * SparsePauliOp(Pauli("X")) +
                              SparsePauliOp(Pauli("Y")))
        self.assertEqual(pauli_sum, expected)

        pauli_sum = X + Y
        summed_op = SummedOp([X, Y])
        self.assertEqual(pauli_sum, summed_op)
    def test_trotter_qrte_trotter_single_qubit(self, product_formula, expected_state):
        """Test for default TrotterQRTE on a single qubit."""
        operator = SummedOp([X, Z])
        initial_state = StateFn([1, 0])
        time = 1
        evolution_problem = EvolutionProblem(operator, time, initial_state)

        trotter_qrte = TrotterQRTE(product_formula=product_formula)
        evolution_result_state_circuit = trotter_qrte.evolve(evolution_problem).evolved_state

        np.testing.assert_equal(evolution_result_state_circuit.eval(), expected_state)
예제 #13
0
 def test_summedop_pauli_evolution(self):
     """SummedOp[PauliOp] evolution test"""
     op = SummedOp([
         (-1.052373245772859 * I ^ I),
         (0.39793742484318045 * I ^ Z),
         (0.18093119978423156 * X ^ X),
         (-0.39793742484318045 * Z ^ I),
         (-0.01128010425623538 * Z ^ Z),
     ])
     evolution = EvolutionFactory.build(operator=op)
     # wf = (Pl^Pl) + (Ze^Ze)
     wf = ((np.pi / 2) * op).exp_i() @ CX @ (H ^ I) @ Zero
     mean = evolution.convert(wf)
     self.assertIsNotNone(mean)
예제 #14
0
def _remove_identity(pauli_sum):
    """Remove any identity operators from `pauli_sum`. Return
    the sum of the coefficients of the identities and the new operator.
    """
    idcoeff = 0.0
    ops = []
    for op in pauli_sum:
        p = op.primitive
        if p.x.any() or p.z.any():
            ops.append(op)
        else:
            idcoeff += op.coeff

    return idcoeff, SummedOp(ops)
예제 #15
0
    def test_coder_operators(self):
        """Test runtime encoder and decoder for operators."""
        x = Parameter("x")
        y = x + 1
        qc = QuantumCircuit(1)
        qc.h(0)
        coeffs = np.array([1, 2, 3, 4, 5, 6])
        table = PauliTable.from_labels(
            ["III", "IXI", "IYY", "YIZ", "XYZ", "III"])
        op = (2.0 * I ^ I)
        z2_symmetries = Z2Symmetries(
            [Pauli("IIZI"), Pauli("ZIII")],
            [Pauli("IIXI"), Pauli("XIII")], [1, 3], [-1, 1])
        isqrt2 = 1 / np.sqrt(2)
        sparse = scipy.sparse.csr_matrix([[0, isqrt2, 0, isqrt2]])

        subtests = (
            PauliSumOp(SparsePauliOp(Pauli("XYZX"), coeffs=[2]), coeff=3),
            PauliSumOp(SparsePauliOp(Pauli("XYZX"), coeffs=[1]), coeff=y),
            PauliSumOp(SparsePauliOp(Pauli("XYZX"), coeffs=[1 + 2j]),
                       coeff=3 - 2j),
            PauliSumOp.from_list([("II", -1.052373245772859),
                                  ("IZ", 0.39793742484318045)]),
            PauliSumOp(SparsePauliOp(table, coeffs), coeff=10),
            MatrixOp(primitive=np.array([[0, -1j], [1j, 0]]), coeff=x),
            PauliOp(primitive=Pauli("Y"), coeff=x),
            CircuitOp(qc, coeff=x),
            EvolvedOp(op, coeff=x),
            TaperedPauliSumOp(SparsePauliOp(Pauli("XYZX"), coeffs=[2]),
                              z2_symmetries),
            StateFn(qc, coeff=x),
            CircuitStateFn(qc, is_measurement=True),
            DictStateFn("1" * 3, is_measurement=True),
            VectorStateFn(np.ones(2**3, dtype=complex)),
            OperatorStateFn(CircuitOp(QuantumCircuit(1))),
            SparseVectorStateFn(sparse),
            Statevector([1, 0]),
            CVaRMeasurement(Z, 0.2),
            ComposedOp([(X ^ Y ^ Z), (Z ^ X ^ Y ^ Z).to_matrix_op()]),
            SummedOp([X ^ X * 2, Y ^ Y], 2),
            TensoredOp([(X ^ Y), (Z ^ I)]),
            (Z ^ Z) ^ (I ^ 2),
        )
        for op in subtests:
            with self.subTest(op=op):
                encoded = json.dumps(op, cls=RuntimeEncoder)
                self.assertIsInstance(encoded, str)
                decoded = json.loads(encoded, cls=RuntimeDecoder)
                self.assertEqual(op, decoded)
예제 #16
0
 def test_qdrift_summed_op(self):
     """QDrift test for SummedOp"""
     op = SummedOp([
         (2 * Z ^ Z),
         (3 * X ^ X),
         (-4 * Y ^ Y),
         (0.5 * Z ^ I),
     ])
     trotterization = QDrift().convert(op)
     self.assertGreater(len(trotterization.oplist), 150)
     last_coeff = None
     # Check that all types are correct and all coefficients are equals
     for op in trotterization.oplist:
         self.assertIsInstance(op, (EvolvedOp, CircuitOp))
         if isinstance(op, EvolvedOp):
             if last_coeff:
                 self.assertEqual(op.primitive.coeff, last_coeff)
             else:
                 last_coeff = op.primitive.coeff
    def test_trotter_qrte_trotter_single_qubit_aux_ops(self):
        """Test for default TrotterQRTE on a single qubit with auxiliary operators."""
        operator = SummedOp([X, Z])
        # LieTrotter with 1 rep
        aux_ops = [X, Y]

        initial_state = Zero
        time = 3
        evolution_problem = EvolutionProblem(operator, time, initial_state, aux_ops)

        expected_evolved_state = VectorStateFn(
            Statevector([0.98008514 + 0.13970775j, 0.01991486 + 0.13970775j], dims=(2,))
        )
        expected_aux_ops_evaluated = [(0.078073, 0.0), (0.268286, 0.0)]
        expected_aux_ops_evaluated_qasm = [
            (0.05799999999999995, 0.011161518713866855),
            (0.2495, 0.010826759383582883),
        ]

        for backend_name in self.backends_names_not_none:
            with self.subTest(msg=f"Test {backend_name} backend."):
                algorithm_globals.random_seed = 0
                backend = self.backends_dict[backend_name]
                expectation = ExpectationFactory.build(
                    operator=operator,
                    backend=backend,
                )
                trotter_qrte = TrotterQRTE(quantum_instance=backend, expectation=expectation)
                evolution_result = trotter_qrte.evolve(evolution_problem)

                np.testing.assert_equal(
                    evolution_result.evolved_state.eval(), expected_evolved_state
                )
                if backend_name == "qi_qasm":
                    expected_aux_ops_evaluated = expected_aux_ops_evaluated_qasm
                np.testing.assert_array_almost_equal(
                    evolution_result.aux_ops_evaluated, expected_aux_ops_evaluated
                )
    def test_summed_op_reduce(self):
        """Test SummedOp"""
        sum_op = (X ^ X * 2) + (Y ^ Y)  # type: PauliSumOp
        sum_op = sum_op.to_pauli_op()  # type: SummedOp[PauliOp]
        with self.subTest("SummedOp test 1"):
            self.assertEqual(sum_op.coeff, 1)
            self.assertListEqual([str(op.primitive) for op in sum_op],
                                 ["XX", "YY"])
            self.assertListEqual([op.coeff for op in sum_op], [2, 1])

        sum_op = (X ^ X * 2) + (Y ^ Y)
        sum_op += Y ^ Y
        sum_op = sum_op.to_pauli_op()  # type: SummedOp[PauliOp]
        with self.subTest("SummedOp test 2-a"):
            self.assertEqual(sum_op.coeff, 1)
            self.assertListEqual([str(op.primitive) for op in sum_op],
                                 ["XX", "YY", "YY"])
            self.assertListEqual([op.coeff for op in sum_op], [2, 1, 1])

        sum_op = sum_op.collapse_summands()
        with self.subTest("SummedOp test 2-b"):
            self.assertEqual(sum_op.coeff, 1)
            self.assertListEqual([str(op.primitive) for op in sum_op],
                                 ["XX", "YY"])
            self.assertListEqual([op.coeff for op in sum_op], [2, 2])

        sum_op = (X ^ X * 2) + (Y ^ Y)
        sum_op += (Y ^ Y) + (X ^ X * 2)
        sum_op = sum_op.to_pauli_op()  # type: SummedOp[PauliOp]
        with self.subTest("SummedOp test 3-a"):
            self.assertEqual(sum_op.coeff, 1)
            self.assertListEqual([str(op.primitive) for op in sum_op],
                                 ["XX", "YY", "YY", "XX"])
            self.assertListEqual([op.coeff for op in sum_op], [2, 1, 1, 2])

        sum_op = sum_op.reduce().to_pauli_op()
        with self.subTest("SummedOp test 3-b"):
            self.assertEqual(sum_op.coeff, 1)
            self.assertListEqual([str(op.primitive) for op in sum_op],
                                 ["XX", "YY"])
            self.assertListEqual([op.coeff for op in sum_op], [4, 2])

        sum_op = SummedOp([X ^ X * 2, Y ^ Y], 2)
        with self.subTest("SummedOp test 4-a"):
            self.assertEqual(sum_op.coeff, 2)
            self.assertListEqual([str(op.primitive) for op in sum_op],
                                 ["XX", "YY"])
            self.assertListEqual([op.coeff for op in sum_op], [2, 1])

        sum_op = sum_op.collapse_summands()
        with self.subTest("SummedOp test 4-b"):
            self.assertEqual(sum_op.coeff, 1)
            self.assertListEqual([str(op.primitive) for op in sum_op],
                                 ["XX", "YY"])
            self.assertListEqual([op.coeff for op in sum_op], [4, 2])

        sum_op = SummedOp([X ^ X * 2, Y ^ Y], 2)
        sum_op += Y ^ Y
        with self.subTest("SummedOp test 5-a"):
            self.assertEqual(sum_op.coeff, 1)
            self.assertListEqual([str(op.primitive) for op in sum_op],
                                 ["XX", "YY", "YY"])
            self.assertListEqual([op.coeff for op in sum_op], [4, 2, 1])

        sum_op = sum_op.collapse_summands()
        with self.subTest("SummedOp test 5-b"):
            self.assertEqual(sum_op.coeff, 1)
            self.assertListEqual([str(op.primitive) for op in sum_op],
                                 ["XX", "YY"])
            self.assertListEqual([op.coeff for op in sum_op], [4, 3])

        sum_op = SummedOp([X ^ X * 2, Y ^ Y], 2)
        sum_op += ((X ^ X) * 2 + (Y ^ Y)).to_pauli_op()
        with self.subTest("SummedOp test 6-a"):
            self.assertEqual(sum_op.coeff, 1)
            self.assertListEqual([str(op.primitive) for op in sum_op],
                                 ["XX", "YY", "XX", "YY"])
            self.assertListEqual([op.coeff for op in sum_op], [4, 2, 2, 1])

        sum_op = sum_op.collapse_summands()
        with self.subTest("SummedOp test 6-b"):
            self.assertEqual(sum_op.coeff, 1)
            self.assertListEqual([str(op.primitive) for op in sum_op],
                                 ["XX", "YY"])
            self.assertListEqual([op.coeff for op in sum_op], [6, 3])

        sum_op = SummedOp([X ^ X * 2, Y ^ Y], 2)
        sum_op += sum_op
        with self.subTest("SummedOp test 7-a"):
            self.assertEqual(sum_op.coeff, 1)
            self.assertListEqual([str(op.primitive) for op in sum_op],
                                 ["XX", "YY", "XX", "YY"])
            self.assertListEqual([op.coeff for op in sum_op], [4, 2, 4, 2])

        sum_op = sum_op.collapse_summands()
        with self.subTest("SummedOp test 7-b"):
            self.assertEqual(sum_op.coeff, 1)
            self.assertListEqual([str(op.primitive) for op in sum_op],
                                 ["XX", "YY"])
            self.assertListEqual([op.coeff for op in sum_op], [8, 4])

        sum_op = SummedOp([X ^ X * 2, Y ^ Y], 2) + SummedOp([X ^ X * 2, Z ^ Z],
                                                            3)
        with self.subTest("SummedOp test 8-a"):
            self.assertEqual(sum_op.coeff, 1)
            self.assertListEqual([str(op.primitive) for op in sum_op],
                                 ["XX", "YY", "XX", "ZZ"])
            self.assertListEqual([op.coeff for op in sum_op], [4, 2, 6, 3])

        sum_op = sum_op.collapse_summands()
        with self.subTest("SummedOp test 8-b"):
            self.assertEqual(sum_op.coeff, 1)
            self.assertListEqual([str(op.primitive) for op in sum_op],
                                 ["XX", "YY", "ZZ"])
            self.assertListEqual([op.coeff for op in sum_op], [10, 2, 3])

        sum_op = SummedOp([])
        with self.subTest("SummedOp test 9"):
            self.assertEqual(sum_op.reduce(), sum_op)

        sum_op = ((Z + I) ^ Z) + (Z ^ X)
        with self.subTest("SummedOp test 10"):
            expected = SummedOp([
                PauliOp(Pauli("ZZ")),
                PauliOp(Pauli("IZ")),
                PauliOp(Pauli("ZX"))
            ])
            self.assertEqual(sum_op.to_pauli_op(), expected)
예제 #19
0
    def test_summed_op_reduce(self):
        """Test SummedOp"""
        sum_op = (X ^ X * 2) + (Y ^ Y)  # type: PauliSumOp
        sum_op = sum_op.to_pauli_op()  # type: SummedOp[PauliOp]
        with self.subTest('SummedOp test 1'):
            self.assertEqual(sum_op.coeff, 1)
            self.assertListEqual([str(op.primitive) for op in sum_op],
                                 ['XX', 'YY'])
            self.assertListEqual([op.coeff for op in sum_op], [2, 1])

        sum_op = (X ^ X * 2) + (Y ^ Y)
        sum_op += Y ^ Y
        sum_op = sum_op.to_pauli_op()  # type: SummedOp[PauliOp]
        with self.subTest('SummedOp test 2-a'):
            self.assertEqual(sum_op.coeff, 1)
            self.assertListEqual([str(op.primitive) for op in sum_op],
                                 ['XX', 'YY', 'YY'])
            self.assertListEqual([op.coeff for op in sum_op], [2, 1, 1])

        sum_op = sum_op.collapse_summands()
        with self.subTest('SummedOp test 2-b'):
            self.assertEqual(sum_op.coeff, 1)
            self.assertListEqual([str(op.primitive) for op in sum_op],
                                 ['XX', 'YY'])
            self.assertListEqual([op.coeff for op in sum_op], [2, 2])

        sum_op = (X ^ X * 2) + (Y ^ Y)
        sum_op += (Y ^ Y) + (X ^ X * 2)
        sum_op = sum_op.to_pauli_op()  # type: SummedOp[PauliOp]
        with self.subTest('SummedOp test 3-a'):
            self.assertEqual(sum_op.coeff, 1)
            self.assertListEqual([str(op.primitive) for op in sum_op],
                                 ['XX', 'YY', 'YY', 'XX'])
            self.assertListEqual([op.coeff for op in sum_op], [2, 1, 1, 2])

        sum_op = sum_op.reduce().to_pauli_op()
        with self.subTest('SummedOp test 3-b'):
            self.assertEqual(sum_op.coeff, 1)
            self.assertListEqual([str(op.primitive) for op in sum_op],
                                 ['XX', 'YY'])
            self.assertListEqual([op.coeff for op in sum_op], [4, 2])

        sum_op = SummedOp([X ^ X * 2, Y ^ Y], 2)
        with self.subTest('SummedOp test 4-a'):
            self.assertEqual(sum_op.coeff, 2)
            self.assertListEqual([str(op.primitive) for op in sum_op],
                                 ['XX', 'YY'])
            self.assertListEqual([op.coeff for op in sum_op], [2, 1])

        sum_op = sum_op.collapse_summands()
        with self.subTest('SummedOp test 4-b'):
            self.assertEqual(sum_op.coeff, 1)
            self.assertListEqual([str(op.primitive) for op in sum_op],
                                 ['XX', 'YY'])
            self.assertListEqual([op.coeff for op in sum_op], [4, 2])

        sum_op = SummedOp([X ^ X * 2, Y ^ Y], 2)
        sum_op += Y ^ Y
        with self.subTest('SummedOp test 5-a'):
            self.assertEqual(sum_op.coeff, 1)
            self.assertListEqual([str(op.primitive) for op in sum_op],
                                 ['XX', 'YY', 'YY'])
            self.assertListEqual([op.coeff for op in sum_op], [4, 2, 1])

        sum_op = sum_op.collapse_summands()
        with self.subTest('SummedOp test 5-b'):
            self.assertEqual(sum_op.coeff, 1)
            self.assertListEqual([str(op.primitive) for op in sum_op],
                                 ['XX', 'YY'])
            self.assertListEqual([op.coeff for op in sum_op], [4, 3])

        sum_op = SummedOp([X ^ X * 2, Y ^ Y], 2)
        sum_op += ((X ^ X) * 2 + (Y ^ Y)).to_pauli_op()
        with self.subTest('SummedOp test 6-a'):
            self.assertEqual(sum_op.coeff, 1)
            self.assertListEqual([str(op.primitive) for op in sum_op],
                                 ['XX', 'YY', 'XX', 'YY'])
            self.assertListEqual([op.coeff for op in sum_op], [4, 2, 2, 1])

        sum_op = sum_op.collapse_summands()
        with self.subTest('SummedOp test 6-b'):
            self.assertEqual(sum_op.coeff, 1)
            self.assertListEqual([str(op.primitive) for op in sum_op],
                                 ['XX', 'YY'])
            self.assertListEqual([op.coeff for op in sum_op], [6, 3])

        sum_op = SummedOp([X ^ X * 2, Y ^ Y], 2)
        sum_op += sum_op
        with self.subTest('SummedOp test 7-a'):
            self.assertEqual(sum_op.coeff, 1)
            self.assertListEqual([str(op.primitive) for op in sum_op],
                                 ['XX', 'YY', 'XX', 'YY'])
            self.assertListEqual([op.coeff for op in sum_op], [4, 2, 4, 2])

        sum_op = sum_op.collapse_summands()
        with self.subTest('SummedOp test 7-b'):
            self.assertEqual(sum_op.coeff, 1)
            self.assertListEqual([str(op.primitive) for op in sum_op],
                                 ['XX', 'YY'])
            self.assertListEqual([op.coeff for op in sum_op], [8, 4])

        sum_op = SummedOp([X ^ X * 2, Y ^ Y], 2) + SummedOp([X ^ X * 2, Z ^ Z],
                                                            3)
        with self.subTest('SummedOp test 8-a'):
            self.assertEqual(sum_op.coeff, 1)
            self.assertListEqual([str(op.primitive) for op in sum_op],
                                 ['XX', 'YY', 'XX', 'ZZ'])
            self.assertListEqual([op.coeff for op in sum_op], [4, 2, 6, 3])

        sum_op = sum_op.collapse_summands()
        with self.subTest('SummedOp test 8-b'):
            self.assertEqual(sum_op.coeff, 1)
            self.assertListEqual([str(op.primitive) for op in sum_op],
                                 ['XX', 'YY', 'ZZ'])
            self.assertListEqual([op.coeff for op in sum_op], [10, 2, 3])
class TestTrotterQRTE(QiskitOpflowTestCase):
    """TrotterQRTE tests."""

    def setUp(self):
        super().setUp()
        self.seed = 50
        algorithm_globals.random_seed = self.seed
        backend_statevector = BasicAer.get_backend("statevector_simulator")
        backend_qasm = BasicAer.get_backend("qasm_simulator")
        self.quantum_instance = QuantumInstance(
            backend=backend_statevector,
            shots=1,
            seed_simulator=self.seed,
            seed_transpiler=self.seed,
        )
        self.quantum_instance_qasm = QuantumInstance(
            backend=backend_qasm,
            shots=8000,
            seed_simulator=self.seed,
            seed_transpiler=self.seed,
        )
        self.backends_dict = {
            "qi_sv": self.quantum_instance,
            "qi_qasm": self.quantum_instance_qasm,
            "b_sv": backend_statevector,
            "None": None,
        }

        self.backends_names = ["qi_qasm", "b_sv", "None", "qi_sv"]
        self.backends_names_not_none = ["qi_sv", "b_sv", "qi_qasm"]

    @data(
        (
            None,
            VectorStateFn(
                Statevector([0.29192658 - 0.45464871j, 0.70807342 - 0.45464871j], dims=(2,))
            ),
        ),
        (
            SuzukiTrotter(),
            VectorStateFn(Statevector([0.29192658 - 0.84147098j, 0.0 - 0.45464871j], dims=(2,))),
        ),
    )
    @unpack
    def test_trotter_qrte_trotter_single_qubit(self, product_formula, expected_state):
        """Test for default TrotterQRTE on a single qubit."""
        operator = SummedOp([X, Z])
        initial_state = StateFn([1, 0])
        time = 1
        evolution_problem = EvolutionProblem(operator, time, initial_state)

        trotter_qrte = TrotterQRTE(product_formula=product_formula)
        evolution_result_state_circuit = trotter_qrte.evolve(evolution_problem).evolved_state

        np.testing.assert_equal(evolution_result_state_circuit.eval(), expected_state)

    def test_trotter_qrte_trotter_single_qubit_aux_ops(self):
        """Test for default TrotterQRTE on a single qubit with auxiliary operators."""
        operator = SummedOp([X, Z])
        # LieTrotter with 1 rep
        aux_ops = [X, Y]

        initial_state = Zero
        time = 3
        evolution_problem = EvolutionProblem(operator, time, initial_state, aux_ops)

        expected_evolved_state = VectorStateFn(
            Statevector([0.98008514 + 0.13970775j, 0.01991486 + 0.13970775j], dims=(2,))
        )
        expected_aux_ops_evaluated = [(0.078073, 0.0), (0.268286, 0.0)]
        expected_aux_ops_evaluated_qasm = [
            (0.05799999999999995, 0.011161518713866855),
            (0.2495, 0.010826759383582883),
        ]

        for backend_name in self.backends_names_not_none:
            with self.subTest(msg=f"Test {backend_name} backend."):
                algorithm_globals.random_seed = 0
                backend = self.backends_dict[backend_name]
                expectation = ExpectationFactory.build(
                    operator=operator,
                    backend=backend,
                )
                trotter_qrte = TrotterQRTE(quantum_instance=backend, expectation=expectation)
                evolution_result = trotter_qrte.evolve(evolution_problem)

                np.testing.assert_equal(
                    evolution_result.evolved_state.eval(), expected_evolved_state
                )
                if backend_name == "qi_qasm":
                    expected_aux_ops_evaluated = expected_aux_ops_evaluated_qasm
                np.testing.assert_array_almost_equal(
                    evolution_result.aux_ops_evaluated, expected_aux_ops_evaluated
                )

    @data(
        (
            SummedOp([(X ^ Y), (Y ^ X)]),
            VectorStateFn(
                Statevector(
                    [-0.41614684 + 0.0j, 0.0 + 0.0j, 0.0 + 0.0j, 0.90929743 + 0.0j], dims=(2, 2)
                )
            ),
        ),
        (
            (Z ^ Z) + (Z ^ I) + (I ^ Z),
            VectorStateFn(
                Statevector(
                    [-0.9899925 - 0.14112001j, 0.0 + 0.0j, 0.0 + 0.0j, 0.0 + 0.0j], dims=(2, 2)
                )
            ),
        ),
        (
            Y ^ Y,
            VectorStateFn(
                Statevector(
                    [0.54030231 + 0.0j, 0.0 + 0.0j, 0.0 + 0.0j, 0.0 + 0.84147098j], dims=(2, 2)
                )
            ),
        ),
    )
    @unpack
    def test_trotter_qrte_trotter_two_qubits(self, operator, expected_state):
        """Test for TrotterQRTE on two qubits with various types of a Hamiltonian."""
        # LieTrotter with 1 rep
        initial_state = StateFn([1, 0, 0, 0])
        evolution_problem = EvolutionProblem(operator, 1, initial_state)

        trotter_qrte = TrotterQRTE()
        evolution_result = trotter_qrte.evolve(evolution_problem)
        np.testing.assert_equal(evolution_result.evolved_state.eval(), expected_state)

    def test_trotter_qrte_trotter_two_qubits_with_params(self):
        """Test for TrotterQRTE on two qubits with a parametrized Hamiltonian."""
        # LieTrotter with 1 rep
        initial_state = StateFn([1, 0, 0, 0])
        w_param = Parameter("w")
        u_param = Parameter("u")
        params_dict = {w_param: 2.0, u_param: 3.0}
        operator = w_param * (Z ^ Z) / 2.0 + (Z ^ I) + u_param * (I ^ Z) / 3.0
        time = 1
        evolution_problem = EvolutionProblem(
            operator, time, initial_state, hamiltonian_value_dict=params_dict
        )
        expected_state = VectorStateFn(
            Statevector([-0.9899925 - 0.14112001j, 0.0 + 0.0j, 0.0 + 0.0j, 0.0 + 0.0j], dims=(2, 2))
        )
        trotter_qrte = TrotterQRTE()
        evolution_result = trotter_qrte.evolve(evolution_problem)
        np.testing.assert_equal(evolution_result.evolved_state.eval(), expected_state)

    @data(
        (
            Zero,
            VectorStateFn(
                Statevector([0.23071786 - 0.69436148j, 0.4646314 - 0.49874749j], dims=(2,))
            ),
        ),
        (
            QuantumCircuit(1).compose(ZGate(), [0]),
            VectorStateFn(
                Statevector([0.23071786 - 0.69436148j, 0.4646314 - 0.49874749j], dims=(2,))
            ),
        ),
    )
    @unpack
    def test_trotter_qrte_qdrift(self, initial_state, expected_state):
        """Test for TrotterQRTE with QDrift."""
        operator = SummedOp([X, Z])
        time = 1
        evolution_problem = EvolutionProblem(operator, time, initial_state)

        algorithm_globals.random_seed = 0
        trotter_qrte = TrotterQRTE(product_formula=QDrift())
        evolution_result = trotter_qrte.evolve(evolution_problem)
        np.testing.assert_equal(evolution_result.evolved_state.eval(), expected_state)

    @data((Parameter("t"), {}), (None, {Parameter("x"): 2}), (None, None))
    @unpack
    def test_trotter_qrte_trotter_errors(self, t_param, hamiltonian_value_dict):
        """Test TrotterQRTE with raising errors."""
        operator = X * Parameter("t") + Z
        initial_state = Zero
        time = 1
        algorithm_globals.random_seed = 0
        trotter_qrte = TrotterQRTE()
        with assert_raises(ValueError):
            evolution_problem = EvolutionProblem(
                operator,
                time,
                initial_state,
                t_param=t_param,
                hamiltonian_value_dict=hamiltonian_value_dict,
            )
            _ = trotter_qrte.evolve(evolution_problem)
예제 #21
0
 def test_to_pauli_op(self):
     """ test to_pauli_op method """
     target = X + Y
     self.assertIsInstance(target, PauliSumOp)
     expected = SummedOp([X, Y])
     self.assertEqual(target.to_pauli_op(), expected)
예제 #22
0
    def estimate(
            self,
            hamiltonian: OperatorBase,
            state_preparation: Optional[StateFn] = None,
            evolution: Optional[EvolutionBase] = None,
            bound: Optional[float] = None) -> HamiltonianPhaseEstimationResult:
        """Run the Hamiltonian phase estimation algorithm.

        Args:
            hamiltonian: A Hermitian operator.
            state_preparation: The ``StateFn`` to be prepared, whose eigenphase will be
                measured. If this parameter is omitted, no preparation circuit will be run and
                input state will be the all-zero state in the computational basis.
            evolution: An evolution converter that generates a unitary from ``hamiltonian``. If
                ``None``, then the default ``PauliTrotterEvolution`` is used.
            bound: An upper bound on the absolute value of the eigenvalues of
                ``hamiltonian``. If omitted, then ``hamiltonian`` must be a Pauli sum, or a
                ``PauliOp``, in which case a bound will be computed. If ``hamiltonian``
                is a ``MatrixOp``, then ``bound`` may not be ``None``. The tighter the bound,
                the higher the resolution of computed phases.

        Returns:
            HamiltonianPhaseEstimationResult instance containing the result of the estimation
            and diagnostic information.

        Raises:
            ValueError: If ``bound`` is ``None`` and ``hamiltonian`` is not a Pauli sum, i.e. a
                ``PauliSumOp`` or a ``SummedOp`` whose terms are of type ``PauliOp``.
            TypeError: If ``evolution`` is not of type ``EvolutionBase``.
        """
        if evolution is None:
            evolution = PauliTrotterEvolution()
        elif not isinstance(evolution, EvolutionBase):
            raise TypeError(
                f'Expecting type EvolutionBase, got {type(evolution)}')

        if isinstance(hamiltonian, PauliSumOp):
            hamiltonian = hamiltonian.to_pauli_op()
        elif isinstance(hamiltonian, PauliOp):
            hamiltonian = SummedOp([hamiltonian])

        if isinstance(hamiltonian, SummedOp):
            # remove identitiy terms
            # The term propto the identity is removed from hamiltonian.
            # This is done for three reasons:
            # 1. Work around an unknown bug that otherwise causes the energies to be wrong in some
            #    cases.
            # 2. Allow working with a simpler Hamiltonian, one with fewer terms.
            # 3. Tighten the bound on the eigenvalues so that the spectrum is better resolved, i.e.
            #   occupies more of the range of values representable by the qubit register.
            # The coefficient of this term will be added to the eigenvalues.
            id_coefficient, hamiltonian_no_id = _remove_identity(hamiltonian)

            # get the rescaling object
            pe_scale = self._get_scale(hamiltonian_no_id, bound)

            # get the unitary
            unitary = self._get_unitary(hamiltonian_no_id, pe_scale, evolution)

        elif isinstance(hamiltonian, MatrixOp):
            if bound is None:
                raise ValueError(
                    'bound must be specified if Hermitian operator is MatrixOp'
                )

            # Do not subtract an identity term from the matrix, so do not compensate.
            id_coefficient = 0.0
            pe_scale = self._get_scale(hamiltonian, bound)
            unitary = self._get_unitary(hamiltonian, pe_scale, evolution)
        else:
            raise TypeError(
                f'Hermitian operator of type {type(hamiltonian)} not supported.'
            )

        if state_preparation is not None:
            state_preparation = state_preparation.to_circuit_op().to_circuit()
        # run phase estimation
        phase_estimation_result = self._phase_estimation.estimate(
            unitary=unitary, state_preparation=state_preparation)

        return HamiltonianPhaseEstimationResult(
            phase_estimation_result=phase_estimation_result,
            id_coefficient=id_coefficient,
            phase_estimation_scale=pe_scale)