RGD optimization method for quantum state tomography#1485
RGD optimization method for quantum state tomography#1485HuberyMing wants to merge 31 commits intoqiboteam:masterfrom
Conversation
|
Not entering the other merits of the PR, this would have to be inside the |
|
@renatomello to follow up what I told you about remotes during the Qibo meeting, you could do the following: git remote add hubery-ming [email protected]:HuberyMing/qibo.git
git pull hubery-ming
git switch -c QST -t hubery-ming/QSTin this way you would set up a remote named Of course, you won't have pushing rights (unless @HuberyMing will grant you), but that's in case you want to test it locally. Maybe you were already familiar with this, but this may also be useful for everyone else who'd like to have a look (and it could be a reference to deal for PRs from forks in general). |
update random_density_matrix usage Co-authored-by: Renato Mello <[email protected]>
for more information, see https://pre-commit.ci
| 2 * np.pi * random.random(), | ||
| 2 * np.pi * random.random(), | ||
| 2 * np.pi * random.random(), |
There was a problem hiding this comment.
A tip for the future: This choice of phases does not sample random states uniformly. Please see
and https://pennylane.ai/qml/demos/tutorial_haar_measure| from qibo import gates, quantum_info | ||
|
|
||
|
|
||
| class State: |
There was a problem hiding this comment.
Correct me if I'm wrong, but it seems like this base class is unnecessary since every method is dependent on a qibo.models.Circuit method. I'd say that if these state classes are needed at all (which I'm not convinced of), you could use Circuit as the base class directly.
| class HadamardState(State): | ||
| """ | ||
| Constructor for HadamardState class | ||
| """ | ||
|
|
||
| def __init__(self, n): | ||
| State.__init__(self, n) | ||
| self.circuit_name = "Hadamard" | ||
|
|
||
| def create_circuit(self): | ||
| circuit = qibo.Circuit(self.n) | ||
|
|
||
| for i in range(self.n): | ||
| circuit.add(gates.H(i)) | ||
|
|
||
| self.circuit = circuit |
There was a problem hiding this comment.
Since this is just a layer of Hadamards, this is a Hadamard transform of the initial state. A more concise way to implement this would be to modify the following function:
qibo/src/qibo/quantum_info/utils.py
Line 118 in 958b11b
For instance, if the input is a circuit, then a layer of Hadamard is added. That would perform the Hadamard transform of whatever state one wants, including the zero state in your case.
| def build_projector_naive(label, label_format="big_endian"): | ||
| """to directly generate a Pauli matrix from tensor products | ||
|
|
||
| Args: | ||
| label (str): label of the projection, e.g. 'XXZYZ' | ||
| label_format (str, optional): the ordering of the label. Defaults to 'big_endian'. | ||
|
|
||
| Raises: | ||
| Exception: when the matrix size is too big (i.e. for qubit number > 6) | ||
|
|
||
| Returns: | ||
| ndarray: a matrix representing the Pauli operator | ||
| """ | ||
| if label_format == "little_endian": | ||
| label = label[::-1] | ||
| if len(label) > 6: | ||
| raise Exception("Too big matrix to generate!") | ||
| projector = reduce( | ||
| lambda acc, item: np.kron(acc, item), | ||
| [matrix_dict[letter] for letter in label], | ||
| [1], | ||
| ) | ||
| return projector | ||
|
|
||
|
|
||
| # Generate a projector by computing non-zero coordinates and their values in the matrix, aka the "fast" implementation | ||
| def build_projector_fast(label, label_format="big_endian"): | ||
| """to fastly generate a Pauli projection matrix in sparse matrix format | ||
|
|
||
| Args: | ||
| label (str): label of the projection, e.g. 'XXZYZ' | ||
| label_format (str, optional): the ordering of the label. Defaults to 'big_endian'. | ||
|
|
||
| Returns: | ||
| sparse matrix: sparse matrix of the Pauli operator representing label | ||
| """ | ||
| if label_format == "little_endian": | ||
| label = label[::-1] | ||
|
|
||
| n = len(label) | ||
| d = 2**n | ||
|
|
||
| # map's result NOT subscriptable in py3, just tried map() -> list(map()) for py2 to py3 | ||
| ij = [ | ||
| list(map(binarize, y)) | ||
| for y in [zip(*x) for x in product(*[ij_dict[letter] for letter in label])] | ||
| ] | ||
| values = [ | ||
| reduce(lambda z, w: z * w, y) | ||
| for y in [x for x in product(*[values_dict[letter] for letter in label])] | ||
| ] | ||
| ijv = list(map(lambda x: (x[0][0], x[0][1], x[1]), zip(ij, values))) | ||
|
|
||
| i_coords, j_coords, entries = zip(*ijv) | ||
|
|
||
| projector = sparse.coo_matrix( | ||
| (entries, (i_coords, j_coords)), shape=(d, d), dtype=complex | ||
| ) | ||
| return projector |
There was a problem hiding this comment.
@BrunoLiegiBastonLiegi this is a case where it would be convenient to have the quantum_info.basis.pauli_basis function return a generator because then one could use that to directly access a specific element of the basis.
|
Just curious, would it be helpful to have a call to understand how the algorithm works? It might make it easier to review the code. |
update random_density_matrix usage Co-authored-by: Renato Mello <[email protected]>
for more information, see https://pre-commit.ci
update random_density_matrix usage Co-authored-by: Renato Mello <[email protected]>
for more information, see https://pre-commit.ci
|
@HuberyMing If you're doing the changes locally, you could do |
Specifically, if it fails the involved hook is "declaring" a failure, that may imply that you have to fix something manually. However, most of the hooks we have registered are also auto-fixing the issues they find (e.g. the formatter fails if the result differs from the original - but if it fails, it also reformats the fails).
However, in these cases, I'm sure that @HuberyMing just applied the suggestions from the review from the PR web interface. In which case there is no chance of having (as you also prepended
) |
It might me needed, yes. Let me read the paper first though, so I have a better understanding. |
|
To have better compatibility with qibo, now I have changed the expectation value calculation of each Pauli string from the shot measurements by using the package expectation_from_samples. Here is the imported package: from qibochem.measurement import expectation, expectation_from_samples However, not all Pauli string can be correctly calculated for its expectation value from the shot measurement from this package. I have raised an issue in #1677 |
This creates a circular dependency ( On the other hand, maybe this is not true for the |
Thanks for the comment. Inspired by your comment, I tried something like from qibo.hamiltonians.hamiltonians import AbstractHamiltonian
from qibo.hamiltonians import Hamiltonian
coef_Pauli_exact = AbstractHamiltonian.expectation(stateGHZ, symbolPauli) # NotImplementedError: None
coef_Pauli_exact = Hamiltonian.expectation(stateGHZ, symbolPauli)
coef_Pauli = symbolPauli.expectation_from_samples(frequencies, qubit_map=range(n_qubits)) I found none of them work. Basically they are not implemented. However, I figured out there is no quick way to do this. We can get the correct results by using pauli_term_measurement_expectation such as from qibochem.measurement.result import pauli_term_measurement_expectation
circuit.add(gates.M(0, basis=type(X(0).gate))) # H gate # for 'X' Pauli term
circuit.add(gates.M(1, basis=type(Y(1).gate))) # RX(0.5*pi) gate
circuit.add(gates.M(2, basis=type(Z(2).gate))) # Computational basis remains unchanged
# Now run the circuit to get the circuit measurements
result = circuit(nshots=10000)
frequencies = result.frequencies(binary=True)
# pauli_term_measurement_expectation is a Qibochem function for calculating the expectation value of Hamiltonians with non-Z terms
shots_term1 = pauli_term_measurement_expectation(term1.terms[0], frequencies, qubit_map=range(n_qubits))The conclusion is that pauli_term_measurement_expectation works but expectation_from_samples does not. At least this can fit into my need. Thanks. |
|
To have some updates. The issue #1677 has already solved this problem of getting the correct expectation values by using the |
for more information, see https://pre-commit.ci
|
@HuberyMing what are your plans concerning this PR? |
@scarrazza Thank you for your patience regarding this PR. I am currently refactoring the code to remove unnecessary parts and better align it with the qibo framework. After the Lunar New Year, I will devote more time to finalizing it, with the goal of completing the PR within one to two months. |

Checklist:
To include the optimization method of Riemannian Gradient Descent (RGD) algorithm to do the tomography problem. The implementation follows from the arXiv:2210.04717, which was published in Phys. Rev. Lett. 132, 240804