def test_allowed_cases(self):
        """Ensure all allowed input combinations are upgraded correctly."""
        qubits = cirq.GridQubit.rect(1, 2)

        # Test all symbol-filled circuit configurations
        names_symbol_list = list(sympy.symbols("s0:2"))
        names_string_list = [str(s) for s in names_symbol_list]
        names_symbol_tuple = tuple(names_symbol_list)
        names_string_tuple = tuple(names_string_list)
        names_tensor = tf.convert_to_tensor(names_string_list,
                                            dtype=tf.dtypes.string)
        circuit_alone = cirq.Circuit(
            cirq.H(qubits[0])**names_symbol_list[0],
            cirq.X(qubits[1])**names_symbol_list[1])
        circuit_list = [circuit_alone for _ in range(3)]
        circuit_tuple = tuple(circuit_list)
        circuit_tensor = util.convert_to_tensor(circuit_list)
        values_list = [[1], [2], [3]]
        values_tuple = tuple(values_list)
        values_ndarray = np.array(values_list)
        values_tensor = tf.convert_to_tensor(values_list,
                                             dtype=tf.dtypes.float32)
        for names in [
                names_symbol_list, names_string_list, names_symbol_tuple,
                names_string_tuple, names_tensor
        ]:
            for circuit in [
                    circuit_alone, circuit_list, circuit_tuple, circuit_tensor
            ]:
                for values in [
                        values_list, values_tuple, values_ndarray, values_tensor
                ]:
                    circuit_test, names_test, values_test = \
                        input_checks.expand_circuits(circuit, names, values)
                    self.assertAllEqual(circuit_test, circuit_tensor)
                    self.assertAllEqual(names_test, names_tensor)
                    self.assertAllEqual(values_test, values_tensor)

        # Test the case of empty symbols
        names_tensor = tf.convert_to_tensor([], dtype=tf.dtypes.string)
        values_tensor = tf.convert_to_tensor([[]] * 3, dtype=tf.dtypes.float32)
        for circuit in [circuit_list, circuit_tuple, circuit_tensor]:
            circuit_test, names_test, values_test = \
                input_checks.expand_circuits(circuit)
            self.assertAllEqual(circuit_test, circuit_tensor)
            self.assertAllEqual(names_test, names_tensor)
            self.assertAllEqual(values_test, values_tensor)
Beispiel #2
0
    def call(self, inputs, *, symbol_names=None, symbol_values=None):
        """Keras call function.

        Input options:
            `inputs`, `symbol_names`, `symbol_values`:
                see `input_checks.expand_circuits`

        Output shape:
            `tf.RaggedTensor` with shape:
                [batch size of symbol_values, <size of state>]
                    or
                [number of circuits, <size of state>]
        """
        inputs, symbol_names, symbol_values = input_checks.expand_circuits(
            inputs, symbol_names, symbol_values)
        return self.state_op(inputs, symbol_names, symbol_values)
Beispiel #3
0
    def call(self,
             inputs,
             *,
             symbol_names=None,
             symbol_values=None,
             operators=None,
             initializer=tf.keras.initializers.RandomUniform(0, 2 * np.pi)):
        """Keras call function.

        Input options:
            `inputs`, `symbol_names`, `symbol_values`:
                see `input_checks.expand_circuits`
            `operators`: see `input_checks.expand_operators`

        Output shape:
            `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).
        """
        values_empty = False
        if symbol_values is None:
            values_empty = True

        inputs, symbol_names, symbol_values = input_checks.expand_circuits(
            inputs, symbol_names, symbol_values)

        circuit_batch_dim = tf.gather(tf.shape(inputs), 0)

        operators = input_checks.expand_operators(operators, circuit_batch_dim)

        if values_empty:
            # No symbol_values were provided. So we assume the user wants us
            # to create and manage variables for them. We will do so by
            # creating a weights variable and tiling it up to appropriate
            # size of [batch, num_symbols].

            if self._w is None:
                # don't re-add variable.
                self._w = self.add_weight(name='circuit_learnable_parameters',
                                          shape=symbol_names.shape,
                                          initializer=initializer)

            symbol_values = tf.tile(tf.expand_dims(self._w, axis=0),
                                    tf.stack([circuit_batch_dim, 1]))

        return self._expectation_op(inputs, symbol_names, symbol_values,
                                    operators)
