Exemple #1
0
    def test_single_channel(self, channel):
        """Individually test adding just a single channel type to circuits."""
        symbol_names = []
        batch_size = 5
        n_qubits = 6
        qubits = cirq.GridQubit.rect(1, n_qubits)

        circuit_batch, resolver_batch = \
            util.random_circuit_resolver_batch(
                qubits, batch_size, include_channels=False)

        for i in range(batch_size):
            circuit_batch[i] = circuit_batch[i] + channel.on_each(*qubits)

        symbol_values_array = np.array(
            [[resolver[symbol] for symbol in symbol_names]
             for resolver in resolver_batch])

        pauli_sums1 = util.random_pauli_sums(qubits, 3, batch_size)
        pauli_sums2 = util.random_pauli_sums(qubits, 3, batch_size)
        batch_pauli_sums = [[x, y] for x, y in zip(pauli_sums1, pauli_sums2)]
        num_samples = [[20000] * 2] * batch_size

        op_exps = noisy_sampled_expectation_op.sampled_expectation(
            util.convert_to_tensor(circuit_batch),
            symbol_names, symbol_values_array,
            util.convert_to_tensor(batch_pauli_sums), num_samples)

        cirq_exps = batch_util.batch_calculate_expectation(
            circuit_batch, resolver_batch, batch_pauli_sums,
            cirq.DensityMatrixSimulator())

        self.assertAllClose(cirq_exps, op_exps, atol=0.35, rtol=0.35)
Exemple #2
0
    def test_simulate_consistency(self, batch_size, n_qubits, noisy):
        """Test consistency with batch_util.py simulation."""
        symbol_names = ['alpha', 'beta']
        qubits = cirq.GridQubit.rect(1, n_qubits)

        circuit_batch, resolver_batch = \
            util.random_symbol_circuit_resolver_batch(
                qubits, symbol_names, batch_size, include_channels=noisy)

        symbol_values_array = np.array(
            [[resolver[symbol] for symbol in symbol_names]
             for resolver in resolver_batch])

        pauli_sums1 = util.random_pauli_sums(qubits, 3, batch_size)
        pauli_sums2 = util.random_pauli_sums(qubits, 3, batch_size)
        batch_pauli_sums = [[x, y] for x, y in zip(pauli_sums1, pauli_sums2)]
        num_samples = [[10000] * 2] * batch_size

        op_exps = noisy_sampled_expectation_op.sampled_expectation(
            util.convert_to_tensor(circuit_batch),
            symbol_names, symbol_values_array,
            util.convert_to_tensor(batch_pauli_sums), num_samples)

        cirq_exps = batch_util.batch_calculate_expectation(
            circuit_batch, resolver_batch, batch_pauli_sums,
            cirq.DensityMatrixSimulator() if noisy else cirq.Simulator())
        tol = 0.5
        self.assertAllClose(cirq_exps, op_exps, atol=tol, rtol=tol)
Exemple #3
0
    def test_sampled_expectation_empty(self, op_and_sim, n_qubits,
                                       symbol_names, max_paulisum_length):
        """Test empty circuits for sampled expectation using cirq and tfq."""
        op = op_and_sim[0]
        sim = op_and_sim[1]

        qubits = cirq.GridQubit.rect(1, n_qubits)
        circuit_batch = [cirq.Circuit() for _ in range(BATCH_SIZE)]
        resolver_batch = [cirq.ParamResolver({}) for _ in range(BATCH_SIZE)]

        symbol_values_array = np.array([[0.0 for _ in symbol_names]
                                        for _ in resolver_batch])

        pauli_sums = util.random_pauli_sums(qubits, max_paulisum_length,
                                            BATCH_SIZE)
        num_samples = [[1000]] * BATCH_SIZE

        op_expectations = op(
            util.convert_to_tensor(circuit_batch), symbol_names,
            symbol_values_array,
            util.convert_to_tensor([[psum] for psum in pauli_sums]),
            num_samples)

        cirq_expectations = batch_util.batch_calculate_sampled_expectation(
            circuit_batch, resolver_batch, [[x] for x in pauli_sums],
            num_samples, sim)

        self.assertAllClose(op_expectations.numpy().flatten(),
                            cirq_expectations.flatten(),
                            rtol=1e-1,
                            atol=1e-1)
    def setup(self):
        """Persistent variational circuit, parameters, and observables."""
        qubits = cirq.GridQubit.rect(1, self.params.n_qubits)

        # Generate arbitrary symbol set without name clashes.
        symbol_names = set()
        while len(symbol_names) < self.params.n_symbols:
            symbol_names.add(''.join(
                np.random.choice(list(string.ascii_uppercase),
                                 size=4,
                                 replace=True)))
        symbol_names = list(symbol_names)

        circuit_batch, resolver_batch = util.random_symbol_circuit_resolver_batch(
            qubits=qubits,
            symbols=symbol_names,
            batch_size=self.params.batch_size,
            n_moments=self.params.n_moments,
            p=self.params.op_density)
        psums = util.random_pauli_sums(qubits, 1, self.params.batch_size)

        symbol_values_array = np.array(
            [[resolver[symbol] for symbol in symbol_names]
             for resolver in resolver_batch],
            dtype=np.float32)

        self.symbol_names = symbol_names
        self.symbol_values_tensor = tf.convert_to_tensor(symbol_values_array)
        self.programs = util.convert_to_tensor(circuit_batch)
        self.psums = util.convert_to_tensor([psums])
