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