Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RGD optimization method for quantum state tomography #1485

Draft
wants to merge 21 commits into
base: master
Choose a base branch
from

Conversation

HuberyMing
Copy link

Checklist:

  • Reviewers confirm new code works as expected.
  • Tests are passing.
  • Coverage does not decrease.
  • Documentation is updated.

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

@renatomello
Copy link
Contributor

renatomello commented Oct 14, 2024

Not entering the other merits of the PR, this would have to be inside the tomography module instead of being a separate tomography_RGB module.
Moreover, tests should follow how tests in qibo are done. Right now they're in a folder that is being ignored by gitignore.

@renatomello renatomello self-requested a review October 16, 2024 10:28
@alecandido
Copy link
Member

@renatomello to follow up what I told you about remotes during the Qibo meeting, you could do the following:

git remote add hubery-ming git@github.com:HuberyMing/qibo.git
git pull hubery-ming
git switch -c QST -t hubery-ming/QST

in this way you would set up a remote named hubery-ming, tracking @HuberyMing's repo, and then create a local branch in your local repo named QST, tracking the https://github.com/HuberyMing/qibo/tree/QST branch.

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).

HuberyMing and others added 2 commits October 17, 2024 14:48
update random_density_matrix usage

Co-authored-by: Renato Mello <renato.msf@gmail.com>
Comment on lines +218 to +220
2 * np.pi * random.random(),
2 * np.pi * random.random(),
2 * np.pi * random.random(),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A tip for the future: This choice of phases does not sample random states uniformly. Please see

def uniform_sampling_U3(ngates: int, seed=None, backend=None):
and https://pennylane.ai/qml/demos/tutorial_haar_measure

from qibo import gates, quantum_info


class State:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Comment on lines +174 to +189
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
Copy link
Contributor

@renatomello renatomello Oct 17, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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:

def hadamard_transform(array, implementation: str = "fast", backend=None):

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.

Comment on lines +155 to +171
class GHZState(State):
"""
Constructor for GHZState class
"""

def __init__(self, n):
State.__init__(self, n)
self.circuit_name = "GHZ"

def create_circuit(self):
circuit = qibo.Circuit(self.n)

circuit.add(gates.H(0))
for i in range(1, self.n):
circuit.add(gates.CNOT(0, i))

self.circuit = circuit
Copy link
Contributor

@renatomello renatomello Oct 17, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This fits as a function in qibo.models.encodings receiving nqubits as input and returning the corresponding circuit as output.

EDIT: I'd recommend doing this on a separate PR. It keeps things concise and it's good training on how to implement Qibo code in a smaller scale.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just want to clarify. A separate PR you mean that I have to create a new branch, say QST2 or QST_GHZ, and then pre-commit this new branch? Do I understand correctly?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A new branch starting from master, completely unrelated to this one. You can name whatever, but probably ghz is simpler and better. Then in that branch, you only implement the GHZ circuit as a function in qibo.models.encodings and the corresponding tests. Nothing else. After that is merged into master, we change the code here accordingly so it can communicate with the newly existing function.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for the instruction. I have created a new branch called ghz and push it with sync fork. I have tested some functions inside the directory src/qibo/test. However, I do not understand well the qibo.models.encodings you mentioned. There are some encoders in the qibo.models.encodings but probably we don't need them at the moment. I am not sure if we can add some user-defined properties in the circuit. The way I did it now is to create a new class. Probably some properties do not fit into qibo's standards. I am curious if creating some list as a recorded processed result is allowed. Or do you prefer on-the-fly calculation during processing? Thanks.

Copy link
Contributor

@mho291 mho291 Oct 22, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think what @renatomello is that the GHZ state should be added as a function to qibo.models.encodings. It will probably look something like this:

def GHZ_circuit(nqubits):
    c = QiboCircuit(nqubits)
    c.add(gates.H(0))
    for _i in range(nqubits-1):
        c.add(gates.CNOT(_i, _i+1))
    return c

