Skip to content
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

Closed

Conversation

purva-thakre
Copy link
Contributor

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

GSoC Notebook - Deliverable.pdf

Tutorial of partially working code

  • full final output cannot be checked right now
  • Last output in the notebook is not correct due to Toffoli gates being inserted improperly - the circuit should not have introduced ancillas - see figure in Decomposition scheme for qubits greater than 2

New To-Do :

  • Change output of _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
  • After above change, _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)
  • Add a function to iterate over full output of _paulix_for_control_0 and add CNOT gates for n = 2
  • After the output of all possible gates is a list, introduce a function to iterate over said list of forward gray code and add CNOT gates.
    - [ ] 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.
  • The output of _two_q_CNOT_gates should be a dictionary of lists only - not nested dictionaries and lists
  • Provide option of decomposition scheme for n = 1
  • Provide option of decomposition scheme for n = 3 - keep toffoli undecomposed or not
  • Provide option of decomposition scheme for n > 3 after the recursion scheme and ancilla outputs are same as input gate - another option to further decompose toffoli
  • Define recursion scheme to decompose without ancillas
  • Use recursion scheme to decompose n-qubit toffoli without ancillas (n>3)

return(compact_U_information)


def _two_qubit_lastq_target(last_two_level_array_info):
Copy link
Contributor Author

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
Copy link
Member

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.

Comment on lines +152 to +158
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)
Copy link
Contributor Author

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.

Comment on lines +490 to +491
len_forward_gate_info = len(full_gate_dict)
len_backward_gate_info = len(back_full_gate_dict)
Copy link
Contributor Author

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:
Copy link
Contributor Author

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:
Copy link
Contributor Author

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))
Copy link
Contributor Author

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

Comment on lines +593 to +594
forw = gray_code_info[0]
backw = gray_code_info[1]
Copy link
Contributor Author

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:
Copy link
Contributor Author

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)
Copy link
Contributor Author

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.

@BoxiLi
Copy link
Member

BoxiLi commented Aug 23, 2021

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.

@purva-thakre
Copy link
Contributor Author

Closing this for now because there's a new PR to start with (hopefully) a better design of nested lists.

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

Successfully merging this pull request may close these issues.

2 participants