コード例 #1
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)
コード例 #2
0
    def test_circuit_sampler2(self, method):
        """Test the probability gradient with the circuit sampler

        dp0/da = cos(a)sin(b) / 2
        dp1/da = - cos(a)sin(b) / 2
        dp0/db = sin(a)cos(b) / 2
        dp1/db = - sin(a)cos(b) / 2
        """

        a = Parameter("a")
        b = Parameter("b")
        params = [a, b]

        q = QuantumRegister(1)
        qc = QuantumCircuit(q)
        qc.h(q)
        qc.rz(params[0], q[0])
        qc.rx(params[1], q[0])

        op = CircuitStateFn(primitive=qc, coeff=1.0)

        shots = 8000
        if method == "fin_diff":
            np.random.seed(8)
            prob_grad = Gradient(grad_method=method, epsilon=shots ** (-1 / 6.0)).convert(
                operator=op, params=params
            )
        else:
            prob_grad = Gradient(grad_method=method).convert(operator=op, params=params)
        values_dict = [
            {a: [np.pi / 4], b: [0]},
            {params[0]: [np.pi / 4], params[1]: [np.pi / 4]},
            {params[0]: [np.pi / 2], params[1]: [np.pi]},
        ]
        correct_values = [
            [[0, 0], [1 / (2 * np.sqrt(2)), -1 / (2 * np.sqrt(2))]],
            [[1 / 4, -1 / 4], [1 / 4, -1 / 4]],
            [[0, 0], [-1 / 2, 1 / 2]],
        ]

        backend = BasicAer.get_backend("qasm_simulator")
        q_instance = QuantumInstance(backend=backend, shots=shots)

        for i, value_dict in enumerate(values_dict):
            sampler = CircuitSampler(backend=q_instance).convert(prob_grad, params=value_dict)
            result = sampler.eval()[0]
            self.assertTrue(np.allclose(result[0].toarray(), correct_values[i][0], atol=0.1))
            self.assertTrue(np.allclose(result[1].toarray(), correct_values[i][1], atol=0.1))
コード例 #3
0
    def test_state_hessian_custom_combo_fn(self, method):
        """Test the state Hessian with on an operator which includes
            a user-defined combo_fn.

        Tr(|psi><psi|Z) = sin(a)sin(b)
        Tr(|psi><psi|X) = cos(a)
        d^2<H>/da^2 = - 0.5 cos(a) + 1 sin(a)sin(b)
        d^2<H>/dbda = - 1 cos(a)cos(b)
        d^2<H>/dbda = - 1 cos(a)cos(b)
        d^2<H>/db^2 = + 1 sin(a)sin(b)
        """

        ham = 0.5 * X - 1 * Z
        a = Parameter('a')
        b = Parameter('b')
        params = [(a, a), (a, b), (b, b)]

        q = QuantumRegister(1)
        qc = QuantumCircuit(q)
        qc.h(q)
        qc.rz(a, q[0])
        qc.rx(b, q[0])

        op = ListOp([~StateFn(ham) @ CircuitStateFn(primitive=qc, coeff=1.)],
                    combo_fn=lambda x: x[0]**3 + 4 * x[0])
        state_hess = Hessian(hess_method=method).convert(operator=op,
                                                         params=params)

        values_dict = [{
            a: np.pi / 4,
            b: np.pi
        }, {
            a: np.pi / 4,
            b: np.pi / 4
        }, {
            a: np.pi / 2,
            b: np.pi / 4
        }]

        correct_values = [[-1.28163104, 2.56326208, 1.06066017],
                          [-0.04495626, -2.40716991, 1.8125],
                          [2.82842712, -1.5, 1.76776695]]

        for i, value_dict in enumerate(values_dict):
            np.testing.assert_array_almost_equal(
                state_hess.assign_parameters(value_dict).eval(),
                correct_values[i],
                decimal=1)
コード例 #4
0
    def test_circuit_sampler(self, method):
        """Test the gradient with circuit sampler

        Tr(|psi><psi|Z) = sin(a)sin(b)
        Tr(|psi><psi|X) = cos(a)
        d<H>/da = - 0.5 sin(a) - 1 cos(a)sin(b)
        d<H>/db = - 1 sin(a)cos(b)
        """

        ham = 0.5 * X - 1 * Z
        a = Parameter("a")
        b = Parameter("b")
        params = [a, b]

        q = QuantumRegister(1)
        qc = QuantumCircuit(q)
        qc.h(q)
        qc.rz(params[0], q[0])
        qc.rx(params[1], q[0])
        op = ~StateFn(ham) @ CircuitStateFn(primitive=qc, coeff=1.0)

        shots = 8000
        if method == "fin_diff":
            np.random.seed(8)
            state_grad = Gradient(grad_method=method, epsilon=shots ** (-1 / 6.0)).convert(
                operator=op
            )
        else:
            state_grad = Gradient(grad_method=method).convert(operator=op)
        values_dict = [
            {a: np.pi / 4, b: np.pi},
            {params[0]: np.pi / 4, params[1]: np.pi / 4},
            {params[0]: np.pi / 2, params[1]: np.pi / 4},
        ]
        correct_values = [
            [-0.5 / np.sqrt(2), 1 / np.sqrt(2)],
            [-0.5 / np.sqrt(2) - 0.5, -1 / 2.0],
            [-0.5, -1 / np.sqrt(2)],
        ]

        backend = BasicAer.get_backend("qasm_simulator")
        q_instance = QuantumInstance(backend=backend, shots=shots)

        for i, value_dict in enumerate(values_dict):
            sampler = CircuitSampler(backend=q_instance).convert(
                state_grad, params={k: [v] for k, v in value_dict.items()}
            )
            np.testing.assert_array_almost_equal(sampler.eval()[0], correct_values[i], decimal=1)
コード例 #5
0
    def test_state_gradient1(self, method):
        """Test the state gradient

        Tr(|psi><psi|Z) = sin(a)sin(b)
        Tr(|psi><psi|X) = cos(a)
        d<H>/da = - 0.5 sin(a) - 1 cos(a)sin(b)
        d<H>/db = - 1 sin(a)cos(b)
        """

        ham = 0.5 * X - 1 * Z
        a = Parameter("a")
        b = Parameter("b")
        params = [a, b]

        q = QuantumRegister(1)
        qc = QuantumCircuit(q)
        qc.h(q)
        qc.rz(params[0], q[0])
        qc.rx(params[1], q[0])
        op = ~StateFn(ham) @ CircuitStateFn(primitive=qc, coeff=1.0)

        state_grad = Gradient(grad_method=method).convert(operator=op,
                                                          params=params)
        values_dict = [
            {
                a: np.pi / 4,
                b: np.pi
            },
            {
                params[0]: np.pi / 4,
                params[1]: np.pi / 4
            },
            {
                params[0]: np.pi / 2,
                params[1]: np.pi / 4
            },
        ]
        correct_values = [
            [-0.5 / np.sqrt(2), 1 / np.sqrt(2)],
            [-0.5 / np.sqrt(2) - 0.5, -1 / 2.0],
            [-0.5, -1 / np.sqrt(2)],
        ]

        for i, value_dict in enumerate(values_dict):
            np.testing.assert_array_almost_equal(
                state_grad.assign_parameters(value_dict).eval(),
                correct_values[i],
                decimal=1)
コード例 #6
0
    def test_prob_grad(self, method):
        """Test the probability gradient

        dp0/da = cos(a)sin(b) / 2
        dp1/da = - cos(a)sin(b) / 2
        dp0/db = sin(a)cos(b) / 2
        dp1/db = - sin(a)cos(b) / 2
        """

        a = Parameter("a")
        b = Parameter("b")
        params = [a, b]

        q = QuantumRegister(1)
        qc = QuantumCircuit(q)
        qc.h(q)
        qc.rz(params[0], q[0])
        qc.rx(params[1], q[0])

        op = CircuitStateFn(primitive=qc, coeff=1.0)

        prob_grad = Gradient(grad_method=method).convert(operator=op,
                                                         params=params)
        values_dict = [
            {
                a: np.pi / 4,
                b: 0
            },
            {
                params[0]: np.pi / 4,
                params[1]: np.pi / 4
            },
            {
                params[0]: np.pi / 2,
                params[1]: np.pi
            },
        ]
        correct_values = [
            [[0, 0], [1 / (2 * np.sqrt(2)), -1 / (2 * np.sqrt(2))]],
            [[1 / 4, -1 / 4], [1 / 4, -1 / 4]],
            [[0, 0], [-1 / 2, 1 / 2]],
        ]
        for i, value_dict in enumerate(values_dict):
            for j, prob_grad_result in enumerate(
                    prob_grad.assign_parameters(value_dict).eval()):
                np.testing.assert_array_almost_equal(prob_grad_result,
                                                     correct_values[i][j],
                                                     decimal=1)
コード例 #7
0
ファイル: vqe.py プロジェクト: ecpeterson/qiskit-terra
    def construct_expectation(
        self,
        parameter: Union[List[float], List[Parameter], np.ndarray],
        operator: OperatorBase,
    ) -> OperatorBase:
        r"""
        Generate the ansatz circuit and expectation value measurement, and return their
        runnable composition.

        Args:
            parameter: Parameters for the ansatz circuit.
            operator: Qubit operator of the Observable

        Returns:
            The Operator equalling the measurement of the ansatz :class:`StateFn` by the
            Observable's expectation :class:`StateFn`.

        Raises:
            AlgorithmError: If no operator has been provided.
        """
        if operator is None:
            raise AlgorithmError("The operator was never provided.")

        operator = self._check_operator(operator)

        if isinstance(self.var_form, QuantumCircuit):
            param_dict = dict(zip(self._var_form_params,
                                  parameter))  # type: Dict
            wave_function = self.var_form.assign_parameters(param_dict)
        else:
            wave_function = self.var_form.construct_circuit(parameter)

        # Expectation was never created , try to create one
        if self._expectation is None:
            self._try_set_expectation_value_from_factory(operator)

        # If setting the expectation failed, raise an Error:
        if self._expectation is None:
            raise AlgorithmError(
                'No expectation set and could not automatically set one, please '
                'try explicitly setting an expectation or specify a backend so it '
                'can be chosen automatically.')

        observable_meas = self.expectation.convert(
            StateFn(operator, is_measurement=True))
        ansatz_circuit_op = CircuitStateFn(wave_function)
        return observable_meas.compose(ansatz_circuit_op).reduce()
