Tomography#

Classes and functions used to classically simulate tomography protocols.

Abstract class#

Tomographic protocols that build, execute, and post-process circuits derive from the following abstract class.

class qibo.tomography.abstract.Tomography[source]#

Abstract class for tomographic protocols.

A protocol is defined by (i) circuits(), which builds the circuits that need to be executed, and (ii) __call__(), which runs the whole pipeline, i.e. circuits generation, execution, and post-processing.

abstract __call__(circuit, *args, **kwargs)[source]#

Runs the whole tomographic pipeline for circuit.

Parameters:

circuit (Circuit) –

abstract circuits(circuit, *args, **kwargs)[source]#

Generates the circuits that need to be executed by the protocol.

Parameters:

circuit (Circuit) –

Return type:

list[qibo.models.circuit.Circuit]

execute(circuits, nshots=1000, backend=None)[source]#

Executes a list of circuits.

Parameters:
  • circuits (list[qibo.models.circuit.Circuit]) – circuits to be executed.

  • nshots (int, optional) – number of shots per circuit. Defaults to \(1000\).

  • backend (qibo.backends.abstract.Backend, optional) – backend to be used in the execution. If None, it uses the current backend. Defaults to None.

Returns:

execution results, in the same order as circuits.

Return type:

list

State Tomography#

State tomography reconstructs the density matrix \(\rho\) of \(n\) qubits from Pauli measurements [1, 2]. In the Pauli basis,

\[\rho = \frac{1}{2^{n}} \sum_{P} \text{tr}(P \, \rho) \, P \, ,\]

where the sum runs over the \(4^{n}\) Pauli strings \(P\). Each qubit is measured in the basis \(X\), \(Y\), or \(Z\), which gives \(3^{n}\) settings, each one executed for nshots shots. The Walsh-Hadamard transform of the outcome probabilities of a setting gives the expectation values of the \(2^{n}\) Pauli strings that it measures, i.e. those that have the measured Pauli, or the identity, on each qubit. A Pauli string with \(w\) non-identity factors is measured by \(3^{n - w}\) settings, and the estimates of all of them are averaged. The coefficients of all Pauli strings are then mapped to \(\hat{\rho}\) with a fast Hadamard transform.

The outcomes can be turned into a state with four estimators, selected with the argument method:

  • "linear-inversion", the default, inserts the estimated expectation values in the expansion above. The estimate is Hermitian, with unit trace, and unbiased, but it is not positive semidefinite in general, because of the statistical errors.

  • "physical-linear-inversion" is the density matrix closest to the linear inversion estimate in the Frobenius norm, obtained by projecting its eigenvalues onto the probability simplex [3].

  • "least-squares" is the physical state that minimizes the sum of the squared differences between the observed and the predicted probabilities, found with an accelerated projected gradient method [3, 6].

  • "mle" is the maximum likelihood estimate, found with the diluted iterative algorithm of Refs. [4, 5]. It is physical, and biased towards states with low rank.

The readout errors of the device can be mitigated in all of them by giving the response matrix of the readout in the argument response_matrix, e.g. the one returned by qibo.models.error_mitigation.get_response_matrix() [7]. The number of circuits grows as \(3^{n}\), so the protocol is meant for few qubits. A step-by-step guide is given in the state tomography tutorial.

References:

1. M. A. Nielsen and I. L. Chuang, Quantum Computation and Quantum Information, Cambridge University Press (2010), Sec. 8.4.2.

2. D. F. V. James, P. G. Kwiat, W. J. Munro and A. G. White, Measurement of qubits (2001), Physical Review A 64, 052312.

3. J. A. Smolin, J. M. Gambetta and G. Smith, Efficient method for computing the maximum-likelihood quantum state from measurements with additive Gaussian noise (2012), Physical Review Letters 108, 070502.

4. Z. Hradil, Quantum-state estimation (1997), Physical Review A 55, R1561.

5. A. I. Lvovsky, Iterative maximum-likelihood reconstruction in quantum homodyne tomography (2004), Journal of Optics B 6, S556.

6. A. Beck and M. Teboulle, A fast iterative shrinkage-thresholding algorithm for linear inverse problems (2009), SIAM Journal on Imaging Sciences 2, 183.

7. S. Bravyi, S. Sheldon, A. Kandala, D. C. Mckay and J. M. Gambetta, Mitigating measurement errors in multiqubit experiments (2021), Physical Review A 103, 042605.

class qibo.tomography.state_tomography.StateTomography[source]#

Quantum state tomography with Pauli measurements.

The state \(\rho\) of \(n\) qubits is expanded in the Pauli basis,

\[\rho = \frac{1}{2^{n}} \sum_{P} \text{tr}(P \, \rho) \, P \, ,\]

where the sum runs over the \(4^{n}\) Pauli strings \(P\). Each qubit is measured in one of the bases \(X\), \(Y\), or \(Z\), which gives \(3^{n}\) measurement settings. The expectation value of a Pauli string with \(w\) non-identity factors is estimated from the outcomes of any setting that measures those factors in the right bases, so there are \(3^{n - w}\) such settings, whose estimates are averaged. The number of circuits, \(3^{n}\), and the cost of the reconstruction grow exponentially with \(n\), so this protocol is meant for few qubits.

The estimate of the state, \(\hat{\rho}\), is obtained from the outcomes with one of the following estimators, selected with the argument method of __call__().

  • "linear-inversion": the estimated expectation values are inserted in the expansion above [1, 2]. The estimate is Hermitian, has unit trace, and is unbiased, but it is not positive semidefinite in general, since the statistical errors can make some of its eigenvalues negative.

  • "physical-linear-inversion": the density matrix that is the closest, in the Frobenius norm, to the linear inversion estimate. It is obtained by projecting the eigenvalues of the latter onto the probability simplex, which sets the negative ones to zero and shifts the others to keep the trace [3].

  • "least-squares": the density matrix that minimizes the sum of the squared differences between the observed frequencies and the probabilities that it predicts for all outcomes of all settings. The minimization is constrained to physical states, and it is carried out by an accelerated projected gradient method [3, 6].

  • "mle": the density matrix that maximizes the likelihood of the observed outcomes, found by the diluted iterative algorithm of Refs. [4, 5]. It is always physical, but it is biased towards states with low rank.

Readout errors can be mitigated, in all estimators, with the response matrix of the measurements [7]. In the linear estimators, the probabilities of the outcomes are multiplied by the inverse of the response matrix. In "least-squares" and "mle", the response matrix is included in the model of the probabilities, so that the observed frequencies are used as they are.

Example

from qibo import Circuit, gates
from qibo.tomography import StateTomography

circuit = Circuit(2)
circuit.add(gates.H(0))
circuit.add(gates.CNOT(0, 1))

# reconstruction of the Bell state from 9 circuits of 1000 shots
estimate = StateTomography()(circuit, nshots=1000, seed=1)

# the same data, with a maximum likelihood estimate
estimate = StateTomography()(circuit, nshots=1000, seed=1, method="mle")

