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

Adds single qubit decomposition functions #52

Closed
wants to merge 21 commits into from

Conversation

purva-thakre
Copy link
Contributor

@purva-thakre purva-thakre commented Jun 11, 2021

WIP for 4 single qubit decomposition functions.

To do before marking PR ready for review :

  • Check format --> black
  • Check style --> PEP8

@purva-thakre purva-thakre changed the title Adds sungle qubit decomposition functions Adds single qubit decomposition functions Jun 11, 2021
Comment on lines 82 to 83
except ZeroDivisionError:
input_array = input_array
Copy link
Contributor Author

@purva-thakre purva-thakre Jun 13, 2021

Choose a reason for hiding this comment

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

Discuss at June 14 meeting

Don't think this exception has to be added. If this function's goal is to check if the matrix is unitary or not then a matrix whose determinant is zero is not a unitary matrix.

Copy link
Member

Choose a reason for hiding this comment

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

Yeah you can return False already.

However, I'm not sure if normalizing is needed. It seems very unlikely to me that a not normalized gate will be unitary after the normalization. If someone provides something with |det| != 1, he/she already missed the point of providing a unitary.

Or is there a special reason?

Comment on lines 104 to 105
except ZeroDivisionError:
input_array = input_array
Copy link
Contributor Author

@purva-thakre purva-thakre Jun 13, 2021

Choose a reason for hiding this comment

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

Discuss at June 14 meeting

Same as above. If the determinant is zero then do not need to make this exception. det(U) = 1

src/qutip_qip/decompositions/general_decompositions.py Outdated Show resolved Hide resolved

import numpy as np

def normalize_matrix(input_array)-> np.array:
Copy link
Member

Choose a reason for hiding this comment

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

It would be nice if we can have an optional parameter in the main function that allows turning off some checks if the decomposition is used e.g. for qutip predefined gates. Those gates should, by construction, be valid.

src/qutip_qip/decompositions/general_decompositions.py Outdated Show resolved Hide resolved
Comment on lines 82 to 83
except ZeroDivisionError:
input_array = input_array
Copy link
Member

Choose a reason for hiding this comment

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

Yeah you can return False already.

However, I'm not sure if normalizing is needed. It seems very unlikely to me that a not normalized gate will be unitary after the normalization. If someone provides something with |det| != 1, he/she already missed the point of providing a unitary.

Or is there a special reason?

# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
###############################################################################

# add functions to check the calculated decomposition is equivalent to input array.
Copy link
Member

Choose a reason for hiding this comment

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

If you mean checking whether the decomposed list of matrices is correct after the decomposition, I think it should be in the tests and not here. If we provide something for the user, we should make sure in advance that it is correct by testing it ourselves.

Unless there are some round-off error or special reasons that we cannot tell ahead if the decomposition will succeed?

Comment on lines +91 to +96
if input_check_bool == True:
input_shape = input_gate.shape
if input_shape[0]%2==0.0: # won't be 2 for higher qudits
# TO DO : if d=4 (qu4it) then it will still appear as a d=2 i.e. qubit gate
# change to powers of 2
number_of_qubits = np.log(input_shape[0])/np.log(2)
Copy link
Contributor Author

@purva-thakre purva-thakre Jun 24, 2021

Choose a reason for hiding this comment

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

@hodgestar @BoxiLi Is there a better way to find the number of qubits based on the size/shape of the input gate matrix ? Here, with what I have chosen to do, if the qudits are of dimensions that are power of 2 then my condition is valid for both qubit and said qudit.

Could dims work here ?

If I have a 2 qubit state unitary then dims = [[[2], [2]], [[2], [2]]] but if it was a qu4it state unitary then dims = [[4,4]].

And I think, a qutrit-qudit gate will also be incorrectly identified as a qubit gate. But I can change the line to be division by powers of 2 which will help catch odd-even dimensional states.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@BoxiLi @hodgestar I edited my previous comment. I think I have a better idea now. It's possible my understanding of dims is wrong.

Copy link
Member

Choose a reason for hiding this comment

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

Is there a reason that we need to consider qudits/qutrits? I thought the whole decomposition module assumes that we are working with qubits? Or is there anything also useful for qudits?

This kind of information is much easier to extract from the Qobj, before taking the full numpy matrix. A 2-qubit ket state has dims=[[2, 2], [1, 1]], while a qudit ket dims=[[4], [1]].

Copy link
Member

Choose a reason for hiding this comment

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

For unitaries acting on them: dims=[[2, 2], [2, 2]] and dims=[[4], [4]]

Copy link
Contributor Author

@purva-thakre purva-thakre Jun 24, 2021

Choose a reason for hiding this comment

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

Is there a reason that we need to consider qudits/qutrits?

Not really. As the user can input any n x n unitary, I added this extra check to make sure the unitary acts only on qubits and not on other dimensions.

Plus, this should be able to find the number of qubits a unitary is acting on by looking at the shape/dims.

Copy link
Member

Choose a reason for hiding this comment

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

Ok, then this is just a validity check. Since the input is Qobj, using dims is easier. We can check if it is a list of 2.

input_gate.dims[0] == [2] * len(input_gate.dims[0])

Copy link
Contributor Author

@purva-thakre purva-thakre Jun 24, 2021

Choose a reason for hiding this comment

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

Yeah, that's my problem. dims cannot distinguish between a 4 x 4 input. It could be an object acting on 2 qubits or a qudit of d = 4.

q = Qobj([[0., 0, 0, 0.],[0., 0, 0, 0.],[0., 0, 0, 0.],[0., 0, 0, 0.]])
q.dims = [[4], [4]]

I think I am going to change the input to the function. In addition to the input Qobj, they will also need to input number of qubits. This could help avoid the ambiguity. Then, this function could check if the shape of input gate is compatible with number of qubits.

Copy link
Member

Choose a reason for hiding this comment

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

Well, technically speaking, the example you provided is interpreted in QuTiP as a unitary acting on a qudit system, not two qubits.
E.g.

q = Qobj([[0., 0, 0, 0.],[0., 0, 0, 0.],[0., 0, 0, 0.],[0., 0, 0, 0.]], dims = [[4], [4]])
q * basis([2,2],[0,0])

will raise an error because the dimension does not match. This is how QuTiP distinguish them. If the user is meant to provide an operator acting on qubits, the dimension should match.

Copy link
Member

@BoxiLi BoxiLi Jun 24, 2021

Choose a reason for hiding this comment

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

That said, in decomposition we can also be lenient and allow the user to just produce a 2^n times 2^n Qobj.

So I see two options:

  • We make it strict and all the input must have the dimension [[2,2,2,...],[2,2,2,...]
  • We allow it to be ambiguous a bit and require that input.shape[0] is a power of 2, by some smart bit manipulation: https://stackoverflow.com/questions/57025836/how-to-check-if-a-given-number-is-a-power-of-two. Although it will be a bit hard to find out what is n since technically log2(2^n) is not always reliable to give as n. Asking the user to provide the number of qubits is also fine.

@purva-thakre
Copy link
Contributor Author

Closing this PR because I want to start on a new branch. When trying to rebase this branch, there were a lot of conflicts.

@purva-thakre purva-thakre deleted the phase_su_decomposition branch June 26, 2021 03:39
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.

2 participants