def setUp(self):
        super().setUp()

        # specify "run configuration"
        backend = Aer.get_backend('statevector_simulator')
        quantum_instance = QuantumInstance(backend)

        # specify how to evaluate expected values and gradients
        expval = PauliExpectation()
        gradient = Gradient()

        # construct parametrized circuit
        params = [Parameter('input1'), Parameter('weight1')]
        qc = QuantumCircuit(1)
        qc.h(0)
        qc.ry(params[0], 0)
        qc.rx(params[1], 0)
        qc_sfn = StateFn(qc)

        # construct cost operator
        cost_operator = StateFn(PauliSumOp.from_list([('Z', 1.0), ('X', 1.0)]))

        # combine operator and circuit to objective function
        op = ~cost_operator @ qc_sfn

        # define QNN
        self.qnn = OpflowQNN(op, [params[0]], [params[1]],
                             expval,
                             gradient,
                             quantum_instance=quantum_instance)
def _prepare_list_op(
    quantum_state: Union[Statevector, QuantumCircuit, OperatorBase, ],
    observables: ListOrDict[OperatorBase],
) -> ListOp:
    """
    Accepts a list or a dictionary of operators and converts them to a ``ListOp``.

    Args:
        quantum_state: An unparametrized quantum circuit representing a quantum state that
            expectation values are computed against.
        observables: A list or a dictionary of operators.

    Returns:
        A ``ListOp`` that includes all provided observables.
    """
    if isinstance(observables, dict):
        observables = list(observables.values())

    if not isinstance(quantum_state, StateFn):
        quantum_state = StateFn(quantum_state)

    return ListOp([
        StateFn(obs, is_measurement=True).compose(quantum_state)
        for obs in observables
    ])
    def test_circuit_sampler_caching(self, caching):
        """Test caching all operators works."""
        try:
            from qiskit.providers.aer import Aer
        except Exception as ex:  # pylint: disable=broad-except
            self.skipTest(
                "Aer doesn't appear to be installed. Error: '{}'".format(
                    str(ex)))
            return

        x = Parameter('x')
        circuit = QuantumCircuit(1)
        circuit.ry(x, 0)
        expr1 = ~StateFn(H) @ StateFn(circuit)
        expr2 = ~StateFn(X) @ StateFn(circuit)

        sampler = CircuitSampler(Aer.get_backend('statevector_simulator'),
                                 caching=caching)

        res1 = sampler.convert(expr1, params={x: 0}).eval()
        res2 = sampler.convert(expr2, params={x: 0}).eval()
        res3 = sampler.convert(expr1, params={x: 0}).eval()
        res4 = sampler.convert(expr2, params={x: 0}).eval()

        self.assertEqual(res1, res3)
        self.assertEqual(res2, res4)
        if caching == 'last':
            self.assertEqual(len(sampler._cached_ops.keys()), 1)
        else:
            self.assertEqual(len(sampler._cached_ops.keys()), 2)
Ejemplo n.º 4
0
    def measure_aux_ops(self, obs_wfn, pauli, parameters, expectator, sampler):

        # This function calculates the expectation value of a given operator

        # Prepare the operator and the parameters
        wfn = StateFn(obs_wfn)
        op = StateFn(pauli, is_measurement=True)
        values_obs = dict(zip(self.obs_params[:], parameters.tolist()))

        braket = op @ wfn

        grouped = expectator.convert(braket)
        sampled_op = sampler.convert(grouped, params=values_obs)

        #print(sampled_op.eval())
        mean_value = sampled_op.eval().real
        est_err = 0

        if (not self.instance.is_statevector):
            variance = expectator.compute_variance(sampled_op).real
            est_err = np.sqrt(variance / self.shots)

        res = [mean_value, est_err]

        return res