References

  1. M. A. Nielsen and I. L. Chuang, Quantum Computation and Quantum Information, Cambridge University Press (2010), Sec. 8.4.2.

  2. D. F. V. James, P. G. Kwiat, W. J. Munro and A. G. White, Measurement of qubits, Phys. Rev. A 64, 052312 (2001).

  3. J. A. Smolin, J. M. Gambetta and G. Smith, Efficient method for computing the maximum-likelihood quantum state from measurements with additive Gaussian noise, Phys. Rev. Lett. 108, 070502 (2012).

  4. Z. Hradil, Quantum-state estimation, Phys. Rev. A 55, R1561 (1997).

  5. A. I. Lvovsky, Iterative maximum-likelihood reconstruction in quantum homodyne tomography, J. Opt. B: Quantum Semiclass. Opt. 6, S556 (2004).

  6. A. Beck and M. Teboulle, A fast iterative shrinkage-thresholding algorithm for linear inverse problems, SIAM J. Imaging Sci. 2, 183 (2009).

  7. S. Bravyi, S. Sheldon, A. Kandala, D. C. Mckay and J. M. Gambetta, Mitigating measurement errors in multiqubit experiments, Phys. Rev. A 103, 042605 (2021).

__call__(circuit, nshots=1000, seed=None, method='linear-inversion', response_matrix=None, iterations=1000, tolerance=1e-08, backend=None)[source]#

Estimates the density matrix of the state prepared by circuit.

Parameters:
  • circuit (qibo.models.circuit.Circuit) – circuit preparing the state, without measurements.

  • nshots (int, optional) – number of shots per measurement setting. Defaults to \(1000\).

  • seed (int, optional) – seed of the sampling of the outcomes. If None, the generator of the backend is not reseeded. Defaults to None.

  • method (str, optional) – estimator of the state. It is one of "linear-inversion", "physical-linear-inversion", "least-squares", or "mle". Only the last two are iterative, and use iterations and tolerance. Defaults to "linear-inversion".

  • response_matrix (ArrayLike, optional) – \(2^{n} \times 2^{n}\) response matrix of the readout of the \(n\) qubits, whose element \((i, j)\) is the probability of reading the outcome \(i\) when the computational basis state \(j\) is prepared. It is the matrix returned by qibo.models.error_mitigation.get_response_matrix(). If None, the readout is assumed to be ideal. Defaults to None.

  • iterations (int, optional) – maximum number of iterations of "least-squares" and "mle". Defaults to \(1000\).

  • tolerance (float, optional) – the iterations of "least-squares" and "mle" stop when the largest change of an element of the estimate is smaller than this value. Defaults to \(10^{-8}\).

  • backend (qibo.backends.abstract.Backend, optional) – backend to be used in the execution. If None, it uses the current backend. Defaults to None.

Returns:

\(2^{n} \times 2^{n}\) estimated density matrix.

Return type:

ArrayLike

circuits(circuit)[source]#

Appends the basis changes and the measurements of each setting to circuit.

Parameters:

circuit (qibo.models.circuit.Circuit) – circuit preparing the state, without measurements.

Returns:

\(3^{n}\) circuits, one for each setting, in the order of itertools.product("XYZ", repeat=n), i.e. the Pauli of the first qubit changes the slowest. Each circuit measures all qubits, after rotating the Pauli \(X\) with qibo.gates.H, and the Pauli \(Y\) with qibo.gates.SDG followed by qibo.gates.H.

Return type:

list

Riemannian State Tomography#

Most states of interest have a low rank \(r\), which makes them determined by far fewer than \(d^{2}\) parameters, with \(d = 2^{n}\). The protocol draws \(m\) distinct Pauli strings \(S_{i}\) at random, and estimates each expectation value \(\text{tr}(S_{i} \, \rho)\) from nshots shots, which gives the data \(y\) of the sensing map

\[\mathcal{A}(X)_{i} = \sqrt{\frac{d}{m}} \, \text{tr}(S_{i} \, X) \, ,\]

whose adjoint is \(\mathcal{A}^{\dagger}(y) = \sqrt{d / m} \sum_{i} y_{i} S_{i}\). The state is estimated by minimizing \(\| y - \mathcal{A}(X) \|_{2}^{2} / 2\) over the matrices of rank at most \(r\) with Riemannian gradient descent [1, 2]. The first iterate is the rank-\(r\) truncation of \(\mathcal{A}^{\dagger}(y)\). At each iteration, the gradient is projected onto the tangent space of the rank-\(r\) matrices at the current estimate, the estimate moves along the projection with the step size that minimizes the objective exactly, and it is truncated to rank \(r\) again. The truncation keeps the \(r\) largest eigenvalues and sets the negative ones to zero, which differs from the singular value truncation of Ref. [2], and the unit trace is not enforced, so the estimate is a positive semidefinite matrix of rank at most \(r\).

The contraction factor of the error does not depend on the condition number of \(\rho\), so the number of iterations grows only logarithmically with the target error [2]. The guarantees of Ref. [2] need enough Pauli strings and shots. Measuring between 20% and 40% of the \(4^{n}\) strings was enough in its numerical experiments, but fewer strings can leave several low-rank states that fit the data, particularly for states with few non-zero Pauli expectation values, e.g. GHZ states. Each Pauli string is measured with its own circuit.

References:

1. K. Wei, J.-F. Cai, T. F. Chan and S. Leung, Guarantees of Riemannian optimization for low rank matrix recovery (2016), SIAM Journal on Matrix Analysis and Applications 37, 1198.

2. M.-C. Hsu, E.-J. Kuo, W.-H. Yu, J.-F. Cai and M.-H. Hsieh, Quantum state tomography via non-convex Riemannian gradient descent (2024), Physical Review Letters 132, 240804.

class qibo.tomography.RiemannianStateTomography[source]#

Low-rank state tomography with non-convex Riemannian gradient descent.

The density matrix \(\rho\) of \(n\) qubits, with \(d = 2^{n}\), is assumed to have rank at most \(r\), which is the case of the states of interest in most applications. It is then determined by far fewer than \(d^{2}\) parameters, and \(m = \mathcal{O}(r \, d)\) Pauli expectation values, up to logarithmic factors, are enough to recover it [1, 2]. The protocol draws \(m\) distinct Pauli strings \(S_{i}\) uniformly at random, and estimates each expectation value \(\text{tr}(S_{i} \, \rho)\) from nshots shots, which gives the data \(y_{i}\) of the linear sensing map

\[\mathcal{A}(X)_{i} = \sqrt{\frac{d}{m}} \, \text{tr}(S_{i} \, X) \, , \qquad \mathcal{A}^{\dagger}(y) = \sqrt{\frac{d}{m}} \sum_{i=1}^{m} y_{i} \, S_{i} \, .\]

The estimate seeks the Hermitian matrix of rank at most \(r\) that minimizes \(\|y - \mathcal{A}(X)\|_{2}^{2} / 2\), with the Riemannian gradient descent of Ref. [3], as applied to tomography in Ref. [4]. The first iterate is the best rank-\(r\) approximation of \(\mathcal{A}^{\dagger}(y)\). At each iteration, the gradient \(G = \mathcal{A}^{\dagger}(y - \mathcal{A}(X))\) is projected onto the tangent space \(T\) of the rank-\(r\) matrices at \(X\), and \(X\) is moved along the projection \(\mathcal{P}_{T}(G)\) with the step size that minimizes the objective exactly,

\[\alpha = \frac{\|\mathcal{P}_{T}(G)\|_{F}^{2}} {\|\mathcal{A}(\mathcal{P}_{T}(G))\|_{2}^{2}} \, ,\]

followed by the truncation to rank \(r\). The contraction factor of the error is a constant that does not depend on the condition number of \(\rho\), so the number of iterations grows only logarithmically with the target error [4], while the first-order methods based on a factorization of the state converge more slowly for states with a large condition number. The update involves \(d \times r\) and \(2r \times 2r\) matrices, apart from the sensing maps and the first iterate.

