MarcSerraPeralta / surface-sim

Repository for simulations of surface code experiments
MIT License
0 stars 1 forks source link

Implement the transversal CNOT for the surface code #72

Open MarcSerraPeralta opened 3 weeks ago

MarcSerraPeralta commented 3 weeks ago

TODO:

MarcSerraPeralta commented 2 weeks ago

If the Layout represents a code, then the implementation of the logical transversal CNOT will require two input layouts, one for the logical control and another for the logical target.

This requires a way to "align" a rotated surface code to another one, as for the transversal CNOT we need to do physical CNOTs between the same data qubits but on different patches.

Could this be done with the Tanner graph? Yes, NetworkX offers the isomorphism module (see ref) that can be used to check if graphs are isomorphic and, if so, get a mapping of the nodes (which is what I want).

MarcSerraPeralta commented 1 week ago

One needs to add the property logical_qubit_label(s) in the layout to build the two-qubit gates. In the current implementation, the information about logical gates is stored in the layout using a single label for each gate. However, for the case of transversal CNOT, it is important to specify which logical qubit is the target and which the control because the stabilizer matrix is different (and also one needs to specify the qubits in which the logical gate takes place). I propose having a list in the layout with all the labels for the different logical qubits and specifying the logical gate information as "LOGGATENAME_involvedqubit1_involvedqubit2_...". This way there are no problems of conflicting gates as also the order of the involved qubits is important (e.g. for the CNOT, the first qubit represent the control and the second one the target).

MarcSerraPeralta commented 1 week ago

One needs to add the property logical_qubit_label(s) in the layout to build the two-qubit gates.

Done in PR #82

I propose having a list in the layout with all the labels for the different logical qubits and specifying the logical gate information as "LOGGATENAME_involvedqubit1_involvedqubit2_..."

Done in PR #83

MarcSerraPeralta commented 1 week ago

Another issue that needs to be solved when doing the t-CNOT gate is that the Detectors class will require to have all the stabilizers (from both surface codes). Therefore, we need to enforce that the stabilizers/ancillas have different labels. One could ensure that by adding the logical qubit name to the ancilla label, e.g. "L0_Z1" and "L1_Z1". If we follow this method, then we should have something like Layout.get_qubits(role="anc", add_prefix=True) to return the unique ancilla labels. One issue with this approach is that the functionality Model.meas_rec(anc_label, rel_meas_id) used to build the detectors uses the "bare" ancilla labels (not the unique ones). This also applies for the Setup parameters. Maybe is then better to enforce that the standard ancilla labels are unique?

This problem also applies to qubit indices, they need to be unique for the stim circuit to be the desired one.

MarcSerraPeralta commented 1 week ago

Another issue when dealing with two different layouts is that if we want to run some QEC cycles in both of the patches at the same time it is not possible. The current way of doing it would be:

circuit = stim.Circuit()
circuit += qec_round(model, layout_1, detectors)
circuit += qec_round(model, layout_2, detectors)

This results in the "correct" noise channels but the ticks are not correct (we will have double the amount of ticks, for having two QECs).

A possibility to solve this is to give a list of layouts to the qec_round and then, for each set of instructions between each TICK, do a for loop for all the layouts.

Another option (that would also solve the issue about duplicated labels and indices) would be to have a merge_layouts function that merges two different layouts into a single one and ensures that everything is unique (and other things that I haven't realized yet...). Note that the milestones for v0.4.0 involve adding new functionality for the layouts (e.g. #53 #39).

MarcSerraPeralta commented 5 days ago

I believe the merge_layouts function is the best approach (until now). The checks for this function would be:

For the first three elements in the list, the Layout class will require some modifications. Currently, the indices cannot be specified as inputs and they are automatically built, starting from 0.

EDIT 1: Actually, I believe the option of giving multiple layouts to the QEC cycle is better. The reason being that if one want to perform a logical CNOT gate between two layouts, I don't see the benefit of having a merged layout (I see it more confusing). Regarding the uniqueness of the indices and labels, I can just add a function that checks if the layouts can be "used in the same experiment", i.e. fulfill the constraints listed above.

EDIT 2: After implementing the idea in EDIT 1, I have realized that I would also want to run multiple things when initializing the qubits, measuring the logical qubits, doing logical gates,... Therefore, I believe the suggestion in EDIT 1 to not be optimal, as one would have to also change each function (and I have to say that the code readability is not great...). My other idea is to have a function that does the merging of operations between ticks when given different circuits. This function assumes that each qubit is either idling or participating in one operation in each tick. The basic idea would be: Given a list of circuits, 1) check that they all have the same amount of TICKs 2) split each circuit into chunks that are limited by TICKs 3) merge all the first chunks, then the second ones, ... 4) join all the merged circuits and add TICKs inbetween

Note: some further optimizations would be to sort the operations so that the stim file is not very long, but that might broke the code if the assumption is not satisfied.

MarcSerraPeralta commented 2 days ago

I have realized that the computation of the stab_gen_matrix (which is the responsible for updating the stabilizer generators in the Detectors) is set to be done only for one layout, as it is implemented in Layout.stab_gen_matrix. However, in the implementation of this transversal CNOT, thestab_gen_matrix` involve stabilizers from two layouts, thus it cannot be computed from just a single one.

One solution is to move this computation to the Detectors class and have a method that is Detectors.update and Detectors.update_from_dict (in which the dict is transformed to an xarray and then Detectors.update is called). This solves the issue (and possible other issues) because all the stabilizer generators that are being tracked are present in the Detectors object, and moreover this class is the one responsible for updating these generators.