-
Notifications
You must be signed in to change notification settings - Fork 64
New issue
Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? # to your account
General decomposition method #90
General decomposition method #90
Conversation
return(compact_U_information) | ||
|
||
|
||
def _two_qubit_lastq_target(last_two_level_array_info): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's a general function which recursively decomposes upto when this function can be used.
For print( _gray_code_sequence(2)), the output is [0, 1, 3, 2] i.e. in | ||
terms of the binary sequence, the output is ['00', '01', '11', '10']. | ||
https://docs.python.org/3/library/operator.html#operator.xor' | ||
Parameters |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think there needs to be an empty line before parameters.
gray_code_forward = gray_code | ||
gray_code_backward = gray_code_forward[0:len(gray_code_forward)-1][::-1] | ||
|
||
if num_steps_gray_code == 1: | ||
return(gray_code_forward, num_steps_gray_code) | ||
else: | ||
return(gray_code_forward, gray_code_backward, num_steps_gray_code) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The issue with creating dictionaries began here. The output was made dependent on if the gray code maps directly from one state to another or there's a couple of gates needed before implementing a two-level gate decomposition.
The new plan is to separately return the ctrl-target info for two-level gate itself and a list mapping to the two-level gate. In the case of there just being 1 step in the gray code, it would be easier to just check if list of gates is None
or not.
len_forward_gate_info = len(full_gate_dict) | ||
len_backward_gate_info = len(back_full_gate_dict) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same as above comment - if there's more than one step then the list of gates can be reversed for the backward gray code gates. There's no need to iterate over forward gray code info to find the last gate object - a new function will output it separately.
"""Finds total number of qubits when ancilla qubits are added to create a | ||
qubit circuit. | ||
""" | ||
if num_qubits > 3: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This needs to be changed to number of ctrl qubits - if n is the total number of qubits then total number of possible ctrl qubits are n-1.
"""Decomposes a multi-controlled CNOT with last qubit as target into a | ||
circuit composed of toffoli and ancilla qubits. | ||
""" | ||
if num_qubits >= 3: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if n = 3 : skip adding ancilla qubit
"""When a 2-level unitary with last target is supposed to be decomposed, | ||
4 multi-controlled CNOT will act on num_qubits-1 qubits. | ||
""" | ||
return(_full_CNOT_to_Toffoli(num_qubits-1)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
add condition for n = 3, the current output is for when n > 3
forw = gray_code_info[0] | ||
backw = gray_code_info[1] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This will be changed after forward gray code is separated from the main two-level gate. Then backward gray code is just reversed order of forward gray code.
last qubit or last qubit is a target, | ||
shift the last qubit by number of ancilla qubits added. | ||
""" | ||
if num_qubits > 3: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
add condition for n = 3 : return input
|
||
full_gate_list = list(flatten(sub_lists)) | ||
|
||
return(full_gate_list, total_qubits_for_circ) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
output of this function is not correct since ancilla qubits are not added correctly.
Edit: I realize you also have dictionaries as a controlled gate, so also check that. @purva-thakre Just for your interest. Here is a small example for flattening a nested list/dictionary: def flatten(input, result):
# Stop and return if it is a gate, otherwise iterate over the input.
if not isinstance(input, (dict, list, tuple)):
end = True
elif isinstance(input, dict) and isinstance(list(input.keys())[0], str):
# You also have dictionary as gate representation I remember, check this.
end = True
else:
end = False
if end:
result.append(input)
return
for i in range(len(input)):
flatten(input[i], result)
input = {0: [{0: "gate1", 1: "gate2"}, ["gate3"]], 1: "gate4", 2: {"control": 0, "targets": 1}}
result = []
flatten(input, result)
print(result) It basically uses recursion to reduce the problem into smaller ones and eventually solve the simplest cases. In this case, the smallest case is when the input is just one gate. It can also be understood as a deep-first search. We don't really want to include this in the code, but it will probably help you test your result when you unify the output of the different sub-functions. I would suggest that you always have some (incomplete) tests running when you change the output format. In case changes break the correctness of the current output. |
Closing this for now because there's a new PR to start with (hopefully) a better design of nested lists. |
GSoC Notebook - Deliverable.pdf
Tutorial of partially working code
Decomposition scheme for qubits greater than 2
New To-Do :
_gray_code_gate_info
- do not combine into forward gray code and backward gray code
- return gate info for gates in forward gray code info upto the two-level gate
- information for two-level gate is returned in another list
_paulix_for_control_0
will not need 2 separate loops depending on if there's only 1 controlled gate or it's a forward/backward code.- it is important to keep in mind whatever gates are determined for forward gray code list, the backward gray code applies the same gates in a reverse order. (this could be done by checking if the forward_gray_code list is empty or not)
_paulix_for_control_0
and add CNOT gates for n = 2- [ ] If the number of qubits is n > 2, choose to stop decomposition at toffoli or go further (provide option)
- [ ] If the chosen decomposition method is via using ancilla qubits then the gate target can only be last qubit - if we allow the first qubit to be a target, the number of ancillas being introduced doubles.
_two_q_CNOT_gates
should be a dictionary of lists only - not nested dictionaries and lists