Beispiel #4
0
    def call(self,
             inputs,
             *,
             symbol_names=None,
             symbol_values=None,
             initializer=tf.keras.initializers.RandomUniform(0, 2 * np.pi)):
        """Keras call function.
        Input options:
            `inputs`, `symbol_names`, `symbol_values`:
                see `input_checks.expand_circuits`
        Output shape:
            `tf.RaggedTensor` with shape:
                [batch size of symbol_values, <size of state>, <size of state>]
                    or
                [number of circuits, <size of state>, <size of state>]
        """

        values_empty = False
        if symbol_values is None:
            values_empty = True

        inputs, symbol_names, symbol_values = input_checks.expand_circuits(
            inputs, symbol_names, symbol_values)

        circuit_batch_dim = tf.gather(tf.shape(inputs), 0)

        if values_empty:
            # No symbol_values were provided. So we assume the user wants us
            # to create and manage variables for them. We will do so by
            # creating a weights variable and tiling it up to appropriate
            # size of [batch, num_symbols].

            if self._w is None:
                # don't re-add variable.
                self._w = self.add_weight(name='circuit_learnable_parameters',
                                          shape=symbol_names.shape,
                                          initializer=initializer)

            symbol_values = tf.tile(tf.expand_dims(self._w, axis=0),
                                    tf.stack([circuit_batch_dim, 1]))

        unitary = self.unitary_op(inputs, symbol_names, symbol_values)
        return unitary.to_tensor()
Beispiel #5
0
    def call(self,
             inputs,
             *,
             symbol_names=None,
             symbol_values=None,
             repetitions=None):
        """Keras call function.

        Input options:
            `inputs`, `symbol_names`, `symbol_values`:
                see `input_checks.expand_circuits`
            `repetitions`: a Python `int` or a pre-converted
                `tf.Tensor` containing a single `int` entry.

        Output shape:
            `tf.RaggedTensor` with shape:
                [batch size of symbol_values, repetitions, <ragged string size>]
                    or
                [number of circuits, repetitions, <ragged string size>]
        """
        if repetitions is None:
            raise ValueError("Number of repetitions not specified.")

        # Ingest and promote repetitions.
        if isinstance(repetitions, numbers.Integral):
            if not repetitions > 0:
                raise ValueError("Repetitions must be greater than zero.")
            repetitions = tf.convert_to_tensor([repetitions], dtype=tf.int32)

        if not tf.is_tensor(repetitions):
            raise TypeError("repetitions cannot be parsed to int32 tensor"
                            " tensor given input: ".format(repetitions))

        inputs, symbol_names, symbol_values = input_checks.expand_circuits(
            inputs, symbol_names, symbol_values)

        return self.sample_op(inputs, symbol_names, symbol_values, repetitions)