コード例 #8
0
    def test_gradient_wrapper(self, backend_type):
        """Test the gradient wrapper for probability gradients
        dp0/da = cos(a)sin(b) / 2
        dp1/da = - cos(a)sin(b) / 2
        dp0/db = sin(a)cos(b) / 2
        dp1/db = - sin(a)cos(b) / 2
        """
        method = 'param_shift'
        a = Parameter('a')
        b = Parameter('b')
        params = [a, b]

        q = QuantumRegister(1)
        qc = QuantumCircuit(q)
        qc.h(q)
        qc.rz(params[0], q[0])
        qc.rx(params[1], q[0])

        op = CircuitStateFn(primitive=qc, coeff=1.)

        shots = 8000
        backend = BasicAer.get_backend(backend_type)
        q_instance = QuantumInstance(backend=backend, shots=shots)
        if method == 'fin_diff':
            np.random.seed(8)
            prob_grad = Gradient(grad_method=method,
                                 epsilon=shots**(-1 / 6.)).gradient_wrapper(
                                     operator=op,
                                     bind_params=params,
                                     backend=q_instance)
        else:
            prob_grad = Gradient(grad_method=method).gradient_wrapper(
                operator=op, bind_params=params, backend=q_instance)
        values = [[np.pi / 4, 0], [np.pi / 4, np.pi / 4], [np.pi / 2, np.pi]]
        correct_values = [[[0, 0],
                           [1 / (2 * np.sqrt(2)), -1 / (2 * np.sqrt(2))]],
                          [[1 / 4, -1 / 4], [1 / 4, -1 / 4]],
                          [[0, 0], [-1 / 2, 1 / 2]]]
        for i, value in enumerate(values):
            result = prob_grad(value)
            if backend_type == 'qasm_simulator':  # sparse result
                result = [result[0].toarray(), result[1].toarray()]

            self.assertTrue(
                np.allclose(result[0], correct_values[i][0], atol=0.1))
            self.assertTrue(
                np.allclose(result[1], correct_values[i][1], atol=0.1))
コード例 #9
0
    def test_operator_coefficient_hessian(self, method):
        """Test the operator coefficient hessian

        <Z> = Tr( | psi > < psi | Z) = sin(a)sin(b)
        <X> = Tr( | psi > < psi | X) = cos(a)
        d<H>/dc_0 = 2 * c_0 * <X> + c_1 * <Z>
        d<H>/dc_1 = c_0 * <Z>
        d^2<H>/dc_0^2 = 2 * <X>
        d^2<H>/dc_0dc_1 = <Z>
        d^2<H>/dc_1dc_0 = <Z>
        d^2<H>/dc_1^2 = 0
        """
        a = Parameter('a')
        b = Parameter('b')
        q = QuantumRegister(1)
        qc = QuantumCircuit(q)
        qc.h(q)
        qc.rz(a, q[0])
        qc.rx(b, q[0])

        coeff_0 = Parameter('c_0')
        coeff_1 = Parameter('c_1')
        ham = coeff_0 * coeff_0 * X + coeff_1 * coeff_0 * Z
        op = ~StateFn(ham) @ CircuitStateFn(primitive=qc, coeff=1.)
        gradient_coeffs = [(coeff_0, coeff_0), (coeff_0, coeff_1),
                           (coeff_1, coeff_1)]
        coeff_grad = Hessian(hess_method=method).convert(op, gradient_coeffs)
        values_dict = [{
            coeff_0: 0.5,
            coeff_1: -1,
            a: np.pi / 4,
            b: np.pi
        }, {
            coeff_0: 0.5,
            coeff_1: -1,
            a: np.pi / 4,
            b: np.pi / 4
        }]

        correct_values = [[2 / np.sqrt(2), 0, 0], [2 / np.sqrt(2), 1 / 2, 0]]

        for i, value_dict in enumerate(values_dict):
            np.testing.assert_array_almost_equal(
                coeff_grad.assign_parameters(value_dict).eval(),
                correct_values[i],
                decimal=1)
コード例 #10
0
    def test_gradient_ryy(self, method):
        """Test the state gradient for YY rotation
        """
        ham = Y ^ Y
        a = Parameter('a')

        q = QuantumRegister(2)
        qc = QuantumCircuit(q)
        qc.ryy(a, q[0], q[1])

        op = ~StateFn(ham) @ CircuitStateFn(primitive=qc, coeff=1.)
        state_grad = Gradient(grad_method=method).convert(operator=op, params=a)
        values_dict = [{a: np.pi / 8}, {a: np.pi}]
        correct_values = [[0], [0]]
        for i, value_dict in enumerate(values_dict):
            np.testing.assert_array_almost_equal(state_grad.assign_parameters(value_dict).eval(),
                                                 correct_values[i], decimal=1)
コード例 #11
0
ファイル: vqe.py プロジェクト: wbclark/qiskit-terra
    def _eval_aux_ops(self, threshold=1e-12):
        # Create new CircuitSampler to avoid breaking existing one's caches.
        sampler = CircuitSampler(self.quantum_instance)

        aux_op_meas = self.expectation.convert(StateFn(ListOp(self.aux_operators),
                                                       is_measurement=True))
        aux_op_expect = aux_op_meas.compose(CircuitStateFn(self.get_optimal_circuit()))
        values = np.real(sampler.convert(aux_op_expect).eval())

        # Discard values below threshold
        aux_op_results = (values * (np.abs(values) > threshold))
        # Deal with the aux_op behavior where there can be Nones or Zero qubit Paulis in the list
        self._ret['aux_ops'] = [None if is_none else [result]
                                for (is_none, result) in zip(self._aux_op_nones, aux_op_results)]
        # As this has mixed types, since it can included None, it needs to explicitly pass object
        # data type to avoid numpy 1.19 warning message about implicit conversion being deprecated
        self._ret['aux_ops'] = np.array([self._ret['aux_ops']], dtype=object)
コード例 #12
0
    def test_state_hessian(self, method):
        """Test the state Hessian

        Tr(|psi><psi|Z) = sin(a)sin(b)
        Tr(|psi><psi|X) = cos(a)
        d^2<H>/da^2 = - 0.5 cos(a) + 1 sin(a)sin(b)
        d^2<H>/dbda = - 1 cos(a)cos(b)
        d^2<H>/dbda = - 1 cos(a)cos(b)
        d^2<H>/db^2 = + 1 sin(a)sin(b)
        """

        ham = 0.5 * X - 1 * Z
        a = Parameter('a')
        b = Parameter('b')
        params = [(a, a), (a, b), (b, b)]

        q = QuantumRegister(1)
        qc = QuantumCircuit(q)
        qc.h(q)
        qc.rz(a, q[0])
        qc.rx(b, q[0])

        op = ~StateFn(ham) @ CircuitStateFn(primitive=qc, coeff=1.)
        state_hess = Hessian(hess_method=method).convert(operator=op,
                                                         params=params)

        values_dict = [{
            a: np.pi / 4,
            b: np.pi
        }, {
            a: np.pi / 4,
            b: np.pi / 4
        }, {
            a: np.pi / 2,
            b: np.pi / 4
        }]
        correct_values = [[-0.5 / np.sqrt(2), 1 / np.sqrt(2), 0],
                          [-0.5 / np.sqrt(2) + 0.5, -1 / 2., 0.5],
                          [1 / np.sqrt(2), 0, 1 / np.sqrt(2)]]

        for i, value_dict in enumerate(values_dict):
            np.testing.assert_array_almost_equal(
                state_hess.assign_parameters(value_dict).eval(),
                correct_values[i],
                decimal=1)
コード例 #13
0
    def test_prob_hess(self, method):
        """Test the probability Hessian using linear combination of unitaries method

        d^2p0/da^2 = - sin(a)sin(b) / 2
        d^2p1/da^2 =  sin(a)sin(b) / 2
        d^2p0/dadb = cos(a)cos(b) / 2
        d^2p1/dadb = - cos(a)cos(b) / 2
        """

        a = Parameter("a")
        b = Parameter("b")
        params = [(a, a), (a, b)]

        q = QuantumRegister(1)
        qc = QuantumCircuit(q)
        qc.h(q)
        qc.rz(a, q[0])
        qc.rx(b, q[0])

        op = CircuitStateFn(primitive=qc, coeff=1.0)

        prob_hess = Hessian(hess_method=method).convert(operator=op,
                                                        params=params)
        values_dict = [{
            a: np.pi / 4,
            b: 0
        }, {
            a: np.pi / 4,
            b: np.pi / 4
        }, {
            a: np.pi / 2,
            b: np.pi
        }]
        correct_values = [
            [[0, 0], [1 / (2 * np.sqrt(2)), -1 / (2 * np.sqrt(2))]],
            [[-1 / 4, 1 / 4], [1 / 4, -1 / 4]],
            [[0, 0], [0, 0]],
        ]
        for i, value_dict in enumerate(values_dict):
            for j, prob_hess_result in enumerate(
                    prob_hess.assign_parameters(value_dict).eval()):
                np.testing.assert_array_almost_equal(prob_hess_result,
                                                     correct_values[i][j],
                                                     decimal=1)
コード例 #14
0
    def test_circuit_sampler2(self, method):
        """Test the probability gradient with the circuit sampler

        dp0/da = cos(a)sin(b) / 2
        dp1/da = - cos(a)sin(b) / 2
        dp0/db = sin(a)cos(b) / 2
        dp1/db = - sin(a)cos(b) / 2
        """

        a = Parameter('a')
        b = Parameter('b')
        params = [a, b]

        q = QuantumRegister(1)
        qc = QuantumCircuit(q)
        qc.h(q)
        qc.rz(params[0], q[0])
        qc.rx(params[1], q[0])

        op = CircuitStateFn(primitive=qc, coeff=1.)

        shots = 8000
        if method == 'fin_diff':
            np.random.seed(8)
            prob_grad = Gradient(grad_method=method, epsilon=shots ** (-1 / 6.)).convert(
                operator=op,
                params=params)
        else:
            prob_grad = Gradient(grad_method=method).convert(operator=op, params=params)
        values_dict = [{a: [np.pi / 4], b: [0]}, {params[0]: [np.pi / 4], params[1]: [np.pi / 4]},
                       {params[0]: [np.pi / 2], params[1]: [np.pi]}]
        correct_values = [[[0, 0], [1 / (2 * np.sqrt(2)), - 1 / (2 * np.sqrt(2))]],
                          [[1 / 4, -1 / 4], [1 / 4, - 1 / 4]],
                          [[0, 0], [- 1 / 2, 1 / 2]]]

        backend = BasicAer.get_backend('qasm_simulator')
        q_instance = QuantumInstance(backend=backend, shots=shots)

        for i, value_dict in enumerate(values_dict):
            sampler = CircuitSampler(backend=q_instance).convert(prob_grad,
                                                                 params=value_dict)
            result = sampler.eval()
            np.testing.assert_array_almost_equal(result[0], correct_values[i], decimal=1)
コード例 #15
0
    def test_state_hessian(self, method):
        """Test the state Hessian

        Tr(|psi><psi|Z) = sin(a)sin(b)
        Tr(|psi><psi|X) = cos(a)
        d^2<H>/da^2 = - 0.5 cos(a) + 1 sin(a)sin(b)
        d^2<H>/dbda = - 1 cos(a)cos(b)
        d^2<H>/dbda = - 1 cos(a)cos(b)
        d^2<H>/db^2 = + 1 sin(a)sin(b)
        """

        ham = 0.5 * X - 1 * Z
        params = ParameterVector("a", 2)

        q = QuantumRegister(1)
        qc = QuantumCircuit(q)
        qc.h(q)
        qc.rz(params[0], q[0])
        qc.rx(params[1], q[0])

        op = ~StateFn(ham) @ CircuitStateFn(primitive=qc, coeff=1.0)
        state_hess = Hessian(hess_method=method).convert(operator=op)

        values_dict = [
            {
                params[0]: np.pi / 4,
                params[1]: np.pi
            },
            {
                params[0]: np.pi / 4,
                params[1]: np.pi / 4
            },
        ]
        correct_values = [
            [[-0.5 / np.sqrt(2), 1 / np.sqrt(2)], [1 / np.sqrt(2), 0]],
            [[-0.5 / np.sqrt(2) + 0.5, -1 / 2.0], [-1 / 2.0, 0.5]],
        ]

        for i, value_dict in enumerate(values_dict):
            np.testing.assert_array_almost_equal(
                state_hess.assign_parameters(value_dict).eval(),
                correct_values[i],
                decimal=1)
コード例 #16
0
ファイル: qaoa_ansatz.py プロジェクト: Cryoris/qiskit-terra
    def _construct_circuit(self, parameters) -> QuantumCircuit:
        """Construct a parameterized circuit."""
        if not len(parameters) == self._num_parameters:
            raise ValueError(
                'Incorrect number of angles: expecting {}, but {} given.'.
                format(self._num_parameters, len(parameters)))

        # local imports to avoid circular imports
        from qiskit.opflow import CircuitStateFn
        from qiskit.opflow import CircuitOp, EvolutionFactory
        from qiskit.opflow import OperatorBase

        circuit_op = CircuitStateFn(self.initial_state)

        # iterate over layers
        for idx in range(self._reps):
            # the first [:self._reps] parameters are used for the cost operator,
            # so we apply them here
            circuit_op = (self._cost_operator *
                          parameters[idx]).exp_i().compose(circuit_op)
            mixer = self.mixer_operator
            if isinstance(mixer, OperatorBase):
                mixer = cast(OperatorBase, mixer)
                # we apply beta parameter in case of operator based mixer.
                circuit_op = (
                    mixer *
                    parameters[idx + self._reps]).exp_i().compose(circuit_op)
            else:
                # mixer as a quantum circuit that can be parameterized
                mixer = cast(QuantumCircuit, mixer)
                num_params = mixer.num_parameters
                # the remaining [self._p:] parameters are used for the mixer,
                # there may be multiple layers, so parameters are grouped by layers.
                param_values = parameters[self._reps +
                                          num_params * idx:self._reps +
                                          num_params * (idx + 1)]
                param_dict = dict(zip(mixer.parameters, param_values))
                mixer = mixer.assign_parameters(param_dict)
                circuit_op = CircuitOp(mixer).compose(circuit_op)

        evolution = EvolutionFactory.build(self._cost_operator)
        circuit_op = evolution.convert(circuit_op)
        return circuit_op.to_circuit()
コード例 #17
0
    def test_gradient_rzz(self, method):
        """Test the state gradient for ZZ rotation"""
        ham = Z ^ X
        a = Parameter("a")

        q = QuantumRegister(2)
        qc = QuantumCircuit(q)
        qc.h(q[0])
        qc.rzz(a, q[0], q[1])

        op = ~StateFn(ham) @ CircuitStateFn(primitive=qc, coeff=1.0)
        params = [a]
        state_grad = Gradient(grad_method=method).convert(operator=op, params=params)
        values_dict = [{a: np.pi / 4}, {a: np.pi / 2}]
        correct_values = [[-0.707], [-1.0]]
        for i, value_dict in enumerate(values_dict):
            np.testing.assert_array_almost_equal(
                state_grad.assign_parameters(value_dict).eval(), correct_values[i], decimal=1
            )
コード例 #18
0
    def test_gradient_wrapper2(self, backend_type, atol):
        """Test the gradient wrapper for gradients checking that statevector and qasm gives the
           same results

        dp0/da = cos(a)sin(b) / 2
        dp1/da = - cos(a)sin(b) / 2
        dp0/db = sin(a)cos(b) / 2
        dp1/db = - sin(a)cos(b) / 2
        """
        method = "lin_comb"
        a = Parameter("a")
        b = Parameter("b")
        params = [a, b]

        qc = QuantumCircuit(2)
        qc.h(1)
        qc.h(0)
        qc.sdg(1)
        qc.cz(0, 1)
        qc.ry(params[0], 0)
        qc.rz(params[1], 0)
        qc.h(1)

        obs = (Z ^ X) - (Y ^ Y)
        op = StateFn(obs, is_measurement=True) @ CircuitStateFn(primitive=qc)

        shots = 8192 if backend_type == "qasm_simulator" else 1

        values = [[0, np.pi / 2], [np.pi / 4, np.pi / 4],
                  [np.pi / 3, np.pi / 9]]
        correct_values = [[-4.0, 0], [-2.0, -4.82842712],
                          [-0.68404029, -7.01396121]]
        for i, value in enumerate(values):
            backend = BasicAer.get_backend(backend_type)
            q_instance = QuantumInstance(backend=backend,
                                         shots=shots,
                                         seed_simulator=2,
                                         seed_transpiler=2)
            grad = NaturalGradient(grad_method=method).gradient_wrapper(
                operator=op, bind_params=params, backend=q_instance)
            result = grad(value)
            self.assertTrue(np.allclose(result, correct_values[i], atol=atol))
コード例 #19
0
    def test_operator_coefficient_gradient(self, method):
        """Test the operator coefficient gradient

        Tr( | psi > < psi | Z) = sin(a)sin(b)
        Tr( | psi > < psi | X) = cos(a)
        """
        a = Parameter("a")
        b = Parameter("b")
        q = QuantumRegister(1)
        qc = QuantumCircuit(q)
        qc.h(q)
        qc.rz(a, q[0])
        qc.rx(b, q[0])

        coeff_0 = Parameter("c_0")
        coeff_1 = Parameter("c_1")
        ham = coeff_0 * X + coeff_1 * Z
        op = StateFn(ham, is_measurement=True) @ CircuitStateFn(primitive=qc,
                                                                coeff=1.0)
        gradient_coeffs = [coeff_0, coeff_1]
        coeff_grad = Gradient(grad_method=method).convert(op, gradient_coeffs)
        values_dict = [
            {
                coeff_0: 0.5,
                coeff_1: -1,
                a: np.pi / 4,
                b: np.pi
            },
            {
                coeff_0: 0.5,
                coeff_1: -1,
                a: np.pi / 4,
                b: np.pi / 4
            },
        ]
        correct_values = [[1 / np.sqrt(2), 0], [1 / np.sqrt(2), 1 / 2]]
        for i, value_dict in enumerate(values_dict):
            np.testing.assert_array_almost_equal(
                coeff_grad.assign_parameters(value_dict).eval(),
                correct_values[i],
                decimal=1)
コード例 #20
0
        def gradient_function(current_point):
            """
            Gradient function

            Args:
                current_point (np.ndarray): Current values for the variational parameters.

            Returns:
                np.ndarray: array of partial derivatives of the loss
                    function w.r.t. the variational parameters.
            """
            free_params = self._free_parameters
            generated_data, _ = self.get_output(quantum_instance,
                                                params=current_point,
                                                shots=self._shots)
            prediction_generated = discriminator.get_label(generated_data, detach=True)
            op = ~CircuitStateFn(primitive=self.generator_circuit)
            grad_object = gradient_object.convert(operator=op, params=free_params)
            value_dict = {free_params[i]: current_point[i] for i in range(len(free_params))}
            analytical_gradients = np.array(grad_object.assign_parameters(value_dict).eval())
            loss_gradients = self.loss(prediction_generated, analytical_gradients).real
            return loss_gradients
コード例 #21
0
    def test_state_gradient5(self, method):
        """Test the state gradient

        Tr(|psi><psi|Z) = sin(a0)sin(a1)
        Tr(|psi><psi|X) = cos(a0)
        d<H>/da0 = - 0.5 sin(a0) - 1 cos(a0)sin(a1)
        d<H>/da1 = - 1 sin(a0)cos(a1)
        """

        ham = 0.5 * X - 1 * Z
        a = ParameterVector('a', 2)
        params = a

        q = QuantumRegister(1)
        qc = QuantumCircuit(q)
        qc.h(q)
        qc.rz(params[0], q[0])
        qc.rx(params[1], q[0])
        op = ~StateFn(ham) @ CircuitStateFn(primitive=qc, coeff=1.)

        state_grad = Gradient(grad_method=method).convert(operator=op,
                                                          params=params)
        values_dict = [{
            a: [np.pi / 4, np.pi]
        }, {
            a: [np.pi / 4, np.pi / 4]
        }, {
            a: [np.pi / 2, np.pi / 4]
        }]
        correct_values = [[-0.5 / np.sqrt(2), 1 / np.sqrt(2)],
                          [-0.5 / np.sqrt(2) - 0.5, -1 / 2.],
                          [-0.5, -1 / np.sqrt(2)]]

        for i, value_dict in enumerate(values_dict):
            np.testing.assert_array_almost_equal(
                state_grad.assign_parameters(value_dict).eval(),
                correct_values[i],
                decimal=1)
