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