---
title: bounds (latest version)
description: API reference for qiskit_addon_slc.bounds in the latest version of qiskit-addon-slc
source: https://quantum.cloud.ibm.com/docs/en/api/qiskit-addon-slc/bounds
---

# Bounds

`qiskit_addon_slc.bounds`

Bound computation functions.

This module provides various functions for computing the error bounds that make up a shaded lightcone.

### compute\_forward\_bounds

`compute_forward_bounds(circuit, noise_model_paulis, /, observable, *, evolution_max_terms=1000000, eigval_max_qubits=14, atol=1e-08, atol_simplify=1e-08, atol_eigenvalue=1e-08, **kwargs)`

[GitHub](https://github.com/Qiskit/qiskit-addon-slc/tree/main/qiskit_addon_slc/bounds/forward.py#L205-L315)

Compute the forward-evolved unequal-time commutator bounds.

Starting at the end of the circuit, compute the forward-evolved unequal-time commutator bounds for all Pauli error terms of each noisy layer in the target circuit.

That is, compute $\| \left[ E_F, A_F \right] \|_2$ for all error terms, $E_F$, where $A_F$ is the target `observable` to be measured on `circuit`.

The error terms, $E_I$, are dictated by `noise_model_paulis`. This dictionary maps noise model identifiers (`samplomatic.InjectNoise.ref`) to a list of Pauli error terms. The corresponding terms will be used whenever a [`BoxOp`](/docs/api/qiskit/qiskit.circuit.BoxOp) with a matching [`InjectNoise`](https://qiskit.github.io/samplomatic/api/auto/samplomatic.InjectNoise.html#samplomatic.InjectNoise "(in samplomatic)") annotation is encountered during the iteration over `circuit`.

> **Deprecated since version 0.2.0**
>
> `qiskit_addon_slc.bounds.forward.compute_forward_bounds()`’s argument `atol` is deprecated as of qiskit-addon-slc 0.2.0. It will be removed no earlier than 3 months after the release date. Use atol\_simplify and atol\_eigenvalue instead.

**Parameters**

- **circuit** ([*QuantumCircuit*](/docs/api/qiskit/qiskit.circuit.QuantumCircuit)) – the target circuit.
- **noise\_model\_paulis** ([*dict*](https://docs.python.org/3/library/stdtypes.html#dict)*\[*[*str*](https://docs.python.org/3/library/stdtypes.html#str)*,* [*QubitSparsePauliList*](/docs/api/qiskit/qiskit.quantum_info.QubitSparsePauliList)*]*) – the Pauli error terms to consider for each noise model.
- **observable** ([*Pauli*](/docs/api/qiskit/qiskit.quantum_info.Pauli)  *|*[*PauliList*](/docs/api/qiskit/qiskit.quantum_info.PauliList)  *|*[*SparseObservable*](/docs/api/qiskit/qiskit.quantum_info.SparseObservable)  *|*[*SparsePauliOp*](/docs/api/qiskit/qiskit.quantum_info.SparsePauliOp)) – the target observable to be measured at the end of the circuit.
- **evolution\_max\_terms** ([*int*](https://docs.python.org/3/library/functions.html#int)) – the maximum number of operator terms to keep track of during the evolution.
- **eigval\_max\_qubits** ([*int*](https://docs.python.org/3/library/functions.html#int)) – the maximum number of qubits of a commutator for which the eigenvalue will still be attempted to be computed. When this value is exceeded, the bound is approximated via a simpler and more loose triangle inequality.
- **atol** ([*float*](https://docs.python.org/3/library/functions.html#float)) – **DEPRECATED** use `atol_simplify` and `atol_eigenvalue` instead!
- **atol\_simplify** ([*float*](https://docs.python.org/3/library/functions.html#float)) – the absolute tolerance used for trimming terms from the commutator. Loosening this tolerance will result in a greater truncation of the commutator’s terms, rendering the computation of its eigenvalue cheaper but less accurate.
- **atol\_eigenvalue** ([*float*](https://docs.python.org/3/library/functions.html#float)) – the absolute tolerance used for detecting convergence of the commutator’s eigenvalue. Loosening this tolerance will result in a less accurate eigenvalue as computed by the iterative Davidson eigensolver.
- **kwargs** – any additional keyword arguments will be forward to [`compute_bounds()`](#qiskit_addon_slc.bounds.compute_bounds "qiskit_addon_slc.bounds.compute_bounds").

**Returns**

The unequal-time commutator bound.

**Raises**

[**NotImplementedError**](https://docs.python.org/3/library/exceptions.html#NotImplementedError) – when the `observable` contains more than a single Pauli term. If you run into this, you will need to call this function for each target Pauli separately.

**Return type**

[dict](https://docs.python.org/3/library/stdtypes.html#dict)\[[str](https://docs.python.org/3/library/stdtypes.html#str), [*PauliLindbladMap*](/docs/api/qiskit/qiskit.quantum_info.PauliLindbladMap)]

### tighten\_with\_speed\_limit

`tighten_with_speed_limit(bounds, circuit, noise_model_paulis, /, observable)`

[GitHub](https://github.com/Qiskit/qiskit-addon-slc/tree/main/qiskit_addon_slc/bounds/speed_limit.py#L226-L318)

Tighten the provided bounds using limits on the speed of information propagation.

Inspired by the ideas behind the Lieb-Robinson bounds, this function leverages limits on the speed of information propagation to tighten previously computed forward-evolved unequal-time commutator bounds (see also [`compute_forward_bounds()`](#qiskit_addon_slc.bounds.compute_forward_bounds "qiskit_addon_slc.bounds.compute_forward_bounds")).

**Parameters**

- **bounds** ([*dict*](https://docs.python.org/3/library/stdtypes.html#dict)*\[*[*str*](https://docs.python.org/3/library/stdtypes.html#str)*,* [*PauliLindbladMap*](/docs/api/qiskit/qiskit.quantum_info.PauliLindbladMap)*]*) – the previously computed forward-evolved unequal-time commutator bounds.
- **circuit** ([*QuantumCircuit*](/docs/api/qiskit/qiskit.circuit.QuantumCircuit)) – the target circuit.
- **noise\_model\_paulis** ([*dict*](https://docs.python.org/3/library/stdtypes.html#dict)*\[*[*str*](https://docs.python.org/3/library/stdtypes.html#str)*,* [*QubitSparsePauliList*](/docs/api/qiskit/qiskit.quantum_info.QubitSparsePauliList)*]*) – the Pauli error terms to consider for each noise model.
- **observable** ([*Pauli*](/docs/api/qiskit/qiskit.quantum_info.Pauli)  *|*[*PauliList*](/docs/api/qiskit/qiskit.quantum_info.PauliList)  *|*[*SparseObservable*](/docs/api/qiskit/qiskit.quantum_info.SparseObservable)  *|*[*SparsePauliOp*](/docs/api/qiskit/qiskit.quantum_info.SparsePauliOp)) – the target observable to be measured at the end of the circuit.

**Returns**

A tightened copy of the unequal-time commutator bounds.

**Raises**

- [**NotImplementedError**](https://docs.python.org/3/library/exceptions.html#NotImplementedError) – when the `observable` contains more than a single Pauli term. If you run into this, you will need to call this function for each target Pauli separately.
- [**ValueError**](https://docs.python.org/3/library/exceptions.html#ValueError) – when encountering a gate that acts on more than 2 qubits.

**Return type**

[dict](https://docs.python.org/3/library/stdtypes.html#dict)\[[str](https://docs.python.org/3/library/stdtypes.html#str), [*PauliLindbladMap*](/docs/api/qiskit/qiskit.quantum_info.PauliLindbladMap)]

### compute\_backward\_bounds

`compute_backward_bounds(circuit, noise_model_paulis, /, *, evolution_max_terms=1000000, **kwargs)`

[GitHub](https://github.com/Qiskit/qiskit-addon-slc/tree/main/qiskit_addon_slc/bounds/backward.py#L104-L164)

Compute the backward-evolved unequal-time commutator bounds.

Starting at the beginning of the circuit, compute the backward-evolved unequal-time commutator bounds for all Pauli error terms of each noisy layer in the target circuit.

That is, compute $\| \left[ E_I, \rho_I \right] \|_1$ (using the Schatten 1-norm aka nuclear norm) for all error terms, $E_I$, where $\rho_I$ is assumed to be the all-zero state, $\ket{0 \ldots 0}$, on all active qubits in `circuit`.

The error terms, $E_I$, are dictated by `noise_model_paulis`. This dictionary maps noise model identifiers (`samplomatic.InjectNoise.ref`) to a list of Pauli error terms. The corresponding terms will be used whenever a [`BoxOp`](/docs/api/qiskit/qiskit.circuit.BoxOp) with a matching [`InjectNoise`](https://qiskit.github.io/samplomatic/api/auto/samplomatic.InjectNoise.html#samplomatic.InjectNoise "(in samplomatic)") annotation is encountered during the iteration over `circuit`.

> **Caution**
>
> Before computing the bounds, this function removes **all** `Measure` operations from `circuit`. This is required because the circuit is being inverted before being processed in reverse order, which allows the backward evolution to be treated like a forward evolution (in the inverted circuit).

**Parameters**

- **circuit** ([*QuantumCircuit*](/docs/api/qiskit/qiskit.circuit.QuantumCircuit)) – the target circuit.
- **noise\_model\_paulis** ([*dict*](https://docs.python.org/3/library/stdtypes.html#dict)*\[*[*str*](https://docs.python.org/3/library/stdtypes.html#str)*,* [*QubitSparsePauliList*](/docs/api/qiskit/qiskit.quantum_info.QubitSparsePauliList)*]*) – the Pauli error terms to consider for each noise model.
- **evolution\_max\_terms** ([*int*](https://docs.python.org/3/library/functions.html#int)) – the maximum number of operator terms to keep track of during the evolution. (If the operator exceeds this size, the smallest terms are truncated).
- **kwargs** – any additional keyword arguments will be forward to [`compute_bounds()`](#qiskit_addon_slc.bounds.compute_bounds "qiskit_addon_slc.bounds.compute_bounds").

**Returns**

The backward-evolved unequal-time commutator bounds.

**Return type**

[dict](https://docs.python.org/3/library/stdtypes.html#dict)\[[str](https://docs.python.org/3/library/stdtypes.html#str), [*PauliLindbladMap*](/docs/api/qiskit/qiskit.quantum_info.PauliLindbladMap)]

### merge\_bounds

`merge_bounds(circuit, forward_bounds, backward_bounds, /, noise_rates=None, *, is_clifford_circuit=False)`

[GitHub](https://github.com/Qiskit/qiskit-addon-slc/tree/main/qiskit_addon_slc/bounds/merge.py#L36-L162)

Merge forward and backward bounds.

The layer at which the switch from using backward bounds to using forward bounds takes place will be the same for all qubits. It is determined by taking into account the provided learned `noise_rates`. If these are not provided, uniform noise rates are assumed. While this is an unrealistic assumption, previewing the merged bounds may still be useful.

**Parameters**

- **circuit** ([*QuantumCircuit*](/docs/api/qiskit/qiskit.circuit.QuantumCircuit)) – the target circuit.
- **forward\_bounds** ([*dict*](https://docs.python.org/3/library/stdtypes.html#dict)*\[*[*str*](https://docs.python.org/3/library/stdtypes.html#str)*,* [*PauliLindbladMap*](/docs/api/qiskit/qiskit.quantum_info.PauliLindbladMap)*] | None*) – the forward bounds (see also [`compute_forward_bounds()`](#qiskit_addon_slc.bounds.compute_forward_bounds "qiskit_addon_slc.bounds.compute_forward_bounds")).
- **backward\_bounds** ([*dict*](https://docs.python.org/3/library/stdtypes.html#dict)*\[*[*str*](https://docs.python.org/3/library/stdtypes.html#str)*,* [*PauliLindbladMap*](/docs/api/qiskit/qiskit.quantum_info.PauliLindbladMap)*] | None*) – the backward bounds (see also [`compute_backward_bounds()`](#qiskit_addon_slc.bounds.compute_backward_bounds "qiskit_addon_slc.bounds.compute_backward_bounds")).
- **noise\_rates** ([*dict*](https://docs.python.org/3/library/stdtypes.html#dict)*\[*[*str*](https://docs.python.org/3/library/stdtypes.html#str)*,* [*PauliLindbladMap*](/docs/api/qiskit/qiskit.quantum_info.PauliLindbladMap) *| None] | None*) – the noise rates learned on the target backend.
- **is\_clifford\_circuit** ([*bool*](https://docs.python.org/3/library/functions.html#bool)) – whether the target circuit is fully Clifford.

**Returns**

The merged bounds.

**Raises**

- [**ValueError**](https://docs.python.org/3/library/exceptions.html#ValueError) – when both provided bounds are `None`.
- [**KeyError**](https://docs.python.org/3/library/exceptions.html#KeyError) – when the `bounds` contain an `InjectNoise.modifier_ref` key which does not occur in the target `circuit` or whose `InjectNoise.ref` is not found.
- [**ValueError**](https://docs.python.org/3/library/exceptions.html#ValueError) – if the noise model Pauli terms whose bounds are computed for a given `InjectNoise.modifier_ref` do not match between the `forward_bounds` and `backward_bounds`.
- [**NotImplementedError**](https://docs.python.org/3/library/exceptions.html#NotImplementedError) – when `is_clifford_circuit` is `True`.

**Return type**

[dict](https://docs.python.org/3/library/stdtypes.html#dict)\[[str](https://docs.python.org/3/library/stdtypes.html#str), [*PauliLindbladMap*](/docs/api/qiskit/qiskit.quantum_info.PauliLindbladMap)] | None

### compute\_local\_scales

`compute_local_scales(circuit, bounds, /, noise_rates, *, sampling_cost_budget=inf, bias_tolerance=0.0)`

[GitHub](https://github.com/Qiskit/qiskit-addon-slc/tree/main/qiskit_addon_slc/bounds/local_scales.py#L35-L163)

Computes the `local_scales` argument to a [`Samplex`](https://qiskit.github.io/samplomatic/api/auto/samplomatic.samplex.Samplex.html#samplomatic.samplex.Samplex "(in samplomatic)").

This `local_scales` argument is used to specify which individual error terms to mitigate.

Either the `sampling_cost_budget` or `bias_tolerance` must be specified. The former puts an upper bound on the sampling cost while the latter puts an upper bound on the remaining bias to tolerate.

> **Note**
>
> If the order of Pauli terms in `bounds` and `noise_rates` do not match, the output of this function will assume the order set forth by `noise_rates` in order to ensure that the scales are compatible with the rates that will also be provided to the `QuantumProgram`.

**Parameters**

- **circuit** ([*QuantumCircuit*](/docs/api/qiskit/qiskit.circuit.QuantumCircuit)) – the target circuit.
- **bounds** ([*dict*](https://docs.python.org/3/library/stdtypes.html#dict)*\[*[*str*](https://docs.python.org/3/library/stdtypes.html#str)*,* [*PauliLindbladMap*](/docs/api/qiskit/qiskit.quantum_info.PauliLindbladMap)*]*) – the shaded lightcone bounds.
- **noise\_rates** ([*dict*](https://docs.python.org/3/library/stdtypes.html#dict)*\[*[*str*](https://docs.python.org/3/library/stdtypes.html#str)*,* [*PauliLindbladMap*](/docs/api/qiskit/qiskit.quantum_info.PauliLindbladMap) *| None]*) – the learned noise model rates.
- **sampling\_cost\_budget** ([*float*](https://docs.python.org/3/library/functions.html#float)) – the maximum sampling cost to allow.
- **bias\_tolerance** ([*float*](https://docs.python.org/3/library/functions.html#float)) – the maximum bias to tolerate.

**Returns**

- the `local_scales` dictionary to be provided as the direct input to the [`samplomatic.samplex.Samplex.inputs()`](https://qiskit.github.io/samplomatic/api/auto/samplomatic.samplex.Samplex.html#samplomatic.samplex.Samplex.inputs "(in samplomatic)").
- the sampling cost overhead ($\gamma^2$) required to perform the sampling of `local_scales`.
- the remaining bias on expectation values computed with these bounds.

**Return type**

A tuple of length 3, the items of which are

**Raises**

- [**ValueError**](https://docs.python.org/3/library/exceptions.html#ValueError) – if non-default values are provided for both, the `sampling_cost_budget` and `bias_tolerance`.
- [**KeyError**](https://docs.python.org/3/library/exceptions.html#KeyError) – if `noise_rates` is missing an entry for any noise model identifier (`InjectNoise.ref`) encountered in `circuit`.

***

This module also contains some lower level functions which are usually not accessed by an end-user directly, but may prove useful for additional development on top of this package.

### compute\_bounds

`compute_bounds(circuit, noise_model_paulis, light_cone, norm_fn, *, backwards, max_num_boxes=None, num_processes=1, timeout=None)`

[GitHub](https://github.com/Qiskit/qiskit-addon-slc/tree/main/qiskit_addon_slc/bounds/commutator_bounds.py#L90-L280)

Computes the unequal time commutator bounds.

Given a circuit with `BoxOp` instructions with `InjectNoise` annotations and a mapping of noise model identifiers (`InjectNoise.ref`) to list of Pauli error terms (`noise_model_paulis`), this function computes the unequal time commutator bounds (the details of which are implemented by `norm_fn`). In doing so, it only considers gates that lie within the light-cone of the observable (initialized by `light_cone`). These computed bounds form the basis of the shaded light-cone.

Since this function performs a long-running computation, it gracefully handles `KeyboardInterrupt` exceptions, allowing the user to interrupt the computation at an arbitrary point in time and still obtain the results that have been computed up to that point.

**Parameters**

- **circuit** ([*QuantumCircuit*](/docs/api/qiskit/qiskit.circuit.QuantumCircuit)) – the target circuit.
- **noise\_model\_paulis** ([*dict*](https://docs.python.org/3/library/stdtypes.html#dict)*\[*[*str*](https://docs.python.org/3/library/stdtypes.html#str)*,* [*QubitSparsePauliList*](/docs/api/qiskit/qiskit.quantum_info.QubitSparsePauliList)*]*) – the Pauli error terms to consider for each noise model.
- **light\_cone** (*LightCone*) – the initialized and stateful `LightCone` tracker.
- **norm\_fn** ([*Callable*](https://docs.python.org/3/library/collections.abc.html#collections.abc.Callable)*\[\[*[*Pauli*](/docs/api/qiskit/qiskit.quantum_info.Pauli)*,* [*RotationGates*](/docs/api/pauli-prop/propagation#pauli_prop.propagation.RotationGates "(in Pauli propagation)")*],* [*CommutatorBounds*](#qiskit_addon_slc.bounds.CommutatorBounds "qiskit_addon_slc.bounds.commutator_bounds.CommutatorBounds")*]*) – the function implementing the specific unequal time commutator.
- **backwards** ([*bool*](https://docs.python.org/3/library/functions.html#bool)) – whether to iterate over the `circuit` in reverse.
- **max\_num\_boxes** ([*int*](https://docs.python.org/3/library/functions.html#int) *| None*) – the maximum number of boxes for which to compute bounds. Bounds for any additional boxes will be given the trivial upper bound value of $2.0$.
- **num\_processes** ([*int*](https://docs.python.org/3/library/functions.html#int)) – the number of parallel processes to use.
- **timeout** ([*float*](https://docs.python.org/3/library/functions.html#float) *| None*) – an optional timeout (in seconds) after which all remaining layers are filled with trivial numerical bounds of `2.0`. Note, that this is not a strict timeout and the layer being processed at the time of reaching this timeout will complete normally.

**Returns**

The computed unequal time commutator bounds.

**Return type**

[dict](https://docs.python.org/3/library/stdtypes.html#dict)\[[str](https://docs.python.org/3/library/stdtypes.html#str), [*PauliLindbladMap*](/docs/api/qiskit/qiskit.quantum_info.PauliLindbladMap)]

### CommutatorBounds

*class* `CommutatorBounds(commutator_bound, truncation_bias, fallback_to_tri_ineq)`

[GitHub](https://github.com/Qiskit/qiskit-addon-slc/tree/main/qiskit_addon_slc/bounds/commutator_bounds.py#L52-L87)

Bases: [`NamedTuple`](https://docs.python.org/3/library/typing.html#typing.NamedTuple)

A dataclass to store metadata about the computed commutator bounds.

Create new instance of CommutatorBounds(commutator\_bound, truncation\_bias, fallback\_to\_tri\_ineq)

**Parameters**

- **commutator\_bound** ([*float*](https://docs.python.org/3/library/functions.html#float))
- **truncation\_bias** ([*float*](https://docs.python.org/3/library/functions.html#float))
- **fallback\_to\_tri\_ineq** ([*bool*](https://docs.python.org/3/library/functions.html#bool))

#### commutator\_bound

Type: [`float`](https://docs.python.org/3/library/functions.html#float)

The bound on the commutator.

This bound will be computed in different means depending on the application. For example, backward bounds will compute the nuclear norm (Schatten 1-norm) while forward bounds are typically computed using the spectral norm (Schatten infinity-norm).

If the norm computation exceeds specified difficulty limits, it will be abandoned in favor of a simpler bound based on the triangle inequality, which is indicated by [`fallback_to_tri_ineq`](#qiskit_addon_slc.bounds.CommutatorBounds.fallback_to_tri_ineq "qiskit_addon_slc.bounds.CommutatorBounds.fallback_to_tri_ineq") being set to `True`.

This value may be `NaN` when the computation of the commutor bound was aborted. This can happen when the [`truncation_bias`](#qiskit_addon_slc.bounds.CommutatorBounds.truncation_bias "qiskit_addon_slc.bounds.CommutatorBounds.truncation_bias") already exceeds the theoretical bound of `2.0`.

#### fallback\_to\_tri\_ineq

Type: [`bool`](https://docs.python.org/3/library/functions.html#bool)

Whether [`commutator_bound`](#qiskit_addon_slc.bounds.CommutatorBounds.commutator_bound "qiskit_addon_slc.bounds.CommutatorBounds.commutator_bound") was computed “loosely” using a simple triangle inequality.

#### min

`min()`

[GitHub](https://github.com/Qiskit/qiskit-addon-slc/tree/main/qiskit_addon_slc/bounds/commutator_bounds.py#L78-L87)

Returns the minimum bound encoded by this metadata.

The minimal bound is the smaller of the sum of [`commutator_bound`](#qiskit_addon_slc.bounds.CommutatorBounds.commutator_bound "qiskit_addon_slc.bounds.CommutatorBounds.commutator_bound") and [`truncation_bias`](#qiskit_addon_slc.bounds.CommutatorBounds.truncation_bias "qiskit_addon_slc.bounds.CommutatorBounds.truncation_bias") or the theoretical bound of `2.0`.

The value of `2.0` is used because a Pauli observable bounded on the range `[-1, +1]` cannot be biased by more than `2.0`.

**Return type**

[float](https://docs.python.org/3/library/functions.html#float)

#### truncation\_bias

Type: [`float`](https://docs.python.org/3/library/functions.html#float)

The bias on the bound due to truncation of the commutator.