The truncation keeps the \(r\) largest eigenvalues and sets the negative ones to zero, i.e. it projects onto the positive semidefinite matrices of rank at most \(r\), which contain \(\rho\). The truncation of Ref. [4] keeps instead the singular values of largest magnitude, so that a negative eigenvalue can survive, and in our tests it trapped the iterations in spurious minima for states of rank larger than one. The unit trace is relaxed, as in Ref. [4], so the estimate is positive semidefinite with rank at most \(r\), but its trace is not exactly one when the expectation values have statistical errors.

The Pauli strings must determine the state. Under the conditions of Ref. [4], which require more strings than the number of parameters of the state, and enough shots, the error in the Frobenius norm is bounded by a constant times \(\sqrt{r}\) times the noise level. In the numerical experiments of Ref. [4], between 20% and 40% of the \(4^{n}\) strings were measured. With fewer strings, other low-rank states may fit the data as well as the true one, particularly if only few Pauli expectation values of the state are not zero, as in GHZ states, and the estimate can be any of them. Each Pauli string is measured with its own circuit, so nobservables circuits are executed.

Example

from qibo import Circuit, gates
from qibo.tomography import RiemannianStateTomography

circuit = Circuit(4)
circuit.add(gates.RY(qubit, 0.3 * (qubit + 1)) for qubit in range(4))
circuit.add(gates.CNOT(qubit, qubit + 1) for qubit in range(3))

# pure state, which has rank one, from 128 of the 256 Pauli strings
tomography = RiemannianStateTomography()
estimate = tomography(
    circuit, rank=1, nobservables=128, nshots=2000, seed=1
)

References

  1. D. Gross, Y.-K. Liu, S. T. Flammia, S. Becker and J. Eisert, Quantum state tomography via compressed sensing, Phys. Rev. Lett. 105, 150401 (2010).

  2. S. T. Flammia, D. Gross, Y.-K. Liu and J. Eisert, Quantum tomography via compressed sensing: error bounds, sample complexity and efficient estimators, New J. Phys. 14, 095022 (2012).

  3. K. Wei, J.-F. Cai, T. F. Chan and S. Leung, Guarantees of Riemannian optimization for low rank matrix recovery, SIAM J. Matrix Anal. Appl. 37, 1198 (2016).

  4. M.-C. Hsu, E.-J. Kuo, W.-H. Yu, J.-F. Cai and M.-H. Hsieh, Quantum state tomography via non-convex Riemannian gradient descent, Phys. Rev. Lett. 132, 240804 (2024).

__call__(circuit, rank, nobservables, nshots=1000, iterations=100, tolerance=1e-08, seed=None, backend=None)[source]#

Estimates the low-rank density matrix of the state prepared by circuit.

Parameters:
  • circuit (qibo.models.circuit.Circuit) – circuit preparing the state, without measurements.

  • rank (int) – rank \(r\) of the estimate, which must be at least the rank of the state.

  • nobservables (int) – number \(m\) of Pauli strings that are measured, between \(1\) and \(4^{n}\). It is also the number of circuits.

  • nshots (int, optional) – number of shots per Pauli string. Defaults to \(1000\).

  • iterations (int, optional) – maximum number of Riemannian gradient descent iterations, after the initialization. Defaults to \(100\).

  • tolerance (float, optional) – the iterations stop when the largest change of an element of the estimate is smaller than this value. Defaults to \(10^{-8}\).

  • seed (int, optional) – seed of the sampling of the Pauli strings and of their outcomes. If None, the generator of the backend is not reseeded for the outcomes. Defaults to None.

  • backend (qibo.backends.abstract.Backend, optional) – backend to be used in the execution. If None, it uses the current backend. Defaults to None.

Returns:

\(2^{n} \times 2^{n}\) positive semidefinite estimate of the density matrix, with rank at most rank. Its trace is not constrained.

Return type:

ArrayLike

circuits(circuit, observables)[source]#

Appends the basis changes and the measurements of each Pauli string to circuit.

Parameters:
  • circuit (qibo.models.circuit.Circuit) – circuit preparing the state, without measurements.

  • observables (list) – Pauli strings to be measured, each one a str of "I", "X", "Y" and "Z", one per qubit, e.g. "XIZ".

Returns:

one circuit for each Pauli string, in the same order. Each circuit measures all qubits, after rotating the Pauli \(X\) with qibo.gates.H, and the Pauli \(Y\) with qibo.gates.SDG followed by qibo.gates.H. The identity and the Pauli \(Z\) need no rotation. The outcomes of the qubits of the identity are not used.

Return type:

list

Process Tomography#

Vanilla process tomography characterizes the process \(\mathcal{E}\) implemented by a circuit of \(n\) qubits by linear inversion [1, 2]. The process is described by its Pauli transfer matrix

\[R_{ij} = \frac{1}{2^{n}} \text{tr}\left(P_{i} \, \mathcal{E}(P_{j})\right) \, ,\]

which maps the Pauli coefficients \(s_{j} = \text{tr}(P_{j} \, \rho)\) of a state to those of its output, \(o_{i} = \sum_{j} R_{ij} \, s_{j}\). The process is probed with the \(4^{n}\) product states in which each qubit is in \(|0\rangle\), \(|1\rangle\), \(|+\rangle\), or \(|{+i}\rangle\), which are linearly independent. The output of each of them is reconstructed with state tomography, which needs \(3^{n}\) settings, so there are \(12^{n}\) circuits. If \(S\) and \(O\) have the coefficients of the inputs and of the outputs in their rows, then \(O = S R^{T}\), and the estimate is \(\hat{R} = (S^{-1} O)^{T}\). It can also be returned in the Liouville, or Choi, representation of qibo.quantum_info.

The estimate is unbiased, and it preserves the trace exactly, but it is not completely positive in general, because of the statistical errors. The number of circuits grows as \(12^{n}\), so the protocol is meant for few qubits, and the errors in the preparation of the inputs and in the measurements are part of the reconstructed process. A step-by-step guide is given in the process tomography tutorial.

References:

1. I. L. Chuang and M. A. Nielsen, Prescription for experimental determination of the dynamics of a quantum black box (1997), Journal of Modern Optics 44, 2455.

2. M. A. Nielsen and I. L. Chuang, Quantum Computation and Quantum Information, Cambridge University Press (2010), Sec. 8.4.2.

class qibo.tomography.process_tomography.ProcessTomography[source]#

Vanilla quantum process tomography by linear inversion.

The process \(\mathcal{E}\) of \(n\) qubits, which is the action of a circuit on the state of its qubits, is characterized by its Pauli transfer matrix,

\[R_{ij} = \frac{1}{2^{n}} \text{tr}\left(P_{i} \, \mathcal{E}(P_{j})\right) \, ,\]

where \(P_{i}\) are the \(4^{n}\) Pauli strings. It maps the vector of Pauli coefficients \(s_{j} = \text{tr}(P_{j} \, \rho)\) of a state to that of its output, \(o_{i} = \text{tr}(P_{i} \, \mathcal{E}(\rho)) = \sum_{j} R_{ij} \, s_{j}\).