Beispiel #6
0
    def call(self,
             inputs,
             *,
             symbol_names=None,
             symbol_values=None,
             operators=None,
             repetitions=None,
             initializer=tf.keras.initializers.RandomUniform(0, 2 * np.pi)):
        """Keras call function.

        Input options:
            `inputs`, `symbol_names`, `symbol_values`:
                see `input_checks.expand_circuits`
            `operators`: see `input_checks.expand_operators`

        Output shape:
            `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).
        """
        values_empty = False
        if symbol_values is None:
            values_empty = True

        inputs, symbol_names, symbol_values = input_checks.expand_circuits(
            inputs, symbol_names, symbol_values)

        circuit_batch_dim = tf.gather(tf.shape(inputs), 0)

        operators = input_checks.expand_operators(operators, circuit_batch_dim)

        # Ingest and promote repetitions if using noisy backend.
        if not self.noisy and repetitions is not None:
            raise RuntimeError("repetitions value provided for analytic"
                               " expectation calculation that is noiseless.")

        if self.noisy:
            if repetitions is None:
                raise RuntimeError(
                    "Value for repetitions not provided."
                    " With backend=\'noisy\' a number of trajectory"
                    " repetitions must be provided in the layer"
                    " call method.")

            reps_need_tile = False
            if isinstance(repetitions, numbers.Integral):
                # Must tile it up to size to match operators if many operators
                # were provided but only one number was provided.
                repetitions = tf.ones(tf.shape(operators),
                                      dtype=tf.dtypes.int32) * repetitions

            if isinstance(repetitions, (list, tuple, np.ndarray)):
                if not isinstance(repetitions[0], (list, tuple, np.ndarray)):
                    repetitions = [repetitions]
                    reps_need_tile = True

                repetitions = tf.convert_to_tensor(repetitions,
                                                   dtype=tf.dtypes.int32)

            if reps_need_tile:
                # Don't tile up if the user gave a python list that was
                # precisely the correct size to match circuits outer batch dim.
                repetitions = tf.tile(repetitions, [circuit_batch_dim, 1])

            if not tf.is_tensor(repetitions):
                raise TypeError("repetitions cannot be parsed to int32 tensor"
                                " given input: ".format(repetitions))

        if values_empty:
            # No symbol_values were provided. So we assume the user wants us
            # to create and manage variables for them. We will do so by
            # creating a weights variable and tiling it up to appropriate
            # size of [batch, num_symbols].

            if self._w is None:
                # don't re-add variable.
                self._w = self.add_weight(name='circuit_learnable_parameters',
                                          shape=symbol_names.shape,
                                          initializer=initializer)

            symbol_values = tf.tile(tf.expand_dims(self._w, axis=0),
                                    tf.stack([circuit_batch_dim, 1]))

        num_samples = repetitions  # needed to help autographer.

        # pylint: disable=no-else-return
        if self.noisy:
            return self._expectation_op(inputs, symbol_names, symbol_values,
                                        operators, num_samples)
        else:
            return self._expectation_op(inputs, symbol_names, symbol_values,
                                        operators)
    def test_expand_circuits_error(self):
        """Test that expand_circuits errors on bad arguments."""

        # Valid test constants
        qubit = cirq.GridQubit(0, 0)
        symbol = sympy.Symbol('alpha')
        names_tensor = tf.convert_to_tensor([str(symbol)],
                                            dtype=tf.dtypes.string)
        circuit_tensor = util.convert_to_tensor(
            [cirq.Circuit(cirq.H(qubit)**symbol)])
        values_tensor = tf.convert_to_tensor([[0.5]], dtype=tf.dtypes.float32)

        # Bad circuit arg
        with self.assertRaisesRegex(TypeError,
                                    expected_regex="circuits cannot be parsed"):
            input_checks.expand_circuits('junk',
                                         symbol_names=names_tensor,
                                         symbol_values=values_tensor)

        # Bad name arg
        with self.assertRaisesRegex(TypeError,
                                    expected_regex="string or sympy.Symbol"):
            input_checks.expand_circuits(circuit_tensor,
                                         symbol_names=[symbol, 5.0],
                                         symbol_values=values_tensor)
        with self.assertRaisesRegex(TypeError,
                                    expected_regex="string or sympy.Symbol"):
            input_checks.expand_circuits(circuit_tensor,
                                         symbol_names=[[]],
                                         symbol_values=values_tensor)
        with self.assertRaisesRegex(ValueError,
                                    expected_regex="must be unique."):
            input_checks.expand_circuits(circuit_tensor,
                                         symbol_names=[symbol, symbol],
                                         symbol_values=values_tensor)
        with self.assertRaisesRegex(
                TypeError, expected_regex="symbol_names cannot be parsed"):
            input_checks.expand_circuits(circuit_tensor,
                                         symbol_names='junk',
                                         symbol_values=values_tensor)

        # Bad value arg
        with self.assertRaisesRegex(
                TypeError, expected_regex="symbol_values cannot be parsed"):
            input_checks.expand_circuits(circuit_tensor,
                                         symbol_names=names_tensor,
                                         symbol_values='junk')