Utility Functions#

Functions that can be used to calculate metrics and distance measures on classical probability arrays.

Hamming weight#

qibo.quantum_info.hamming_weight(bitstring, return_indexes=False)[source]#

Calculates the Hamming weight of a bitstring.

The Hamming weight of a bitstring is the number of \(1\)’s that the bitstring contains.

Parameters:
  • bitstring (int or str or tuple or list) – bitstring to calculate the weight, either in binary or integer representation.

  • return_indexes (bool, optional) – If True, returns the indexes of the non-zero elements. Defaults to False.

Returns:

Hamming weight of bitstring or list of indexes of non-zero elements.

Return type:

int or list

Hamming distance#

qibo.quantum_info.hamming_distance(bitstring_1, bitstring_2, return_indexes=False)[source]#

Calculates the Hamming distance between two bitstrings.

This is done by calculating the Hamming weight (qibo.quantum_info.utils.hamming_weight()) of | bitstring_1 - bitstring_2 |.

Parameters:
  • bitstring_1 (int or str or list or tuple) – first bitstring.

  • bitstring_2 (int or str or list or tuple) – second bitstring.

  • return_indexes (bool, optional) – If True, returns the indexes of the non-zero elements. Defaults to False.

Returns:

Hamming distance or list of indexes of non-zero elements.

Return type:

int or list

Hadamard Transform#

qibo.quantum_info.hadamard_transform(array, implementation='fast', backend=None)[source]#

Calculates the (fast) Hadamard Transform \(\text{HT}\) of a \(2^{n}\)-dimensional vector or \(2^{n} \times 2^{n}\) matrix \(A\), where \(n\) is the number of qubits in the system. If \(A\) is a vector, then

\[\text{HT}(A) = \frac{1}{2^{n / 2}} \, H^{\otimes n} \, A \,\]

where \(H\) is the qibo.gates.H gate. If \(A\) is a matrix, then

\[\text{HT}(A) = \frac{1}{2^{n}} \, H^{\otimes n} \, A \, H^{\otimes n} \, .\]
Parameters:
  • array (ArrayLike) – array or matrix.

  • implementation (str, optional) – if "regular", it uses the straightforward implementation of the algorithm with computational complexity of \(\mathcal{O}(2^{2n})\) for vectors and \(\mathcal{O}(2^{3n})\) for matrices. If "fast", computational complexity is \(\mathcal{O}(n \, 2^{n})\) in both cases.

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

Returns:

(Fast) Hadamard Transform of array.

Return type:

ArrayLike

Hellinger distance#

qibo.quantum_info.hellinger_distance(prob_dist_p, prob_dist_q, validate=False, backend=None)[source]#

Calculates the Hellinger distance \(H\) between two discrete probability distributions.

For probabilities \(\mathbf{p}\) and \(\mathbf{q}\), it is defined as

\[H(\mathbf{p} \, , \, \mathbf{q}) = \frac{1}{\sqrt{2}} \, \| \sqrt{\mathbf{p}} - \sqrt{\mathbf{q}} \|_{2}\]

where \(\|\cdot\|_{2}\) is the Euclidean norm.

Parameters:
  • prob_dist_p (ArrayLike or list) – discrete probability distribution \(p\).

  • prob_dist_q (ArrayLike or list) – discrete probability distribution \(q\).

  • validate (bool, optional) – If True, checks if \(p\) and \(q\) are proper probability distributions. Defaults to False.

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

Returns:

Hellinger distance \(H(p, q)\).

Return type:

float

Hellinger fidelity#

qibo.quantum_info.hellinger_fidelity(prob_dist_p, prob_dist_q, validate=False, backend=None)[source]#

Calculates the Hellinger fidelity between two discrete probability distributions.

For probabilities \(p\) and \(q\), the fidelity is defined as

\[(1 - H^{2}(p, q))^{2} \, ,\]

where \(H(p, q)\) is the qibo.quantum_info.hellinger_distance().

Parameters:
  • prob_dist_p (ArrayLike or list) – discrete probability distribution \(p\).

  • prob_dist_q (ArrayLike or list) – discrete probability distribution \(q\).

  • validate (bool, optional) – if True, checks if \(p\) and \(q\) are proper probability distributions. Defaults to False.

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

Returns:

Hellinger fidelity.

Return type:

float

Hellinger shot error#

qibo.quantum_info.hellinger_shot_error(prob_dist_p, prob_dist_q, nshots, validate=False, backend=None)[source]#