The process is probed with the \(4^{n}\) product states in which each qubit is in one of \(|0\rangle\), \(|1\rangle\), \(|+\rangle\), or \(|{+i}\rangle\), whose Pauli coefficients \(s^{(k)}\) are linearly independent. The output of each of them is reconstructed with qibo.tomography.state_tomography.StateTomography, which needs \(3^{n}\) measurement settings, so there are \(12^{n}\) circuits. Collecting the coefficients in the matrices \(S_{kj} = s^{(k)}_{j}\) and \(O_{ki} = o^{(k)}_{i}\), which satisfy \(O = S \, R^{T}\), the estimate is \(\hat{R} = (S^{-1} \, O)^{T}\) [1, 2].

The estimate is unbiased, and it is trace preserving, i.e. its first row is exactly \((1, 0, \dots, 0)\), but in general it is not completely positive, since the statistical errors can make the Choi matrix have negative eigenvalues. The number of circuits grows as \(12^{n}\), so this protocol is meant for few qubits. The errors in the preparation of the input states and in the measurements are not corrected, and they are part of the reconstructed process.

Example

from qibo import Circuit, gates
from qibo.tomography import ProcessTomography

circuit = Circuit(1)
circuit.add(gates.H(0))

# Pauli transfer matrix of the Hadamard gate, from 12 circuits of 1000 shots
estimate = ProcessTomography()(circuit, nshots=1000, seed=1)

References

  1. I. L. Chuang and M. A. Nielsen, Prescription for experimental determination of the dynamics of a quantum black box, J. Mod. Opt. 44, 2455 (1997).

  2. M. A. Nielsen and I. L. Chuang, Quantum Computation and Quantum Information, Cambridge University Press (2010), Sec. 8.4.2.

__call__(circuit, nshots=1000, representation='pauli', seed=None, backend=None)[source]#

Estimates the process implemented by circuit.

Parameters:
  • circuit (qibo.models.circuit.Circuit) – circuit that implements the process, without measurements. It can have noise channels, and it can be a circuit of density matrices.

  • nshots (int, optional) – number of shots per circuit. Defaults to \(1000\).

  • representation (str, optional) – representation of the estimated process. If "pauli", it is the Pauli transfer matrix, which is real, in the Pauli basis ordered as \(I, X, Y, Z\) for each qubit, the first qubit being the most significant. This is the Pauli-Liouville representation, in the normalized Pauli basis, of qibo.quantum_info. If "liouville", or "choi", it is converted to that representation, with the row vectorization, using qibo.quantum_info.pauli_to_liouville(), or qibo.quantum_info.pauli_to_choi(). Defaults to "pauli".

  • seed (int, optional) – seed of the sampling of the outcomes. If None, the generator of the backend is not reseeded. Defaults to None.

  • backend (qibo.backends.abstract.Backend, optional) – backend to be used in the execution. If None, it uses the current backend. Defaults to None.

Returns:

\(4^{n} \times 4^{n}\) estimated process, in representation.

Return type:

ArrayLike

circuits(circuit)[source]#

Builds the circuits that probe the process implemented by circuit.

Each input state is prepared before circuit, and the output state is measured in all the settings of qibo.tomography.state_tomography.StateTomography.circuits().

Parameters:

circuit (qibo.models.circuit.Circuit) – circuit that implements the process, without measurements.

Returns:

\(12^{n}\) circuits. The input states change the slowest, in the order of itertools.product(range(4), repeat=n), with \(|0\rangle, |1\rangle, |+\rangle, |{+i}\rangle\) as \(0, 1, 2, 3\), and the first qubit changes the slowest. They are prepared from the zero state with qibo.gates.X, for \(|1\rangle\), qibo.gates.H, for \(|+\rangle\), and qibo.gates.H followed by qibo.gates.S, for \(|{+i}\rangle\). For each of them, there are the \(3^{n}\) circuits of the settings, in their order.

Return type:

list

Gate Set Tomography#

Gate Set Tomography (GST) is a powerful technique employed in quantum information processing to characterize the behavior of quantum gates on quantum hardware [1, 2, 3]. The primary objective of GST is to provide a robust framework for obtaining a representation of quantum gates within a predefined gate set when subjected to noise inherent to the quantum hardware.

By characterizing the impact of noise on quantum gates, GST enables the identification and quantification of errors, laying the groundwork for subsequent error mitigation strategies. The insights gained from GST are instrumental, for instance, in setting up the necessary parameters for Probabilistic Error Cancellation (PEC).

In practice, given a set of operators (or gates), \(\mathcal{O}=\{O_0, O_1, \dots, O_n\}\), a set of initial states \(\{\rho_k\}\), and a set of measurement bases \(\{M_j\}\), one performs GST on the \(l\)-th operator by choosing an initial state \(\rho_k\), applying the gate \(O_l \in \mathcal{O}\), measuring in the \(M_j\) basis in order to obtain the following matrix:

\[\{\tilde{O}_l\}_{jk} = \text{tr}(M_j\,O_l\,\rho_k) \, ,\]

which provides an estimated representation of the operator \(O_l\) in the specific system.

This implementation makes use, in particular, of \(\rho_k \in \{ \ketbra{0}{0}, \ketbra{1}{1}, \ketbra{+}{+}, \ketbra{y+}{y+} \}^{\otimes n}\) and \(M_j \in \{ I, X, Y, Z\}^{\otimes n}\) [4], with \(n\in\{1,2\}\) being the number of qubits. However, \(\{\tilde{O}_l\}_{jk}\) is not yet given in the Pauli-Liouville representation (also known as Pauli Transfer Matrix). To obtain the Pauli-Liouville representation, one needs the two matrices, described below. The matrix \(\tilde{g}\) has its elements \(\tilde{g}_{jk}\) defined as

\[\tilde{g}_{jk} = \text{tr}(M_j\,\rho_k) \, ,\]

which is obtained by measuring the initial states \(\{\rho_k\}\) in each basis element \(\{M_j\}\) without any gates’ application. The gauge matrix \(T\) is given by

\[\begin{split}T = \begin{pmatrix} 1 & 1 & 1 & 1 \\ 0 & 0 & 1 & 0 \\ 0 & 0 & 0 & 1 \\ 1 & -1 & 0 & 0 \\ \end{pmatrix} \, .\end{split}\]

This is the matrix, in a common gauge, implementing a change of basis. Therefore, the Pauli-Liouville representation can be recovered as

\[O_l^{PL} = T\,g^{-1}\,\tilde{O_l}\,T^{-1} \, .\]
References:

1. R. Blume-Kohout et al. Robust, self-consistent, closed-form tomography of quantum logic gates on a trapped ion qubit (2013), arXiv:1310.4492.

2. D. Greenbaum, Introduction to quantum gate set tomography (2015), arXiv:1509.02921.

3. E. Nielsen et al., Gate set tomography (2021), Quantum 5, 557.

4. S. Endo, S. C. Benjamin, and Y. Li, Practical quantum error mitigation for near-future applications (2018), Physical Review X 8.3: 031027.

qibo.tomography.gate_set_tomography.GST(gate_set, nshots=10000, noise_model=None, include_empty=False, pauli_liouville=False, gauge_matrix=None, backend=None, transpiler=None, two_qubit_basis_op_diff_registers=False, ancilla=None)[source]#

Run Gate Set Tomography on the input gate_set.

Warning

This function is deprecated and will be removed in a future release. Use qibo.tomography.gate_set_tomography.GateSetTomography instead.

Example 1:

Given the following gate_set:

gate_set = [(gates.RX, [np.pi/3]), gates.Z,
            (gates.PRX, [np.pi/2, np.pi/3]), (gates.GPI, [np.pi/7]),
            (gates.Unitary, [np.array([[1, 0], [0, 1]])]), gates.CNOT]

one can simply run GST to extract calibration matrices for 1- and 2-qubits (g_1q and g_2q respectively):

g_1q, g_2q, *gates_GST = GST(gate_set=gate_set,
                              nshots=int(1e4),
                              include_empty=True,
                              backend=NumpyBackend(),
                              )
Parameters:
  • gate_set (tuple or set or list) – set of qibo.gates.Gate and parameters to run GST on. For instance, gate_set = [(gates.RX, [np.pi/3]), gates.Z, (gates.PRX, [np.pi/2, np.pi/3]), (gates.GPI, [np.pi/7]), (gates.Unitary, [np.array([[1, 0], [0, 1]])]), gates.CNOT].

  • nshots (int, optional) – number of shots used in Gate Set Tomography per gate. Defaults to \(10^{4}\).

  • noise_model (qibo.noise.NoiseModel, optional) – noise model applied to simulate noisy computations.

  • include_empty (bool, optional) – if True, additionally performs gate set tomography for \(1\)- and \(2\)-qubit empty circuits, returning the corresponding empty matrices in the first and second position of the ouput list.

  • pauli_liouville (bool, optional) – if True, returns the matrices in the Pauli-Liouville representation. Defaults to False.

  • gauge_matrix (ndarray, optional) –

    gauge matrix transformation to the Pauli-Liouville representation. Defaults to

    \[\begin{split}\begin{pmatrix} 1 & 1 & 1 & 1 \\ 0 & 0 & 1 & 0 \\ 0 & 0 & 0 & 1 \\ 1 & -1 & 0 & 0 \\ \end{pmatrix}\end{split}\]

  • backend (qibo.backends.abstract.Backend, optional) – backend to be used in the execution. If None, it uses the current backend. Defaults to None.

  • two_qubit_basis_op_diff_registers (bool) – If True, the input gate_set must contain exactly two \(1\)-qubit gates, one for each qubit, and gate set tomography will be performed simultaneously on a \(2\)-qubit circuit. If False, gate set tomography will be performed separately for each gate in gate_set. ‘Defaults to False. (Not to be confused with a single two-qubit basis operation i.e. a single \(2\)-qubit gate.)

  • ancilla (int, optional) –

    Controls whether SWAP gates are applied to replace qubits 0 and/or 1 with fresh ancilla qubits.

    • If ancilla = 0, a single SWAP gate is applied on qubit0 and an ancilla qubit

    • If ancilla = 1, a single SWAP gate is applied on qubit1 and an ancilla qubit

    • If ancilla = 2, SWAP gates are applied between qubit 0 and one ancilla qubit, and between qubit 1 and another ancilla qubit

    • If ancilla = None, no SWAP gates are used. Defaults to None.

Returns:

Input gate_set represented by matrices estimaded via GST.

Return type:

List[ArrayLike]

Gate Set Tomography of a circuit#

The class qibo.tomography.gate_set_tomography.GateSetTomography, built on qibo.tomography.abstract.Tomography, performs the Gate Set Tomography above on a circuit that implements the operation to be characterized.

In practice, given a circuit implementing an operation \(O\) on \(n \in \{1, 2\}\) qubits, a set of initial states \(\{\rho_{k}\}\), and a set of measurement bases \(\{M_{j}\}\), one performs GST on \(O\) by choosing an initial state \(\rho_{k}\), applying the operation \(O\), and measuring in the \(M_{j}\) basis in order to obtain the following matrix [1]:

\[\tilde{O}_{jk} = \text{tr}(M_{j}\,O\,\rho_{k}) \, ,\]

which provides an estimated representation of the operation \(O\) in the specific system.

This implementation makes use, in particular, of \(\rho_{k} \in \{ \ketbra{0}{0}, \ketbra{1}{1}, \ketbra{+}{+}, \ketbra{y+}{y+} \}^{\otimes n}\) and \(M_{j} \in \{ I, X, Y, Z\}^{\otimes n}\) [4]. The states are prepared, and the measurement bases are implemented, by gates of the circuit itself, which makes it the linear inversion variant of GST (LGST) of Ref. [1] (Sec. 3). However, \(\tilde{O}_{jk}\) is not yet given in the Pauli-Liouville representation (also known as Pauli Transfer Matrix). To obtain the Pauli-Liouville representation, one needs the two matrices, described below. The matrix \(\tilde{g}\), the Gram matrix of the fiducial states and measurements, has its elements \(\tilde{g}_{jk}\) defined as

\[\tilde{g}_{jk} = \text{tr}(M_{j}\,\rho_{k}) \, ,\]

which is obtained by measuring the initial states \(\{\rho_{k}\}\) in each basis element \(\{M_{j}\}\) without any gates’ application, i.e. by running GST on an empty circuit. Hence, it accounts for the errors of state preparation and measurement. The gauge matrix \(T\) is given by

\[\begin{split}T = \begin{pmatrix} 1 & 1 & 1 & 1 \\ 0 & 0 & 1 & 0 \\ 0 & 0 & 0 & 1 \\ 1 & -1 & 0 & 0 \\ \end{pmatrix} \, .\end{split}\]

This is the matrix, in a common gauge, implementing a change of basis. Its columns are the ideal fiducial states in the Pauli basis, which is the best a priori choice of gauge [1]. Therefore, the Pauli-Liouville representation can be recovered as

\[O^{\text{PL}} = T\,\tilde{g}^{-1}\,\tilde{O}\,T^{-1} \, .\]

For \(n = 2\) qubits, the tensor product \(T \otimes T\) is used. The Gram matrix must be well-conditioned for its inverse not to amplify the statistical error [1].

References:

1. E. Nielsen et al., Gate set tomography (2021), Quantum 5, 557, arXiv:2009.07301.

2. R. Blume-Kohout et al. Robust, self-consistent, closed-form tomography of quantum logic gates on a trapped ion qubit (2013), arXiv:1310.4492.

3. D. Greenbaum, Introduction to quantum gate set tomography (2015), arXiv:1509.02921.

4. S. Endo, S. C. Benjamin, and Y. Li, Practical quantum error mitigation for near-future applications (2018), Physical Review X 8.3: 031027.

class qibo.tomography.gate_set_tomography.GateSetTomography[source]#

Gate set tomography (GST) of one- and two-qubit circuits by linear inversion.

Given a circuit implementing an operation \(O\) on \(n \in \{1, 2\}\) qubits, each fiducial state \(\rho_{k} \in \{ |0\rangle\langle 0|, |1\rangle\langle 1|, |+\rangle\langle +|, |y+\rangle\langle y+| \}^{\otimes n}\) is prepared and \(O\) is applied. The output is then measured in each Pauli basis \(M_{j} \in \{ I, X, Y, Z \}^{\otimes n}\), which estimates the \(4^{n} \times 4^{n}\) matrix

\[\tilde{O}_{jk} = \text{tr}(M_{j} \, O \, \rho_{k}) \, .\]

The same experiments for an empty circuit estimate the Gram matrix of the fiducial states and measurements,

\[\tilde{g}_{jk} = \text{tr}(M_{j} \, \rho_{k}) \, ,\]

which accounts for state preparation and measurement errors. Then, the linear inversion of Ref. [1] (Sec. 3.2) gives the estimate of \(O\) in the Pauli-Liouville representation, also known as Pauli transfer matrix,