コード例 #22
0
    def test_qfi_maxcut(self):
        """Test the QFI for a simple MaxCut problem.

        This is interesting because it contains the same parameters in different gates.
        """
        # create maxcut circuit for the hamiltonian
        # H = (I ^ I ^ Z ^ Z) + (I ^ Z ^ I ^ Z) + (Z ^ I ^ I ^ Z) + (I ^ Z ^ Z ^ I)

        x = ParameterVector("x", 2)
        ansatz = QuantumCircuit(4)

        # initial hadamard layer
        ansatz.h(ansatz.qubits)

        # e^{iZZ} layers
        def expiz(qubit0, qubit1):
            ansatz.cx(qubit0, qubit1)
            ansatz.rz(2 * x[0], qubit1)
            ansatz.cx(qubit0, qubit1)

        expiz(2, 1)
        expiz(3, 0)
        expiz(2, 0)
        expiz(1, 0)

        # mixer layer with RX gates
        for i in range(ansatz.num_qubits):
            ansatz.rx(2 * x[1], i)

        point = {x[0]: 0.4, x[1]: 0.69}

        # reference computed via finite difference
        reference = np.array([[16.0, -5.551], [-5.551, 18.497]])

        # QFI from gradient framework
        qfi = QFI().convert(CircuitStateFn(ansatz), params=x[:])
        actual = np.array(qfi.bind_parameters(point).eval()).real
        np.testing.assert_array_almost_equal(actual, reference, decimal=3)
コード例 #23
0
ファイル: vqe.py プロジェクト: Bhargavishnu/qiskit-terra
    def _eval_aux_ops(
        self,
        parameters: np.ndarray,
        aux_operators: ListOrDict[OperatorBase],
        expectation: ExpectationBase,
        threshold: float = 1e-12,
    ) -> ListOrDict[complex]:
        # Create new CircuitSampler to avoid breaking existing one's caches.
        sampler = CircuitSampler(self.quantum_instance)

        if isinstance(aux_operators, dict):
            list_op = ListOp(list(aux_operators.values()))
        else:
            list_op = ListOp(aux_operators)

        aux_op_meas = expectation.convert(StateFn(list_op,
                                                  is_measurement=True))
        aux_op_expect = aux_op_meas.compose(
            CircuitStateFn(self.ansatz.bind_parameters(parameters)))
        values = np.real(sampler.convert(aux_op_expect).eval())

        # Discard values below threshold
        aux_op_results = values * (np.abs(values) > threshold)

        # Return None eigenvalues for None operators if aux_operators is a list.
        # None operators are already dropped in compute_minimum_eigenvalue if aux_operators is a dict.
        if isinstance(aux_operators, list):
            aux_operator_eigenvalues = [None] * len(aux_operators)
            key_value_iterator = enumerate(aux_op_results)
        else:
            aux_operator_eigenvalues = {}
            key_value_iterator = zip(aux_operators.keys(), aux_op_results)

        for key, value in key_value_iterator:
            if aux_operators[key] is not None:
                aux_operator_eigenvalues[key] = value

        return aux_operator_eigenvalues
コード例 #24
0
    def test_qfi_simple(self, method):
        """Test if the quantum fisher information calculation is correct for a simple test case.

        QFI = [[1, 0], [0, 1]] - [[0, 0], [0, cos^2(a)]]
        """
        # create the circuit
        a, b = Parameter("a"), Parameter("b")
        qc = QuantumCircuit(1)
        qc.h(0)
        qc.rz(a, 0)
        qc.rx(b, 0)

        # convert the circuit to a QFI object
        op = CircuitStateFn(qc)
        qfi = QFI(qfi_method=method).convert(operator=op)

        # test for different values
        values_dict = [{a: np.pi / 4, b: 0.1}, {a: np.pi, b: 0.1}, {a: np.pi / 2, b: 0.1}]
        correct_values = [[[1, 0], [0, 0.5]], [[1, 0], [0, 0]], [[1, 0], [0, 1]]]

        for i, value_dict in enumerate(values_dict):
            actual = qfi.assign_parameters(value_dict).eval()
            np.testing.assert_array_almost_equal(actual, correct_values[i], decimal=1)
コード例 #25
0
    def test_gradient_p(self, method):
        """Test the state gradient for p
        |psi> = 1/sqrt(2)[[1, exp(ia)]]
        Tr(|psi><psi|Z) = 0
        Tr(|psi><psi|X) = cos(a)
        d<H>/da = - 0.5 sin(a)
        """
        ham = 0.5 * X - 1 * Z
        a = Parameter('a')
        params = a

        q = QuantumRegister(1)
        qc = QuantumCircuit(q)
        qc.h(q)
        qc.p(a, q[0])
        op = ~StateFn(ham) @ CircuitStateFn(primitive=qc, coeff=1.)

        state_grad = Gradient(grad_method=method).convert(operator=op, params=params)
        values_dict = [{a: np.pi / 4}, {a: 0}, {a: np.pi / 2}]
        correct_values = [-0.5 / np.sqrt(2), 0, -0.5]

        for i, value_dict in enumerate(values_dict):
            np.testing.assert_array_almost_equal(state_grad.assign_parameters(value_dict).eval(),
                                                 correct_values[i], decimal=1)
コード例 #26
0
    def test_compose_with_indices(self):
        """Test compose method using its permutation feature."""

        pauli_op = X ^ Y ^ Z
        circuit_op = T ^ H
        matrix_op = (X ^ Y ^ H ^ T).to_matrix_op()
        evolved_op = EvolvedOp(matrix_op)

        # composition of PrimitiveOps
        num_qubits = 4
        primitive_op = pauli_op @ circuit_op @ matrix_op
        composed_op = pauli_op @ circuit_op @ evolved_op
        self.assertEqual(primitive_op.num_qubits, num_qubits)
        self.assertEqual(composed_op.num_qubits, num_qubits)

        # with permutation
        num_qubits = 5
        indices = [1, 4]
        permuted_primitive_op = evolved_op @ circuit_op.permute(
            indices) @ pauli_op @ matrix_op
        composed_primitive_op = (evolved_op @ pauli_op.compose(
            circuit_op, permutation=indices, front=True) @ matrix_op)

        self.assertTrue(
            np.allclose(permuted_primitive_op.to_matrix(),
                        composed_primitive_op.to_matrix()))
        self.assertEqual(num_qubits, permuted_primitive_op.num_qubits)

        # ListOp
        num_qubits = 6
        tensored_op = TensoredOp([pauli_op, circuit_op])
        summed_op = pauli_op + circuit_op.permute([2, 1])
        composed_op = circuit_op @ evolved_op @ matrix_op

        list_op = summed_op @ composed_op.compose(
            tensored_op, permutation=[1, 2, 3, 5, 4], front=True)
        self.assertEqual(num_qubits, list_op.num_qubits)

        num_qubits = 4
        circuit_fn = CircuitStateFn(primitive=circuit_op.primitive,
                                    is_measurement=True)
        operator_fn = OperatorStateFn(primitive=circuit_op ^ circuit_op,
                                      is_measurement=True)

        no_perm_op = circuit_fn @ operator_fn
        self.assertEqual(no_perm_op.num_qubits, num_qubits)

        indices = [0, 4]
        perm_op = operator_fn.compose(circuit_fn,
                                      permutation=indices,
                                      front=True)
        self.assertEqual(perm_op.num_qubits, max(indices) + 1)

        # StateFn
        num_qubits = 3
        dim = 2**num_qubits
        vec = [1.0 / (i + 1) for i in range(dim)]
        dic = {
            format(i, "b").zfill(num_qubits): 1.0 / (i + 1)
            for i in range(dim)
        }

        is_measurement = True
        op_state_fn = OperatorStateFn(
            matrix_op, is_measurement=is_measurement)  # num_qubit = 4
        vec_state_fn = VectorStateFn(vec, is_measurement=is_measurement)  # 3
        dic_state_fn = DictStateFn(dic, is_measurement=is_measurement)  # 3
        circ_state_fn = CircuitStateFn(circuit_op.to_circuit(),
                                       is_measurement=is_measurement)  # 2

        composed_op = op_state_fn @ vec_state_fn @ dic_state_fn @ circ_state_fn
        self.assertEqual(composed_op.num_qubits, op_state_fn.num_qubits)

        # with permutation
        perm = [2, 4, 6]
        composed = (op_state_fn @ dic_state_fn.compose(
            vec_state_fn, permutation=perm, front=True) @ circ_state_fn)
        self.assertEqual(composed.num_qubits, max(perm) + 1)
