<br />

|---|
| [![](https://www.tensorflow.org/images/GitHub-Mark-32px.png) View source on GitHub](https://github.com/tensorflow/quantum/blob/v0.7.6/tensorflow_quantum/python/layers/circuit_executors/sample.py#L25-L201) |

A Layer that samples from a quantum circuit.

    tfq.layers.Sample(
        backend='noiseless', **kwargs
    )

### Used in the notebooks

| Used in the tutorials |
|---|
| - [Noise](https://www.tensorflow.org/quantum/tutorials/noise) - [Research tools](https://www.tensorflow.org/quantum/tutorials/research_tools) |

Given an input circuit and set of parameter values, output samples
taken from the end of the circuit.

First lets define a simple circuit to sample from:

    def get_circuit():
        q0 = cirq.GridQubit(0, 0)
        q1 = cirq.GridQubit(1, 0)
        circuit = cirq.Circuit(
            cirq.X(q0),
            cirq.CNOT(q0, q1)
        )

        return circuit

#### When printed:

    get_circuit()
    (0, 0): ───X───@───
                   │
    (1, 0): ───────X───

Using [`tfq.layers.Sample`](https://www.tensorflow.org/quantum/api_docs/python/tfq/layers/Sample), it's possible to sample outputs from a given
circuit. The circuit above will put both qubits in the \|1\> state.

To retrieve samples of the output state:

    sample_layer = tfq.layers.Sample()
    output = sample_layer(get_circuit(), repetitions=4)
    output
    <tf.RaggedTensor [[[1, 1], [1, 1], [1, 1], [1, 1]]]>

Notice above that there were no parameters passed as input into the
layer, because the circuit wasn't parameterized. If instead the circuit
had parameters, e.g.

    def get_parameterized_circuit(symbols):
        q0 = cirq.GridQubit(0, 0)
        q1 = cirq.GridQubit(1, 0)
        circuit = cirq.Circuit(
            cirq.X(q0) ** symbols[0],
            cirq.CNOT(q1)
        )

        return circuit

Then it becomes necessary to provide a value for the symbol using
`symbol_names` and `symbol_values`.

    symbols = sympy.symbols(['x'])
    sample_layer = tfq.layers.Sample()
    output = sample_layer(get_parameterized_circuit(),
        symbol_names=symbols, symbol_values=[[0.5]], repetitions=4)
    tf.shape(output.to_tensor())
    tf.Tensor([1 4 2], shape=(3,), dtype=int32)

Note that using multiple sets of parameters returns multiple
independent samples on the same circuit.

    symbols = sympy.symbols(['x'])
    sample_layer = tfq.layers.Sample()
    params = tf.convert_to_tensor([[0.5], [0.4]],
                                  dtype=tf.dtypes.float32)
    output = sample_layer(get_parameterized_circuit(),
        symbol_names=symbols, symbol_values=params, repetitions=4)
    tf.shape(output.to_tensor())
    tf.Tensor([2 4 2], shape=(3,), dtype=int32)

The sample layer can also be used without explicitly passing in a
circuit, but instead using the layer with a batch of circuits. This layer
will then sample the circuits provided in the batch with multiple sets of
parameters, at the same time. Note that the parameters will not be
crossed along all circuits, the circuit at index i will be run with the
parameters at index i.

    symbols = sympy.symbols(['x'])
    sample_layer = tfq.layers.Sample()

With the sample layer defined, just define both the circuit and
parameter inputs.

    q0 = cirq.GridQubit(0, 0)
    q1 = cirq.GridQubit(1, 0)
    circuits = tfq.convert_to_tensor([
        cirq.Circuit(
            cirq.X(q0) ** s[0],
            cirq.CNOT(q0, q1),
        ),
        cirq.Circuit(
            cirq.Y(q0) ** s[0],
            cirq.CNOT(q0, q1),
        )
    ])
    params = tf.convert_to_tensor([[0.5], [0.4]],
                                 dtype=tf.dtypes.float32)

The layer can be used as usual:

    output = sample_layer(circuits,
        symbol_names=symbols, symbol_values = params, repetitions=4)
    tf.shape(output.to_tensor())
        tf.Tensor([2 4 2], shape=(3,), dtype=int32)

> [!NOTE]
> **Note:** When specifying a new layer for a *compiled* [`tf.keras.Model`](https://www.tensorflow.org/api_docs/python/tf/keras/Model) using something like `tfq.layers.Sample()(cirq.Circuit(...), ...)` please be sure to instead use `tfq.layers.Sample()(circuit_input, ...)` where `circuit_input` is a [`tf.keras.Input`](https://www.tensorflow.org/api_docs/python/tf/keras/Input) that is filled with `tfq.conver_to_tensor([cirq.Circuit(..)] * batch_size)` at runtime. This is because compiled Keras models require non keyword layer `call` inputs to be traceable back to a [`tf.keras.Input`](https://www.tensorflow.org/api_docs/python/tf/keras/Input).

<br />

<br />

<br />

| ## Args ||
|---|---|
| `backend` | Optional Backend to use to simulate this state. Defaults to the noiseless simulator. Options are {'noisy', 'noiseless'}, however users may also specify a preconfigured cirq execution object to use instead, which must inherit [`cirq.Sampler`](https://quantumai.google/reference/python/cirq/Sampler). |

<br />

<br />

<br />

<br />

| ## Attributes ||
|---|---|
| `compute_dtype` | The dtype of the computations performed by the layer. |
| `dtype` | Alias of `layer.variable_dtype`. |
| `dtype_policy` | <br /> <br /> |
| `input` | Retrieves the input tensor(s) of a symbolic operation. <br /> Only returns the tensor(s) corresponding to the *first time* the operation was called. |
| `input_dtype` | The dtype layer inputs should be converted to. |
| `input_spec` | <br /> <br /> |
| `losses` | List of scalar losses from `add_loss`, regularizers and sublayers. |
| `metrics` | List of all metrics. |
| `metrics_variables` | List of all metric variables. |
| `non_trainable_variables` | List of all non-trainable layer state. <br /> This extends `layer.non_trainable_weights` to include all state used by the layer including state for metrics and `SeedGenerator`s. |
| `non_trainable_weights` | List of all non-trainable weight variables of the layer. <br /> These are the weights that should not be updated by the optimizer during training. Unlike, `layer.non_trainable_variables` this excludes metric state and random seeds. |
| `output` | Retrieves the output tensor(s) of a layer. <br /> Only returns the tensor(s) corresponding to the *first time* the operation was called. |
| `path` | The path of the layer. <br /> If the layer has not been built yet, it will be `None`. |
| `quantization_mode` | The quantization mode of this layer, `None` if not quantized. |
| `supports_masking` | Whether this layer supports computing a mask using `compute_mask`. |
| `trainable` | Settable boolean, whether this layer should be trainable or not. |
| `trainable_variables` | List of all trainable layer state. <br /> This is equivalent to `layer.trainable_weights`. |
| `trainable_weights` | List of all trainable weight variables of the layer. <br /> These are the weights that get updated by the optimizer during training. |
| `variable_dtype` | The dtype of the state (weights) of the layer. |
| `variables` | List of all layer state, including random seeds. <br /> This extends `layer.weights` to include all state used by the layer including `SeedGenerator`s. Note that metrics variables are not included here, use `metrics_variables` to visit all the metric variables. |
| `weights` | List of all weight variables of the layer. <br /> Unlike, `layer.variables` this excludes metric state and random seeds. |

<br />

## Methods

### `add_loss`

    add_loss(
        loss
    )

Can be called inside of the `call()` method to add a scalar loss.

#### Example:

    class MyLayer(Layer):
        ...
        def call(self, x):
            self.add_loss(ops.sum(x))
            return x

### `add_metric`

    add_metric(
        *args, **kwargs
    )

### `add_variable`

    add_variable(
        shape,
        initializer,
        dtype=None,
        trainable=True,
        autocast=True,
        regularizer=None,
        constraint=None,
        name=None
    )

Add a weight variable to the layer.

Alias of `add_weight()`.

### `add_weight`

    add_weight(
        *args,
        shape=None,
        initializer=None,
        dtype=None,
        trainable=True,
        autocast=True,
        regularizer=None,
        constraint=None,
        aggregation='none',
        overwrite_with_gradient=False,
        name=None
    )

Add a weight variable to the layer.

<br />

<br />

<br />

| Args ||
|---|---|
| `shape` | Shape tuple for the variable. Must be fully-defined (no `None` entries). Defaults to `()` (scalar) if unspecified. |
| `initializer` | Initializer object to use to populate the initial variable value, or string name of a built-in initializer (e.g. `"random_normal"`). If unspecified, defaults to `"glorot_uniform"` for floating-point variables and to `"zeros"` for all other types (e.g. int, bool). |
| `dtype` | Dtype of the variable to create, e.g. `"float32"`. If unspecified, defaults to the layer's variable dtype (which itself defaults to `"float32"` if unspecified). |
| `trainable` | Boolean, whether the variable should be trainable via backprop or whether its updates are managed manually. Defaults to `True`. |
| `autocast` | Boolean, whether to autocast layers variables when accessing them. Defaults to `True`. |
| `regularizer` | Regularizer object to call to apply penalty on the weight. These penalties are summed into the loss function during optimization. Defaults to `None`. |
| `constraint` | Contrainst object to call on the variable after any optimizer update, or string name of a built-in constraint. Defaults to `None`. |
| `aggregation` | Optional string, one of `None`, `"none"`, `"mean"`, `"sum"` or `"only_first_replica"`. Annotates the variable with the type of multi-replica aggregation to be used for this variable when writing custom data parallel training loops. Defaults to `"none"`. |
| `overwrite_with_gradient` | Boolean, whether to overwrite the variable with the computed gradient. This is useful for float8 training. Defaults to `False`. |
| `name` | String name of the variable. Useful for debugging purposes. |

<br />

### `build`

    build(
        input_shape
    )

### `build_from_config`

    build_from_config(
        config
    )

Builds the layer's states with the supplied config dict.

By default, this method calls the `build(config["input_shape"])` method,
which creates weights based on the layer's input shape in the supplied
config. If your config contains other information needed to load the
layer's state, you should override this method.

<br />

<br />

<br />

| Args ||
|---|---|
| `config` | Dict containing the input shape associated with this layer. |

<br />

### `call`

[View source](https://github.com/tensorflow/quantum/blob/v0.7.6/tensorflow_quantum/python/layers/circuit_executors/sample.py#L165-L201)

    call(
        inputs, *, symbol_names=None, symbol_values=None, repetitions=None
    )

Keras call function.

<br />

<br />

<br />

| Input options ||
|---|---|
| `inputs`, `symbol_names`, `symbol_values`: see `input_checks.expand_circuits` `repetitions`: a Python `int` or a pre-converted [`tf.Tensor`](https://www.tensorflow.org/api_docs/python/tf/Tensor) containing a single `int` entry. ||

<br />

<br />

<br />

<br />

| Output shape ||
|---|---|
| [`tf.RaggedTensor`](https://www.tensorflow.org/api_docs/python/tf/RaggedTensor) with shape: \[batch size of symbol_values, repetitions, \] or \[number of circuits, repetitions, \] ||

<br />

### `compute_mask`

    compute_mask(
        inputs, previous_mask
    )

### `compute_output_shape`

    compute_output_shape(
        *args, **kwargs
    )

### `compute_output_spec`

    compute_output_spec(
        *args, **kwargs
    )

### `count_params`

    count_params()

Count the total number of scalars composing the weights.

<br />

<br />

<br />

| Returns ||
|---|---|
| An integer count. ||

<br />

### `from_config`

    @classmethod
    from_config(
        config
    )

Creates an operation from its config.

This method is the reverse of `get_config`, capable of instantiating the
same operation from the config dictionary.

> [!NOTE]
> **Note:** If you override this method, you might receive a serialized dtype config, which is a `dict`. You can deserialize it as follows:

    if "dtype" in config and isinstance(config["dtype"], dict):
        policy = dtype_policies.deserialize(config["dtype"])

<br />

<br />

<br />

| Args ||
|---|---|
| `config` | A Python dictionary, typically the output of `get_config`. |

<br />

<br />

<br />

<br />

| Returns ||
|---|---|
| An operation instance. ||

<br />

### `get_build_config`

    get_build_config()

Returns a dictionary with the layer's input shape.

This method returns a config dict that can be used by
`build_from_config(config)` to create all states (e.g. Variables and
Lookup tables) needed by the layer.

By default, the config only contains the input shape that the layer
was built with. If you're writing a custom layer that creates state in
an unusual way, you should override this method to make sure this state
is already created when Keras attempts to load its value upon model
loading.

<br />

<br />

<br />

| Returns ||
|---|---|
| A dict containing the input shape associated with the layer. ||

<br />

### `get_config`

    get_config()

Returns the config of the object.

An object config is a Python dictionary (serializable)
containing the information needed to re-instantiate it.

### `get_weights`

    get_weights()

Return the values of `layer.weights` as a list of NumPy arrays.

### `load_own_variables`

    load_own_variables(
        store
    )

Loads the state of the layer.

You can override this method to take full control of how the state of
the layer is loaded upon calling [`keras.models.load_model()`](https://www.tensorflow.org/api_docs/python/tf/keras/models/load_model).

<br />

<br />

<br />

| Args ||
|---|---|
| `store` | Dict from which the state of the model will be loaded. |

<br />

### `quantize`

    quantize(
        mode=None, type_check=True, config=None
    )

### `quantized_build`

    quantized_build(
        input_shape, mode
    )

### `quantized_call`

    quantized_call(
        *args, **kwargs
    )

### `rematerialized_call`

    rematerialized_call(
        layer_call, *args, **kwargs
    )

Enable rematerialization dynamically for layer's call method.

<br />

<br />

<br />

| Args ||
|---|---|
| `layer_call` | The original `call` method of a layer. |

<br />

<br />

<br />

<br />

| Returns ||
|---|---|
| Rematerialized layer's `call` method. ||

<br />

### `save_own_variables`

    save_own_variables(
        store
    )

Saves the state of the layer.

You can override this method to take full control of how the state of
the layer is saved upon calling `model.save()`.

<br />

<br />

<br />

| Args ||
|---|---|
| `store` | Dict where the state of the model will be saved. |

<br />

### `set_weights`

    set_weights(
        weights
    )

Sets the values of `layer.weights` from a list of NumPy arrays.

### `stateless_call`

    stateless_call(
        trainable_variables,
        non_trainable_variables,
        *args,
        return_losses=False,
        **kwargs
    )

Call the layer without any side effects.

<br />

<br />

<br />

| Args ||
|---|---|
| `trainable_variables` | List of trainable variables of the model. |
| `non_trainable_variables` | List of non-trainable variables of the model. |
| `*args` | Positional arguments to be passed to `call()`. |
| `return_losses` | If `True`, `stateless_call()` will return the list of losses created during `call()` as part of its return values. |
| `**kwargs` | Keyword arguments to be passed to `call()`. |

<br />

<br />

<br />

<br />

| Returns ||
|---|---|
| A tuple. By default, returns `(outputs, non_trainable_variables)`. If `return_losses = True`, then returns `(outputs, non_trainable_variables, losses)`. ||

<br />

> [!NOTE]
> **Note:** `non_trainable_variables` include not only non-trainable weights such as `BatchNormalization` statistics, but also RNG seed state (if there are any random operations part of the layer, such as dropout), and `Metric` state (if there are any metrics attached to the layer). These are all elements of state of the layer.

#### Example:

    model = ...
    data = ...
    trainable_variables = model.trainable_variables
    non_trainable_variables = model.non_trainable_variables
    # Call the model with zero side effects
    outputs, non_trainable_variables = model.stateless_call(
        trainable_variables,
        non_trainable_variables,
        data,
    )
    # Attach the updated state to the model
    # (until you do this, the model is still in its pre-call state).
    for ref_var, value in zip(
        model.non_trainable_variables, non_trainable_variables
    ):
        ref_var.assign(value)

### `symbolic_call`

    symbolic_call(
        *args, **kwargs
    )

### `__call__`

    __call__(
        *args, **kwargs
    )

Call self as a function.