\[O^{\text{PL}} = T \, \tilde{g}^{-1} \, \tilde{O} \, T^{-1} \, ,\]

where \(T\) is the gauge matrix. The estimate is defined up to a gauge transformation, and the default \(T\) is the one that corresponds to the ideal fiducial states, which is the best a priori choice in Ref. [1] (Sec. 3.2). It is the tensor product of the single-qubit matrix

\[\begin{split}T = \begin{pmatrix} 1 & 1 & 1 & 1 \\ 0 & 0 & 1 & 0 \\ 0 & 0 & 0 & 1 \\ 1 & -1 & 0 & 0 \end{pmatrix} \, .\end{split}\]

Note

The Gram matrix must be well-conditioned for its inverse not to amplify the statistical error. Its singular values can be inspected before the inversion, by calling the protocol on an empty circuit [1].

Example

from qibo import Circuit, gates
from qibo.tomography import GateSetTomography

circuit = Circuit(1)
circuit.add(gates.X(0))

# Pauli-Liouville representation of a Pauli X gate
gst = GateSetTomography()
estimate = gst(circuit, nshots=1000, pauli_liouville=True)

References

  1. E. Nielsen et al., Gate set tomography, Quantum 5, 557 (2021), arXiv:2009.07301.

  2. R. Blume-Kohout et al., Robust, self-consistent, closed-form tomography of quantum logic gates on a trapped ion qubit, arXiv:1310.4492.

  3. D. Greenbaum, Introduction to quantum gate set tomography, arXiv:1509.02921.

  4. S. Endo, S. C. Benjamin and Y. Li, Practical quantum error mitigation for near-future applications, Phys. Rev. X 8, 031027 (2018).

__call__(circuit, nshots=10000, noise_model=None, auxiliary=None, pauli_liouville=False, gauge_matrix=None, gram_matrix=None, transpiler=None, backend=None)[source]#

Estimates the matrix of the operation implemented by circuit.

Parameters:
  • circuit (qibo.models.circuit.Circuit) – circuit, on \(1\) or \(2\) qubits and without measurements, implementing the operation to be characterized. An empty circuit gives the Gram matrix. Two single-qubit gates acting on different qubits of a \(2\)-qubit circuit are characterized simultaneously.

  • nshots (int, optional) – number of shots per circuit. Defaults to \(10^{4}\).

  • noise_model (qibo.noise.NoiseModel, optional) – noise model applied to simulate noisy computations. Defaults to None.

  • auxiliary (list[int], optional) – qubits of circuit that are swapped with fresh auxiliary qubits, in the zero state, right after the fiducial state is prepared, i.e. they are reset before circuit acts on them. Then, the columns of the matrix do not depend on the fiducial state of those qubits. The Gram matrix is always estimated without auxiliary qubits. Defaults to None.

  • pauli_liouville (bool, optional) – if True, returns the estimate in the Pauli-Liouville representation. Defaults to False.

  • gauge_matrix (ArrayLike, optional) – invertible \(4 \times 4\) gauge matrix of a single qubit, used if pauli_liouville=True. For \(2\) qubits, its tensor product with itself is used. If None, it is the matrix of the ideal fiducial states, given in the class description. Defaults to None.

  • gram_matrix (ArrayLike, optional) – Gram matrix used if pauli_liouville=True. If None, it is estimated with the same nshots, noise_model and transpiler. It can be provided to avoid estimating it again when characterizing several circuits. Defaults to None.

  • transpiler (qibo.transpiler.pipeline.Passes, optional) – transpiler applied to the circuits before their execution. If None and the backend is qibolab, it uses a transpiler built from the connectivity and the native gates of the backend. The placement is the same for all the circuits. Defaults to None.

  • backend (qibo.backends.abstract.Backend, optional) – backend to be used in the execution. If None, it uses the current backend. Defaults to None.

Returns:

\(4^{n} \times 4^{n}\) matrix \(\tilde{O}\), or \(O^{\text{PL}}\) if pauli_liouville=True.

Return type:

ArrayLike

circuits(circuit, auxiliary=None)[source]#

Builds the circuits that estimate the matrix of circuit.

Each circuit prepares a fiducial state, applies circuit, and measures all the qubits in the basis of a Pauli string. The qubits are measured in the \(Z\) basis for the identity, and the outcome is not used.

Parameters:
  • circuit (qibo.models.circuit.Circuit) – circuit, on \(1\) or \(2\) qubits and without measurements, implementing the operation to be characterized.

  • auxiliary (list[int], optional) – qubits of circuit that are swapped with fresh auxiliary qubits, appended to the circuit in the same order, right after the fiducial state is prepared. Defaults to None.

Returns:

\(4^{n} (4^{n} - 1)\) circuits, ordered by fiducial state, and then by Pauli string. The identity string is excluded, since its expectation value is always \(1\).

Return type:

list

Classical Shadows#

Classical shadows estimate the expectation values of many observables from the outcomes of randomized measurements [1]. Each sample applies a random unitary \(U\) to the state \(\rho\), and measures all qubits in the computational basis, returning \(b\). The resulting snapshot is

\[\sigma = U^{\dagger} \ketbra{b}{b} U \, ,\]

and the average snapshot over many samples is mapped through the inverse of the frame operator \(\mathcal{M}\), i.e. the measurement channel of the ensemble of \(U\),

\[\mathcal{M}(\rho) = \mathbb{E}_{U} \sum_{b} \bra{b} U \rho U^{\dagger} \ket{b} \, U^{\dagger} \ketbra{b}{b} U \, ,\]

giving \(\hat{\rho} = \mathcal{M}^{-1}(\bar{\sigma})\). Then, \(\text{tr}(O \hat{\rho})\) is an unbiased estimate of \(\text{tr}(O \rho)\) for any observable \(O\) [1, 2].

A step-by-step guide to all the options is given in the classical shadows tutorial.

The ensemble of \(U\) is chosen through the argument method, which defines the frame operator. All the ensembles are locally invariant, so \(\mathcal{M}\) is diagonal in the Pauli basis, with \(\mathcal{M}(P) = f_{P} P\) for each Pauli string \(P\):

  • "global-clifford": \(U\) is sampled from the Clifford group \(\text{Cl}(2^{n})\) of \(n\) qubits, and \(f_{P} = 1 / (2^{n} + 1)\) for any \(P \neq I^{\otimes n}\).

  • "local-clifford": \(U\) is sampled from \(\text{Cl}(2)^{\otimes n}\), and \(f_{P} = 3^{-w}\) for a Pauli string of weight \(w\).

  • "ultra-shallow": \(U\) has depth + 1 layers of random single-qubit Cliffords, with a layer of CNOT gates (the "shifted" architecture of qibo.models.encodings.entangling_layer()) before each layer but the first [3]. For depth=0 it is "local-clifford". For larger depths, \(f_{P}\) depends only on the support \(k \in \{0, 1\}^{n}\) of \(P\), and has no analytical form. It is sampled instead as

    \[f_{k} = \mathbb{E}_{g} \sum_{z} \bra{0} g^{\dagger} \ketbra{z}{z} g \ket{0} \, \bra{z} g Z^{k} g^{\dagger} \ket{z} \, ,\]

    with \(Z^{k} = \bigotimes_{l} Z^{k_{l}}\), that is, from the same random circuits \(g\) applied to the zero state, whose number is given by ncalibration. Hence, if the circuits are noisy, the sampled frame includes the noise [3].