コード例 #27
0
class TestOpConstruction(QiskitOpflowTestCase):
    """Operator Construction tests."""
    def test_pauli_primitives(self):
        """from to file test"""
        newop = X ^ Y ^ Z ^ I
        self.assertEqual(newop.primitive, Pauli("XYZI"))

        kpower_op = (Y ^ 5) ^ (I ^ 3)
        self.assertEqual(kpower_op.primitive, Pauli("YYYYYIII"))

        kpower_op2 = (Y ^ I) ^ 4
        self.assertEqual(kpower_op2.primitive, Pauli("YIYIYIYI"))

        # Check immutability
        self.assertEqual(X.primitive, Pauli("X"))
        self.assertEqual(Y.primitive, Pauli("Y"))
        self.assertEqual(Z.primitive, Pauli("Z"))
        self.assertEqual(I.primitive, Pauli("I"))

    def test_composed_eval(self):
        """Test eval of ComposedOp"""
        self.assertAlmostEqual(Minus.eval("1"), -(0.5**0.5))

    def test_xz_compose_phase(self):
        """Test phase composition"""
        self.assertEqual((-1j * Y).eval("0").eval("0"), 0)
        self.assertEqual((-1j * Y).eval("0").eval("1"), 1)
        self.assertEqual((-1j * Y).eval("1").eval("0"), -1)
        self.assertEqual((-1j * Y).eval("1").eval("1"), 0)
        self.assertEqual((X @ Z).eval("0").eval("0"), 0)
        self.assertEqual((X @ Z).eval("0").eval("1"), 1)
        self.assertEqual((X @ Z).eval("1").eval("0"), -1)
        self.assertEqual((X @ Z).eval("1").eval("1"), 0)
        self.assertEqual((1j * Y).eval("0").eval("0"), 0)
        self.assertEqual((1j * Y).eval("0").eval("1"), -1)
        self.assertEqual((1j * Y).eval("1").eval("0"), 1)
        self.assertEqual((1j * Y).eval("1").eval("1"), 0)
        self.assertEqual((Z @ X).eval("0").eval("0"), 0)
        self.assertEqual((Z @ X).eval("0").eval("1"), -1)
        self.assertEqual((Z @ X).eval("1").eval("0"), 1)
        self.assertEqual((Z @ X).eval("1").eval("1"), 0)

    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 + 0.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_circuit_construction(self):
        """circuit construction test"""
        hadq2 = H ^ I
        cz = hadq2.compose(CX).compose(hadq2)
        qc = QuantumCircuit(2)
        qc.append(cz.primitive, qargs=range(2))

        ref_cz_mat = PrimitiveOp(CZGate()).to_matrix()
        np.testing.assert_array_almost_equal(cz.to_matrix(), ref_cz_mat)

    def test_io_consistency(self):
        """consistency test"""
        new_op = X ^ Y ^ I
        label = "XYI"
        # label = new_op.primitive.to_label()
        self.assertEqual(str(new_op.primitive), label)
        np.testing.assert_array_almost_equal(new_op.primitive.to_matrix(),
                                             Operator.from_label(label).data)
        self.assertEqual(new_op.primitive, Pauli(label))

        x_mat = X.primitive.to_matrix()
        y_mat = Y.primitive.to_matrix()
        i_mat = np.eye(2, 2)
        np.testing.assert_array_almost_equal(
            new_op.primitive.to_matrix(), np.kron(np.kron(x_mat, y_mat),
                                                  i_mat))

        hi = np.kron(H.to_matrix(), I.to_matrix())
        hi2 = Operator.from_label("HI").data
        hi3 = (H ^ I).to_matrix()
        np.testing.assert_array_almost_equal(hi, hi2)
        np.testing.assert_array_almost_equal(hi2, hi3)

        xy = np.kron(X.to_matrix(), Y.to_matrix())
        xy2 = Operator.from_label("XY").data
        xy3 = (X ^ Y).to_matrix()
        np.testing.assert_array_almost_equal(xy, xy2)
        np.testing.assert_array_almost_equal(xy2, xy3)

        # Check if numpy array instantiation is the same as from Operator
        matrix_op = Operator.from_label("+r")
        np.testing.assert_array_almost_equal(
            PrimitiveOp(matrix_op).to_matrix(),
            PrimitiveOp(matrix_op.data).to_matrix())
        # Ditto list of lists
        np.testing.assert_array_almost_equal(
            PrimitiveOp(matrix_op.data.tolist()).to_matrix(),
            PrimitiveOp(matrix_op.data).to_matrix(),
        )

        # TODO make sure this works once we resolve endianness mayhem
        # qc = QuantumCircuit(3)
        # qc.x(2)
        # qc.y(1)
        # from qiskit import BasicAer, QuantumCircuit, execute
        # unitary = execute(qc, BasicAer.get_backend('unitary_simulator')).result().get_unitary()
        # np.testing.assert_array_almost_equal(new_op.primitive.to_matrix(), unitary)

    def test_to_matrix(self):
        """to matrix text"""
        np.testing.assert_array_equal(X.to_matrix(),
                                      Operator.from_label("X").data)
        np.testing.assert_array_equal(Y.to_matrix(),
                                      Operator.from_label("Y").data)
        np.testing.assert_array_equal(Z.to_matrix(),
                                      Operator.from_label("Z").data)

        op1 = Y + H
        np.testing.assert_array_almost_equal(op1.to_matrix(),
                                             Y.to_matrix() + H.to_matrix())

        op2 = op1 * 0.5
        np.testing.assert_array_almost_equal(op2.to_matrix(),
                                             op1.to_matrix() * 0.5)

        op3 = (4 - 0.6j) * op2
        np.testing.assert_array_almost_equal(op3.to_matrix(),
                                             op2.to_matrix() * (4 - 0.6j))

        op4 = op3.tensor(X)
        np.testing.assert_array_almost_equal(
            op4.to_matrix(), np.kron(op3.to_matrix(), X.to_matrix()))

        op5 = op4.compose(H ^ I)
        np.testing.assert_array_almost_equal(
            op5.to_matrix(), np.dot(op4.to_matrix(), (H ^ I).to_matrix()))

        op6 = op5 + PrimitiveOp(Operator.from_label("+r").data)
        np.testing.assert_array_almost_equal(
            op6.to_matrix(),
            op5.to_matrix() + Operator.from_label("+r").data)

        param = Parameter("α")
        m = np.array([[0, -1j], [1j, 0]])
        op7 = MatrixOp(m, param)
        np.testing.assert_array_equal(op7.to_matrix(), m * param)

        param = Parameter("β")
        op8 = PauliOp(primitive=Pauli("Y"), coeff=param)
        np.testing.assert_array_equal(op8.to_matrix(), m * param)

        param = Parameter("γ")
        qc = QuantumCircuit(1)
        qc.h(0)
        op9 = CircuitOp(qc, coeff=param)
        m = np.array([[1, 1], [1, -1]]) / np.sqrt(2)
        np.testing.assert_array_equal(op9.to_matrix(), m * param)

    def test_circuit_op_to_matrix(self):
        """test CircuitOp.to_matrix"""
        qc = QuantumCircuit(1)
        qc.rz(1.0, 0)
        qcop = CircuitOp(qc)
        np.testing.assert_array_almost_equal(
            qcop.to_matrix(), scipy.linalg.expm(-0.5j * Z.to_matrix()))

    def test_matrix_to_instruction(self):
        """Test MatrixOp.to_instruction yields an Instruction object."""
        matop = (H ^ 3).to_matrix_op()
        with self.subTest("assert to_instruction returns Instruction"):
            self.assertIsInstance(matop.to_instruction(), Instruction)

        matop = ((H ^ 3) + (Z ^ 3)).to_matrix_op()
        with self.subTest("matrix operator is not unitary"):
            with self.assertRaises(ExtensionError):
                matop.to_instruction()

    def test_adjoint(self):
        """adjoint test"""
        gnarly_op = 3 * (H ^ I
                         ^ Y).compose(X ^ X ^ Z).tensor(T ^ Z) + PrimitiveOp(
                             Operator.from_label("+r0IX").data)
        np.testing.assert_array_almost_equal(
            np.conj(np.transpose(gnarly_op.to_matrix())),
            gnarly_op.adjoint().to_matrix())

    def test_primitive_strings(self):
        """get primitives test"""
        self.assertEqual(X.primitive_strings(), {"Pauli"})

        gnarly_op = 3 * (H ^ I
                         ^ Y).compose(X ^ X ^ Z).tensor(T ^ Z) + PrimitiveOp(
                             Operator.from_label("+r0IX").data)
        self.assertEqual(gnarly_op.primitive_strings(),
                         {"QuantumCircuit", "Matrix"})

    def test_to_pauli_op(self):
        """Test to_pauli_op method"""
        gnarly_op = 3 * (H ^ I
                         ^ Y).compose(X ^ X ^ Z).tensor(T ^ Z) + PrimitiveOp(
                             Operator.from_label("+r0IX").data)
        mat_op = gnarly_op.to_matrix_op()
        pauli_op = gnarly_op.to_pauli_op()
        self.assertIsInstance(pauli_op, SummedOp)
        for p in pauli_op:
            self.assertIsInstance(p, PauliOp)
        np.testing.assert_array_almost_equal(mat_op.to_matrix(),
                                             pauli_op.to_matrix())

    def test_circuit_permute(self):
        r"""Test the CircuitOp's .permute method"""
        perm = range(7)[::-1]
        c_op = (((CX ^ 3) ^ X) @ (H ^ 7) @ (X ^ Y ^ Z ^ I ^ X ^ X ^ X)
                @ (Y ^ (CX ^ 3)) @ (X ^ Y ^ Z ^ I ^ X ^ X ^ X))
        c_op_perm = c_op.permute(perm)
        self.assertNotEqual(c_op, c_op_perm)
        c_op_id = c_op_perm.permute(perm)
        self.assertEqual(c_op, c_op_id)

    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)

    def test_compose_op_of_different_dim(self):
        """
        Test if smaller operator expands to correct dim when composed with bigger operator.
        Test if PrimitiveOps compose methods are consistent.
        """
        # PauliOps of different dim
        xy_p = X ^ Y
        xyz_p = X ^ Y ^ Z

        pauli_op = xy_p @ xyz_p
        expected_result = I ^ I ^ Z
        self.assertEqual(pauli_op, expected_result)

        # MatrixOps of different dim
        xy_m = xy_p.to_matrix_op()
        xyz_m = xyz_p.to_matrix_op()

        matrix_op = xy_m @ xyz_m
        self.assertEqual(matrix_op, expected_result.to_matrix_op())

        # CircuitOps of different dim
        xy_c = xy_p.to_circuit_op()
        xyz_c = xyz_p.to_circuit_op()

        circuit_op = xy_c @ xyz_c

        self.assertTrue(
            np.array_equal(pauli_op.to_matrix(), matrix_op.to_matrix()))
        self.assertTrue(
            np.allclose(pauli_op.to_matrix(),
                        circuit_op.to_matrix(),
                        rtol=1e-14))
        self.assertTrue(
            np.allclose(matrix_op.to_matrix(),
                        circuit_op.to_matrix(),
                        rtol=1e-14))

    def test_permute_on_primitive_op(self):
        """Test if permute methods of PrimitiveOps are consistent and work as expected."""
        indices = [1, 2, 4]

        # PauliOp
        pauli_op = X ^ Y ^ Z
        permuted_pauli_op = pauli_op.permute(indices)
        expected_pauli_op = X ^ I ^ Y ^ Z ^ I

        self.assertEqual(permuted_pauli_op, expected_pauli_op)

        # CircuitOp
        circuit_op = pauli_op.to_circuit_op()
        permuted_circuit_op = circuit_op.permute(indices)
        expected_circuit_op = expected_pauli_op.to_circuit_op()

        self.assertEqual(Operator(permuted_circuit_op.primitive),
                         Operator(expected_circuit_op.primitive))

        # MatrixOp
        matrix_op = pauli_op.to_matrix_op()
        permuted_matrix_op = matrix_op.permute(indices)
        expected_matrix_op = expected_pauli_op.to_matrix_op()

        equal = np.allclose(permuted_matrix_op.to_matrix(),
                            expected_matrix_op.to_matrix())
        self.assertTrue(equal)

    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_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)

    def test_expand_on_state_fn(self):
        """Test if expanded StateFn has expected num_qubits."""
        num_qubits = 3
        add_qubits = 2

        # case CircuitStateFn, with primitive QuantumCircuit
        qc2 = QuantumCircuit(num_qubits)
        qc2.cx(0, 1)

        cfn = CircuitStateFn(qc2, is_measurement=True)

        cfn_exp = cfn._expand_dim(add_qubits)
        self.assertEqual(cfn_exp.num_qubits, add_qubits + num_qubits)

        # case OperatorStateFn, with OperatorBase primitive, in our case CircuitStateFn
        osfn = OperatorStateFn(cfn)
        osfn_exp = osfn._expand_dim(add_qubits)

        self.assertEqual(osfn_exp.num_qubits, add_qubits + num_qubits)

        # case DictStateFn
        dsfn = DictStateFn("1" * num_qubits, is_measurement=True)
        self.assertEqual(dsfn.num_qubits, num_qubits)

        dsfn_exp = dsfn._expand_dim(add_qubits)
        self.assertEqual(dsfn_exp.num_qubits, num_qubits + add_qubits)

        # case VectorStateFn
        vsfn = VectorStateFn(np.ones(2**num_qubits, dtype=complex))
        self.assertEqual(vsfn.num_qubits, num_qubits)

        vsfn_exp = vsfn._expand_dim(add_qubits)
        self.assertEqual(vsfn_exp.num_qubits, num_qubits + add_qubits)

    def test_permute_on_state_fn(self):
        """Test if StateFns permute are consistent."""

        num_qubits = 4
        dim = 2**num_qubits
        primitive_list = [1.0 / (i + 1) for i in range(dim)]
        primitive_dict = {
            format(i, "b").zfill(num_qubits): 1.0 / (i + 1)
            for i in range(dim)
        }

        dict_fn = DictStateFn(primitive=primitive_dict, is_measurement=True)
        vec_fn = VectorStateFn(primitive=primitive_list, is_measurement=True)

        # check if dict_fn and vec_fn are equivalent
        equivalent = np.allclose(dict_fn.to_matrix(), vec_fn.to_matrix())
        self.assertTrue(equivalent)

        # permute
        indices = [2, 3, 0, 1]
        permute_dict = dict_fn.permute(indices)
        permute_vect = vec_fn.permute(indices)

        equivalent = np.allclose(permute_dict.to_matrix(),
                                 permute_vect.to_matrix())
        self.assertTrue(equivalent)

    def test_compose_consistency(self):
        """Test if PrimitiveOp @ ComposedOp is consistent with ComposedOp @ PrimitiveOp."""

        # PauliOp
        op1 = X ^ Y ^ Z
        op2 = X ^ Y ^ Z
        op3 = (X ^ Y ^ Z).to_circuit_op()

        comp1 = op1 @ ComposedOp([op2, op3])
        comp2 = ComposedOp([op3, op2]) @ op1
        self.assertListEqual(comp1.oplist, list(reversed(comp2.oplist)))

        # CircitOp
        op1 = op1.to_circuit_op()
        op2 = op2.to_circuit_op()
        op3 = op3.to_matrix_op()

        comp1 = op1 @ ComposedOp([op2, op3])
        comp2 = ComposedOp([op3, op2]) @ op1
        self.assertListEqual(comp1.oplist, list(reversed(comp2.oplist)))

        # MatrixOp
        op1 = op1.to_matrix_op()
        op2 = op2.to_matrix_op()
        op3 = op3.to_pauli_op()

        comp1 = op1 @ ComposedOp([op2, op3])
        comp2 = ComposedOp([op3, op2]) @ op1
        self.assertListEqual(comp1.oplist, list(reversed(comp2.oplist)))

    def test_compose_with_indices(self):
        """Test compose method using its permutation feature."""

        pauli_op = X ^ Y ^ Z
        circuit_op = T ^ H
        matrix_op = (X ^ Y ^ H ^ T).to_matrix_op()
        evolved_op = EvolvedOp(matrix_op)

        # composition of PrimitiveOps
        num_qubits = 4
        primitive_op = pauli_op @ circuit_op @ matrix_op
        composed_op = pauli_op @ circuit_op @ evolved_op
        self.assertEqual(primitive_op.num_qubits, num_qubits)
        self.assertEqual(composed_op.num_qubits, num_qubits)

        # with permutation
        num_qubits = 5
        indices = [1, 4]
        permuted_primitive_op = evolved_op @ circuit_op.permute(
            indices) @ pauli_op @ matrix_op
        composed_primitive_op = (evolved_op @ pauli_op.compose(
            circuit_op, permutation=indices, front=True) @ matrix_op)

        self.assertTrue(
            np.allclose(permuted_primitive_op.to_matrix(),
                        composed_primitive_op.to_matrix()))
        self.assertEqual(num_qubits, permuted_primitive_op.num_qubits)

        # ListOp
        num_qubits = 6
        tensored_op = TensoredOp([pauli_op, circuit_op])
        summed_op = pauli_op + circuit_op.permute([2, 1])
        composed_op = circuit_op @ evolved_op @ matrix_op

        list_op = summed_op @ composed_op.compose(
            tensored_op, permutation=[1, 2, 3, 5, 4], front=True)
        self.assertEqual(num_qubits, list_op.num_qubits)

        num_qubits = 4
        circuit_fn = CircuitStateFn(primitive=circuit_op.primitive,
                                    is_measurement=True)
        operator_fn = OperatorStateFn(primitive=circuit_op ^ circuit_op,
                                      is_measurement=True)

        no_perm_op = circuit_fn @ operator_fn
        self.assertEqual(no_perm_op.num_qubits, num_qubits)

        indices = [0, 4]
        perm_op = operator_fn.compose(circuit_fn,
                                      permutation=indices,
                                      front=True)
        self.assertEqual(perm_op.num_qubits, max(indices) + 1)

        # StateFn
        num_qubits = 3
        dim = 2**num_qubits
        vec = [1.0 / (i + 1) for i in range(dim)]
        dic = {
            format(i, "b").zfill(num_qubits): 1.0 / (i + 1)
            for i in range(dim)
        }

        is_measurement = True
        op_state_fn = OperatorStateFn(
            matrix_op, is_measurement=is_measurement)  # num_qubit = 4
        vec_state_fn = VectorStateFn(vec, is_measurement=is_measurement)  # 3
        dic_state_fn = DictStateFn(dic, is_measurement=is_measurement)  # 3
        circ_state_fn = CircuitStateFn(circuit_op.to_circuit(),
                                       is_measurement=is_measurement)  # 2

        composed_op = op_state_fn @ vec_state_fn @ dic_state_fn @ circ_state_fn
        self.assertEqual(composed_op.num_qubits, op_state_fn.num_qubits)

        # with permutation
        perm = [2, 4, 6]
        composed = (op_state_fn @ dic_state_fn.compose(
            vec_state_fn, permutation=perm, front=True) @ circ_state_fn)
        self.assertEqual(composed.num_qubits, max(perm) + 1)

    def test_summed_op_equals(self):
        """Test corner cases of SummedOp's equals function."""
        with self.subTest("multiplicative factor"):
            self.assertEqual(2 * X, X + X)

        with self.subTest("commutative"):
            self.assertEqual(X + Z, Z + X)

        with self.subTest("circuit and paulis"):
            z = CircuitOp(ZGate())
            self.assertEqual(Z + z, z + Z)

        with self.subTest("matrix op and paulis"):
            z = MatrixOp([[1, 0], [0, -1]])
            self.assertEqual(Z + z, z + Z)

        with self.subTest("matrix multiplicative"):
            z = MatrixOp([[1, 0], [0, -1]])
            self.assertEqual(2 * z, z + z)

        with self.subTest("parameter coefficients"):
            expr = Parameter("theta")
            z = MatrixOp([[1, 0], [0, -1]])
            self.assertEqual(expr * z, expr * z)

        with self.subTest("different coefficient types"):
            expr = Parameter("theta")
            z = MatrixOp([[1, 0], [0, -1]])
            self.assertNotEqual(expr * z, 2 * z)

        with self.subTest("additions aggregation"):
            z = MatrixOp([[1, 0], [0, -1]])
            a = z + z + Z
            b = 2 * z + Z
            c = z + Z + z
            self.assertEqual(a, b)
            self.assertEqual(b, c)
            self.assertEqual(a, c)

    def test_circuit_compose_register_independent(self):
        """Test that CircuitOp uses combines circuits independent of the register.

        I.e. that is uses ``QuantumCircuit.compose`` over ``combine`` or ``extend``.
        """
        op = Z ^ 2
        qr = QuantumRegister(2, "my_qr")
        circuit = QuantumCircuit(qr)
        composed = op.compose(CircuitOp(circuit))

        self.assertEqual(composed.num_qubits, 2)

    def test_matrix_op_conversions(self):
        """Test to reveal QiskitError when to_instruction or to_circuit method is called on
        parameterized matrix op."""
        m = np.array([[0, 0, 1, 0], [0, 0, 0, -1], [1, 0, 0, 0], [0, -1, 0,
                                                                  0]])
        matrix_op = MatrixOp(m, Parameter("beta"))
        for method in ["to_instruction", "to_circuit"]:
            with self.subTest(method):
                # QiskitError: multiplication of Operator with ParameterExpression isn't implemented
                self.assertRaises(QiskitError, getattr(matrix_op, method))

    def test_list_op_to_circuit(self):
        """Test if unitary ListOps transpile to circuit."""

        # generate unitary matrices of dimension 2,4,8, seed is fixed
        np.random.seed(233423)
        u2 = unitary_group.rvs(2)
        u4 = unitary_group.rvs(4)
        u8 = unitary_group.rvs(8)

        # pauli matrices as numpy.arrays
        x = np.array([[0.0, 1.0], [1.0, 0.0]])
        y = np.array([[0.0, -1.0j], [1.0j, 0.0]])
        z = np.array([[1.0, 0.0], [0.0, -1.0]])

        # create MatrixOp and CircuitOp out of matrices
        op2 = MatrixOp(u2)
        op4 = MatrixOp(u4)
        op8 = MatrixOp(u8)
        c2 = op2.to_circuit_op()

        # algorithm using only matrix operations on numpy.arrays
        xu4 = np.kron(x, u4)
        zc2 = np.kron(z, u2)
        zc2y = np.kron(zc2, y)
        matrix = np.matmul(xu4, zc2y)
        matrix = np.matmul(matrix, u8)
        matrix = np.kron(matrix, u2)
        operator = Operator(matrix)

        # same algorithm as above, but using PrimitiveOps
        list_op = ((X ^ op4) @ (Z ^ c2 ^ Y) @ op8) ^ op2
        circuit = list_op.to_circuit()

        # verify that ListOp.to_circuit() outputs correct quantum circuit
        self.assertTrue(operator.equiv(circuit),
                        "ListOp.to_circuit() outputs wrong circuit!")

    def test_composed_op_to_circuit(self):
        """
        Test if unitary ComposedOp transpile to circuit and represents expected operator.
        Test if to_circuit on non-unitary ListOp raises exception.
        """

        x = np.array([[0.0, 1.0], [1.0, 0.0]])  # Pauli X as numpy array
        y = np.array([[0.0, -1.0j], [1.0j, 0.0]])  # Pauli Y as numpy array

        m1 = np.array([[0, 0, 1, 0], [0, 0, 0, -1], [0, 0, 0, 0],
                       [0, 0, 0, 0]])  # non-unitary
        m2 = np.array([[0, 0, 0, 0], [0, 0, 0, 0], [1, 0, 0, 0],
                       [0, -1, 0, 0]])  # non-unitary

        m_op1 = MatrixOp(m1)
        m_op2 = MatrixOp(m2)

        pm1 = (X ^ Y) ^ m_op1  # non-unitary TensoredOp
        pm2 = (X ^ Y) ^ m_op2  # non-unitary TensoredOp

        self.assertRaises(ExtensionError, pm1.to_circuit)
        self.assertRaises(ExtensionError, pm2.to_circuit)

        summed_op = pm1 + pm2  # unitary SummedOp([TensoredOp, TensoredOp])
        circuit = summed_op.to_circuit(
        )  # should transpile without any exception

        # same algorithm that leads to summed_op above, but using only arrays and matrix operations
        unitary = np.kron(np.kron(x, y), m1 + m2)

        self.assertTrue(Operator(unitary).equiv(circuit))

    def test_pauli_op_to_circuit(self):
        """Test PauliOp.to_circuit()"""
        with self.subTest("single Pauli"):
            pauli = PauliOp(Pauli("Y"))
            expected = QuantumCircuit(1)
            expected.y(0)
            self.assertEqual(pauli.to_circuit(), expected)

        with self.subTest("single Pauli with phase"):
            pauli = PauliOp(Pauli("-iX"))
            expected = QuantumCircuit(1)
            expected.x(0)
            expected.global_phase = -pi / 2
            self.assertEqual(Operator(pauli.to_circuit()), Operator(expected))

        with self.subTest("two qubit"):
            pauli = PauliOp(Pauli("IX"))
            expected = QuantumCircuit(2)
            expected.pauli("IX", range(2))
            self.assertEqual(pauli.to_circuit(), expected)
            expected = QuantumCircuit(2)
            expected.x(0)
            expected.id(1)
            self.assertEqual(pauli.to_circuit().decompose(), expected)

        with self.subTest("two qubit with phase"):
            pauli = PauliOp(Pauli("iXZ"))
            expected = QuantumCircuit(2)
            expected.pauli("XZ", range(2))
            expected.global_phase = pi / 2
            self.assertEqual(pauli.to_circuit(), expected)
            expected = QuantumCircuit(2)
            expected.z(0)
            expected.x(1)
            expected.global_phase = pi / 2
            self.assertEqual(pauli.to_circuit().decompose(), expected)

    def test_op_to_circuit_with_parameters(self):
        """On parameterized SummedOp, to_matrix_op returns ListOp, instead of MatrixOp. To avoid
        the infinite recursion, OpflowError is raised."""
        m1 = np.array([[0, 0, 1, 0], [0, 0, 0, -1], [0, 0, 0, 0],
                       [0, 0, 0, 0]])  # non-unitary
        m2 = np.array([[0, 0, 0, 0], [0, 0, 0, 0], [1, 0, 0, 0],
                       [0, -1, 0, 0]])  # non-unitary

        op1_with_param = MatrixOp(m1, Parameter("alpha"))  # non-unitary
        op2_with_param = MatrixOp(m2, Parameter("beta"))  # non-unitary

        summed_op_with_param = op1_with_param + op2_with_param  # unitary
        # should raise OpflowError error
        self.assertRaises(OpflowError, summed_op_with_param.to_circuit)

    def test_permute_list_op_with_inconsistent_num_qubits(self):
        """Test if permute raises error if ListOp contains operators with different num_qubits."""
        list_op = ListOp([X, X ^ X])
        self.assertRaises(OpflowError, list_op.permute, [0, 1])

    @data(Z, CircuitOp(ZGate()), MatrixOp([[1, 0], [0, -1]]))
    def test_op_indent(self, op):
        """Test that indentation correctly adds INDENTATION at the beginning of each line"""
        initial_str = str(op)
        indented_str = op._indent(initial_str)
        starts_with_indent = indented_str.startswith(op.INDENTATION)
        self.assertTrue(starts_with_indent)
        indented_str_content = (
            indented_str[len(op.INDENTATION):]).split(f"\n{op.INDENTATION}")
        self.assertListEqual(indented_str_content, initial_str.split("\n"))

    def test_composed_op_immutable_under_eval(self):
        """Test ``ComposedOp.eval`` does not change the operator instance."""
        op = 2 * ComposedOp([X])
        _ = op.eval()
        # previous bug: after op.eval(), op was 2 * ComposedOp([2 * X])
        self.assertEqual(op, 2 * ComposedOp([X]))

    def test_op_parameters(self):
        """Test that Parameters are stored correctly"""
        phi = Parameter("φ")
        theta = ParameterVector(name="θ", length=2)

        qc = QuantumCircuit(2)
        qc.rz(phi, 0)
        qc.rz(phi, 1)
        for i in range(2):
            qc.rx(theta[i], i)
        qc.h(0)
        qc.x(1)

        l = Parameter("λ")
        op = PrimitiveOp(qc, coeff=l)

        params = {phi, l, *theta.params}

        self.assertEqual(params, op.parameters)
        self.assertEqual(params, StateFn(op).parameters)
        self.assertEqual(params, StateFn(qc, coeff=l).parameters)

    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))

    @data(
        VectorStateFn([1, 0]),
        CircuitStateFn(QuantumCircuit(1)),
        OperatorStateFn(I),
        OperatorStateFn(MatrixOp([[1, 0], [0, 1]])),
        OperatorStateFn(CircuitOp(QuantumCircuit(1))),
    )
    def test_statefn_eval(self, op):
        """Test calling eval on StateFn returns the statevector."""
        expected = Statevector([1, 0])
        self.assertEqual(op.eval().primitive, expected)

    def test_sparse_eval(self):
        """Test calling eval on a DictStateFn returns a sparse statevector."""
        op = DictStateFn({"0": 1})
        expected = scipy.sparse.csr_matrix([[1, 0]])
        self.assertFalse((op.eval().primitive != expected).toarray().any())

    def test_sparse_to_dict(self):
        """Test converting a sparse vector state function to a dict state function."""
        isqrt2 = 1 / np.sqrt(2)
        sparse = scipy.sparse.csr_matrix([[0, isqrt2, 0, isqrt2]])
        sparse_fn = SparseVectorStateFn(sparse)
        dict_fn = DictStateFn({"01": isqrt2, "11": isqrt2})

        with self.subTest("sparse to dict"):
            self.assertEqual(dict_fn, sparse_fn.to_dict_fn())

        with self.subTest("dict to sparse"):
            self.assertEqual(dict_fn.to_spmatrix_op(), sparse_fn)

    def test_to_circuit_op(self):
        """Test to_circuit_op method."""
        vector = np.array([2, 2])
        vsfn = VectorStateFn([1, 1], coeff=2)
        dsfn = DictStateFn({"0": 1, "1": 1}, coeff=2)

        for sfn in [vsfn, dsfn]:
            np.testing.assert_array_almost_equal(
                sfn.to_circuit_op().eval().primitive.data, vector)

    def test_invalid_primitive(self):
        """Test invalid MatrixOp construction"""
        msg = ("MatrixOp can only be instantiated with "
               "['list', 'ndarray', 'spmatrix', 'Operator'], not ")

        with self.assertRaises(TypeError) as cm:
            _ = MatrixOp("invalid")

        self.assertEqual(str(cm.exception), msg + "'str'")

        with self.assertRaises(TypeError) as cm:
            _ = MatrixOp(None)

        self.assertEqual(str(cm.exception), msg + "'NoneType'")

        with self.assertRaises(TypeError) as cm:
            _ = MatrixOp(2.0)

        self.assertEqual(str(cm.exception), msg + "'float'")

    def test_summedop_equals(self):
        """Test SummedOp.equals"""
        ops = [Z, CircuitOp(ZGate()), MatrixOp([[1, 0], [0, -1]]), Zero, Minus]
        sum_op = sum(ops + [ListOp(ops)])
        self.assertEqual(sum_op, sum_op)
        self.assertEqual(sum_op + sum_op, 2 * sum_op)
        self.assertEqual(sum_op + sum_op + sum_op, 3 * sum_op)
        ops2 = [Z, CircuitOp(ZGate()), MatrixOp([[1, 0], [0, 1]]), Zero, Minus]
        sum_op2 = sum(ops2 + [ListOp(ops)])
        self.assertNotEqual(sum_op, sum_op2)
        self.assertEqual(sum_op2, sum_op2)
        sum_op3 = sum(ops)
        self.assertNotEqual(sum_op, sum_op3)
        self.assertNotEqual(sum_op2, sum_op3)
        self.assertEqual(sum_op3, sum_op3)

    def test_empty_listops(self):
        """Test reduce and eval on ListOp with empty oplist."""
        with self.subTest("reduce empty ComposedOp "):
            self.assertEqual(ComposedOp([]).reduce(), ComposedOp([]))
        with self.subTest("reduce empty TensoredOp "):
            self.assertEqual(TensoredOp([]).reduce(), TensoredOp([]))
        with self.subTest("eval empty ComposedOp "):
            self.assertEqual(ComposedOp([]).eval(), 0.0)
        with self.subTest("eval empty TensoredOp "):
            self.assertEqual(TensoredOp([]).eval(), 0.0)
