示例#1
0
    def test_log_i(self):
        """ MatrixOp.log_i() test """
        op = (-1.052373245772859 * I ^ I) + \
             (0.39793742484318045 * I ^ Z) + \
             (0.18093119978423156 * X ^ X) + \
             (-0.39793742484318045 * Z ^ I) + \
             (-0.01128010425623538 * Z ^ Z) * np.pi/2
        # Test with CircuitOp
        log_exp_op = op.to_matrix_op().exp_i().log_i().to_pauli_op()
        np.testing.assert_array_almost_equal(op.to_matrix(), log_exp_op.to_matrix())

        # Test with MatrixOp
        log_exp_op = op.to_matrix_op().exp_i().to_matrix_op().log_i().to_pauli_op()
        np.testing.assert_array_almost_equal(op.to_matrix(), log_exp_op.to_matrix())

        # Test with PauliOp
        log_exp_op = op.to_matrix_op().exp_i().to_pauli_op().log_i().to_pauli_op()
        np.testing.assert_array_almost_equal(op.to_matrix(), log_exp_op.to_matrix())

        # Test with EvolvedOp
        log_exp_op = op.exp_i().to_pauli_op().log_i().to_pauli_op()
        np.testing.assert_array_almost_equal(op.to_matrix(), log_exp_op.to_matrix())

        # Test with proper ListOp
        op = ListOp([(0.39793742484318045 * I ^ Z),
                     (0.18093119978423156 * X ^ X),
                     (-0.39793742484318045 * Z ^ I),
                     (-0.01128010425623538 * Z ^ Z) * np.pi / 2])
        log_exp_op = op.to_matrix_op().exp_i().to_matrix_op().log_i().to_pauli_op()
        np.testing.assert_array_almost_equal(op.to_matrix(), log_exp_op.to_matrix())
示例#2
0
    def test_not_to_matrix_called(self):
        """ 45 qubit calculation - literally will not work if to_matrix is
            somehow called (in addition to massive=False throwing an error)"""

        qs = 45
        states_op = ListOp([Zero ^ qs, One ^ qs, (Zero ^ qs) + (One ^ qs)])
        paulis_op = ListOp([Z ^ qs, (I ^ Z ^ I) ^ int(qs / 3)])

        converted_meas = self.expect.convert(~StateFn(paulis_op) @ states_op)
        np.testing.assert_array_almost_equal(converted_meas.eval(),
                                             [[1, -1, 0], [1, -1, 0]])
示例#3
0
    def test_ibmq_grouped_pauli_expectation(self):
        """ pauli expect op vector state vector test """
        from qiskit import IBMQ
        p = IBMQ.load_account()
        backend = p.get_backend('ibmq_qasm_simulator')
        paulis_op = ListOp([X, Y, Z, I])
        states_op = ListOp([One, Zero, Plus, Minus])

        valids = [[+0, 0, 1, -1], [+0, 0, 0, 0], [-1, 1, 0, -0], [+1, 1, 1, 1]]
        converted_meas = self.expect.convert(~StateFn(paulis_op) @ states_op)
        sampled = CircuitSampler(backend).convert(converted_meas)
        np.testing.assert_array_almost_equal(sampled.eval(), valids, decimal=1)
    def test_listop_num_qubits(self):
        """Test that ListOp.num_qubits checks that all operators have the same number of qubits."""
        op = ListOp([X ^ Y, Y ^ Z])
        with self.subTest('All operators have the same numbers of qubits'):
            self.assertEqual(op.num_qubits, 2)

        op = ListOp([X ^ Y, Y])
        with self.subTest('Operators have different numbers of qubits'):
            with self.assertRaises(ValueError):
                op.num_qubits  # pylint: disable=pointless-statement

            with self.assertRaises(ValueError):
                X @ op  # pylint: disable=pointless-statement
示例#5
0
    def test_pauli_expect_op_vector_state_vector(self):
        """ pauli expect op vector state vector test """
        paulis_op = ListOp([X, Y, Z, I])
        states_op = ListOp([One, Zero, Plus, Minus])

        valids = [[+0, 0, 1, -1], [+0, 0, 0, 0], [-1, 1, 0, -0], [+1, 1, 1, 1]]
        converted_meas = self.expect.convert(~StateFn(paulis_op) @ states_op)
        np.testing.assert_array_almost_equal(converted_meas.eval(),
                                             valids,
                                             decimal=1)

        sampled = self.sampler.convert(converted_meas)
        np.testing.assert_array_almost_equal(sampled.eval(), valids, decimal=1)
 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)