The frame operator is applied in the Pauli basis (default) or in the computational basis, selected by the argument basis. In the Pauli basis, the observable must be given as the Pauli strings and coefficients \(O = \sum_{P} \alpha_{P} P\), and the estimate is

\[\hat{o} = \sum_{P} \alpha_{P} \, f_{P}^{-1} \, \text{tr}(P \bar{\sigma}) \, ,\]

where the coefficients \(\text{tr}(P \bar{\sigma})\) of all Pauli strings are obtained with a fast Hadamard transform, and only the diagonal of the frame is needed. In the computational basis, the observable is a Hamiltonian or a matrix, and \(\mathcal{M}^{-1}\) is a matrix.

If robust=True, the frame of "local-clifford" is also sampled from ncalibration circuits applied to the zero state, in the same way as for "ultra-shallow", instead of taking the analytical eigenvalues \(3^{-w}\). The sampled frame includes the noise of the measurement circuits, so the estimator remains unbiased under noise that is the same in the calibration and the measurement circuits, which is the robust shadow estimation of Ref. [4]. The frame of "global-clifford" has no robust version.

The method density_matrix() returns the estimated state \(\hat{\rho}\) itself, instead of the expectation value of an observable. It is Hermitian, with unit trace and unbiased, but not positive semidefinite in general.

The samples can be split into batches to use the median-of-means estimator [1], which is the empirical average for a single batch. The circuits are generated and executed in chunks, which bounds the memory they use, and each batch is processed as soon as it is complete.

References:

1. H.-Y. Huang, R. Kueng and J. Preskill, Predicting many properties of a quantum system from very few measurements (2020), Nature Physics 16, 1050.

2. L. Innocenti et al., Shadow tomography on general measurement frames (2023), PRX Quantum 4, 040328.

3. R. M. S. Farias, R. D. Peddinti, I. Roth and L. Aolita, Robust ultra-shallow shadows, Quantum Science and Technology 10, 025044.

4. S. Chen, W. Yu, P. Zeng and S. T. Flammia, Robust shadow estimation (2021), PRX Quantum 2, 030348.

class qibo.tomography.classical_shadows.ClassicalShadow[source]#

Classical shadows protocol with random Clifford measurements.

The state is rotated by a random unitary \(U\) and measured in the computational basis, returning \(b\). Each snapshot \(U^{\dagger} |b\rangle\langle b| U\) is averaged and mapped through the inverse of the frame operator, i.e. the measurement channel of the ensemble of \(U\), which is one of the following method.

  • "global-clifford": \(U \in \text{Cl}(2^{n})\).

  • "local-clifford": \(U \in \text{Cl}(2)^{\otimes n}\).

  • "ultra-shallow": \(U\) has depth + 1 layers of random single-qubit Cliffords, with a layer of CNOT gates before each layer but the first. Its frame operator has no analytical form, and is sampled from the same circuits applied to the zero state.

With robust=True, the frame operator of "local-clifford" is sampled in the same way instead of taking its analytical form, so that it includes the noise of the measurement circuits. This is the robust shadow estimation of Ref. [4].

The frame operator is applied in the Pauli basis, where it is diagonal, or in the computational basis. Estimates can be combined by the median of means, and circuits are generated and executed in chunks to bound the memory used. Besides expectation values, density_matrix() returns the estimated density matrix itself, i.e. the classical shadow.

Example

from qibo import Circuit, gates
from qibo.tomography import ClassicalShadow

circuit = Circuit(2)
circuit.add(gates.H(0))
circuit.add(gates.CNOT(0, 1))

# expectation value of 0.5 ZZ + 0.5 XX in a Bell state
shadow = ClassicalShadow()
estimate = shadow(
    circuit, {"ZZ": 0.5, "XX": 0.5}, 100, "local-clifford", seed=42
)

References

  1. H.-Y. Huang, R. Kueng and J. Preskill, Predicting many properties of a quantum system from very few measurements, Nat. Phys. 16, 1050 (2020).

  2. L. Innocenti et al., Shadow tomography on general measurement frames, PRX Quantum 4, 040328 (2023).

  3. R. M. S. Farias, R. D. Peddinti, I. Roth and L. Aolita, Robust ultra-shallow shadows, Quantum Sci. Technol..

  4. S. Chen, W. Yu, P. Zeng and S. T. Flammia, Robust shadow estimation, PRX Quantum 2, 030348 (2021).

__call__(circuit, observable, nsamples, method='global-clifford', basis='pauli', nshots=1, nbatches=1, chunksize=1000, depth=1, ncalibration=None, robust=False, seed=None, backend=None)[source]#

Estimates the expectation value of observable on the output of circuit.

Parameters:
  • circuit (qibo.models.circuit.Circuit) – circuit preparing the state, without measurements.

  • (list (observable) – or ArrayLike): if basis="pauli", a list of tuples (pauli_string, coefficient) or a dictionary {pauli_string: coefficient}, with pauli_string a str of "I", "X", "Y" and "Z", one per qubit, e.g. "XIZ". If basis="computational", a Hamiltonian or a matrix.

  • dict – or ArrayLike): if basis="pauli", a list of tuples (pauli_string, coefficient) or a dictionary {pauli_string: coefficient}, with pauli_string a str of "I", "X", "Y" and "Z", one per qubit, e.g. "XIZ". If basis="computational", a Hamiltonian or a matrix.

  • observable (list[tuple[str, float]] | dict[str, float] | AbstractHamiltonian | _Buffer | _SupportsArray[dtype[Any]] | _NestedSequence[_SupportsArray[dtype[Any]]] | bool | int | float | complex | str | bytes | _NestedSequence[bool | int | float | complex | str | bytes]) –

  • nsamples (int) –

  • method (str) –

  • basis (str) –

  • nshots (int) –

  • nbatches (int) –

  • chunksize (int) –

  • depth (int) –

  • ncalibration (int | None) –

  • robust (bool) –

  • seed (int | None) –

  • backend (Backend) –

:param qibo.hamiltonians.abstract.AbstractHamiltonian: or ArrayLike): if basis="pauli", a list of tuples

(pauli_string, coefficient) or a dictionary {pauli_string: coefficient}, with pauli_string a str of "I", "X", "Y" and "Z", one per qubit, e.g. "XIZ". If basis="computational", a Hamiltonian or a matrix.

Parameters:
  • nsamples (int) – number of random unitaries.

  • method (str, optional) – "global-clifford", "local-clifford", or "ultra-shallow". Defaults to "global-clifford".

  • basis (str, optional) – "pauli" or "computational", the basis in which the frame is applied. Defaults to "pauli".

  • nshots (int, optional) – number of shots per random unitary. Defaults to \(1\).

  • nbatches (int, optional) – number of batches of the median-of-means estimator. The nsamples unitaries are split into nbatches batches of (almost) equal size, and the median of the batch estimates is returned. If \(1\), it is the empirical mean. Defaults to \(1\).

  • chunksize (int, optional) – maximum number of circuits generated and executed at once, which bounds the memory used by the circuits. Defaults to \(1000\).

  • depth (int, optional) – number of entangling layers of the measurement circuits of "ultra-shallow", which has depth + 1 layers of single-qubit Cliffords. It is ignored by the other methods. Defaults to \(1\).

  • ncalibration (int, optional) – number of circuits used to sample the frame operator of "ultra-shallow", which has no analytical form, or of "local-clifford" if robust=True. It is ignored otherwise. If None, it is nsamples. Defaults to None.

  • robust (bool, optional) – if True, the frame operator of "local-clifford" is sampled from ncalibration circuits applied to the zero state, so that it includes the noise of the measurement circuits. The frame of "ultra-shallow" is always sampled, and "global-clifford" raises NotImplementedError. Defaults to False.

  • seed (int, optional) – seed of the random unitaries. The calibration of the frame, if sampled, uses seed + 1. Defaults to None.

  • backend (qibo.backends.abstract.Backend, optional) – backend to be used in the execution. If None, it uses the current backend. Defaults to None.

  • circuit (Circuit) –

  • observable (list[tuple[str, float]] | dict[str, float] | AbstractHamiltonian | _Buffer | _SupportsArray[dtype[Any]] | _NestedSequence[_SupportsArray[dtype[Any]]] | bool | int | float | complex | str | bytes | _NestedSequence[bool | int | float | complex | str | bytes]) –