コード例 #28
0
ファイル: vqd.py プロジェクト: merav-aharoni/qiskit-terra
    def compute_eigenvalues(
        self,
        operator: OperatorBase,
        aux_operators: Optional[ListOrDict[OperatorBase]] = None
    ) -> EigensolverResult:
        super().compute_eigenvalues(operator, aux_operators)

        if self.quantum_instance is None:
            raise AlgorithmError(
                "A QuantumInstance or Backend must be supplied to run the quantum algorithm."
            )
        self.quantum_instance.circuit_summary = True

        # this sets the size of the ansatz, so it must be called before the initial point
        # validation
        self._check_operator_ansatz(operator)

        # set an expectation for this algorithm run (will be reset to None at the end)
        initial_point = _validate_initial_point(self.initial_point,
                                                self.ansatz)

        bounds = _validate_bounds(self.ansatz)
        # We need to handle the array entries being zero or Optional i.e. having value None
        if aux_operators:
            zero_op = PauliSumOp.from_list([("I" * self.ansatz.num_qubits, 0)])

            # Convert the None and zero values when aux_operators is a list.
            # Drop None and convert zero values when aux_operators is a dict.
            if isinstance(aux_operators, list):
                key_op_iterator = enumerate(aux_operators)
                converted = [zero_op] * len(aux_operators)
            else:
                key_op_iterator = aux_operators.items()
                converted = {}
            for key, op in key_op_iterator:
                if op is not None:
                    converted[key] = zero_op if op == 0 else op

            aux_operators = converted

        else:
            aux_operators = None

        if self.betas is None:
            upper_bound = (abs(operator.coeff) if isinstance(
                operator, PauliOp) else abs(operator.coeff) *
                           sum(abs(operation.coeff) for operation in operator))
            self.betas = [upper_bound * 10] * (self.k)
            logger.info("beta autoevaluated to %s", self.betas[0])

        result = VQDResult()
        result.optimal_point = []
        result.optimal_parameters = []
        result.optimal_value = []
        result.cost_function_evals = []
        result.optimizer_time = []
        result.eigenvalues = []
        result.eigenstates = []

        if aux_operators is not None:
            aux_values = []

        for step in range(1, self.k + 1):

            self._eval_count = 0
            energy_evaluation, expectation = self.get_energy_evaluation(
                step,
                operator,
                return_expectation=True,
                prev_states=result.optimal_parameters)

            # Convert the gradient operator into a callable function that is compatible with the
            # optimization routine. Only used for the ground state currently as Gradient() doesnt
            # support SumOps yet
            if isinstance(self._gradient, GradientBase):
                gradient = self._gradient.gradient_wrapper(
                    StateFn(operator, is_measurement=True) @ StateFn(
                        self.ansatz),
                    bind_params=list(self.ansatz.parameters),
                    backend=self._quantum_instance,
                )
            else:
                gradient = self._gradient

            start_time = time()

            if callable(self.optimizer):
                opt_result = self.optimizer(  # pylint: disable=not-callable
                    fun=energy_evaluation,
                    x0=initial_point,
                    jac=gradient,
                    bounds=bounds)
            else:
                opt_result = self.optimizer.minimize(fun=energy_evaluation,
                                                     x0=initial_point,
                                                     jac=gradient,
                                                     bounds=bounds)

            eval_time = time() - start_time

            result.optimal_point.append(opt_result.x)
            result.optimal_parameters.append(
                dict(zip(self.ansatz.parameters, opt_result.x)))
            result.optimal_value.append(opt_result.fun)
            result.cost_function_evals.append(opt_result.nfev)
            result.optimizer_time.append(eval_time)

            eigenvalue = (StateFn(operator, is_measurement=True).compose(
                CircuitStateFn(
                    self.ansatz.bind_parameters(
                        result.optimal_parameters[-1]))).reduce().eval())

            result.eigenvalues.append(eigenvalue)
            result.eigenstates.append(
                self._get_eigenstate(result.optimal_parameters[-1]))

            if aux_operators is not None:
                bound_ansatz = self.ansatz.bind_parameters(
                    result.optimal_point[-1])
                aux_value = eval_observables(self.quantum_instance,
                                             bound_ansatz,
                                             aux_operators,
                                             expectation=expectation)
                aux_values.append(aux_value)

            if step == 1:

                logger.info(
                    "Ground state optimization complete in %s seconds.\nFound opt_params %s in %s evals",
                    eval_time,
                    result.optimal_point,
                    self._eval_count,
                )
            else:
                logger.info(
                    ("%s excited state optimization complete in %s s.\nFound opt_parms %s in %s evals"
                     ),
                    str(step - 1),
                    eval_time,
                    result.optimal_point,
                    self._eval_count,
                )

        # To match the siignature of NumpyEigenSolver Result
        result.eigenstates = ListOp(
            [StateFn(vec) for vec in result.eigenstates])
        result.eigenvalues = np.array(result.eigenvalues)
        result.optimal_point = np.array(result.optimal_point)
        result.optimal_value = np.array(result.optimal_value)
        result.cost_function_evals = np.array(result.cost_function_evals)
        result.optimizer_time = np.array(result.optimizer_time)

        if aux_operators is not None:
            result.aux_operator_eigenvalues = aux_values

        return result