Exemple #5
0
    def test_sampled_expectation(self, op_and_sim, n_qubits, symbol_names,
                                 max_paulisum_length):
        """Compute sampled expectations using cirq and tfq."""
        op = op_and_sim[0]
        sim = op_and_sim[1]

        qubits = cirq.GridQubit.rect(1, n_qubits)
        circuit_batch, resolver_batch = \
            util.random_symbol_circuit_resolver_batch(
                qubits, symbol_names, BATCH_SIZE)

        symbol_values_array = np.array(
            [[resolver[symbol] for symbol in symbol_names]
             for resolver in resolver_batch])

        pauli_sums = util.random_pauli_sums(qubits, max_paulisum_length,
                                            BATCH_SIZE)
        num_samples = [[2000]] * BATCH_SIZE

        op_expectations = op(
            util.convert_to_tensor(circuit_batch), symbol_names,
            symbol_values_array,
            util.convert_to_tensor([[psum] for psum in pauli_sums]),
            num_samples)

        cirq_expectations = batch_util.batch_calculate_sampled_expectation(
            circuit_batch, resolver_batch, [[x] for x in pauli_sums],
            num_samples, sim)

        self.assertAllClose(op_expectations.numpy().flatten(),
                            cirq_expectations.flatten(),
                            rtol=1e-1,
                            atol=1e-1)
    def test_gradient_circuits_grad_comparison(self, differentiator, n_qubits,
                                               n_programs, n_ops,
                                               symbol_names):
        """Test that analytic gradient agrees with the one from grad circuits"""
        # Get random circuits to check.
        qubits = cirq.GridQubit.rect(1, n_qubits)
        circuit_batch, resolver_batch = \
            util.random_symbol_circuit_resolver_batch(
                cirq.GridQubit.rect(1, n_qubits), symbol_names, n_programs)
        psums = [
            util.random_pauli_sums(qubits, 1, n_ops) for _ in circuit_batch
        ]

        # Convert to tensors.
        symbol_names_array = np.array(symbol_names)
        symbol_values_array = np.array(
            [[resolver[symbol] for symbol in symbol_names]
             for resolver in resolver_batch],
            dtype=np.float32)
        symbol_names_tensor = tf.convert_to_tensor(symbol_names_array)
        symbol_values_tensor = tf.convert_to_tensor(symbol_values_array)
        programs = util.convert_to_tensor(circuit_batch)
        ops_tensor = util.convert_to_tensor(psums)

        # Get gradients using expectations of gradient circuits.
        (batch_programs, new_symbol_names, batch_symbol_values, batch_weights,
         batch_mapper) = differentiator.get_gradient_circuits(
             programs, symbol_names_tensor, symbol_values_tensor)
        analytic_op = circuit_execution_ops.get_expectation_op()
        batch_pauli_sums = tf.tile(tf.expand_dims(ops_tensor, 1),
                                   [1, tf.shape(batch_programs)[1], 1])
        n_batch_programs = tf.reduce_prod(tf.shape(batch_programs))
        n_symbols = len(symbol_names)
        batch_expectations = analytic_op(
            tf.reshape(batch_programs, [n_batch_programs]), new_symbol_names,
            tf.reshape(batch_symbol_values, [n_batch_programs, n_symbols]),
            tf.reshape(batch_pauli_sums, [n_batch_programs, n_ops]))
        batch_expectations = tf.reshape(batch_expectations,
                                        tf.shape(batch_pauli_sums))

        batch_jacobian = tf.map_fn(
            lambda x: tf.einsum('km,kmp->kp', x[0], tf.gather(x[1], x[2])),
            (batch_weights, batch_expectations, batch_mapper),
            fn_output_signature=tf.float32)
        grad_manual = tf.reduce_sum(batch_jacobian, -1)

        # Get gradients using autodiff.
        differentiator.refresh()
        differentiable_op = differentiator.generate_differentiable_op(
            analytic_op=analytic_op)
        with tf.GradientTape() as g:
            g.watch(symbol_values_tensor)
            exact_outputs = differentiable_op(programs, symbol_names_tensor,
                                              symbol_values_tensor, ops_tensor)
        grad_auto = g.gradient(exact_outputs, symbol_values_tensor)
        self.assertAllClose(grad_manual, grad_auto)
Exemple #7
0
    def test_empty_circuits(self, sim):
        """Test functions with empty circuits."""
        # Common preparation
        resolver_batch = [cirq.ParamResolver({}) for _ in range(BATCH_SIZE)]
        circuit_batch = [cirq.Circuit() for _ in range(BATCH_SIZE)]
        qubits = cirq.GridQubit.rect(1, N_QUBITS)
        ops = util.random_pauli_sums(qubits, PAULI_LENGTH, BATCH_SIZE)
        n_samples = [[1000] for _ in range(len(ops))]
        # If there is no op on a qubit, the expectation answer is -2.0
        true_expectation = (-2.0, )

        # (1) Test expectation
        results = batch_util.batch_calculate_expectation(
            circuit_batch, resolver_batch, [[x] for x in ops], sim)

        for _, _, result, _ in zip(circuit_batch, resolver_batch, results,
                                   ops):
            self.assertAllClose(true_expectation, result, rtol=1e-5, atol=1e-5)

        self.assertDTypeEqual(results, np.float32)

        # (2) Test sampled_expectation
        results = batch_util.batch_calculate_sampled_expectation(
            circuit_batch, resolver_batch, [[x] for x in ops], n_samples, sim)

        for _, _, result, _ in zip(circuit_batch, resolver_batch, results,
                                   ops):
            self.assertAllClose(true_expectation, result, rtol=1.0, atol=1e-1)

        self.assertDTypeEqual(results, np.float32)

        # (3) Test state
        results = batch_util.batch_calculate_state(circuit_batch,
                                                   resolver_batch, sim)

        for circuit, resolver, result in zip(circuit_batch, resolver_batch,
                                             results):
            r = _pad_state(sim, sim.simulate(circuit, resolver), 0)
            self.assertAllClose(r, result, rtol=1e-5, atol=1e-5)

        self.assertDTypeEqual(results, np.complex64)

        # (4) Test sampling
        n_samples = 2000 * (2**N_QUBITS)
        results = batch_util.batch_sample(circuit_batch, resolver_batch,
                                          n_samples, sim)

        for circuit, resolver, a in zip(circuit_batch, resolver_batch,
                                        results):
            state = sim.simulate(circuit, resolver)
            r = _sample_helper(sim, state, len(circuit.all_qubits()),
                               n_samples)
            self.assertAllClose(r, a, atol=1e-5)

        self.assertDTypeEqual(results, np.int32)
Exemple #8
0
def _items_to_tensorize():
    """Objects on which convert_to_tensor convert_from_tensor will be tested."""
    return [{
        'item': x
    } for x in (util.random_pauli_sums(BITS, 5, 5) + [
        cirq.PauliSum.from_pauli_strings([
            cirq.PauliString(),
            cirq.PauliString(cirq.Z(cirq.GridQubit(0, 0)))
        ])
    ] + [cirq.PauliString(), cirq.PauliString()] + [cirq.Circuit()] + [
        cirq.testing.random_circuit(BITS, 25, 0.9, util.get_supported_gates())
        for _ in range(5)
    ])]
Exemple #9
0
    def test_gradients_vs_cirq_finite_difference(self, differentiator, op,
                                                 n_qubits, n_programs, n_ops,
                                                 symbol_names):
        """Compare TFQ differentiators to fine-grained noiseless cirq finite
        differencing.
        DISCLAIMER : the consistency of STOCHASTIC_DIFFS is hard to be checked.
        Its expectation value should be checked, but it takes long time because
        SGDifferentiator is not optimized. Until optimized, the consistency
        will be performed in benchmarks/scripts/differentiators:convergence_test
        TODO(jaeyoo) : move convergence_test here once SGDifferentiator is
         optimized.
        """
        differentiator.refresh()
        op = differentiator.generate_differentiable_op(analytic_op=op)

        qubits = cirq.GridQubit.rect(1, n_qubits)
        circuit_batch, resolver_batch = \
            util.random_symbol_circuit_resolver_batch(
                cirq.GridQubit.rect(1, n_qubits), symbol_names, n_programs)

        psums = [
            util.random_pauli_sums(qubits, 1, n_ops) for _ in circuit_batch
        ]

        symbol_values_array = np.array(
            [[resolver[symbol]
              for symbol in symbol_names]
             for resolver in resolver_batch],
            dtype=np.float32)

        # calculate tfq gradient
        symbol_values_tensor = tf.convert_to_tensor(symbol_values_array)
        programs = util.convert_to_tensor(circuit_batch)
        ops = util.convert_to_tensor(psums)
        with tf.GradientTape() as g:
            g.watch(symbol_values_tensor)
            expectations = op(programs, tf.convert_to_tensor(symbol_names),
                              symbol_values_tensor, ops)
        tfq_grads = g.gradient(expectations, symbol_values_tensor)

        # calculate gradients in cirq using a very simple forward differencing
        # scheme
        cirq_grads = _cirq_simple_finite_difference(circuit_batch,
                                                    resolver_batch,
                                                    symbol_names, psums)

        # will this be too tight? time will tell.
        self.assertAllClose(cirq_grads, tfq_grads, rtol=1e-2, atol=1e-2)
Exemple #10
0
    def test_batch_expectation(self, sim):
        """Test expectation."""
        qubits = cirq.GridQubit.rect(1, N_QUBITS)
        circuit_batch, resolver_batch = _get_mixed_batch(
            qubits + [cirq.GridQubit(9, 9)], SYMBOLS, BATCH_SIZE)
        ops = util.random_pauli_sums(qubits, PAULI_LENGTH, BATCH_SIZE)

        results = batch_util.batch_calculate_expectation(
            circuit_batch, resolver_batch, [[x] for x in ops], sim)

        for circuit, resolver, result, op in zip(circuit_batch, resolver_batch,
                                                 results, ops):
            r = _expectation_helper(sim, circuit, resolver, op)
            self.assertAllClose(r, result, rtol=1e-5, atol=1e-5)

        self.assertDTypeEqual(results, np.float32)
    def test_approx_equality_shallow(self, diff_and_tol, op, n_qubits,
                                     symbol_names, n_ops, n_programs,
                                     num_samples):
        """Test small circuits with limited depth."""
        differentiator, tol = diff_and_tol
        differentiator.refresh()
        op = differentiator.generate_differentiable_op(sampled_op=op)

        qubits = cirq.GridQubit.rect(1, n_qubits)
        circuit_batch, resolver_batch = \
            util.random_symbol_circuit_resolver_batch(
                cirq.GridQubit.rect(1, n_qubits), symbol_names, n_programs)

        # Prepare random pauli sums and add initial superposition gates.
        psums = []
        for i in range(len(circuit_batch)):
            psums.append(util.random_pauli_sums(qubits, 1, n_ops))
            circuit_batch[i] = cirq.Circuit(
                cirq.H.on_each(qubits)) + circuit_batch[i]

        symbol_values_array = np.array(
            [[resolver[symbol]
              for symbol in symbol_names]
             for resolver in resolver_batch],
            dtype=np.float32)

        # calculate tfq gradient
        symbol_values_tensor = tf.convert_to_tensor(symbol_values_array)
        programs = util.convert_to_tensor(circuit_batch)
        ops = util.convert_to_tensor(psums)
        with tf.GradientTape() as g:
            g.watch(symbol_values_tensor)
            expectations = op(
                programs, tf.convert_to_tensor(symbol_names),
                symbol_values_tensor, ops,
                tf.convert_to_tensor([[num_samples] * n_ops] * n_programs))
        tfq_grads = g.gradient(expectations, symbol_values_tensor)

        # calculate gradients in cirq using a very simple forward differencing
        # scheme
        cirq_grads = _cirq_simple_finite_difference(circuit_batch,
                                                    resolver_batch,
                                                    symbol_names, psums)

        self.assertAllClose(cirq_grads, tfq_grads, rtol=tol, atol=tol)
    def test_gradients_vs_cirq_finite_difference(self, differentiator, op,
                                                 n_qubits, n_programs, n_ops,
                                                 symbol_names):
        """Compare TFQ differentiators to fine-grained noiseless cirq finite
        differencing.
        """
        differentiator.refresh()
        op = differentiator.generate_differentiable_op(analytic_op=op)

        qubits = cirq.GridQubit.rect(1, n_qubits)
        circuit_batch, resolver_batch = \
            util.random_symbol_circuit_resolver_batch(
                cirq.GridQubit.rect(1, n_qubits), symbol_names, n_programs)

        psums = [
            util.random_pauli_sums(qubits, 1, n_ops) for _ in circuit_batch
        ]

        symbol_values_array = np.array(
            [[resolver[symbol]
              for symbol in symbol_names]
             for resolver in resolver_batch],
            dtype=np.float32)

        # calculate tfq gradient
        symbol_values_tensor = tf.convert_to_tensor(symbol_values_array)
        programs = util.convert_to_tensor(circuit_batch)
        ops = util.convert_to_tensor(psums)
        with tf.GradientTape() as g:
            g.watch(symbol_values_tensor)
            expectations = op(programs, tf.convert_to_tensor(symbol_names),
                              symbol_values_tensor, ops)
        tfq_grads = g.gradient(expectations, symbol_values_tensor)

        # calculate gradients in cirq using a very simple forward differencing
        # scheme
        cirq_grads = _cirq_simple_finite_difference(circuit_batch,
                                                    resolver_batch,
                                                    symbol_names, psums)

        # will this be too tight? time will tell.
        self.assertAllClose(cirq_grads, tfq_grads, rtol=2e-2, atol=2e-2)
Exemple #13
0
    def test_symbol_values_type(self, symbol_type):
        """Tests all three ops for the different types. """
        qubit = cirq.GridQubit(0, 0)
        circuits = util.convert_to_tensor([cirq.Circuit(cirq.H(qubit))])
        symbol_names = ['symbol']
        symbol_values = tf.convert_to_tensor([[1]], dtype=symbol_type)
        pauli_sums = util.random_pauli_sums([qubit], 3, 1)
        pauli_sums = util.convert_to_tensor([[x] for x in pauli_sums])

        result = tfq_simulate_ops.tfq_simulate_state(circuits, symbol_names,
                                                     symbol_values)
        self.assertDTypeEqual(result, np.complex64)

        result = tfq_simulate_ops.tfq_simulate_expectation(
            circuits, symbol_names, symbol_values, pauli_sums)
        self.assertDTypeEqual(result, np.float32)

        result = tfq_simulate_ops.tfq_simulate_samples(circuits, symbol_names,
                                                       symbol_values, [100])
        self.assertDTypeEqual(result, np.int8)
Exemple #14
0
    def test_noisy_expectation_inputs(self):
        """Make sure noisy expectation op fails gracefully on bad inputs."""
        n_qubits = 5
        batch_size = 5
        symbol_names = ['alpha']
        qubits = cirq.GridQubit.rect(1, n_qubits)
        circuit_batch, resolver_batch = \
            util.random_symbol_circuit_resolver_batch(
                qubits, symbol_names, batch_size, include_channels=True)

        symbol_values_array = np.array(
            [[resolver[symbol] for symbol in symbol_names]
             for resolver in resolver_batch])

        pauli_sums = util.random_pauli_sums(qubits, 3, batch_size)
        num_samples = [[10]] * batch_size

        with self.assertRaisesRegex(tf.errors.InvalidArgumentError,
                                    'programs must be rank 1'):
            # Circuit tensor has too many dimensions.
            noisy_sampled_expectation_op.sampled_expectation(
                util.convert_to_tensor([circuit_batch]), symbol_names,
                symbol_values_array,
                util.convert_to_tensor([[x] for x in pauli_sums]), num_samples)

        with self.assertRaisesRegex(tf.errors.InvalidArgumentError,
                                    'symbol_names must be rank 1.'):
            # symbol_names tensor has too many dimensions.
            noisy_sampled_expectation_op.sampled_expectation(
                util.convert_to_tensor(circuit_batch),
                np.array([symbol_names]), symbol_values_array,
                util.convert_to_tensor([[x] for x in pauli_sums]), num_samples)

        with self.assertRaisesRegex(tf.errors.InvalidArgumentError,
                                    'symbol_values must be rank 2.'):
            # symbol_values_array tensor has too many dimensions.
            noisy_sampled_expectation_op.sampled_expectation(
                util.convert_to_tensor(circuit_batch), symbol_names,
                np.array([symbol_values_array]),
                util.convert_to_tensor([[x] for x in pauli_sums]), num_samples)

        with self.assertRaisesRegex(tf.errors.InvalidArgumentError,
                                    'symbol_values must be rank 2.'):
            # symbol_values_array tensor has too few dimensions.
            noisy_sampled_expectation_op.sampled_expectation(
                util.convert_to_tensor(circuit_batch), symbol_names,
                symbol_values_array[0],
                util.convert_to_tensor([[x] for x in pauli_sums]), num_samples)

        with self.assertRaisesRegex(tf.errors.InvalidArgumentError,
                                    'pauli_sums must be rank 2.'):
            # pauli_sums tensor has too few dimensions.
            noisy_sampled_expectation_op.sampled_expectation(
                util.convert_to_tensor(circuit_batch),
                symbol_names, symbol_values_array,
                util.convert_to_tensor(list(pauli_sums)), num_samples)

        with self.assertRaisesRegex(tf.errors.InvalidArgumentError,
                                    'pauli_sums must be rank 2.'):
            # pauli_sums tensor has too many dimensions.
            noisy_sampled_expectation_op.sampled_expectation(
                util.convert_to_tensor(circuit_batch), symbol_names,
                symbol_values_array,
                [util.convert_to_tensor([[x]
                                         for x in pauli_sums])], num_samples)

        with self.assertRaisesRegex(tf.errors.InvalidArgumentError,
                                    'num_samples must be rank 2'):
            # num_samples tensor has the wrong shape.
            noisy_sampled_expectation_op.sampled_expectation(
                util.convert_to_tensor(circuit_batch), symbol_names,
                symbol_values_array,
                util.convert_to_tensor([[x] for x in pauli_sums]),
                [num_samples])

        with self.assertRaisesRegex(tf.errors.InvalidArgumentError,
                                    'num_samples must be rank 2'):
            # num_samples tensor has the wrong shape.
            noisy_sampled_expectation_op.sampled_expectation(
                util.convert_to_tensor(circuit_batch), symbol_names,
                symbol_values_array,
                util.convert_to_tensor([[x] for x in pauli_sums]),
                num_samples[0])

        with self.assertRaisesRegex(tf.errors.InvalidArgumentError,
                                    'Unparseable proto'):
            # circuit tensor has the right type but invalid values.
            noisy_sampled_expectation_op.sampled_expectation(
                ['junk'] * batch_size, symbol_names, symbol_values_array,
                util.convert_to_tensor([[x] for x in pauli_sums]), num_samples)

        with self.assertRaisesRegex(tf.errors.InvalidArgumentError,
                                    'Could not find symbol in parameter map'):
            # symbol_names tensor has the right type but invalid values.
            noisy_sampled_expectation_op.sampled_expectation(
                util.convert_to_tensor(circuit_batch), ['junk'],
                symbol_values_array,
                util.convert_to_tensor([[x] for x in pauli_sums]), num_samples)

        with self.assertRaisesRegex(tf.errors.InvalidArgumentError,
                                    'qubits not found in circuit'):
            # pauli_sums tensor has the right type but invalid values.
            new_qubits = [cirq.GridQubit(5, 5), cirq.GridQubit(9, 9)]
            new_pauli_sums = util.random_pauli_sums(new_qubits, 2, batch_size)
            noisy_sampled_expectation_op.sampled_expectation(
                util.convert_to_tensor(circuit_batch), symbol_names,
                symbol_values_array,
                util.convert_to_tensor([[x] for x in new_pauli_sums]),
                num_samples)

        with self.assertRaisesRegex(tf.errors.InvalidArgumentError,
                                    'Unparseable proto'):
            # pauli_sums tensor has the right type but invalid values 2.
            noisy_sampled_expectation_op.sampled_expectation(
                util.convert_to_tensor(circuit_batch), symbol_names,
                symbol_values_array, [['junk']] * batch_size, num_samples)

        with self.assertRaisesRegex(TypeError, 'Cannot convert'):
            # circuits tensor has the wrong type.
            noisy_sampled_expectation_op.sampled_expectation(
                [1.0] * batch_size, symbol_names, symbol_values_array,
                util.convert_to_tensor([[x] for x in pauli_sums]), num_samples)

        with self.assertRaisesRegex(TypeError, 'Cannot convert'):
            # symbol_names tensor has the wrong type.
            noisy_sampled_expectation_op.sampled_expectation(
                util.convert_to_tensor(circuit_batch), [0.1234],
                symbol_values_array,
                util.convert_to_tensor([[x] for x in pauli_sums]), num_samples)

        with self.assertRaisesRegex(tf.errors.UnimplementedError, ''):
            # symbol_values tensor has the wrong type.
            noisy_sampled_expectation_op.sampled_expectation(
                util.convert_to_tensor(circuit_batch), symbol_names,
                [['junk']] * batch_size,
                util.convert_to_tensor([[x] for x in pauli_sums]), num_samples)

        with self.assertRaisesRegex(TypeError, 'Cannot convert'):
            # pauli_sums tensor has the wrong type.
            noisy_sampled_expectation_op.sampled_expectation(
                util.convert_to_tensor(circuit_batch), symbol_names,
                symbol_values_array, [[1.0]] * batch_size, num_samples)

        with self.assertRaisesRegex(TypeError, 'missing'):
            # we are missing an argument.
            # pylint: disable=no-value-for-parameter
            noisy_sampled_expectation_op.sampled_expectation(
                util.convert_to_tensor(circuit_batch), symbol_names,
                symbol_values_array, num_samples)
            # pylint: enable=no-value-for-parameter

        with self.assertRaisesRegex(TypeError, 'positional arguments'):
            # pylint: disable=too-many-function-args
            noisy_sampled_expectation_op.sampled_expectation(
                util.convert_to_tensor(circuit_batch), symbol_names,
                symbol_values_array,
                util.convert_to_tensor([[x] for x in pauli_sums]), [],
                num_samples)
            # pylint: enable=too-many-function-args

        with self.assertRaisesRegex(tf.errors.InvalidArgumentError,
                                    expected_regex='do not match'):
            # wrong op size.
            noisy_sampled_expectation_op.sampled_expectation(
                util.convert_to_tensor([cirq.Circuit()]), symbol_names,
                symbol_values_array.astype(np.float64),
                util.convert_to_tensor([[x] for x in pauli_sums]), num_samples)

        with self.assertRaisesRegex(tf.errors.InvalidArgumentError,
                                    'greater than 0'):
            # pylint: disable=too-many-function-args
            noisy_sampled_expectation_op.sampled_expectation(
                util.convert_to_tensor(circuit_batch), symbol_names,
                symbol_values_array,
                util.convert_to_tensor([[x] for x in pauli_sums]),
                [[-1]] * batch_size)
            # pylint: enable=too-many-function-args

        with self.assertRaisesRegex(tf.errors.InvalidArgumentError,
                                    expected_regex='do not match'):
            # wrong symbol_values size.
            noisy_sampled_expectation_op.sampled_expectation(
                util.convert_to_tensor(circuit_batch), symbol_names,
                symbol_values_array[:int(batch_size * 0.5)],
                util.convert_to_tensor([[x] for x in pauli_sums]), num_samples)
