Utility Functions#

Functions that can be used to calculate metrics and distance measures on classical probability arrays, and to convert classical bitstrings and measurement outcomes into phases.

Bitstring to phase#

qibo.quantum_info.bitstring_to_phase(bitstring)[source]#

Converts a bitstring into the phase it encodes as a binary fraction.

The bitstring \(b_{1} b_{2} \cdots b_{t}\), with \(b_{1}\) being the most significant bit, is mapped to

\[\varphi = 0.b_{1} b_{2} \cdots b_{t} = \sum_{j=1}^{t} \, b_{j} \, 2^{-j} \, ,\]

which belongs to the interval \([0, \, 1)\) (for \(t > 53\), the result can be rounded to \(1\), as it is a float). This is the outcome of measuring the \(t\) counting qubits at the end of quantum phase estimation, where the eigenvalue of the unitary is :math:`e^{2 pi i

arphi}`. The corresponding angle is

:math:`2 pi

arphi`. In the keys of qibo.result.MeasurementOutcomes.frequencies()

with binary=True, the first bit is the outcome of the first measured qubit, which must then be the most significant one.

Args:
bitstring (str or list or tuple or ndarray): sequence of bits, e.g. "0101" or

[0, 1, 0, 1], with the most significant bit first. It cannot be an integer, since the leading zeros of a bitstring are part of the phase and are lost in the integer representation. A TypeError is raised for integers and for any other object that is not a sequence.

Returns:

float: phase encoded in bitstring.

Example:

from qibo.quantum_info import bitstring_to_phase

# 0.0101 in binary is 1/4 + 1/16
print(bitstring_to_phase("0101"))
0.3125
References:

1. R. Cleve, A. Ekert, C. Macchiavello, and M. Mosca, Quantum algorithms revisited, Proc. R. Soc. Lond. A 454, 339 (1998).

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

Parameters:

bitstring (str | list | tuple | ArrayLike) –

Return type:

float

Estimate phase#

qibo.quantum_info.estimate_phase(outcomes)[source]#

Estimates the phase from the outcomes of the counting qubits of quantum phase estimation.

The estimate is the phase encoded in the most probable outcome, as given by qibo.quantum_info.bitstring_to_phase(). If several outcomes are equally probable, the first one is used. The outcomes can be given as

:param outcomes (qibo.result.MeasurementOutcomes or: qibo.measurements.MeasurementResult or dict or ndarray): measurement

outcomes of the counting qubits. If it is a mapping, the bitstrings must all have the same length.

Returns:

estimate of the phase, which belongs to the interval \([0, \, 1)\).

Return type:

float

Parameters:

outcomes (Mapping[str, float] | ArrayLike | MeasurementOutcomes | MeasurementResult) –

Example

import math

from qibo import Circuit, gates
from qibo.models import QPE
from qibo.quantum_info import estimate_phase

# unitary with eigenstate |1> and eigenvalue exp(2 pi i phase)
unitary = Circuit(1)
unitary.add(gates.U1(0, theta=2 * math.pi * 5 / 16))

nqubits_counting = 4
qpe = QPE(unitary, nqubits_counting)

# prepare the eigenstate in the target qubit and apply the phase estimation
circuit = Circuit(qpe.nqubits)
circuit.add(gates.X(nqubits_counting))
circuit.add(qpe)

result = circuit(nshots=100)
print(estimate_phase(result))
print(estimate_phase(result.frequencies()))
0.3125
0.3125

References

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

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]]]