コード例 #29
0
ファイル: vqd.py プロジェクト: merav-aharoni/qiskit-terra
    def get_energy_evaluation(
        self,
        step: int,
        operator: OperatorBase,
        return_expectation: bool = False,
        prev_states: Optional[List[np.ndarray]] = None,
    ) -> Callable[[np.ndarray], Union[float, List[float]]]:
        """Returns a function handle to evaluates the energy at given parameters for the ansatz.

        This return value is the objective function to be passed to the optimizer for evaluation.

        Args:
            step: level of enegy being calculated. 0 for ground, 1 for first excited state and so on.
            operator: The operator whose energy to evaluate.
            return_expectation: If True, return the ``ExpectationBase`` expectation converter used
                in the construction of the expectation value. Useful e.g. to evaluate other
                operators with the same expectation value converter.
            prev_states: List of parameters from previous rounds of optimization.


        Returns:
            A callable that computes and returns the energy of the hamiltonian
            of each parameter, and, optionally, the expectation

        Raises:
            RuntimeError: If the circuit is not parameterized (i.e. has 0 free parameters).
            AlgorithmError: If operator was not provided.

        """

        num_parameters = self.ansatz.num_parameters
        if num_parameters == 0:
            raise RuntimeError(
                "The ansatz must be parameterized, but has 0 free parameters.")

        if operator is None:
            raise AlgorithmError("The operator was never provided.")

        if step > 1 and (len(prev_states) + 1) != step:
            raise RuntimeError(
                f"Passed previous states of the wrong size."
                f"Passed array has length {str(len(prev_states))}")

        self._check_operator_ansatz(operator)
        overlap_op = []

        ansatz_params = self.ansatz.parameters
        expect_op, expectation = self.construct_expectation(
            ansatz_params, operator, return_expectation=True)

        for state in range(step - 1):

            prev_circ = self.ansatz.bind_parameters(prev_states[state])
            overlap_op.append(
                ~CircuitStateFn(prev_circ) @ CircuitStateFn(self.ansatz))

        def energy_evaluation(parameters):
            parameter_sets = np.reshape(parameters, (-1, num_parameters))
            # Create dict associating each parameter with the lists of parameterization values for it
            param_bindings = dict(
                zip(ansatz_params,
                    parameter_sets.transpose().tolist()))

            sampled_expect_op = self._circuit_sampler.convert(
                expect_op, params=param_bindings)
            mean = np.real(sampled_expect_op.eval())

            for state in range(step - 1):
                sampled_final_op = self._circuit_sampler.convert(
                    overlap_op[state], params=param_bindings)
                cost = sampled_final_op.eval()
                mean += np.real(self.betas[state] * np.conj(cost) * cost)

            self._eval_count += len(mean)

            return mean if len(mean) > 1 else mean[0]

        if return_expectation:
            return energy_evaluation, expectation

        return energy_evaluation