Exemple #15
0
    def gradients_vs_cirq_finite_difference(self, differentiator, op, n_qubits,
                                            n_programs, n_ops, symbol_names,
                                            stochastic_cost_eps):
        """Compare TFQ differentiators to fine-grained noiseless cirq finite
        differencing with a larger margin of error."""

        # TODO (jaeyoo): cleanup this hacky wordkaround so variable
        #   assignment doesn't need to take place like this.
        differentiator.stochastic_cost, eps = stochastic_cost_eps
        differentiator.refresh()
        op = differentiator.generate_differentiable_op(analytic_op=op)

        qubits = cirq.GridQubit.rect(1, n_qubits)
        circuit_batch, resolver_batch = \
            util.random_symbol_circuit_resolver_batch(
                cirq.GridQubit.rect(1, n_qubits), symbol_names, n_programs)

        psums = [
            util.random_pauli_sums(qubits, 1, n_ops) for _ in circuit_batch
        ]

        symbol_values_array = np.array(
            [[resolver[symbol] for symbol in symbol_names]
             for resolver in resolver_batch],
            dtype=np.float32)

        # calculate tfq gradient
        symbol_values_tensor = tf.convert_to_tensor(symbol_values_array)
        programs = util.convert_to_tensor(circuit_batch)
        ops = util.convert_to_tensor(psums)

        # calculate gradients in cirq using a very simple forward differencing
        # scheme
        cirq_grads = _cirq_simple_finite_difference(circuit_batch,
                                                    resolver_batch,
                                                    symbol_names, psums)

        def _get_gradient():
            with tf.GradientTape() as g:
                g.watch(symbol_values_tensor)
                expectations = op(programs, tf.convert_to_tesor(symbol_names),
                                  symbol_values_tensor, ops)
            return g.gradient(expectations, symbol_values_tensor)

        def _abs_diff(grad, mask):
            return np.sum(np.abs(grad - cirq_grads * mask))

        def _get_nonzero_mask(grad):
            return (grad.numpy() != 0.0).astype(np.float32)

        # Get the non-zero mask because a few initial gradients have not sampled
        # zero values.
        tfq_grads_1 = _get_gradient()
        mask_1 = _get_nonzero_mask(tfq_grads_1)

        if not np.allclose(tfq_grads_1, cirq_grads * mask_1, atol=eps):
            tfq_grads_2 = 0.5 * (tfq_grads_1 + _get_gradient())
            mask_2 = _get_nonzero_mask(tfq_grads_2)
            # Check if the 2nd error becomes smaller that 1st one.
            if not _abs_diff(tfq_grads_1, mask_1) > _abs_diff(
                    tfq_grads_2, mask_2):
                cnt = 2
                tfq_grads = (cnt * tfq_grads_2 + _get_gradient()) / (cnt + 1)
                while (cnt < 10
                       and not np.allclose(cirq_grads, tfq_grads, atol=eps)):
                    cnt += 1
                    tfq_grads = (cnt * tfq_grads + _get_gradient()) / (cnt + 1)
                self.assertAllClose(cirq_grads, tfq_grads, atol=eps)