Ejemplo n.º 5
0
 def test_flatten_statefn_composed_with_composed_op(self):
     """Test that composing a StateFn with a ComposedOp constructs a single ComposedOp"""
     circuit = QuantumCircuit(1)
     vector = [1, 0]
     ex = ~StateFn(I) @ (CircuitOp(circuit) @ StateFn(vector))
     self.assertEqual(len(ex), 3)
     self.assertEqual(ex.eval(), 1)
    def test_coefficients_correctly_propagated(self):
        """Test that the coefficients in SummedOp and states are correctly used."""
        try:
            from qiskit.providers.aer import Aer
        except Exception as ex:  # pylint: disable=broad-except
            self.skipTest(
                "Aer doesn't appear to be installed. Error: '{}'".format(
                    str(ex)))
            return
        with self.subTest('zero coeff in SummedOp'):
            op = 0 * (I + Z)
            state = Plus
            self.assertEqual((~StateFn(op) @ state).eval(), 0j)

        backend = Aer.get_backend('qasm_simulator')
        q_instance = QuantumInstance(backend,
                                     seed_simulator=97,
                                     seed_transpiler=97)
        op = I
        with self.subTest('zero coeff in summed StateFn and CircuitSampler'):
            state = 0 * (Plus + Minus)
            sampler = CircuitSampler(q_instance).convert(~StateFn(op) @ state)
            self.assertEqual(sampler.eval(), 0j)

        with self.subTest(
                'coeff gets squared in CircuitSampler shot-based readout'):
            state = (Plus + Minus) / numpy.sqrt(2)
            sampler = CircuitSampler(q_instance).convert(~StateFn(op) @ state)
            self.assertAlmostEqual(sampler.eval(), 1 + 0j)
Ejemplo n.º 7
0
    def test_pauli_two_design(self):
        """Test standard gradient descent on the Pauli two-design example."""
        circuit = PauliTwoDesign(3, reps=3, seed=2)
        parameters = list(circuit.parameters)
        obs = Z ^ Z ^ I
        expr = ~StateFn(obs) @ StateFn(circuit)

        initial_point = np.array([
            0.1822308,
            -0.27254251,
            0.83684425,
            0.86153976,
            -0.7111668,
            0.82766631,
            0.97867993,
            0.46136964,
            2.27079901,
            0.13382699,
            0.29589915,
            0.64883193,
        ])

        def objective(x):
            return expr.bind_parameters(dict(zip(parameters, x))).eval().real

        optimizer = GradientDescent(maxiter=100,
                                    learning_rate=0.1,
                                    perturbation=0.1)

        result = optimizer.optimize(circuit.num_parameters,
                                    objective,
                                    initial_point=initial_point)

        self.assertLess(result[1], -0.95)  # final loss
        self.assertEqual(result[2], 100)  # function evaluations
Ejemplo n.º 8
0
    def test_qiskit_result_instantiation(self):
        """qiskit result instantiation test"""
        qc = QuantumCircuit(3)
        # REMEMBER: This is Qubit 2 in Operator land.
        qc.h(0)
        sv_res = execute(
            qc, BasicAer.get_backend("statevector_simulator")).result()
        sv_vector = sv_res.get_statevector()
        qc_op = PrimitiveOp(qc) @ Zero

        qasm_res = execute(qc_op.to_circuit(meas=True),
                           BasicAer.get_backend("qasm_simulator")).result()

        np.testing.assert_array_almost_equal(
            StateFn(sv_res).to_matrix(),
            [0.5**0.5, 0.5**0.5, 0, 0, 0, 0, 0, 0])
        np.testing.assert_array_almost_equal(
            StateFn(sv_vector).to_matrix(),
            [0.5**0.5, 0.5**0.5, 0, 0, 0, 0, 0, 0])
        np.testing.assert_array_almost_equal(
            StateFn(qasm_res).to_matrix(),
            [0.5**0.5, 0.5**0.5, 0, 0, 0, 0, 0, 0],
            decimal=1)

        np.testing.assert_array_almost_equal(
            ((I ^ I ^ H) @ Zero).to_matrix(),
            [0.5**0.5, 0.5**0.5, 0, 0, 0, 0, 0, 0])
        np.testing.assert_array_almost_equal(
            qc_op.to_matrix(), [0.5**0.5, 0.5**0.5, 0, 0, 0, 0, 0, 0])
Ejemplo n.º 9
0
    def test_grouped_pauli_expectation(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))
        wf = CX @ (H ^ I) @ Zero
        expect_op = PauliExpectation(group_paulis=False).convert(
            ~StateFn(two_qubit_H2) @ wf)
        self.sampler._extract_circuitstatefns(expect_op)
        num_circuits_ungrouped = len(self.sampler._circuit_ops_cache)
        self.assertEqual(num_circuits_ungrouped, 5)

        expect_op_grouped = PauliExpectation(group_paulis=True).convert(
            ~StateFn(two_qubit_H2) @ wf)
        q_instance = QuantumInstance(
            BasicAer.get_backend("statevector_simulator"),
            seed_simulator=self.seed,
            seed_transpiler=self.seed,
        )
        sampler = CircuitSampler(q_instance)
        sampler._extract_circuitstatefns(expect_op_grouped)
        num_circuits_grouped = len(sampler._circuit_ops_cache)
        self.assertEqual(num_circuits_grouped, 2)
