Пример #1
0
    def test_batch_sample_basic(self, sim):
        """Test sampling."""
        n_samples = 1
        n_qubits = 8
        qubits = cirq.GridQubit.rect(1, n_qubits)
        circuit = cirq.Circuit(*cirq.Z.on_each(*qubits[:n_qubits // 2]),
                               *cirq.X.on_each(*qubits[n_qubits // 2:]))

        test_results = batch_util.batch_sample([circuit],
                                               [cirq.ParamResolver({})],
                                               n_samples, sim)

        state = sim.simulate(circuit, cirq.ParamResolver({}))
        expected_results = _sample_helper(sim, state, len(qubits), n_samples)

        self.assertAllEqual(expected_results, test_results[0])
        self.assertDTypeEqual(test_results, np.int32)
    def test_sampling(self, op_and_sim, n_qubits, symbol_names):
        """Compare sampling with tfq ops and Cirq."""
        op = op_and_sim[0]
        sim = op_and_sim[1]
        qubits = cirq.GridQubit.rect(1, n_qubits)
        n_samples = int((2**n_qubits) * 1000)

        circuit_batch, resolver_batch = \
            util.random_symbol_circuit_resolver_batch(
                qubits, symbol_names, BATCH_SIZE, n_moments=30)
        for i in range(BATCH_SIZE):
            circuit_batch[i] += cirq.Circuit(
                *[cirq.H(qubit) for qubit in qubits])

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

        op_samples = np.array(
            op(util.convert_to_tensor(circuit_batch), symbol_names,
               symbol_values_array, [n_samples]).to_list())

        op_histograms = [
            np.histogram(
                sample.dot(1 << np.arange(sample.shape[-1] - 1, -1, -1)),
                range=(0, 2**len(qubits)),
                bins=2**len(qubits))[0] for sample in op_samples
        ]

        cirq_samples = batch_util.batch_sample(circuit_batch, resolver_batch,
                                               n_samples, sim)

        cirq_histograms = [
            np.histogram(
                sample.dot(1 << np.arange(sample.shape[-1] - 1, -1, -1)),
                range=(0, 2**len(qubits)),
                bins=2**len(qubits))[0] for sample in cirq_samples
        ]

        for a, b in zip(op_histograms, cirq_histograms):
            self.assertLess(stats.entropy(a + 1e-8, b + 1e-8), 0.005)
Пример #3
0
    def test_sampling_empty(self, op_and_sim, n_qubits, symbol_names):
        """Test empty circuits for sampling using cirq and tfq."""
        op = op_and_sim[0]
        sim = op_and_sim[1]
        qubits = cirq.GridQubit.rect(1, n_qubits)
        n_samples = int((2**n_qubits) * 1000)

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

        op_samples = np.array(
            op(util.convert_to_tensor(circuit_batch), symbol_names,
               symbol_values_array, [n_samples]).to_list())

        op_histograms = [
            np.histogram(
                sample.dot(1 << np.arange(sample.shape[-1] - 1, -1, -1)),
                range=(0, 2**len(qubits)),
                bins=2**len(qubits))[0] for sample in op_samples
        ]

        cirq_samples = batch_util.batch_sample(circuit_batch, resolver_batch,
                                               n_samples, sim)

        cirq_histograms = [
            np.histogram(
                sample.dot(1 << np.arange(sample.shape[-1] - 1, -1, -1)),
                range=(0, 2**len(qubits)),
                bins=2**len(qubits))[0] for sample in cirq_samples
        ]

        for a, b in zip(op_histograms, cirq_histograms):
            self.assertLess(stats.entropy(a + 1e-8, b + 1e-8), 0.005)
Пример #4
0
    def cirq_sample(programs, symbol_names, symbol_values, num_samples):
        """Draw samples from circuits.

        Draw samples from `circuits` where 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]]
        n_samples = [100]

        cirq_sample(programs, symbol_names, sybmol_values, n_samples)
        ```

        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
        draw 100 samples from the circuit.

        Note: In the case of circuits with varying size, all nonexistant
        samples for a particular circuit are padded with -2.

        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`.
            num_samples: `tf.Tensor` with one element indicating the number of
                samples to draw.

        Returns:
            `tf.Tensor` with shape
                [batch_size, num_samples, <# qubits in largest circuit>] that
                holds samples (as boolean values) for each circuit.
        """

        def _no_grad(grad):
            raise RuntimeError(
                'Differentiation through a sampling operation is not supported.'
            )

        _input_check_helper(programs, symbol_names, symbol_values)

        if not (int(tf.size(num_samples)) == 1):
            raise ValueError("num_samples tensor must have size 1")
        if not isinstance(num_samples.dtype.as_numpy_dtype(), numbers.Integral):
            raise TypeError("num_samples tensor must be of integer type")

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

        num_samples = int(num_samples.numpy())

        if isinstance(sampler, (cirq.Simulator, cirq.DensityMatrixSimulator)):
            # Only local simulators can be handled by batch_sample
            results = batch_util.batch_sample(programs, resolvers, num_samples,
                                              sampler)
            return np.array(results, dtype=np.int8), _no_grad

        # All other samplers need terminal measurement gates.
        programs = [
            p + cirq.Circuit(cirq.measure(*sorted(p.all_qubits()), key='tfq'))
            for p in programs
        ]
        max_n_qubits = max(len(p.all_qubits()) for p in programs)

        if isinstance(sampler, cirq.google.QuantumEngineSampler):
            # group samples from identical circuits to reduce communication
            # overhead. Have to keep track of the order in which things came
            # in to make sure the output is ordered correctly
            to_be_grouped = [
                (ser_prog.numpy(), resolver, index)
                for index, (
                    ser_prog,
                    resolver) in enumerate(zip(serialized_programs, resolvers))
            ]

            grouped = _group_tuples(to_be_grouped)

            # start all the necessary jobs
            results_mapping = {}
            for key, value in grouped.items():
                program = programs[value[0][1]]
                resolvers = [x[0] for x in value]
                orders = [x[1] for x in value]

                # sampler.run_sweep blocks until results are in, so go around it
                result = sampler._engine.run_sweep(
                    program=program,
                    params=resolvers,
                    repetitions=num_samples,
                    processor_ids=sampler._processor_ids,
                    gate_set=sampler._gate_set)
                results_mapping[result] = orders

            # get all results
            cirq_results = [None] * len(programs)
            for key, value in results_mapping.items():
                this_results = key.results()
                for result, index in zip(this_results, value):
                    cirq_results[index] = result

        else:
            # All other cirq.Samplers handled here.
            #TODO(zaqqwerty): replace with run_batch once Cirq #3148 is resolved
            cirq_results = []
            for p, r in zip(programs, resolvers):
                cirq_results.append(sampler.run(p, r, num_samples))

        results = []
        for r in cirq_results:
            results.append(
                tf.keras.preprocessing.sequence.pad_sequences(
                    r.measurements['tfq'],
                    maxlen=max_n_qubits,
                    dtype=np.int8,
                    value=-2,
                    padding='pre'))

        return np.array(results, dtype=np.int8), _no_grad