Beispiel #1
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)
Beispiel #2
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)
Beispiel #3
0
    def test_analytical_expectation(self, op_and_sim, n_qubits, symbol_names,
                                    max_paulisum_length):
        """Compute 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)

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

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

        self.assertAllClose(op_expectations.numpy().flatten(),
                            cirq_expectations.flatten(),
                            rtol=1e-5,
                            atol=1e-5)
Beispiel #4
0
    def test_analytical_expectation_empty(self, op_and_sim, n_qubits,
                                          symbol_names, max_paulisum_length):
        """Test empty circuits for analytical 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)

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

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

        self.assertAllClose(op_expectations.numpy().flatten(),
                            cirq_expectations.flatten(),
                            rtol=1e-5,
                            atol=1e-5)
Beispiel #5
0
    def test_no_circuit(self, sim):
        """Test functions with no circuits and empty arrays."""
        # (1) Test expectation
        results = batch_util.batch_calculate_expectation([], [], [[]], sim)
        self.assertDTypeEqual(results, np.float32)
        self.assertEqual(np.zeros(shape=(0, 0)).shape, results.shape)

        # (2) Test sampled_expectation
        results = batch_util.batch_calculate_sampled_expectation([], [], [[]],
                                                                 [[]], sim)
        self.assertDTypeEqual(results, np.float32)
        self.assertEqual(np.zeros(shape=(0, 0)).shape, results.shape)

        # (3) Test state
        results = batch_util.batch_calculate_state([], [], sim)
        self.assertDTypeEqual(results, np.complex64)
        if isinstance(sim, cirq.Simulator):
            self.assertEqual(np.zeros(shape=(0, 0)).shape, results.shape)
        else:
            self.assertEqual(np.zeros(shape=(0, 0, 0)).shape, results.shape)

        # (4) Test sampling
        results = batch_util.batch_sample([], [], [], sim)
        self.assertDTypeEqual(results, np.int8)
        self.assertEqual(np.zeros(shape=(0, 0, 0)).shape, results.shape)
Beispiel #6
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)
Beispiel #7
0
def _cirq_simple_finite_difference(circuit_batch,
                                   resolvers,
                                   symbol_names,
                                   op_batch,
                                   grid_spacing=0.0001):
    """A simple finite difference code that calculates the gradient of a
    batch of circuits using cirq."""
    simulator = cirq.sim.Simulator()

    init_vals = batch_util.batch_calculate_expectation(circuit_batch,
                                                       resolvers, op_batch,
                                                       simulator)
    grad_circuits = []
    grad_resolvers = []
    grad_pauli_sums = []
    for this_program, this_pauli_sums, this_resolver in \
        zip(circuit_batch, op_batch, resolvers):
        for symbol in symbol_names:
            perturbed_resolver = copy.deepcopy(this_resolver)
            perturbed_resolver.param_dict[symbol] += grid_spacing
            grad_circuits.append(this_program)
            grad_pauli_sums.append(this_pauli_sums)
            grad_resolvers.append(perturbed_resolver)

    # shape: [n_programs * len(symbol_names), n_pauli_sums]
    results = np.array(
        batch_util.batch_calculate_expectation(circuits=grad_circuits,
                                               param_resolvers=grad_resolvers,
                                               ops=grad_pauli_sums,
                                               simulator=simulator))

    # shape: [n_pauli_sums, n_programs, len(symbol_names)]
    gradient_generator = results.transpose().reshape(
        (len(op_batch[0]), len(circuit_batch), len(symbol_names)))

    # shape: [n_pauli_sums, n_programs, len(symbol_names)]
    forward_pass_vals = np.transpose(
        np.vstack([np.expand_dims(init_vals, axis=0)] * len(symbol_names)),
        (2, 1, 0))

    return np.sum(1 / grid_spacing * (gradient_generator - forward_pass_vals),
                  axis=0)
    def test_analytical_expectation_no_circuits(self, op_and_sim):
        """Test no circuits for states using cirq and tfq."""
        op = op_and_sim[0]
        sim = op_and_sim[1]

        circuit_batch = tf.raw_ops.Empty(shape=(0,), dtype=tf.string)
        empty_params = tf.raw_ops.Empty(shape=(0, 0), dtype=tf.float32)
        empty_ops = tf.raw_ops.Empty(shape=(0, 0), dtype=tf.string)

        op_exp = op(circuit_batch, [], empty_params, empty_ops).numpy()
        cirq_exp = batch_util.batch_calculate_expectation([], [], [[]], sim)
        self.assertEqual(op_exp.shape, cirq_exp.shape)
Beispiel #9
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)
Beispiel #10
0
    def cirq_analytical_expectation(programs, symbol_names, symbol_values,
                                    pauli_sums):
        """Calculate the expectation value of circuits wrt some operator(s).

        Calculate the expectation value for all the `cirq.PauliSum`s in
        `pauli_sums` on each `cirq.Circuit` in `programs`. Each circuit will
        have the values in `symbol_values` resolved into the symbols in the
        circuit (with the ordering defined by `symbol_names`).

        ```python

        symbol_names = ['a', 'b', 'c']
        programs = tfq.convert_to_tensor(
            [cirq.Circuit(H(q0) ** sympy.Symbol('a'),
                          X(q1) ** sympy.Symbol('b'),
                          Y(q2) ** sympy.Symbol('c'))]
        )

        symbol_values = [[3,2,1]]
        pauli_sums = tfq.convert_to_tensor(
            [1.5 * cirq.Z(q0) * cirq.Z(q1)]
        )

        cirq_analytical_expectation(
            programs, symbol_names, sybmol_values, pauli_sums)
        ```

        Would place the values of 3 into the Symbol labeled 'a', 2 into the
        symbol labeled 'b' and 1 into the symbol labeled 'c'. Then it would
        calculate the ZZ expectation on this circuit.

        Args:
            programs: `tf.Tensor` of strings with shape [batch_size] containing
                the string representations of the circuits to be executed.
            symbol_names: `tf.Tensor` of strings with shape [n_params], which
                is used to specify the order in which the values in
                `symbol_values` should be placed inside of the circuits in
                `programs`.
            symbol_values: `tf.Tensor` of real numbers with shape
                [batch_size, n_params] specifying parameter values to resolve
                into the circuits specified by programs, following the ordering
                dictated by `symbol_names`.
            pauli_sums: `tf.Tensor` of strings with shape [batch_size, n_ops]
                containing the string representation of the operators that will
                be used on all of the circuits in the expectation calculations.

        Returns:
            `tf.Tensor` with shape [batch_size, n_ops] that holds the
                expectation value for each circuit with each op applied to it
                (after resolving the corresponding parameters in).
        """
        _input_check_helper(programs, symbol_names, symbol_values)
        if not (pauli_sums.dtype == tf.dtypes.string):
            raise TypeError('pauli_sums tensor must be of type string.')
        if not (pauli_sums.shape[0] == programs.shape[0]):
            raise TypeError('pauli_sums tensor must have the same batch shape '
                            'as programs tensor.')

        programs, resolvers = _batch_deserialize_helper(programs, symbol_names,
                                                        symbol_values)

        sum_inputs = []
        for sub_list in pauli_sums.numpy():
            to_append = []
            for x in sub_list:
                obj = pauli_sum_pb2.PauliSum()
                obj.ParseFromString(x)
                to_append.append(serializer.deserialize_paulisum(obj))
            sum_inputs.append(to_append)

        expectations = batch_util.batch_calculate_expectation(
            programs, resolvers, sum_inputs, simulator)

        return expectations