Returns:

estimated expectation value.

Return type:

float

circuits(circuit, nsamples, method='global-clifford', depth=1, seed=None, backend=None)[source]#

Appends random Clifford unitaries and measurements to circuit.

Parameters:
  • circuit (qibo.models.circuit.Circuit) – circuit preparing the state, without measurements.

  • nsamples (int) – number of random unitaries, i.e. of circuits.

  • method (str, optional) – "global-clifford" samples from \(\text{Cl}(2^{n})\); "local-clifford" samples from \(\text{Cl}(2)^{\otimes n}\); "ultra-shallow" alternates depth + 1 layers of random single-qubit Cliffords with depth layers of CNOT gates, built with the "shifted" architecture of qibo.models.encodings.entangling_layer(), i.e. CNOTs on even pairs followed by odd pairs, so that depth=0 is "local-clifford". Defaults to "global-clifford".

  • depth (int, optional) – number of entangling layers of "ultra-shallow". It is ignored by the other methods. Defaults to \(1\).

  • seed (int, optional) – seed of the random unitaries. Defaults to None.

  • backend (qibo.backends.abstract.Backend, optional) – backend to be used in the sampling. If None, it uses the current backend. Defaults to None.

Returns:

nsamples circuits, each followed by a measurement of all qubits.

Return type:

list

density_matrix(circuit, nsamples, method='global-clifford', basis='pauli', nshots=1, chunksize=1000, depth=1, ncalibration=None, robust=False, seed=None, backend=None)[source]#

Estimates the density matrix of the state prepared by circuit.

The estimate is the classical shadow \(\hat{\rho} = \mathcal{M}^{-1}(\bar{\sigma})\), where \(\bar{\sigma}\) is the average snapshot over the nsamples random unitaries, and \(\mathcal{M}\) is the frame operator. It is Hermitian with unit trace, and it is an unbiased estimate of the density matrix, but it is not positive semidefinite in general. For the same arguments, expectation values computed from it are those returned by __call__() with nbatches=1, up to numerical precision.

Parameters:
  • circuit (qibo.models.circuit.Circuit) – circuit preparing the state, without measurements.

  • nsamples (int) – number of random unitaries.

  • method (str, optional) – "global-clifford", "local-clifford", or "ultra-shallow". Defaults to "global-clifford".

  • basis (str, optional) – "pauli" or "computational", the basis in which the inverse frame is applied. Both give the same estimate, but "computational" builds a \(4^{n} \times 4^{n}\) matrix, while "pauli" uses a fast Hadamard transform. Defaults to "pauli".

  • nshots (int, optional) – number of shots per random unitary. Defaults to \(1\).

  • chunksize (int, optional) – maximum number of circuits generated and executed at once, which bounds the memory used by the circuits. Defaults to \(1000\).

  • depth (int, optional) – number of entangling layers of the measurement circuits of "ultra-shallow", which has depth + 1 layers of single-qubit Cliffords. It is ignored by the other methods. Defaults to \(1\).

  • ncalibration (int, optional) – number of circuits used to sample the frame operator of "ultra-shallow", which has no analytical form, or of "local-clifford" if robust=True. It is ignored otherwise. If None, it is nsamples. Defaults to None.

  • robust (bool, optional) – if True, the frame operator of "local-clifford" is sampled from ncalibration circuits applied to the zero state, so that it includes the noise of the measurement circuits. The frame of "ultra-shallow" is always sampled, and "global-clifford" raises NotImplementedError. Defaults to False.

  • seed (int, optional) – seed of the random unitaries. The calibration of the frame, if sampled, uses seed + 1. Defaults to None.

  • backend (qibo.backends.abstract.Backend, optional) – backend to be used in the execution. If None, it uses the current backend. Defaults to None.

Returns:

\(2^{n} \times 2^{n}\) estimated density matrix.

Return type:

ArrayLike

frame_operator(nqubits, method='global-clifford', inverse=False, basis='pauli', depth=1, nsamples=1000, chunksize=1000, robust=False, seed=None, backend=None)[source]#

Frame operator, i.e. the measurement channel, of the Clifford ensemble.

In the Pauli basis, the frame is diagonal with eigenvalue \(1\) for the identity. Any other Pauli string of weight \(w\) has eigenvalue \(1 / (2^{n} + 1)\) if method="global-clifford", and \(3^{-w}\) if method="local-clifford". If method="ultra-shallow", or method="local-clifford" with robust=True, the eigenvalue \(f_{k}\) depends only on the support \(k \in \{0, 1\}^{n}\) of the Pauli string, and it is sampled: it is the average of \(\langle z | g Z^{k} g^{\dagger} | z \rangle\) over nsamples random circuits \(g\) applied to the zero state, with outcomes \(z\), where \(Z^{k} = \bigotimes_{l} Z^{k_{l}}\). If the circuits are noisy, so is the sampled frame, which makes the estimates robust to that noise.

Note

If basis="pauli", only the diagonal of the frame is returned, as a real-valued vector of size \(4^{n}\), with Pauli strings ordered as in qibo.quantum_info.pauli_basis().

Parameters:
  • nqubits (int) – number of qubits.

  • method (str, optional) – "global-clifford", "local-clifford", or "ultra-shallow". Defaults to "global-clifford".

  • inverse (bool, optional) – if True, returns the inverse frame. If the frame is sampled, it raises an error if a sampled eigenvalue is not positive. Defaults to False.

  • basis (str, optional) – "pauli" or "computational". If "computational", the full \(4^{n} \times 4^{n}\) matrix acting on the row-vectorized density matrix is returned. Defaults to "pauli".

  • depth (int, optional) – number of entangling layers of "ultra-shallow". It is ignored by the other methods. Defaults to \(1\).

  • nsamples (int, optional) – number of circuits used to sample the frame of "ultra-shallow", or of "local-clifford" if robust=True. It is ignored otherwise. Defaults to \(1000\).

  • chunksize (int, optional) – maximum number of circuits executed at once when sampling. Defaults to \(1000\).

  • robust (bool, optional) – if True, the frame of "local-clifford" is sampled instead of using its analytical form. The frame of "ultra-shallow" is always sampled, and "global-clifford" raises NotImplementedError. Defaults to False.

  • seed (int, optional) – seed of the sampling. Defaults to None.

  • backend (qibo.backends.abstract.Backend, optional) – backend to be used in the calculation. If None, it uses the current backend. Defaults to None.

Returns:

frame operator, or its inverse.

Return type:

ArrayLike