Ejemplo n.º 10
0
def _get_observable_evaluator(
    ansatz: QuantumCircuit,
    observables: Union[OperatorBase, List[OperatorBase]],
    expectation: ExpectationBase,
    sampler: CircuitSampler,
) -> Callable[[np.ndarray], Union[float, List[float]]]:
    """Get a callable to evaluate a (list of) observable(s) for given circuit parameters."""

    if isinstance(observables, list):
        observables = ListOp(observables)

    expectation_value = StateFn(observables,
                                is_measurement=True) @ StateFn(ansatz)
    converted = expectation.convert(expectation_value)

    ansatz_parameters = ansatz.parameters

    def evaluate_observables(theta: np.ndarray) -> Union[float, List[float]]:
        """Evaluate the observables for the ansatz parameters ``theta``.

        Args:
            theta: The ansatz parameters.

        Returns:
            The observables evaluated at the ansatz parameters.
        """
        value_dict = dict(zip(ansatz_parameters, theta))
        sampled = sampler.convert(converted, params=value_dict)
        return sampled.eval()

    return evaluate_observables
Ejemplo n.º 11
0
 def test_add_direct(self):
     """ add direct test """
     wf = StateFn({'101010': .5, '111111': .3}) + (Zero ^ 6)
     self.assertEqual(wf.primitive, {'101010': 0.5, '111111': 0.3, '000000': 1.0})
     wf = (4 * StateFn({'101010': .5, '111111': .3})) + ((3 + .1j) * (Zero ^ 6))
     self.assertEqual(wf.primitive, {'000000': (3 + 0.1j), '101010': (2 + 0j),
                                     '111111': (1.2 + 0j)})
    def test_jax_chain_rule(self, method: str, autograd: bool):
        """Test the chain rule functionality using Jax

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

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

        def combo_fn(x):
            return jnp.power(x[0], 2) + jnp.cos(x[1])

        def grad_combo_fn(x):
            return np.array([2 * x[0], -np.sin(x[1])])

        op = ListOp(
            [
                ~StateFn(X) @ CircuitStateFn(primitive=qc, coeff=1.0),
                ~StateFn(Z) @ CircuitStateFn(primitive=qc, coeff=1.0),
            ],
            combo_fn=combo_fn,
            grad_combo_fn=None if autograd else grad_combo_fn,
        )

        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 = [[-1.0, 0.0], [-1.2397, -0.2397], [0, -0.45936]]
        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)
    def test_opflow_qnn_2_2(self, q_i):
        """Test Torch Connector + Opflow QNN with input/output dimension 2/2."""
        from torch import Tensor

        if q_i == "sv":
            quantum_instance = self._sv_quantum_instance
        else:
            quantum_instance = self._qasm_quantum_instance

        # construct parametrized circuit
        params_1 = [Parameter("input1"), Parameter("weight1")]
        qc_1 = QuantumCircuit(1)
        qc_1.h(0)
        qc_1.ry(params_1[0], 0)
        qc_1.rx(params_1[1], 0)
        qc_sfn_1 = StateFn(qc_1)

        # construct cost operator
        h_1 = StateFn(PauliSumOp.from_list([("Z", 1.0), ("X", 1.0)]))

        # combine operator and circuit to objective function
        op_1 = ~h_1 @ qc_sfn_1

        # construct parametrized circuit
        params_2 = [Parameter("input2"), Parameter("weight2")]
        qc_2 = QuantumCircuit(1)
        qc_2.h(0)
        qc_2.ry(params_2[0], 0)
        qc_2.rx(params_2[1], 0)
        qc_sfn_2 = StateFn(qc_2)

        # construct cost operator
        h_2 = StateFn(PauliSumOp.from_list([("Z", 1.0), ("X", 1.0)]))

        # combine operator and circuit to objective function
        op_2 = ~h_2 @ qc_sfn_2

        op = ListOp([op_1, op_2])

        qnn = OpflowQNN(
            op,
            [params_1[0], params_2[0]],
            [params_1[1], params_2[1]],
            quantum_instance=quantum_instance,
            input_gradients=True,
        )
        model = TorchConnector(qnn)

        test_data = [
            Tensor([1]),
            Tensor([1, 2]),
            Tensor([[1], [2]]),
            Tensor([[1, 2], [3, 4]]),
        ]

        # test model
        self._validate_output_shape(model, test_data)
        if q_i == "sv":
            self._validate_backward_pass(model)
Ejemplo n.º 14
0
 def test_statefn_overlaps(self):
     """state functions overlaps test"""
     wf = (4 * StateFn({"101010": 0.5, "111111": 0.3})) + ((3 + 0.1j) * (Zero ^ 6))
     wf_vec = StateFn(wf.to_matrix())
     self.assertAlmostEqual(wf.adjoint().eval(wf), 14.45)
     self.assertAlmostEqual(wf_vec.adjoint().eval(wf_vec), 14.45)
     self.assertAlmostEqual(wf_vec.adjoint().eval(wf), 14.45)
     self.assertAlmostEqual(wf.adjoint().eval(wf_vec), 14.45)
    def test_opflow_qnn_2_2(self, config):
        """Test Opflow QNN with input/output dimension 2/2."""
        q_i, input_grad_required = config

        if q_i == STATEVECTOR:
            quantum_instance = self.sv_quantum_instance
        elif q_i == QASM:
            quantum_instance = self.qasm_quantum_instance
        else:
            quantum_instance = None

        # construct parametrized circuit
        params_1 = [Parameter("input1"), Parameter("weight1")]
        qc_1 = QuantumCircuit(1)
        qc_1.h(0)
        qc_1.ry(params_1[0], 0)
        qc_1.rx(params_1[1], 0)
        qc_sfn_1 = StateFn(qc_1)

        # construct cost operator
        h_1 = StateFn(PauliSumOp.from_list([("Z", 1.0), ("X", 1.0)]))

        # combine operator and circuit to objective function
        op_1 = ~h_1 @ qc_sfn_1

        # construct parametrized circuit
        params_2 = [Parameter("input2"), Parameter("weight2")]
        qc_2 = QuantumCircuit(1)
        qc_2.h(0)
        qc_2.ry(params_2[0], 0)
        qc_2.rx(params_2[1], 0)
        qc_sfn_2 = StateFn(qc_2)

        # construct cost operator
        h_2 = StateFn(PauliSumOp.from_list([("Z", 1.0), ("X", 1.0)]))

        # combine operator and circuit to objective function
        op_2 = ~h_2 @ qc_sfn_2

        op = ListOp([op_1, op_2])

        qnn = OpflowQNN(
            op,
            [params_1[0], params_2[0]],
            [params_1[1], params_2[1]],
            quantum_instance=quantum_instance,
        )
        qnn.input_gradients = input_grad_required

        test_data = [np.array([1, 2]), np.array([[1, 2], [3, 4]])]

        # test model
        self.validate_output_shape(qnn, test_data)

        # test the qnn after we set a quantum instance
        if quantum_instance is None:
            qnn.quantum_instance = self.qasm_quantum_instance
            self.validate_output_shape(qnn, test_data)
    def test_opflow_qnn_2_1(self, config):
        """Test Opflow QNN with input/output dimension 2/1."""
        q_i, input_grad_required = config

        # construct QNN
        if q_i == STATEVECTOR:
            quantum_instance = self.sv_quantum_instance
        elif q_i == QASM:
            quantum_instance = self.qasm_quantum_instance
        else:
            quantum_instance = None

        # specify how to evaluate expected values and gradients
        expval = PauliExpectation()
        gradient = Gradient()

        # construct parametrized circuit
        params = [
            Parameter("input1"),
            Parameter("input2"),
            Parameter("weight1"),
            Parameter("weight2"),
        ]
        qc = QuantumCircuit(2)
        qc.h(0)
        qc.ry(params[0], 0)
        qc.ry(params[1], 1)
        qc.rx(params[2], 0)
        qc.rx(params[3], 1)
        qc_sfn = StateFn(qc)

        # construct cost operator
        cost_operator = StateFn(PauliSumOp.from_list([("ZZ", 1.0), ("XX", 1.0)]))

        # combine operator and circuit to objective function
        op = ~cost_operator @ qc_sfn

        # define QNN
        qnn = OpflowQNN(
            op,
            params[:2],
            params[2:],
            expval,
            gradient,
            quantum_instance=quantum_instance,
        )
        qnn.input_gradients = input_grad_required

        test_data = [np.array([1, 2]), np.array([[1, 2]]), np.array([[1, 2], [3, 4]])]

        # test model
        self.validate_output_shape(qnn, test_data)

        # test the qnn after we set a quantum instance
        if quantum_instance is None:
            qnn.quantum_instance = self.qasm_quantum_instance
            self.validate_output_shape(qnn, test_data)
Ejemplo n.º 17
0
    def test_opflow_qnn_2_2(self, q_i):
        """ Test Torch Connector + Opflow QNN with input/output dimension 2/2."""

        if q_i == 'sv':
            quantum_instance = self.sv_quantum_instance
        else:
            quantum_instance = self.qasm_quantum_instance

        # construct parametrized circuit
        params_1 = [Parameter('input1'), Parameter('weight1')]
        qc_1 = QuantumCircuit(1)
        qc_1.h(0)
        qc_1.ry(params_1[0], 0)
        qc_1.rx(params_1[1], 0)
        qc_sfn_1 = StateFn(qc_1)

        # construct cost operator
        h_1 = StateFn(PauliSumOp.from_list([('Z', 1.0), ('X', 1.0)]))

        # combine operator and circuit to objective function
        op_1 = ~h_1 @ qc_sfn_1

        # construct parametrized circuit
        params_2 = [Parameter('input2'), Parameter('weight2')]
        qc_2 = QuantumCircuit(1)
        qc_2.h(0)
        qc_2.ry(params_2[0], 0)
        qc_2.rx(params_2[1], 0)
        qc_sfn_2 = StateFn(qc_2)

        # construct cost operator
        h_2 = StateFn(PauliSumOp.from_list([('Z', 1.0), ('X', 1.0)]))

        # combine operator and circuit to objective function
        op_2 = ~h_2 @ qc_sfn_2

        op = ListOp([op_1, op_2])

        qnn = OpflowQNN(op, [params_1[0], params_2[0]],
                        [params_1[1], params_2[1]],
                        quantum_instance=quantum_instance)
        try:
            model = TorchConnector(qnn)

            test_data = [
                Tensor(1),
                Tensor([1, 2]),
                Tensor([[1], [2]]),
                Tensor([[1, 2], [3, 4]])
            ]

            # test model
            self.validate_output_shape(model, test_data)
            if q_i == 'sv':
                self.validate_backward_pass(model)
        except MissingOptionalLibraryError as ex:
            self.skipTest(str(ex))
Ejemplo n.º 18
0
    def get_fidelity(
        circuit: QuantumCircuit,
        backend: Optional[Union[Backend, QuantumInstance]] = None,
        expectation: Optional[ExpectationBase] = None,
    ) -> Callable[[np.ndarray, np.ndarray], float]:
        r"""Get a function to compute the fidelity of ``circuit`` with itself.

        Let ``circuit`` be a parameterized quantum circuit performing the operation
        :math:`U(\theta)` given a set of parameters :math:`\theta`. Then this method returns
        a function to evaluate

        .. math::

            F(\theta, \phi) = \big|\langle 0 | U^\dagger(\theta) U(\phi) |0\rangle  \big|^2.

        The output of this function can be used as input for the ``fidelity`` to the
        :class:~`qiskit.algorithms.optimizers.QNSPSA` optimizer.

        Args:
            circuit: The circuit preparing the parameterized ansatz.
            backend: A backend of quantum instance to evaluate the circuits. If None, plain
                matrix multiplication will be used.
            expectation: An expectation converter to specify how the expected value is computed.
                If a shot-based readout is used this should be set to ``PauliExpectation``.

        Returns:
            A handle to the function :math:`F`.

        """
        params_x = ParameterVector("x", circuit.num_parameters)
        params_y = ParameterVector("y", circuit.num_parameters)

        expression = ~StateFn(circuit.assign_parameters(params_x)) @ StateFn(
            circuit.assign_parameters(params_y))

        if expectation is not None:
            expression = expectation.convert(expression)

        if backend is None:

            def fidelity(values_x, values_y):
                value_dict = dict(
                    zip(params_x[:] + params_y[:],
                        values_x.tolist() + values_y.tolist()))
                return np.abs(expression.bind_parameters(value_dict).eval())**2

        else:
            sampler = CircuitSampler(backend)

            def fidelity(values_x, values_y):
                value_dict = dict(
                    zip(params_x[:] + params_y[:],
                        values_x.tolist() + values_y.tolist()))
                return np.abs(
                    sampler.convert(expression, params=value_dict).eval())**2

        return fidelity
    def test_gradient_u(self, method):
        """Test the state gradient for U
        Tr(|psi><psi|Z) = - 0.5 sin(a)cos(c)
        Tr(|psi><psi|X) = cos^2(a/2) cos(b+c) - sin^2(a/2) cos(b-c)
        """

        ham = 0.5 * X - 1 * Z
        a = Parameter("a")
        b = Parameter("b")
        c = Parameter("c")

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

        op = ~StateFn(ham) @ CircuitStateFn(primitive=qc, coeff=1.0)
        params = [a, b, c]
        state_grad = Gradient(grad_method=method).convert(operator=op,
                                                          params=params)
        values_dict = [{
            a: np.pi / 4,
            b: 0,
            c: 0
        }, {
            a: np.pi / 4,
            b: np.pi / 4,
            c: np.pi / 4
        }]
        correct_values = [[0.3536, 0, 0], [0.3232, -0.42678, -0.92678]]
        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)

        # Tr(|psi><psi|Z) = - 0.5 sin(a)cos(c)
        # Tr(|psi><psi|X) = cos^2(a/2) cos(b+c) - sin^2(a/2) cos(b-c)
        # dTr(|psi><psi|H)/da = 0.5(cos(2a)) + 0.5()

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

        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 = [[-1.03033], [-1]]
        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)
    def test_expectation_with_coeff(self):
        """Test AerPauliExpectation with coefficients."""
        with self.subTest("integer coefficients"):
            exp = 3 * ~StateFn(X) @ (2 * Minus)
            target = self.sampler.convert(self.expect.convert(exp)).eval()
            self.assertEqual(target, -12)

        with self.subTest("complex coefficients"):
            exp = 3j * ~StateFn(X) @ (2j * Minus)
            target = self.sampler.convert(self.expect.convert(exp)).eval()
            self.assertEqual(target, -12j)
Ejemplo n.º 21
0
    def test_evaluating_nonunitary_circuit_state(self):
        """Test evaluating a circuit works even if it contains non-unitary instruction (resets).

        TODO: allow this for (~StateFn(circuit) @ op @ StateFn(circuit)), but this requires
        refactoring how the AerPauliExpectation works, since that currently relies on
        composing with CircuitMeasurements
        """
        circuit = QuantumCircuit(1)
        circuit.initialize([0, 1], [0])
        op = Z

        res = (~StateFn(op) @ StateFn(circuit)).eval()
        self.assertAlmostEqual(-1 + 0j, res)
Ejemplo n.º 22
0
    def test_opflow_qnn_2_1(self, q_i):
        """ Test Opflow QNN with input/output dimension 2/1."""

        # construct QNN
        if q_i == 'sv':
            quantum_instance = self.sv_quantum_instance
        else:
            quantum_instance = self.qasm_quantum_instance

        # specify how to evaluate expected values and gradients
        expval = PauliExpectation()
        gradient = Gradient()

        # construct parametrized circuit
        params = [
            Parameter('input1'),
            Parameter('input2'),
            Parameter('weight1'),
            Parameter('weight2')
        ]
        qc = QuantumCircuit(2)
        qc.h(0)
        qc.ry(params[0], 0)
        qc.ry(params[1], 1)
        qc.rx(params[2], 0)
        qc.rx(params[3], 1)
        qc_sfn = StateFn(qc)

        # construct cost operator
        cost_operator = StateFn(
            PauliSumOp.from_list([('ZZ', 1.0), ('XX', 1.0)]))

        # combine operator and circuit to objective function
        op = ~cost_operator @ qc_sfn

        # define QNN
        qnn = OpflowQNN(op,
                        params[:2],
                        params[2:],
                        expval,
                        gradient,
                        quantum_instance=quantum_instance)

        test_data = [
            np.array([1, 2]),
            np.array([[1, 2]]),
            np.array([[1, 2], [3, 4]])
        ]

        # test model
        self.validate_output_shape(qnn, test_data)
    def __init__(self,
                 num_qubits: int,
                 feature_map: QuantumCircuit = None,
                 var_form: QuantumCircuit = None,
                 observable: Union[QuantumCircuit, OperatorBase] = None,
                 quantum_instance: Optional[Union[QuantumInstance, BaseBackend,
                                                  Backend]] = None):
        r"""Initializes the Two Layer Quantum Neural Network.

        Args:
            num_qubits: The number of qubits to represent the network.
            feature_map: The (parametrized) circuit to be used as feature map. If None is given,
                the `ZZFeatureMap` is used.
            var_form: The (parametrized) circuit to be used as variational form. If None is given,
                the `RealAmplitudes` circuit is used.
            observable: observable to be measured to determine the output of the network. If None
                is given, the `Z^{\otimes num_qubits}` observable is used.
        """

        self.num_qubits = num_qubits

        # TODO: circuits need to have well-defined parameter order!
        self.feature_map = feature_map if feature_map else ZZFeatureMap(
            num_qubits)
        idx = np.argsort([p.name for p in self.feature_map.parameters])
        input_params = list(self.feature_map.parameters)
        input_params = [input_params[i] for i in idx]

        # TODO: circuits need to have well-defined parameter order!
        self.var_form = var_form if var_form else RealAmplitudes(num_qubits)
        idx = np.argsort([p.name for p in self.var_form.parameters])
        weight_params = list(self.var_form.parameters)
        weight_params = [weight_params[i] for i in idx]

        # construct circuit
        self.qc = QuantumCircuit(num_qubits)
        self.qc.append(self.feature_map, range(num_qubits))
        self.qc.append(self.var_form, range(num_qubits))

        # construct observable
        self.observable = observable if observable else PauliSumOp.from_list(
            [('Z' * num_qubits, 1)])

        # combine all to operator
        operator = ~StateFn(self.observable) @ StateFn(self.qc)

        super().__init__(operator,
                         input_params,
                         weight_params,
                         quantum_instance=quantum_instance)
    def test_opflow_qnn_2_2(self, q_i):
        """ Test Opflow QNN with input/output dimension 2/2."""

        if q_i == 'sv':
            quantum_instance = self.sv_quantum_instance
        else:
            quantum_instance = self.qasm_quantum_instance

        # construct parametrized circuit
        params_1 = [Parameter('input1'), Parameter('weight1')]
        qc_1 = QuantumCircuit(1)
        qc_1.h(0)
        qc_1.ry(params_1[0], 0)
        qc_1.rx(params_1[1], 0)
        qc_sfn_1 = StateFn(qc_1)

        # construct cost operator
        h_1 = StateFn(PauliSumOp.from_list([('Z', 1.0), ('X', 1.0)]))

        # combine operator and circuit to objective function
        op_1 = ~h_1 @ qc_sfn_1

        # construct parametrized circuit
        params_2 = [Parameter('input2'), Parameter('weight2')]
        qc_2 = QuantumCircuit(1)
        qc_2.h(0)
        qc_2.ry(params_2[0], 0)
        qc_2.rx(params_2[1], 0)
        qc_sfn_2 = StateFn(qc_2)

        # construct cost operator
        h_2 = StateFn(PauliSumOp.from_list([('Z', 1.0), ('X', 1.0)]))

        # combine operator and circuit to objective function
        op_2 = ~h_2 @ qc_sfn_2

        op = ListOp([op_1, op_2])

        qnn = OpflowQNN(op, [params_1[0], params_2[0]], [params_1[1], params_2[1]],
                        quantum_instance=quantum_instance)

        test_data = [
            np.array([1, 2]),
            np.array([[1, 2], [3, 4]])
        ]

        # test model
        self.validate_output_shape(qnn, test_data)
    def test_state_gradient3(self, method):
        """Test the state gradient 3

        Tr(|psi><psi|Z) = sin(a)sin(c(a)) = sin(a)sin(cos(a)+1)
        Tr(|psi><psi|X) = cos(a)
        d<H>/da = - 0.5 sin(a) - 1 cos(a)sin(cos(a)+1) + 1 sin^2(a)cos(cos(a)+1)
        """
        ham = 0.5 * X - 1 * Z
        a = Parameter("a")
        # b = Parameter('b')
        params = a
        c = np.cos(a) + 1
        q = QuantumRegister(1)
        qc = QuantumCircuit(q)
        qc.h(q)
        qc.rz(a, q[0])
        qc.rx(c, 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}, {a: 0}, {a: np.pi / 2}]
        correct_values = [-1.1220, -0.9093, 0.0403]
        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)
    def test_grad_combo_fn_chain_rule(self, method):
        """Test the chain rule for a custom gradient combo function."""
        np.random.seed(2)

        def combo_fn(x):
            amplitudes = x[0].primitive.data
            pdf = np.multiply(amplitudes, np.conj(amplitudes))
            return np.sum(np.log(pdf)) / (-len(amplitudes))

        def grad_combo_fn(x):
            amplitudes = x[0].primitive.data
            pdf = np.multiply(amplitudes, np.conj(amplitudes))
            grad = []
            for prob in pdf:
                grad += [-1 / prob]
            return grad

        qc = RealAmplitudes(2, reps=1)
        grad_op = ListOp([StateFn(qc.decompose())],
                         combo_fn=combo_fn,
                         grad_combo_fn=grad_combo_fn)
        grad = Gradient(grad_method=method).convert(grad_op)
        value_dict = dict(
            zip(qc.ordered_parameters,
                np.random.rand(len(qc.ordered_parameters))))
        correct_values = [
            [(-0.16666259133549044 + 0j)],
            [(-7.244949702732864 + 0j)],
            [(-2.979791752749964 + 0j)],
            [(-5.310186078432614 + 0j)],
        ]
        np.testing.assert_array_almost_equal(
            grad.assign_parameters(value_dict).eval(), correct_values)
    def test_state_gradient4(self, method):
        """Test the state gradient 4
        Tr(|psi><psi|ZX) = -cos(a)
        daTr(|psi><psi|ZX) = sin(a)
        """

        ham = X ^ Z
        a = Parameter("a")
        params = a

        q = QuantumRegister(2)
        qc = QuantumCircuit(q)
        qc.x(q[0])
        qc.h(q[1])
        qc.crz(a, q[0], q[1])
        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}, {a: 0}, {a: np.pi / 2}]
        correct_values = [1 / np.sqrt(2), 0, 1]

        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)
    def test_natural_gradient4(self, grad_method, qfi_method, regularization):
        """Test the natural gradient 4"""

        # Avoid regularization = lasso intentionally because it does not converge
        try:
            ham = 0.5 * X - 1 * Z
            a = Parameter("a")
            params = a

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

            op = ~StateFn(ham) @ CircuitStateFn(primitive=qc, coeff=1.0)
            nat_grad = NaturalGradient(grad_method=grad_method,
                                       qfi_method=qfi_method,
                                       regularization=regularization).convert(
                                           operator=op, params=params)
            values_dict = [{a: np.pi / 4}]
            correct_values = [[0.0]] if regularization == "ridge" else [[
                -1.41421342
            ]]
            for i, value_dict in enumerate(values_dict):
                np.testing.assert_array_almost_equal(
                    nat_grad.assign_parameters(value_dict).eval(),
                    correct_values[i],
                    decimal=3)
        except MissingOptionalLibraryError as ex:
            self.skipTest(str(ex))
    def test_natural_gradient(self, method, regularization):
        """Test the natural gradient"""
        try:
            for params in (ParameterVector("a", 2),
                           [Parameter("a"), Parameter("b")]):
                ham = 0.5 * X - 1 * Z

                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)
                nat_grad = NaturalGradient(
                    grad_method=method,
                    regularization=regularization).convert(operator=op)
                values_dict = [{params[0]: np.pi / 4, params[1]: np.pi / 2}]

                # reference values obtained by classically computing the natural gradients
                correct_values = [[
                    -3.26, 1.63
                ]] if regularization == "ridge" else [[-4.24, 0]]

                for i, value_dict in enumerate(values_dict):
                    np.testing.assert_array_almost_equal(
                        nat_grad.assign_parameters(value_dict).eval(),
                        correct_values[i],
                        decimal=1)
        except MissingOptionalLibraryError as ex:
            self.skipTest(str(ex))
    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.0)

        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)