Calculates the Hellinger fidelity error between two discrete probability distributions estimated from finite statistics.

It is calculated propagating the probability error of each state of the system. The complete formula is:

\[\frac{1 - H^{2}(p, q)}{\sqrt{nshots}} \, \sum_{k} \, \left(\sqrt{p_{k} \, (1 - q_{k})} + \sqrt{q_{k} \, (1 - p_{k})}\right)\]

where \(H(p, q)\) is the qibo.quantum_info.hellinger_distance(), and \(1 - H^{2}(p, q)\) is the square root of the qibo.quantum_info.hellinger_fidelity().

Parameters:
  • prob_dist_p (ArrayLike or list) – discrete probability distribution \(p\).

  • prob_dist_q (ArrayLike or list) – discrete probability distribution \(q\).

  • nshots (int) – number of shots we used to run the circuit to obtain \(p\) and \(q\).

  • validate (bool, optional) – if True, checks if \(p\) and \(q\) are proper probability distributions. Defaults to False.

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

Returns:

Hellinger fidelity error.

Return type:

float

Total variation distance#

qibo.quantum_info.total_variation_distance(prob_dist_p, prob_dist_q, validate=False, backend=None)[source]#

Calculate the total variation distance between two discrete probability distributions.

For probabilities \(p\) and \(q\), the total variation distance is defined as

\[\operatorname{TVD}(p, \, q) = \frac{1}{2} \, \|p - q\|_{1} = \frac{1}{2} \, \sum_{x} \, \left|p(x) - q(x)\right| \, ,\]

where \(\|\cdot\|_{1}\) denotes the \(\ell_{1}\)-norm.

Parameters:
  • prob_dist_p (ArrayLike or list) – discrete probability distribution \(p\).

  • prob_dist_q (ArrayLike or list) – discrete probability distribution \(q\).

  • validate (bool, optional) – if True, checks if \(p\) and \(q\) are proper probability distributions. Defaults to False.

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

Returns:

Total variation distance measure.

Return type:

float

Haar integral#

qibo.quantum_info.haar_integral(nqubits, power_t, samples=None, backend=None)[source]#

Returns the integral over pure states over the Haar measure.

\[\int_{\text{Haar}} d\psi \, \left(|\psi\rangle\right.\left. \langle\psi|\right)^{\otimes t}\]
Parameters:
  • nqubits (int) – Number of qubits.

  • power_t (int) – power that defines the \(t\)-design.

  • samples (int, optional) – If None, estimated the integral exactly. Otherwise, number of samples to estimate the integral via sampling. 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:

Estimation of the Haar integral.

Return type:

ArrayLike

Note

The exact method (samples=None) is implemented using Lemma 34 of Kliesch and Roth (2020).

Parameterized quantum circuit integral#

qibo.quantum_info.pqc_integral(circuit, power_t, samples, backend=None)[source]#

Returns the integral over pure states generated by uniformly sampling in the parameter space described by a parameterized circuit.

\[\int_{\Theta} d\psi \, \left(|\psi_{\theta}\rangle\right.\left. \langle\psi_{\theta}|\right)^{\otimes t}\]
Parameters:
  • circuit (qibo.models.Circuit) – Parametrized circuit.

  • power_t (int) – power that defines the \(t\)-design.

  • samples (int) – number of samples to estimate the integral.

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

Returns:

Estimation of the integral.

Return type:

ArrayLike

Decompose permutation into the fewest pairwise transpositions#

qibo.quantum_info.decompose_permutation(sigma, m, backend=None)[source]#

Given permutation sigma on \(\{0, \, 1, \, \dots, \, d-1\}\) and a power‑of‑two budget m, this function factors sigma into the fewest layers \(\sigma_{1}, \, \sigma_{2}, \, \cdots, \, \sigma_{t}\) such that: - each layer has at most \(m\) disjoint transpositions - each layer moves a power‑of‑two number of indices.

We do this as follows: 1) Cycle extraction – split sigma into disjoint cycles. 2) Star factorisation – a k‑cycle becomes (k-1) hub–spoke swaps. 3) Greedy packing – merge swaps into layers while keeping rules.

Parameters:
  • sigma (list[int] or tuple[int]) – permutation description on \(\{0, \, 1, \, \dots, \, d-1\}\).

  • m (int) – power‑of‑two budget.

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

Returns:

\(t\) layers of pairwise transpositions.

Return type:

list[list[tuple[int, int]]]