示例#7
0
    def test_grad_combo_fn_chain_rule_nat_grad(self):
        """
        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)], combo_fn=combo_fn, grad_combo_fn=grad_combo_fn)
        grad = NaturalGradient(grad_method='lin_comb', regularization='ridge'
                               ).convert(grad_op, qc.ordered_parameters)
        value_dict = dict(
            zip(qc.ordered_parameters, np.random.rand(len(qc.ordered_parameters))))
        correct_values = [[0.20777236], [-18.92560338], [-15.89005475], [-10.44002031]]
        np.testing.assert_array_almost_equal(grad.assign_parameters(value_dict).eval(),
                                             correct_values, decimal=3)
示例#8
0
    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)],
                         combo_fn=combo_fn,
                         grad_combo_fn=grad_combo_fn)
        grad = Gradient(grad_method=method).convert(grad_op,
                                                    qc.ordered_parameters)
        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 _run(self):
        """
        Run the algorithm to compute up to the requested k number of eigenvalues.
        Returns:
            dict: Dictionary of results
        Raises:
            AquaError: if no operator has been provided
        """
        if self._operator is None:
            raise AquaError("Operator was never provided")

        self._ret = {}
        self._solve()
        self._get_ground_state_energy()
        self._get_energies()

        logger.debug('NumPyEigensolver _run result:\n%s',
                     pprint.pformat(self._ret, indent=4))
        result = EigensolverResult()
        if 'eigvals' in self._ret:
            result.eigenvalues = self._ret['eigvals']
        if 'eigvecs' in self._ret:
            result.eigenstates = ListOp(
                [StateFn(vec) for vec in self._ret['eigvecs']])
        if 'aux_ops' in self._ret:
            result.aux_operator_eigenvalues = self._ret['aux_ops']

        logger.debug('EigensolverResult dict:\n%s',
                     pprint.pformat(result.data, indent=4))
        return result
示例#10
0
    def invalid_input(self):
        """Test invalid input raises an error."""
        op = Z

        with self.subTest('alpha < 0'):
            with self.assertRaises(ValueError):
                _ = CVaRMeasurement(op, alpha=-0.2)

        with self.subTest('alpha > 1'):
            with self.assertRaises(ValueError):
                _ = CVaRMeasurement(op, alpha=12.3)

        with self.subTest('Single pauli operator not diagonal'):
            op = Y
            with self.assertRaises(AquaError):
                _ = CVaRMeasurement(op)

        with self.subTest('Summed pauli operator not diagonal'):
            op = X ^ Z + Z ^ I
            with self.assertRaises(AquaError):
                _ = CVaRMeasurement(op)

        with self.subTest('List operator not diagonal'):
            op = ListOp([X ^ Z, Z ^ I])
            with self.assertRaises(AquaError):
                _ = CVaRMeasurement(op)

        with self.subTest('Matrix operator not diagonal'):
            op = MatrixOp([[1, 1], [0, 1]])
            with self.assertRaises(AquaError):
                _ = CVaRMeasurement(op)
    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))
def grad_classify(x_list, params, class_labels):
    qc = deepcopy(circuit)
    qc_list = []
    for x in x_list:
        parameters = {}
        for i, p in enumerate(feature_map.ordered_parameters):
            parameters[p] = x[i]
        circ_ = qc.assign_parameters(parameters)
        if sv_sim:
            raise TypeError(
                'For now the gradient implementation only allows for Aer backends.'
            )
        qc_list += [StateFn(circ_)]
    if not sv_sim:
        qc_list = ListOp(qc_list)
        grad_fn = Gradient(method='lin_comb').gradient_wrapper(
            qc_list, var_form.ordered_parameters, backend=qi)
        grad = grad_fn(params)
    probs = []
    for grad_vec in grad:
        prob = []
        for i, qc in enumerate(qc_list):
            counts = VectorStateFn(grad_vec[i]).to_dict_fn().primitive
            prob += [return_probabilities(counts, class_labels)]
        probs += [prob]
    return probs
示例#13
0
    def test_pauli_expect_op_vector(self):
        """ pauli expect op vector test """
        paulis_op = ListOp([X, Y, Z, I])
        converted_meas = self.expect.convert(~StateFn(paulis_op))

        plus_mean = (converted_meas @ Plus)
        sampled_plus = self.sampler.convert(plus_mean)
        np.testing.assert_array_almost_equal(sampled_plus.eval(), [1, 0, 0, 1],
                                             decimal=1)

        minus_mean = (converted_meas @ Minus)
        sampled_minus = self.sampler.convert(minus_mean)
        np.testing.assert_array_almost_equal(sampled_minus.eval(),
                                             [-1, 0, 0, 1],
                                             decimal=1)

        zero_mean = (converted_meas @ Zero)
        sampled_zero = self.sampler.convert(zero_mean)
        # TODO bug with Aer's Y
        np.testing.assert_array_almost_equal(sampled_zero.eval(), [0, 1, 1, 1],
                                             decimal=1)

        sum_zero = (Plus + Minus) * (.5**.5)
        sum_zero_mean = (converted_meas @ sum_zero)
        sampled_zero_mean = self.sampler.convert(sum_zero_mean)
        # !!NOTE!!: Depolarizing channel (Sampling) means interference
        # does not happen between circuits in sum, so expectation does
        # not equal expectation for Zero!!
        np.testing.assert_array_almost_equal(sampled_zero_mean.eval(),
                                             [0, 0, 0, 2],
                                             decimal=1)
示例#14
0
    def test_multi_representation_ops(self):
        """ Test observables with mixed representations """
        mixed_ops = ListOp([X.to_matrix_op(), H, H + I, X])
        converted_meas = self.expect.convert(~StateFn(mixed_ops))

        plus_mean = (converted_meas @ Plus)
        sampled_plus = self.sampler.convert(plus_mean)
        np.testing.assert_array_almost_equal(sampled_plus.eval(),
                                             [1, .5**.5, (1 + .5**.5), 1],
                                             decimal=1)
示例#15
0
    def test_pauli_expect_op_vector(self):
        """ pauli expect op vector test """
        paulis_op = ListOp([X, Y, Z, I])
        converted_meas = self.expect.convert(~StateFn(paulis_op))

        plus_mean = (converted_meas @ Plus)
        np.testing.assert_array_almost_equal(plus_mean.eval(), [1, 0, 0, 1],
                                             decimal=1)
        sampled_plus = self.sampler.convert(plus_mean)
        np.testing.assert_array_almost_equal(sampled_plus.eval(), [1, 0, 0, 1],
                                             decimal=1)

        minus_mean = (converted_meas @ Minus)
        np.testing.assert_array_almost_equal(minus_mean.eval(), [-1, 0, 0, 1],
                                             decimal=1)
        sampled_minus = self.sampler.convert(minus_mean)
        np.testing.assert_array_almost_equal(sampled_minus.eval(),
                                             [-1, 0, 0, 1],
                                             decimal=1)

        zero_mean = (converted_meas @ Zero)
        np.testing.assert_array_almost_equal(zero_mean.eval(), [0, 0, 1, 1],
                                             decimal=1)
        sampled_zero = self.sampler.convert(zero_mean)
        np.testing.assert_array_almost_equal(sampled_zero.eval(), [0, 0, 1, 1],
                                             decimal=1)

        sum_zero = (Plus + Minus) * (.5**.5)
        sum_zero_mean = (converted_meas @ sum_zero)
        np.testing.assert_array_almost_equal(sum_zero_mean.eval(),
                                             [0, 0, 1, 1],
                                             decimal=1)
        sampled_zero_mean = self.sampler.convert(sum_zero_mean)
        # !!NOTE!!: Depolarizing channel (Sampling) means interference
        # does not happen between circuits in sum, so expectation does
        # not equal expectation for Zero!!
        np.testing.assert_array_almost_equal(sampled_zero_mean.eval(),
                                             [0, 0, 0, 2],
                                             decimal=1)

        for i, op in enumerate(paulis_op.oplist):
            mat_op = op.to_matrix()
            np.testing.assert_array_almost_equal(
                zero_mean.eval()[i],
                Zero.adjoint().to_matrix() @ mat_op @ Zero.to_matrix(),
                decimal=1)
            np.testing.assert_array_almost_equal(
                plus_mean.eval()[i],
                Plus.adjoint().to_matrix() @ mat_op @ Plus.to_matrix(),
                decimal=1)
            np.testing.assert_array_almost_equal(
                minus_mean.eval()[i],
                Minus.adjoint().to_matrix() @ mat_op @ Minus.to_matrix(),
                decimal=1)
示例#16
0
    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.),
            ~StateFn(Z) @ CircuitStateFn(primitive=qc, coeff=1.)
        ],
                    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.], [-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)
示例#17
0
    def convert(
        self,
        operator: OperatorBase,
        params: Optional[Union[ParameterVector, ParameterExpression,
                               List[ParameterExpression]]] = None
    ) -> OperatorBase:
        r"""
        Args:
            operator: The operator we are taking the gradient of.
            params: The parameters we are taking the gradient with respect to.

        Returns:
            An operator whose evaluation yields the NaturalGradient.

        Raises:
            TypeError: If ``operator`` does not represent an expectation value or the quantum
                state is not ``CircuitStateFn``.
            ValueError: If ``params`` contains a parameter not present in ``operator``.
        """
        if not isinstance(operator[-1], CircuitStateFn):
            raise TypeError(
                'Please make sure that the operator for which you want to compute '
                'Quantum Fisher Information represents an expectation value or a '
                'loss function and that the quantum state is given as '
                'CircuitStateFn.')
        if not isinstance(params, Iterable):
            params = [params]
        # Instantiate the gradient
        grad = Gradient(self._grad_method,
                        epsilon=self._epsilon).convert(operator, params)
        # Instantiate the QFI metric which is used to re-scale the gradient
        metric = self._qfi_method.convert(operator[-1], params) * 0.25

        # Define the function which compute the natural gradient from the gradient and the QFI.
        def combo_fn(x):
            c = np.real(x[0])
            a = np.real(x[1])
            if self.regularization:
                # If a regularization method is chosen then use a regularized solver to
                # construct the natural gradient.
                nat_grad = NaturalGradient._regularized_sle_solver(
                    a, c, regularization=self.regularization)
            else:
                try:
                    # Try to solve the system of linear equations Ax = C.
                    nat_grad = np.linalg.solve(a, c)
                except np.linalg.LinAlgError:  # singular matrix
                    nat_grad = np.linalg.lstsq(a, c)[0]
            return np.real(nat_grad)

        # Define the ListOp which combines the gradient and the QFI according to the combination
        # function defined above.
        return ListOp([grad, metric], combo_fn=combo_fn)
示例#18
0
    def test_construction(self):
        """Test the correct operator expression is constructed."""

        alpha = 0.5
        base_expecation = PauliExpectation()
        cvar_expecation = CVaRExpectation(alpha=alpha,
                                          expectation=base_expecation)

        with self.subTest('single operator'):
            op = ~StateFn(Z) @ Plus
            expected = CVaRMeasurement(Z, alpha) @ Plus
            cvar = cvar_expecation.convert(op)
            self.assertEqual(cvar, expected)

        with self.subTest('list operator'):
            op = ~StateFn(ListOp([Z ^ Z, I ^ Z])) @ (Plus ^ Plus)
            expected = ListOp([
                CVaRMeasurement((Z ^ Z), alpha) @ (Plus ^ Plus),
                CVaRMeasurement((I ^ Z), alpha) @ (Plus ^ Plus)
            ])
            cvar = cvar_expecation.convert(op)
            self.assertEqual(cvar, expected)
    def test_pauli_expect_state_vector(self):
        """ pauli expect state vector test """
        states_op = ListOp([One, Zero, Plus, Minus])

        paulis_op = X
        converted_meas = self.expect.convert(~StateFn(paulis_op) @ states_op)
        sampled = self.sampler.convert(converted_meas)

        # Small test to see if execution results are accessible
        for composed_op in sampled:
            self.assertIn('counts', composed_op[0].execution_results)

        np.testing.assert_array_almost_equal(sampled.eval(), [0, 0, 1, -1], decimal=1)
class TestListOpComboFn(QiskitAquaTestCase):
    """Test combo fn is propagated."""

    def setUp(self):
        super().setUp()
        self.combo_fn = lambda x: [x_i ** 2 for x_i in x]
        self.listop = ListOp([X], combo_fn=self.combo_fn)

    def assertComboFnPreserved(self, processed_op):
        """Assert the quadratic combo_fn is preserved."""
        x = [1, 2, 3]
        self.assertListEqual(processed_op.combo_fn(x), self.combo_fn(x))

    def test_at_conversion(self):
        """Test after conversion the combo_fn is preserved."""
        for method in ['to_matrix_op', 'to_pauli_op', 'to_circuit_op']:
            with self.subTest(method):
                converted = getattr(self.listop, method)()
                self.assertComboFnPreserved(converted)

    def test_after_mul(self):
        """Test after multiplication the combo_fn is preserved."""
        self.assertComboFnPreserved(2 * self.listop)

    def test_at_traverse(self):
        """Test after traversing the combo_fn is preserved."""
        def traverse_fn(op):
            return -op

        traversed = self.listop.traverse(traverse_fn)
        self.assertComboFnPreserved(traversed)

    def test_after_adjoint(self):
        """Test after traversing the combo_fn is preserved."""
        self.assertComboFnPreserved(self.listop.adjoint())

    def test_after_reduce(self):
        """Test after reducing the combo_fn is preserved."""
        self.assertComboFnPreserved(self.listop.reduce())
    def test_pauli_expect_op_vector(self):
        """ pauli expect op vector test """
        paulis_op = ListOp([X, Y, Z, I])
        converted_meas = self.expect.convert(~StateFn(paulis_op))

        plus_mean = (converted_meas @ Plus)
        np.testing.assert_array_almost_equal(plus_mean.eval(), [1, 0, 0, 1],
                                             decimal=1)
        sampled_plus = self.sampler.convert(plus_mean)
        np.testing.assert_array_almost_equal(sampled_plus.eval(), [1, 0, 0, 1],
                                             decimal=1)

        minus_mean = (converted_meas @ Minus)
        np.testing.assert_array_almost_equal(minus_mean.eval(), [-1, 0, 0, 1],
                                             decimal=1)
        sampled_minus = self.sampler.convert(minus_mean)
        np.testing.assert_array_almost_equal(sampled_minus.eval(),
                                             [-1, 0, 0, 1],
                                             decimal=1)

        zero_mean = (converted_meas @ Zero)
        np.testing.assert_array_almost_equal(zero_mean.eval(), [0, 0, 1, 1],
                                             decimal=1)
        sampled_zero = self.sampler.convert(zero_mean)
        np.testing.assert_array_almost_equal(sampled_zero.eval(), [0, 0, 1, 1],
                                             decimal=1)

        sum_zero = (Plus + Minus) * (.5**.5)
        sum_zero_mean = (converted_meas @ sum_zero)
        np.testing.assert_array_almost_equal(sum_zero_mean.eval(),
                                             [0, 0, 1, 1],
                                             decimal=1)
        sampled_zero = self.sampler.convert(sum_zero)
        np.testing.assert_array_almost_equal(
            (converted_meas @ sampled_zero).eval(), [0, 0, 1, 1], decimal=1)

        for i, op in enumerate(paulis_op.oplist):
            mat_op = op.to_matrix()
            np.testing.assert_array_almost_equal(
                zero_mean.eval()[i],
                Zero.adjoint().to_matrix() @ mat_op @ Zero.to_matrix(),
                decimal=1)
            np.testing.assert_array_almost_equal(
                plus_mean.eval()[i],
                Plus.adjoint().to_matrix() @ mat_op @ Plus.to_matrix(),
                decimal=1)
            np.testing.assert_array_almost_equal(
                minus_mean.eval()[i],
                Minus.adjoint().to_matrix() @ mat_op @ Minus.to_matrix(),
                decimal=1)
示例#22
0
    def convert(
        self,
        operator: OperatorBase,
        params: Optional[Union[ParameterExpression, ParameterVector,
                               List[ParameterExpression],
                               Tuple[ParameterExpression, ParameterExpression],
                               List[Tuple[ParameterExpression,
                                          ParameterExpression]]]] = None
    ) -> OperatorBase:
        """
        Args:
            operator: The operator corresponding to our quantum state we are taking the
                      gradient of: |ψ(ω)〉
            params: The parameters we are taking the gradient wrt: ω
                    If a ParameterExpression, ParameterVector or List[ParameterExpression] is given,
                    then the 1st order derivative of the operator is calculated.
                    If a Tuple[ParameterExpression, ParameterExpression] or
                    List[Tuple[ParameterExpression, ParameterExpression]]
                    is given, then the 2nd order derivative of the operator is calculated.

        Returns:
            An operator corresponding to the gradient resp. Hessian. The order is in accordance with
            the order of the given parameters.
        Raises:
            AquaError: If the parameters are given in an invalid format.

        """
        if isinstance(params, (ParameterExpression, ParameterVector)):
            return self._parameter_shift(operator, params)
        elif isinstance(params, tuple):
            return self._parameter_shift(
                self._parameter_shift(operator, params[0]), params[1])
        elif isinstance(params, Iterable):
            if all(isinstance(param, ParameterExpression) for param in params):
                return self._parameter_shift(operator, params)
            elif all(isinstance(param, tuple) for param in params):
                return ListOp([
                    self._parameter_shift(
                        self._parameter_shift(operator, pair[0]), pair[1])
                    for pair in params
                ])
            else:
                raise AquaError(
                    'The linear combination gradient does only support the computation '
                    'of 1st gradients and 2nd order gradients.')
        else:
            raise AquaError(
                'The linear combination gradient does only support the computation '
                'of 1st gradients and 2nd order gradients.')
    def test_indexing(self):
        """Test indexing and slicing"""
        coeff = 3 + .2j
        states_op = ListOp([X, Y, Z, I], coeff=coeff)

        single_op = states_op[1]
        self.assertIsInstance(single_op, OperatorBase)
        self.assertNotIsInstance(single_op, ListOp)

        list_one_element = states_op[1:2]
        self.assertIsInstance(list_one_element, ListOp)
        self.assertEqual(len(list_one_element), 1)
        self.assertEqual(list_one_element[0], Y)

        list_two_elements = states_op[::2]
        self.assertIsInstance(list_two_elements, ListOp)
        self.assertEqual(len(list_two_elements), 2)
        self.assertEqual(list_two_elements[0], X)
        self.assertEqual(list_two_elements[1], Z)

        states_op = ListOp([X, Y, Z, I], coeff=coeff)

        self.assertEqual(list_one_element.coeff, coeff)
        self.assertEqual(list_two_elements.coeff, coeff)
示例#24
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)
示例#25
0
 def aux_operators(self,
                   aux_operators: Optional[List[Optional[Union[OperatorBase,
                                                               LegacyBaseOperator]]]]) -> None:
     """ Set aux operators """
     # We need to handle the array entries being Optional i.e. having value None
     self._aux_op_nones = None
     if isinstance(aux_operators, list):
         self._aux_op_nones = [op is None for op in aux_operators]
         zero_op = I.tensorpower(self.operator.num_qubits) * 0.0
         converted = [op.to_opflow() if op else zero_op for op in aux_operators]
         # For some reason Chemistry passes aux_ops with 0 qubits and paulis sometimes.
         converted = [zero_op if op == 0 else op for op in converted]
         aux_operators = ListOp(converted)
     elif isinstance(aux_operators, LegacyBaseOperator):
         aux_operators = [aux_operators.to_opflow()]
     self._aux_operators = aux_operators
示例#26
0
 def aux_operators(self,
                   aux_operators: Optional[List[Optional[Union[OperatorBase,
                                                               LegacyBaseOperator]]]]) -> None:
     """ Set aux operators """
     # This is all terrible code to deal with weight 0-qubit None aux_ops.
     self._aux_op_nones = None
     if isinstance(aux_operators, list):
         self._aux_op_nones = [op is None for op in aux_operators]
         zero_op = I.tensorpower(self.operator.num_qubits) * 0.0
         converted = [op.to_opflow() if op else zero_op for op in aux_operators]
         # For some reason Chemistry passes aux_ops with 0 qubits and paulis sometimes.
         converted = [zero_op if op == 0 else op for op in converted]
         aux_operators = ListOp(converted)
     elif isinstance(aux_operators, LegacyBaseOperator):
         aux_operators = [aux_operators.to_opflow()]
     self._aux_operators = aux_operators
示例#27
0
文件: vqe.py 项目: AW-AlanWu/PuGua
    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)
示例#28
0
    def convert(
        self,
        operator: OperatorBase,
        params: Optional[Union[ParameterVector, ParameterExpression,
                               List[ParameterExpression]]] = None
    ) -> OperatorBase:
        r"""
        Args:
            operator: The operator we are taking the gradient of.
            params: The parameters we are taking the gradient with respect to.

        Returns:
            An operator whose evaluation yields the NaturalGradient.

        Raises:
            TypeError: If ``operator`` does not represent an expectation value or the quantum
                state is not ``CircuitStateFn``.
            ValueError: If ``params`` contains a parameter not present in ``operator``.
        """
        if not isinstance(operator[-1], CircuitStateFn):
            raise TypeError(
                'Please make sure that the operator for which you want to compute '
                'Quantum Fisher Information represents an expectation value or a '
                'loss function and that the quantum state is given as '
                'CircuitStateFn.')
        if not isinstance(params, Iterable):
            params = [params]
        grad = Gradient(self._grad_method,
                        epsilon=self._epsilon).convert(operator, params)
        metric = self._qfi_method.convert(operator[-1], params) * 0.25

        def combo_fn(x):
            c = np.real(x[0])
            a = np.real(x[1])
            if self.regularization:
                nat_grad = NaturalGradient._regularized_sle_solver(
                    a, c, regularization=self.regularization)
            else:
                try:
                    nat_grad = np.linalg.solve(a, c)
                except np.linalg.LinAlgError:  # singular matrix
                    nat_grad = np.linalg.lstsq(a, c)[0]
            return np.real(nat_grad)

        return ListOp([grad, metric], combo_fn=combo_fn)
示例#29
0
    def test_parameter_binding_on_listop(self):
        """Test passing a ListOp with differing parameters works with the circuit sampler."""
        x, y = Parameter('x'), Parameter('y')

        circuit1 = QuantumCircuit(1)
        circuit1.p(0.2, 0)
        circuit2 = QuantumCircuit(1)
        circuit2.p(x, 0)
        circuit3 = QuantumCircuit(1)
        circuit3.p(y, 0)

        bindings = {x: -0.4, y: 0.4}
        listop = ListOp(
            [StateFn(circuit) for circuit in [circuit1, circuit2, circuit3]])

        sampler = CircuitSampler(Aer.get_backend('qasm_simulator'))
        sampled = sampler.convert(listop, params=bindings)

        self.assertTrue(all(len(op.parameters) == 0 for op in sampled.oplist))
示例#30
0
    def _hessian_states(
        self,
        state_op: StateFn,
        meas_op: Optional[OperatorBase] = None,
        target_params: Optional[Union[Tuple[ParameterExpression,
                                            ParameterExpression],
                                      List[Tuple[ParameterExpression,
                                                 ParameterExpression]]]] = None
    ) -> OperatorBase:
        """Generate the operator states whose evaluation returns the Hessian (items).

        Args:
            state_op: The operator representing the quantum state for which we compute the Hessian.
            meas_op: The operator representing the observable for which we compute the gradient.
            target_params: The parameters we are computing the Hessian wrt: ω

        Returns:
            Operators which give the Hessian. If a parameter appears multiple times, one circuit is
            created per parameterized gates to compute the product rule.

        Raises:
            AquaError: If one of the circuits could not be constructed.
            TypeError: If ``operator`` is of unsupported type.
        """
        state_qc = deepcopy(state_op.primitive)
        if isinstance(target_params, list) and isinstance(
                target_params[0], tuple):
            tuples_list = deepcopy(target_params)
            target_params = []
            for tuples in tuples_list:
                if all([
                        param in state_qc._parameter_table.get_keys()
                        for param in tuples
                ]):
                    for param in tuples:
                        if param not in target_params:
                            target_params.append(param)
        elif isinstance(target_params, tuple):
            tuples_list = deepcopy([target_params])
            target_params = []
            for tuples in tuples_list:
                if all([
                        param in state_qc._parameter_table.get_keys()
                        for param in tuples
                ]):
                    for param in tuples:
                        if param not in target_params:
                            target_params.append(param)
        else:
            raise TypeError(
                'Please define in the parameters for which the Hessian is evaluated either '
                'as parameter tuple or a list of parameter tuples')

        qr_add0 = QuantumRegister(1, 'work_qubit0')
        work_q0 = qr_add0[0]
        qr_add1 = QuantumRegister(1, 'work_qubit1')
        work_q1 = qr_add1[0]
        # create a copy of the original circuit with an additional working qubit register
        circuit = state_qc.copy()
        circuit.add_register(qr_add0, qr_add1)
        # Get the circuits needed to compute the Hessian
        hessian_ops = None
        for param_a, param_b in tuples_list:

            if param_a not in state_qc._parameter_table.get_keys() or param_b \
                    not in state_qc._parameter_table.get_keys():
                hessian_op = ~Zero @ One
            else:
                param_gates_a = state_qc._parameter_table[param_a]
                param_gates_b = state_qc._parameter_table[param_b]
                for i, param_occurence_a in enumerate(param_gates_a):
                    coeffs_a, gates_a = self._gate_gradient_dict(
                        param_occurence_a[0])[param_occurence_a[1]]
                    # apply Hadamard on working qubit
                    self.insert_gate(circuit,
                                     param_occurence_a[0],
                                     HGate(),
                                     qubits=[work_q0])
                    self.insert_gate(circuit,
                                     param_occurence_a[0],
                                     HGate(),
                                     qubits=[work_q1])
                    for j, gate_to_insert_a in enumerate(gates_a):

                        coeff_a = coeffs_a[j]
                        hessian_circuit_temp = QuantumCircuit(*circuit.qregs)
                        hessian_circuit_temp.data = circuit.data
                        # Fix working qubit 0 phase
                        sign = np.sign(coeff_a)
                        is_complex = np.iscomplex(coeff_a)
                        if sign == -1:
                            if is_complex:
                                self.insert_gate(hessian_circuit_temp,
                                                 param_occurence_a[0],
                                                 SdgGate(),
                                                 qubits=[work_q0])
                            else:
                                self.insert_gate(hessian_circuit_temp,
                                                 param_occurence_a[0],
                                                 ZGate(),
                                                 qubits=[work_q0])
                        else:
                            if is_complex:
                                self.insert_gate(hessian_circuit_temp,
                                                 param_occurence_a[0],
                                                 SGate(),
                                                 qubits=[work_q0])

                        # Insert controlled, intercepting gate - controlled by |1>
                        if isinstance(param_occurence_a[0], UGate):
                            if param_occurence_a[1] == 0:
                                self.insert_gate(
                                    hessian_circuit_temp, param_occurence_a[0],
                                    RZGate(param_occurence_a[0].params[2]))
                                self.insert_gate(hessian_circuit_temp,
                                                 param_occurence_a[0],
                                                 RXGate(np.pi / 2))
                                self.insert_gate(hessian_circuit_temp,
                                                 param_occurence_a[0],
                                                 gate_to_insert_a,
                                                 additional_qubits=([work_q0],
                                                                    []))
                                self.insert_gate(hessian_circuit_temp,
                                                 param_occurence_a[0],
                                                 RXGate(-np.pi / 2))
                                self.insert_gate(
                                    hessian_circuit_temp, param_occurence_a[0],
                                    RZGate(-param_occurence_a[0].params[2]))

                            elif param_occurence_a[1] == 1:
                                self.insert_gate(hessian_circuit_temp,
                                                 param_occurence_a[0],
                                                 gate_to_insert_a,
                                                 after=True,
                                                 additional_qubits=([work_q0],
                                                                    []))
                            else:
                                self.insert_gate(hessian_circuit_temp,
                                                 param_occurence_a[0],
                                                 gate_to_insert_a,
                                                 additional_qubits=([work_q0],
                                                                    []))
                        else:
                            self.insert_gate(hessian_circuit_temp,
                                             param_occurence_a[0],
                                             gate_to_insert_a,
                                             additional_qubits=([work_q0], []))

                        for m, param_occurence_b in enumerate(param_gates_b):
                            coeffs_b, gates_b = self._gate_gradient_dict(
                                param_occurence_b[0])[param_occurence_b[1]]
                            for n, gate_to_insert_b in enumerate(gates_b):
                                coeff_b = coeffs_b[n]
                                # create a copy of the original circuit with the same registers
                                hessian_circuit = QuantumCircuit(
                                    *hessian_circuit_temp.qregs)
                                hessian_circuit.data = hessian_circuit_temp.data

                                # Fix working qubit 1 phase
                                sign = np.sign(coeff_b)
                                is_complex = np.iscomplex(coeff_b)
                                if sign == -1:
                                    if is_complex:
                                        self.insert_gate(hessian_circuit,
                                                         param_occurence_b[0],
                                                         SdgGate(),
                                                         qubits=[work_q1])
                                    else:
                                        self.insert_gate(hessian_circuit,
                                                         param_occurence_b[0],
                                                         ZGate(),
                                                         qubits=[work_q1])
                                else:
                                    if is_complex:
                                        self.insert_gate(hessian_circuit,
                                                         param_occurence_b[0],
                                                         SGate(),
                                                         qubits=[work_q1])

                                # Insert controlled, intercepting gate - controlled by |1>

                                if isinstance(param_occurence_b[0], UGate):
                                    if param_occurence_b[1] == 0:
                                        self.insert_gate(
                                            hessian_circuit,
                                            param_occurence_b[0],
                                            RZGate(param_occurence_b[0].
                                                   params[2]))
                                        self.insert_gate(
                                            hessian_circuit,
                                            param_occurence_b[0],
                                            RXGate(np.pi / 2))
                                        self.insert_gate(
                                            hessian_circuit,
                                            param_occurence_b[0],
                                            gate_to_insert_b,
                                            additional_qubits=([work_q1], []))
                                        self.insert_gate(
                                            hessian_circuit,
                                            param_occurence_b[0],
                                            RXGate(-np.pi / 2))
                                        self.insert_gate(
                                            hessian_circuit,
                                            param_occurence_b[0],
                                            RZGate(-param_occurence_b[0].
                                                   params[2]))

                                    elif param_occurence_b[1] == 1:
                                        self.insert_gate(
                                            hessian_circuit,
                                            param_occurence_b[0],
                                            gate_to_insert_b,
                                            after=True,
                                            additional_qubits=([work_q1], []))
                                    else:
                                        self.insert_gate(
                                            hessian_circuit,
                                            param_occurence_b[0],
                                            gate_to_insert_b,
                                            additional_qubits=([work_q1], []))
                                else:
                                    self.insert_gate(
                                        hessian_circuit,
                                        param_occurence_b[0],
                                        gate_to_insert_b,
                                        additional_qubits=([work_q1], []))

                                hessian_circuit.h(work_q0)
                                hessian_circuit.cz(work_q1, work_q0)
                                hessian_circuit.h(work_q1)

                                term = state_op.coeff * np.sqrt(np.abs(coeff_a) * np.abs(coeff_b)) \
                                                      * CircuitStateFn(hessian_circuit)

                                # Chain Rule Parameter Expression
                                gate_param_a = param_occurence_a[0].params[
                                    param_occurence_a[1]]
                                gate_param_b = param_occurence_b[0].params[
                                    param_occurence_b[1]]

                                if meas_op:
                                    meas = deepcopy(meas_op)
                                    if isinstance(gate_param_a,
                                                  ParameterExpression):
                                        expr_grad = DerivativeBase.parameter_expression_grad(
                                            gate_param_a, param_a)
                                        meas *= expr_grad
                                    if isinstance(gate_param_b,
                                                  ParameterExpression):
                                        expr_grad = DerivativeBase.parameter_expression_grad(
                                            gate_param_a, param_a)
                                        meas *= expr_grad
                                    term = meas @ term
                                else:
                                    term = ListOp([term],
                                                  combo_fn=partial(
                                                      self._hess_combo_fn,
                                                      state_op=state_op))
                                    if isinstance(gate_param_a,
                                                  ParameterExpression):
                                        expr_grad = DerivativeBase.parameter_expression_grad(
                                            gate_param_a, param_a)
                                        term *= expr_grad
                                    if isinstance(gate_param_b,
                                                  ParameterExpression):
                                        expr_grad = DerivativeBase.parameter_expression_grad(
                                            gate_param_a, param_a)
                                        term *= expr_grad

                                if i == 0 and j == 0 and m == 0 and n == 0:
                                    hessian_op = term
                                else:
                                    # Product Rule
                                    hessian_op += term
            # Create a list of Hessian elements w.r.t. the given parameter tuples
            if len(tuples_list) == 1:
                return hessian_op
            else:
                if not hessian_ops:
                    hessian_ops = [hessian_op]
                else:
                    hessian_ops += [hessian_op]
        return ListOp(hessian_ops)