I don't think it will take so much time to add it in, I can do it after dinner.
Anyway, would qibo.models.utils be a more suitable location than qibo.models.encodings?

EDIT: Upon closer inspection, I see that qibo.models.encodings has a lot of "create circuit" functions. I think qibo.models.encodings will be the suitable location. :)

Comment on lines +110 to +168
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
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@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.

@mho291
Copy link
Contributor

mho291 commented Oct 17, 2024

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.

HuberyMing and others added 5 commits October 17, 2024 15:39
update random_density_matrix usage

Co-authored-by: Renato Mello <renato.msf@gmail.com>
update random_density_matrix usage

Co-authored-by: Renato Mello <renato.msf@gmail.com>
@mho291
Copy link
Contributor

mho291 commented Oct 17, 2024

@HuberyMing If you're doing the changes locally, you could do pip install pre-commit followed by pre-commit install inside your environment. Each time you do git commit -m "message", the pre-commit will run. If anything fails, you have to do git commit again before git push. Then we we will avoid having extra commits in this PR.

@alecandido
Copy link
Member

Each time you do git commit -m "message", the pre-commit will run. If anything fails, you have to do git commit again before git push.

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).
The auto-fixes are not staged, so you also need to git add the fixed files.

image

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 pre-commit running anywhere else...

(as you also prepended

@HuberyMing If you're doing the changes locally,

)

@renatomello
Copy link
Contributor

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.

It might me needed, yes. Let me read the paper first though, so I have a better understanding.

@HuberyMing
Copy link
Author

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.

It might me needed, yes. Let me read the paper first though, so I have a better understanding.

Hi @renatomello Thank you for the review. No problem. How do we discuss?

HuberyMing and others added 2 commits October 17, 2024 16:19
simplify generating all labels

Co-authored-by: Renato Mello <renato.msf@gmail.com>
@renatomello
Copy link
Contributor

renatomello commented Oct 17, 2024

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.

It might me needed, yes. Let me read the paper first though, so I have a better understanding.

Hi @renatomello Thank you for the review. No problem. How do we discuss?

We can try to arrange a chat via Zoom next week. Right now, I'd like to see a separate PR adding the GHZ state to qibo.models.encodings. I think it will be a good lesson on a small scale on how this PR should move forward in terms of code implementation.
You can follow the style of the functions inside qibo.models.encodings as well as the test style inside tests/test_models_encodings.py.

It's a good first issue.

@HuberyMing
Copy link
Author

HuberyMing commented Oct 17, 2024

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.

It might me needed, yes. Let me read the paper first though, so I have a better understanding.

Hi @renatomello Thank you for the review. No problem. How do we discuss?

We can try to arrange a chat via Zoom next week. Right now, I'd like to see a separate PR adding the GHZ state to qibo.models.encodings. I think it will be a good lesson on a small scale on how this PR should move forward in terms of code implementation. You can follow the style of the functions inside qibo.models.encodings as well as the test style inside tests/test_models_encodings.py.

It's a good first issue.

Thanks. I will do these first.


elif circuit_Choice == 2: # directly generate density matrix via qutip
Nr = 1
rho = qu.rand_dm_ginibre(2**n, dims=[[2] * n, [2] * n], rank=Nr)
Copy link
Contributor

@renatomello renatomello Oct 17, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
rho = qu.rand_dm_ginibre(2**n, dims=[[2] * n, [2] * n], rank=Nr)
rho = random_density_matrix(2**n, rank=Nr, metric="ginibre")

import methodsRGD_core
import numpy as np
import projectors
import qutip as qu
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
import qutip as qu

@MatteoRobbiati
Copy link
Contributor

Do you plan to continue with this PR @HuberyMing? :)

@HuberyMing
Copy link
Author

Do you plan to continue with this PR @HuberyMing? :)

Sorry for not pushing forward much. I will continue the PR. Hope to finish it soon.

@MatteoRobbiati
Copy link
Contributor

Sorry for not pushing forward much. I will continue the PR. Hope to finish it soon.

No problem! Take your time :) I just wanted to check the status!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants