def test_expand_operators_errors(self):
     """Confirm error on bad input."""
     with self.assertRaisesRegex(RuntimeError,
                                 expected_regex="operators not provided"):
         input_checks.expand_operators()
     with self.assertRaisesRegex(
             TypeError, expected_regex="operators cannot be parsed"):
         input_checks.expand_operators('junk')
Example #2
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)
 def test_allowed_cases(self):
     """Confirm that allowed inputs are upgraded correctly."""
     batch_dim = 3
     bare_string = cirq.Z(cirq.GridQubit(0, 0))
     bare_sum = cirq.PauliSum.from_pauli_strings([bare_string])
     bare_list = [bare_string]
     bare_tuple = tuple(bare_list)
     shaped_list = [[bare_string]] * batch_dim
     shaped_tuple = tuple(shaped_list)
     op_tensor_single = util.convert_to_tensor([[bare_string]])
     op_tensor = tf.tile(op_tensor_single, [batch_dim, 1])
     for op in [
             bare_string, bare_sum, bare_list, bare_tuple, shaped_list,
             shaped_tuple, op_tensor
     ]:
         op_test = input_checks.expand_operators(op, batch_dim)
         self.assertAllEqual(op_test, op_tensor)
Example #4
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)