Exemple #16
0
    def test_simulate_expectation_inputs(self):
        """Make sure the the expectation op fails gracefully on bad inputs."""
        n_qubits = 5
        batch_size = 5
        symbol_names = ['alpha']
        qubits = cirq.GridQubit.rect(1, n_qubits)
        circuit_batch, resolver_batch = \
            util.random_symbol_circuit_resolver_batch(
                qubits, symbol_names, batch_size)

        symbol_values_array = np.array(
            [[resolver[symbol] for symbol in symbol_names]
             for resolver in resolver_batch])

        pauli_sums = util.random_pauli_sums(qubits, 3, batch_size)

        with self.assertRaisesRegex(tf.errors.InvalidArgumentError,
                                    'programs must be rank 1'):
            # Circuit tensor has too many dimensions.
            tfq_simulate_ops.tfq_simulate_expectation(
                util.convert_to_tensor([circuit_batch]), symbol_names,
                symbol_values_array,
                util.convert_to_tensor([[x] for x in pauli_sums]))

        with self.assertRaisesRegex(tf.errors.InvalidArgumentError,
                                    'symbol_names must be rank 1.'):
            # symbol_names tensor has too many dimensions.
            tfq_simulate_ops.tfq_simulate_expectation(
                util.convert_to_tensor(circuit_batch),
                np.array([symbol_names]), symbol_values_array,
                util.convert_to_tensor([[x] for x in pauli_sums]))

        with self.assertRaisesRegex(tf.errors.InvalidArgumentError,
                                    'symbol_values must be rank 2.'):
            # symbol_values_array tensor has too many dimensions.
            tfq_simulate_ops.tfq_simulate_expectation(
                util.convert_to_tensor(circuit_batch), symbol_names,
                np.array([symbol_values_array]),
                util.convert_to_tensor([[x] for x in pauli_sums]))

        with self.assertRaisesRegex(tf.errors.InvalidArgumentError,
                                    'symbol_values must be rank 2.'):
            # symbol_values_array tensor has too few dimensions.
            tfq_simulate_ops.tfq_simulate_expectation(
                util.convert_to_tensor(circuit_batch), symbol_names,
                symbol_values_array[0],
                util.convert_to_tensor([[x] for x in pauli_sums]))

        with self.assertRaisesRegex(tf.errors.InvalidArgumentError,
                                    'pauli_sums must be rank 2.'):
            # pauli_sums tensor has too few dimensions.
            tfq_simulate_ops.tfq_simulate_expectation(
                util.convert_to_tensor(circuit_batch), symbol_names,
                symbol_values_array,
                util.convert_to_tensor([x for x in pauli_sums]))

        with self.assertRaisesRegex(tf.errors.InvalidArgumentError,
                                    'pauli_sums must be rank 2.'):
            # pauli_sums tensor has too many dimensions.
            tfq_simulate_ops.tfq_simulate_expectation(
                util.convert_to_tensor(circuit_batch), symbol_names,
                symbol_values_array,
                util.convert_to_tensor([[[x]] for x in pauli_sums]))

        with self.assertRaisesRegex(tf.errors.InvalidArgumentError,
                                    'Unparseable proto'):
            # circuit tensor has the right type but invalid values.
            tfq_simulate_ops.tfq_simulate_expectation(
                ['junk'] * batch_size, symbol_names, symbol_values_array,
                util.convert_to_tensor([[x] for x in pauli_sums]))

        with self.assertRaisesRegex(tf.errors.InvalidArgumentError,
                                    'Could not find symbol in parameter map'):
            # symbol_names tensor has the right type but invalid values.
            tfq_simulate_ops.tfq_simulate_expectation(
                util.convert_to_tensor(circuit_batch), ['junk'],
                symbol_values_array,
                util.convert_to_tensor([[x] for x in pauli_sums]))

        with self.assertRaisesRegex(tf.errors.InvalidArgumentError,
                                    'qubits not found in circuit'):
            # pauli_sums tensor has the right type but invalid values.
            new_qubits = [cirq.GridQubit(5, 5), cirq.GridQubit(9, 9)]
            new_pauli_sums = util.random_pauli_sums(new_qubits, 2, batch_size)
            tfq_simulate_ops.tfq_simulate_expectation(
                util.convert_to_tensor(circuit_batch), symbol_names,
                symbol_values_array,
                util.convert_to_tensor([[x] for x in new_pauli_sums]))

        with self.assertRaisesRegex(tf.errors.InvalidArgumentError,
                                    'Unparseable proto'):
            # pauli_sums tensor has the right type but invalid values 2.
            tfq_simulate_ops.tfq_simulate_expectation(
                util.convert_to_tensor(circuit_batch), symbol_names,
                symbol_values_array, [['junk']] * batch_size)

        with self.assertRaisesRegex(TypeError, 'Cannot convert'):
            # circuits tensor has the wrong type.
            tfq_simulate_ops.tfq_simulate_expectation(
                [1.0] * batch_size, symbol_names, symbol_values_array,
                util.convert_to_tensor([[x] for x in pauli_sums]))

        with self.assertRaisesRegex(TypeError, 'Cannot convert'):
            # symbol_names tensor has the wrong type.
            tfq_simulate_ops.tfq_simulate_expectation(
                util.convert_to_tensor(circuit_batch), [0.1234],
                symbol_values_array,
                util.convert_to_tensor([[x] for x in pauli_sums]))

        with self.assertRaisesRegex(tf.errors.UnimplementedError, ''):
            # symbol_values tensor has the wrong type.
            tfq_simulate_ops.tfq_simulate_expectation(
                util.convert_to_tensor(circuit_batch), symbol_names,
                [['junk']] * batch_size,
                util.convert_to_tensor([[x] for x in pauli_sums]))

        with self.assertRaisesRegex(TypeError, 'Cannot convert'):
            # pauli_sums tensor has the wrong type.
            tfq_simulate_ops.tfq_simulate_expectation(
                util.convert_to_tensor(circuit_batch), symbol_names,
                symbol_values_array, [[1.0]] * batch_size)

        with self.assertRaisesRegex(TypeError, 'missing'):
            # we are missing an argument.
            # pylint: disable=no-value-for-parameter
            tfq_simulate_ops.tfq_simulate_expectation(
                util.convert_to_tensor(circuit_batch), symbol_names,
                symbol_values_array)
            # pylint: enable=no-value-for-parameter

        with self.assertRaisesRegex(TypeError, 'positional arguments'):
            # pylint: disable=too-many-function-args
            tfq_simulate_ops.tfq_simulate_expectation(
                util.convert_to_tensor(circuit_batch), symbol_names,
                symbol_values_array,
                util.convert_to_tensor([[x] for x in pauli_sums]), [])

        with self.assertRaisesRegex(tf.errors.InvalidArgumentError,
                                    expected_regex='do not match'):
            # wrong op size.
            tfq_simulate_ops.tfq_simulate_expectation(
                util.convert_to_tensor([cirq.Circuit()]), symbol_names,
                symbol_values_array.astype(np.float64),
                util.convert_to_tensor([[x] for x in pauli_sums]))

        res = tfq_simulate_ops.tfq_simulate_expectation(
            util.convert_to_tensor([cirq.Circuit() for _ in pauli_sums]),
            symbol_names, symbol_values_array.astype(np.float64),
            util.convert_to_tensor([[x] for x in pauli_sums]))
        self.assertDTypeEqual(res, np.float32)
    def test_adj_grad_inputs(self):
        """Make sure that the expectation op fails gracefully on bad inputs."""
        n_qubits = 5
        batch_size = 5
        symbol_names = ['alpha']
        qubits = cirq.GridQubit.rect(1, n_qubits)
        circuit_batch, resolver_batch = \
            util.random_symbol_circuit_resolver_batch(
                qubits, symbol_names, batch_size)

        symbol_values_array = np.array(
            [[resolver[symbol] for symbol in symbol_names]
             for resolver in resolver_batch])

        pauli_sums = util.random_pauli_sums(qubits, 3, batch_size)
        upstream_grads = np.ones((batch_size, len(symbol_names)))

        with self.assertRaisesRegex(tf.errors.InvalidArgumentError,
                                    'programs must be rank 1'):
            # Circuit tensor has too many dimensions.
            tfq_adj_grad_op.tfq_adj_grad(
                util.convert_to_tensor([circuit_batch]), symbol_names,
                tf.convert_to_tensor(symbol_values_array),
                util.convert_to_tensor([[x] for x in pauli_sums]),
                tf.convert_to_tensor(upstream_grads))

        with self.assertRaisesRegex(tf.errors.InvalidArgumentError,
                                    'symbol_names must be rank 1.'):
            # symbol_names tensor has too many dimensions.
            tfq_adj_grad_op.tfq_adj_grad(
                util.convert_to_tensor(circuit_batch),
                np.array([symbol_names]),
                tf.convert_to_tensor(symbol_values_array),
                util.convert_to_tensor([[x] for x in pauli_sums]),
                tf.convert_to_tensor(upstream_grads))

        with self.assertRaisesRegex(tf.errors.InvalidArgumentError,
                                    'symbol_values must be rank 2.'):
            # symbol_values_array tensor has too many dimensions.
            tfq_adj_grad_op.tfq_adj_grad(
                util.convert_to_tensor(circuit_batch), symbol_names,
                tf.convert_to_tensor(np.array([symbol_values_array])),
                util.convert_to_tensor([[x] for x in pauli_sums]),
                tf.convert_to_tensor(upstream_grads))

        with self.assertRaisesRegex(tf.errors.InvalidArgumentError,
                                    'symbol_values must be rank 2.'):
            # symbol_values_array tensor has too few dimensions.
            tfq_adj_grad_op.tfq_adj_grad(
                util.convert_to_tensor(circuit_batch), symbol_names,
                tf.convert_to_tensor(symbol_values_array[0]),
                util.convert_to_tensor([[x] for x in pauli_sums]),
                tf.convert_to_tensor(upstream_grads))

        with self.assertRaisesRegex(tf.errors.InvalidArgumentError,
                                    'pauli_sums must be rank 2.'):
            # pauli_sums tensor has too few dimensions.
            tfq_adj_grad_op.tfq_adj_grad(
                util.convert_to_tensor(circuit_batch), symbol_names,
                tf.convert_to_tensor(symbol_values_array),
                util.convert_to_tensor([x for x in pauli_sums]),
                tf.convert_to_tensor(upstream_grads))

        with self.assertRaisesRegex(tf.errors.InvalidArgumentError,
                                    'pauli_sums must be rank 2.'):
            # pauli_sums tensor has too many dimensions.
            tfq_adj_grad_op.tfq_adj_grad(
                util.convert_to_tensor(circuit_batch), symbol_names,
                tf.convert_to_tensor(symbol_values_array),
                util.convert_to_tensor([[[x]] for x in pauli_sums]),
                tf.convert_to_tensor(upstream_grads))

        with self.assertRaisesRegex(tf.errors.InvalidArgumentError,
                                    'Unparseable proto'):
            # circuit tensor has the right type but invalid values.
            tfq_adj_grad_op.tfq_adj_grad(
                ['junk'] * batch_size, symbol_names,
                tf.convert_to_tensor(symbol_values_array),
                util.convert_to_tensor([[x] for x in pauli_sums]),
                tf.convert_to_tensor(upstream_grads))

        with self.assertRaisesRegex(tf.errors.InvalidArgumentError,
                                    'Could not find symbol in parameter map'):
            # symbol_names tensor has the right type but invalid values.
            tfq_adj_grad_op.tfq_adj_grad(
                util.convert_to_tensor(circuit_batch), ['junk'],
                tf.convert_to_tensor(symbol_values_array),
                util.convert_to_tensor([[x] for x in pauli_sums]),
                tf.convert_to_tensor(upstream_grads))

        with self.assertRaisesRegex(tf.errors.InvalidArgumentError,
                                    'qubits not found in circuit'):
            # pauli_sums tensor has the right type but invalid values.
            new_qubits = [cirq.GridQubit(5, 5), cirq.GridQubit(9, 9)]
            new_pauli_sums = util.random_pauli_sums(new_qubits, 2, batch_size)
            tfq_adj_grad_op.tfq_adj_grad(
                util.convert_to_tensor(circuit_batch), symbol_names,
                tf.convert_to_tensor(symbol_values_array),
                util.convert_to_tensor([[x] for x in new_pauli_sums]),
                tf.convert_to_tensor(upstream_grads))

        with self.assertRaisesRegex(tf.errors.InvalidArgumentError,
                                    'Unparseable proto'):
            # pauli_sums tensor has the right type but invalid values 2.
            tfq_adj_grad_op.tfq_adj_grad(
                util.convert_to_tensor(circuit_batch), symbol_names,
                tf.convert_to_tensor(symbol_values_array),
                [['junk']] * batch_size, tf.convert_to_tensor(upstream_grads))

        with self.assertRaisesRegex(TypeError, 'Cannot convert'):
            # circuits tensor has the wrong type.
            tfq_adj_grad_op.tfq_adj_grad(
                [1.0] * batch_size, symbol_names,
                tf.convert_to_tensor(symbol_values_array),
                util.convert_to_tensor([[x] for x in pauli_sums]),
                tf.convert_to_tensor(upstream_grads))

        with self.assertRaisesRegex(TypeError, 'Cannot convert'):
            # symbol_names tensor has the wrong type.
            tfq_adj_grad_op.tfq_adj_grad(
                util.convert_to_tensor(circuit_batch), [0.1234],
                tf.convert_to_tensor(symbol_values_array),
                util.convert_to_tensor([[x] for x in pauli_sums]),
                tf.convert_to_tensor(upstream_grads))

        with self.assertRaisesRegex(tf.errors.UnimplementedError, ''):
            # symbol_values tensor has the wrong type.
            tfq_adj_grad_op.tfq_adj_grad(
                util.convert_to_tensor(circuit_batch), symbol_names,
                [['junk']] * batch_size,
                util.convert_to_tensor([[x] for x in pauli_sums]),
                tf.convert_to_tensor(upstream_grads))

        with self.assertRaisesRegex(TypeError, 'Cannot convert'):
            # pauli_sums tensor has the wrong type.
            tfq_adj_grad_op.tfq_adj_grad(
                util.convert_to_tensor(circuit_batch), symbol_names,
                tf.convert_to_tensor(symbol_values_array),
                [[1.0]] * batch_size, tf.convert_to_tensor(upstream_grads))

        with self.assertRaisesRegex(TypeError, 'missing'):
            # we are missing an argument.
            # pylint: disable=no-value-for-parameter
            tfq_adj_grad_op.tfq_adj_grad(
                util.convert_to_tensor(circuit_batch), symbol_names,
                tf.convert_to_tensor(symbol_values_array),
                tf.convert_to_tensor(upstream_grads))
            # pylint: enable=no-value-for-parameter

        with self.assertRaisesRegex(TypeError, 'positional arguments'):
            # pylint: disable=too-many-function-args
            tfq_adj_grad_op.tfq_adj_grad(
                util.convert_to_tensor(circuit_batch), symbol_names,
                tf.convert_to_tensor(symbol_values_array),
                util.convert_to_tensor([[x] for x in pauli_sums]),
                tf.convert_to_tensor(upstream_grads), [])

        with self.assertRaisesRegex(tf.errors.InvalidArgumentError,
                                    expected_regex='do not match'):
            # wrong op size.
            tfq_adj_grad_op.tfq_adj_grad(
                util.convert_to_tensor([cirq.Circuit()]), symbol_names,
                symbol_values_array.astype(np.float64),
                util.convert_to_tensor([[x] for x in pauli_sums]),
                tf.convert_to_tensor(upstream_grads))

        with self.assertRaisesRegex(tf.errors.InvalidArgumentError,
                                    expected_regex='rank 2'):
            # wrong grad shape.
            tfq_adj_grad_op.tfq_adj_grad(
                util.convert_to_tensor(circuit_batch), symbol_names,
                tf.convert_to_tensor(symbol_values_array),
                util.convert_to_tensor([[x] for x in pauli_sums]),
                tf.convert_to_tensor([upstream_grads]))

        with self.assertRaisesRegex(
                tf.errors.InvalidArgumentError,
                expected_regex='gradients and circuits do not match'):
            # wrong grad batch size.
            tfq_adj_grad_op.tfq_adj_grad(
                util.convert_to_tensor(circuit_batch), symbol_names,
                tf.convert_to_tensor(symbol_values_array),
                util.convert_to_tensor([[x] for x in pauli_sums]),
                tf.convert_to_tensor([[0 for i in range(len(symbol_names))]]))

        with self.assertRaisesRegex(
                tf.errors.InvalidArgumentError,
                expected_regex='gradients and pauli sum dimension do not match'
        ):
            # wrong grad inner size.
            tfq_adj_grad_op.tfq_adj_grad(
                util.convert_to_tensor(circuit_batch), symbol_names,
                tf.convert_to_tensor(symbol_values_array),
                util.convert_to_tensor([[x] for x in pauli_sums]),
                tf.convert_to_tensor([[0, 0]
                                      for _ in range(len(circuit_batch))]))

        with self.assertRaisesRegex(tf.errors.InvalidArgumentError,
                                    expected_regex='cirq.Channel'):
            # attempting to use noisy circuit.
            noisy_circuit = cirq.Circuit(cirq.depolarize(0.3).on_each(*qubits))
            tfq_adj_grad_op.tfq_adj_grad(
                util.convert_to_tensor([noisy_circuit for _ in circuit_batch]),
                symbol_names, tf.convert_to_tensor(symbol_values_array),
                util.convert_to_tensor([[x] for x in pauli_sums]),
                tf.convert_to_tensor(upstream_grads))
    def test_gradients_vs_cirq_finite_difference(self, differentiator_num_runs,
                                                 n_qubits, n_programs, n_ops,
                                                 symbol_names, eps):
        """Convergence tests on SGDifferentiator variants."""

        # TODO(trevormccrt): remove this once I build the user-facing op
        #  interface
        differentiator, num_runs = differentiator_num_runs
        differentiator.refresh()
        op = differentiator.generate_differentiable_op(
            analytic_op=tfq_simulate_ops.tfq_simulate_expectation)

        qubits = cirq.GridQubit.rect(1, n_qubits)
        circuit_batch, resolver_batch = \
            util.random_symbol_circuit_resolver_batch(
                cirq.GridQubit.rect(1, n_qubits), symbol_names, n_programs)

        psums = [
            util.random_pauli_sums(qubits, 1, n_ops) for _ in circuit_batch
        ]

        symbol_values_array = np.array(
            [[resolver[symbol] for symbol in symbol_names]
             for resolver in resolver_batch],
            dtype=np.float32)

        # calculate tfq gradient
        symbol_values_tensor = tf.convert_to_tensor(symbol_values_array)
        programs = util.convert_to_tensor(circuit_batch)
        ops = util.convert_to_tensor(psums)

        def _get_gradient():
            with tf.GradientTape() as g:
                g.watch(symbol_values_tensor)
                expectations = op(programs, symbol_names, symbol_values_tensor,
                                  ops)
            return tf.cast(g.gradient(expectations, symbol_values_tensor),
                           dtype=tf.float64)

        # warm-up & initialize tfq_grads.
        grads_sum = _get_gradient()
        tfq_grads = grads_sum

        # calculate gradients in cirq using a very simple forward differencing
        # scheme
        cirq_grads = _cirq_simple_finite_difference(circuit_batch,
                                                    resolver_batch,
                                                    symbol_names, psums)
        cnt = 1
        # Since self.assertAllClose() has more strict atol than that of
        # np.allclose(), it is required to set smaller value to np.allclose()
        total_time = 0
        while cnt < num_runs and (not np.allclose(
                tfq_grads, cirq_grads, atol=eps * 0.9)):
            cnt = cnt + 1
            s = time.time()
            grads_sum = grads_sum + _get_gradient()
            total_time += time.time() - s
            tfq_grads = grads_sum / cnt

        self.assertAllClose(cirq_grads, tfq_grads, atol=eps)
        print('Passed: count {}, total_time {} ({}sec/shot)'.format(
            cnt, total_time, total_time / cnt))