コード例 #30
0
    def test_parameterized_qobj(self):
        """grouped pauli expectation test"""
        two_qubit_h2 = (
            (-1.052373245772859 * I ^ I)
            + (0.39793742484318045 * I ^ Z)
            + (-0.39793742484318045 * Z ^ I)
            + (-0.01128010425623538 * Z ^ Z)
            + (0.18093119978423156 * X ^ X)
        )

        aer_sampler = CircuitSampler(
            self.sampler.quantum_instance, param_qobj=True, attach_results=True
        )

        ansatz = RealAmplitudes()
        ansatz.num_qubits = 2

        observable_meas = self.expect.convert(StateFn(two_qubit_h2, is_measurement=True))
        ansatz_circuit_op = CircuitStateFn(ansatz)
        expect_op = observable_meas.compose(ansatz_circuit_op).reduce()

        def generate_parameters(num):
            param_bindings = {}
            for param in ansatz.parameters:
                values = []
                for _ in range(num):
                    values.append(np.random.rand())
                param_bindings[param] = values
            return param_bindings

        def validate_sampler(ideal, sut, param_bindings):
            expect_sampled = ideal.convert(expect_op, params=param_bindings).eval()
            actual_sampled = sut.convert(expect_op, params=param_bindings).eval()
            self.assertTrue(
                np.allclose(actual_sampled, expect_sampled),
                "%s != %s" % (actual_sampled, expect_sampled),
            )

        def get_circuit_templates(sampler):
            return sampler._transpiled_circ_templates

        def validate_aer_binding_used(templates):
            self.assertIsNotNone(templates)

        def validate_aer_templates_reused(prev_templates, cur_templates):
            self.assertIs(prev_templates, cur_templates)

        validate_sampler(self.sampler, aer_sampler, generate_parameters(1))
        cur_templates = get_circuit_templates(aer_sampler)

        validate_aer_binding_used(cur_templates)

        prev_templates = cur_templates
        validate_sampler(self.sampler, aer_sampler, generate_parameters(2))
        cur_templates = get_circuit_templates(aer_sampler)

        validate_aer_templates_reused(prev_templates, cur_templates)

        prev_templates = cur_templates
        validate_sampler(self.sampler, aer_sampler, generate_parameters(2))  # same num of params
        cur_templates = get_circuit_templates(aer_sampler)

        validate_aer_templates_reused(prev_templates, cur_templates)