QCHackers / tqec

Design automation software tools for Topological Quantum Error Correction
https://tqec.app
Apache License 2.0
58 stars 15 forks source link

Lifting the "`Plaquette.shape` should all be the same" assumption #34

Closed nelimee closed 5 months ago

nelimee commented 6 months ago

The tqec Python package currently works under the assumption that all the Plaquette instances provided when calling the generate_circuit function are of the same shape.

The shape of a Plaquette instance is currently defined as the coordinates of the lower-right-most qubit, each increased by one, which assumes that qubits are the closest possible to the origin (0, 0). This definition (and how we compute the shape, if we still need to compute it) have to change.

Lifting this assumption will likely require non-trivial changes, I am open to any suggestion.

afowler commented 6 months ago

Provided a plaquette has a nominated qubit that serves as its corner and this corner can be pinned to a template, it is not clear to me why each plaquette needs to be the same shape. Fundamentally, a plaquette is just a human visualization of an underlying quantum circuit, which is the real thing that is being loaded into the template. In principle, the underlying quantum circuit could be rather random in structure reaching into qubits outside any typical square, but provided these quantum gates are compatible in the sense they are all applied in different non-overlapping time steps, this shouldn't be an issue.

Thoughts?

On Tue, Jan 9, 2024 at 11:28 PM Adrien Suau @.***> wrote:

The tqec Python package currently works under the assumption that all the Plaquette https://github.com/QCHackers/tqec/blob/f6f29323ebf2544ae576c6866167026adbfa6359/tqec/plaquette/plaquette.py#L10 instances provided when calling the generate_circuit https://github.com/QCHackers/tqec/blob/f6f29323ebf2544ae576c6866167026adbfa6359/tqec/generation/circuit.py#L11 function are of the same shape.

The shape https://github.com/QCHackers/tqec/blob/f6f29323ebf2544ae576c6866167026adbfa6359/tqec/plaquette/plaquette.py#L31 of a Plaquette https://github.com/QCHackers/tqec/blob/f6f29323ebf2544ae576c6866167026adbfa6359/tqec/plaquette/plaquette.py#L10 instance is currently defined as the coordinates of the lower-right-most qubit, each increased by one, which assumes that qubits are the closest possible to the origin (0, 0). This definition (and how we compute the shape, if we still need to compute it) have to change.

Lifting this assumption will likely require non-trivial changes, I am open to any suggestion.

— Reply to this email directly, view it on GitHub https://github.com/QCHackers/tqec/issues/34, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAKAXTENCIIGY4F6P4FTIKLYNY7I5AVCNFSM6AAAAABBUJYRJOVHI2DSMVQWIX3LMV43ASLTON2WKOZSGA3TGNZWGE3TGNI . You are receiving this because you are subscribed to this thread.Message ID: @.***>

nelimee commented 6 months ago

This is an assumption I made when initially writing the code because it seemed simpler to me and allowed me to make some simplifications. The idea was to remove this assumption at one point, when the code was mature enough, and the time as come. Initially, I made this assumption because it helped in computing the global position of the local coordinate system origin of each plaquette. The computation will likely be a little bit more involved now, but as long as we are able to get the global coordinate of each plaquette "origin", everything should work as expected. Now, computing this global position in the most general case would require us to re-think the way plaquettes are organised within a template, and how this organisation is encoded. To be as generic as possible, we might have to think about theoretical results on tiling, and how to compute the position of each tile (plaquettes here). This is not something I was feeling confident thinking and taking a decision on alone.

So let's use this issue to think about the way(s) we could store plaquettes in a template, knowing that as soon as we are able, for each plaquette within a template, to compute the global coordinates of at least one of its qubit, the rest should follow quite easily.

afowler commented 5 months ago

Hi Adrien,

One proposal that I think would be fine is for a template to have a central location on which one of the qubits in a plaquette will be placed. For example for a standard surface code, there is a natural notion of the central qubit in each plaquette in a template. The first chosen qubit in the quantum circuit associated with each plaquette could be coded to go on this central qubit. You would then only need to check that various quantum circuits in the plaquettes do indeed fit together.

Does that make sense? Does that seem workable?

Regards, Austin.

On Wed, Jan 10, 2024 at 2:48 PM Adrien Suau @.***> wrote:

This is an assumption I made when initially writing the code because it seemed simpler to me and allowed me to make some simplifications. The idea was to remove this assumption at one point, when the code was mature enough, and the time as come. Initially, I made this assumption because it helped in computing the global position of the local coordinate system origin of each plaquette. The computation will likely be a little bit more involved now, but as long as we are able to get the global coordinate of each plaquette "origin", everything should work as expected. Now, computing this global position in the most general case would require us to re-think the way plaquettes are organised within a template, and how this organisation is encoded. To be as generic as possible, we might have to think about theoretical results on tiling, and how to compute the position of each tile (plaquettes here). This is not something I was feeling confident thinking and taking a decision on alone.

So let's use this issue to think about the way(s) we could store plaquettes in a template, knowing that as soon as we are able, for each plaquette within a template, to compute the global coordinates of at least one of its qubit, the rest should follow quite easily.

— Reply to this email directly, view it on GitHub https://github.com/QCHackers/tqec/issues/34#issuecomment-1885868430, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAKAXTDKQN2YKCNE7WC5GLTYN4LEVAVCNFSM6AAAAABBUJYRJOVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMYTQOBVHA3DQNBTGA . You are receiving this because you commented.Message ID: @.***>

nelimee commented 5 months ago

First, a quick summary of the current state of the code.

The Plaquette class does not assume anything about the qubits it is provided with at construction, except that their number should match the requirements of the provided quantum circuit.

[!NOTE]
I just realized that this assumption is not checked at the instance construction. It would make sense to check it directly when constructing the Plaquette instance to provide an early and clear diagnostic of the issue with a nice error message. I will do that soon.

I created a few sub-classes of Plaquette, namely SquarePlaquette and RoundedPlaquette, that do assume some specific qubit placement, but this is done intentionally to provide expressive ways for the user to create some plaquettes that are very common. Basically, these classes help creating Plaquette instances with less boilerplate, and are only used for this purpose. Any place in the code that performs "computation" on plaquette uses the generic Plaquette class (that does not assume anything on the shape of the plaquette).

Now, there are only 2 places in the code that use the shape information.

First, https://github.com/QCHackers/tqec/blob/f6f29323ebf2544ae576c6866167026adbfa6359/tqec/generation/circuit.py#L26-L29 that enforce the "all plaquettes should have the same shape" assumption.

Second, https://github.com/QCHackers/tqec/blob/f6f29323ebf2544ae576c6866167026adbfa6359/tqec/generation/circuit.py#L52-L53 that computes the position of the upper-left corner (that is, by definition, considered as the origin of the local Plaquette coordinate system) of a given Plaquette from:

Basically, the assumption was initially made to be able to compute the global position of a Plaquette origin with the trivial function https://github.com/QCHackers/tqec/blob/f6f29323ebf2544ae576c6866167026adbfa6359/tqec/generation/topology.py#L25-L39

This means that lifting the assumption will likely be easier than what I initially thought.

Now, about your comment.

We basically have several ways of defining what will be considered the origin of the local Plaquette coordinate system:

  1. the first qubit of the Plaquette instance,
  2. the "central" qubit of the Plaquette instance (when "central" is well defined),
  3. a user-defined qubit of the Plaquette instance.

At the time being, the origin of a Plaquette instance is implicitly defined by the coordinates of the qubits provided at the Plaquette instance creation. Basically, the provided qubit coordinates are not changed in any way and are stored as they are provided, assuming that the user placed the qubit as he/she wanted them to appear.

I think any of the 4 solutions (the 3 listed above and the current way of defining the origin) are rather equivalent in terms of usability, so any of the 4 is fine for me.

How to tackle this issue

For anyone wanting to contribute, solving this issue amounts to picking one of the 4 definitions of "origin" for the local Plaquette coordinate system and change https://github.com/QCHackers/tqec/blob/f6f29323ebf2544ae576c6866167026adbfa6359/tqec/generation/topology.py#L25-L39 along with maybe the place where it is called https://github.com/QCHackers/tqec/blob/f6f29323ebf2544ae576c6866167026adbfa6359/tqec/generation/circuit.py#L52-L53

Also, as a check you can try to remove all the shape-related methods/properties from the code and see if anything breaks. Below is a list of the places where the shape is defined: https://github.com/QCHackers/tqec/blob/f6f29323ebf2544ae576c6866167026adbfa6359/tqec/plaquette/plaquette.py#L31-L34 https://github.com/QCHackers/tqec/blob/f6f29323ebf2544ae576c6866167026adbfa6359/tqec/plaquette/library/xxxx.py#L13-L15 https://github.com/QCHackers/tqec/blob/f6f29323ebf2544ae576c6866167026adbfa6359/tqec/plaquette/library/xx.py#L16-L18 https://github.com/QCHackers/tqec/blob/f6f29323ebf2544ae576c6866167026adbfa6359/tqec/plaquette/library/zz.py#L16-L18 https://github.com/QCHackers/tqec/blob/f6f29323ebf2544ae576c6866167026adbfa6359/tqec/plaquette/library/zzzz.py#L15-L17 I might have forgotten a few places, but according to my IDE and my memory, this is it.

afowler commented 5 months ago

As a concrete proposal, a template could be associated with a scale variable. Under normal circumstances, that scale variable would be 2, meaning that the centers of different neighboring entries in a template are separated by 2 units of coordinates in both the X and Y directions. If you then also have a definition of a preferred qubit within a plaquette, these preferred qubits can go on the central locations of each plaquette and can then be tested to see whether they form a valid quantum circuit. Every other qubit in the plaquette would have relative coordinates.

Regards, Austin.

On Thu, Jan 11, 2024 at 12:47 PM Adrien Suau @.***> wrote:

First, a quick summary of the current state of the code.

The Plaquette https://github.com/QCHackers/tqec/blob/f6f29323ebf2544ae576c6866167026adbfa6359/tqec/plaquette/plaquette.py#L10 class does not assume anything about the qubits it is provided with at construction, except that their number should match the requirements of the provided quantum circuit.

Note

I just realized that this assumption is not checked at the instance construction. It would make sense to check it directly when constructing the Plaquette https://github.com/QCHackers/tqec/blob/f6f29323ebf2544ae576c6866167026adbfa6359/tqec/plaquette/plaquette.py#L10 instance to provide an early and clear diagnostic of the issue with a nice error message. I will do that soon.

I created a few sub-classes of Plaquette https://github.com/QCHackers/tqec/blob/f6f29323ebf2544ae576c6866167026adbfa6359/tqec/plaquette/plaquette.py#L10, namely SquarePlaquette https://github.com/QCHackers/tqec/blob/f6f29323ebf2544ae576c6866167026adbfa6359/tqec/plaquette/plaquette.py#L45C7-L45C22 and RoundedPlaquette https://github.com/QCHackers/tqec/blob/f6f29323ebf2544ae576c6866167026adbfa6359/tqec/plaquette/plaquette.py#L74C7-L74C23, that do assume some specific qubit placement, but this is done intentionally to provide expressive ways for the user to create some plaquettes that are very common. Basically, these classes help creating Plaquette https://github.com/QCHackers/tqec/blob/f6f29323ebf2544ae576c6866167026adbfa6359/tqec/plaquette/plaquette.py#L10 instances with less boilerplate, and are only used for this purpose. Any place in the code that performs "computation" on plaquette uses the generic Plaquette https://github.com/QCHackers/tqec/blob/f6f29323ebf2544ae576c6866167026adbfa6359/tqec/plaquette/plaquette.py#L10 class (that does not assume anything on the shape of the plaquette).

Now, there are only 2 places in the code that use the shape information.

First,

https://github.com/QCHackers/tqec/blob/f6f29323ebf2544ae576c6866167026adbfa6359/tqec/generation/circuit.py#L26-L29 that enforce the "all plaquettes should have the same shape" assumption.

Second,

https://github.com/QCHackers/tqec/blob/f6f29323ebf2544ae576c6866167026adbfa6359/tqec/generation/circuit.py#L52-L53 that computes the position of the upper-left corner (that is, by definition, considered as the origin of the local Plaquette https://github.com/QCHackers/tqec/blob/f6f29323ebf2544ae576c6866167026adbfa6359/tqec/plaquette/plaquette.py#L10 coordinate system) of a given Plaquette https://github.com/QCHackers/tqec/blob/f6f29323ebf2544ae576c6866167026adbfa6359/tqec/plaquette/plaquette.py#L10 from:

  • its shape,
  • its x and y coordinates on the numpy.ndarray we compute from the scalable template instantiation.

Basically, the assumption was initially made to be able to compute the global position of a Plaquette https://github.com/QCHackers/tqec/blob/f6f29323ebf2544ae576c6866167026adbfa6359/tqec/plaquette/plaquette.py#L10 origin with the trivial function

https://github.com/QCHackers/tqec/blob/f6f29323ebf2544ae576c6866167026adbfa6359/tqec/generation/topology.py#L25-L39

This means that lifting the assumption will likely be easier than what I initially thought. Now, about your comment.

We basically have several ways of defining what will be considered the origin of the local Plaquette https://github.com/QCHackers/tqec/blob/f6f29323ebf2544ae576c6866167026adbfa6359/tqec/plaquette/plaquette.py#L10 coordinate system:

  1. the first qubit of the Plaquette https://github.com/QCHackers/tqec/blob/f6f29323ebf2544ae576c6866167026adbfa6359/tqec/plaquette/plaquette.py#L10 instance,
  2. the "central" qubit of the Plaquette https://github.com/QCHackers/tqec/blob/f6f29323ebf2544ae576c6866167026adbfa6359/tqec/plaquette/plaquette.py#L10 instance (when "central" is well defined),
  3. a user-defined qubit of the Plaquette https://github.com/QCHackers/tqec/blob/f6f29323ebf2544ae576c6866167026adbfa6359/tqec/plaquette/plaquette.py#L10 instance.

At the time being, the origin of a Plaquette https://github.com/QCHackers/tqec/blob/f6f29323ebf2544ae576c6866167026adbfa6359/tqec/plaquette/plaquette.py#L10 instance is implicitly defined by the coordinates of the qubits provided at the Plaquette https://github.com/QCHackers/tqec/blob/f6f29323ebf2544ae576c6866167026adbfa6359/tqec/plaquette/plaquette.py#L10 instance creation. Basically, the provided qubit coordinates are not changed in any way and are stored as they are provided, assuming that the user placed the qubit as he/she wanted them to appear.

I think any of the 4 solutions (the 3 listed above and the current way of defining the origin) are rather equivalent in terms of usability, so any of the 4 is fine for me. How to tackle this issue

For anyone wanting to contribute, solving this issue amounts to picking one of the 4 definitions of "origin" for the local Plaquette https://github.com/QCHackers/tqec/blob/f6f29323ebf2544ae576c6866167026adbfa6359/tqec/plaquette/plaquette.py#L10 coordinate system and change

https://github.com/QCHackers/tqec/blob/f6f29323ebf2544ae576c6866167026adbfa6359/tqec/generation/topology.py#L25-L39 along with maybe the place where it is called

https://github.com/QCHackers/tqec/blob/f6f29323ebf2544ae576c6866167026adbfa6359/tqec/generation/circuit.py#L52-L53

Also, as a check you can try to remove all the shape-related methods/properties from the code and see if anything breaks. Below is a list of the places where the shape is defined:

https://github.com/QCHackers/tqec/blob/f6f29323ebf2544ae576c6866167026adbfa6359/tqec/plaquette/plaquette.py#L31-L34

https://github.com/QCHackers/tqec/blob/f6f29323ebf2544ae576c6866167026adbfa6359/tqec/plaquette/library/xxxx.py#L13-L15

https://github.com/QCHackers/tqec/blob/f6f29323ebf2544ae576c6866167026adbfa6359/tqec/plaquette/library/xx.py#L16-L18

https://github.com/QCHackers/tqec/blob/f6f29323ebf2544ae576c6866167026adbfa6359/tqec/plaquette/library/zz.py#L16-L18

https://github.com/QCHackers/tqec/blob/f6f29323ebf2544ae576c6866167026adbfa6359/tqec/plaquette/library/zzzz.py#L15-L17 I might have forgotten a few places, but according to my IDE and my memory, this is it.

— Reply to this email directly, view it on GitHub https://github.com/QCHackers/tqec/issues/34#issuecomment-1887937598, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAKAXTHCLKIQDLBPZRIGASTYOBFXJAVCNFSM6AAAAABBUJYRJOVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMYTQOBXHEZTONJZHA . You are receiving this because you commented.Message ID: @.***>

Gistbatch commented 5 months ago

I could have a look at this. From @afowler 's last comment, I'm a little confused, though. As far as I understand, the template doesn't need the information of the plaquette. @nelimee can you confirm? I think Austins comment would then be separate issue?

nelimee commented 5 months ago

@Gistbatch I will be able to make a more detailed answer tomorrow if needed.

The template does not need any information on the plaquette, and the plaquette does not need any information on the template either. But at one point, we need both information to compute the qubits we should apply the plaquette's circuit to.

I think we will have to compute, once all the information is available, the global position of the upper-left corner of each plaquette (like what is currently done for templates on the orchestrator, but for each plaquette this time).

The plaquette basically need to store whatever information is sufficient to perform the above computation.

afowler commented 5 months ago

+1 to Adrien's explanation.

On Wed, Jan 24, 2024 at 9:32 AM Adrien Suau @.***> wrote:

@Gistbatch https://github.com/Gistbatch I will be able to make a more detailed answer tomorrow if needed.

The template does not need any information on the plaquette, and the plaquette does not need any information on the template either. But at one point, we need both information to compute the qubits we should apply the plaquette's circuit to.

I think we will have to compute, once all the information is available, the global position of the upper-left corner of each plaquette (like what is currently done for templates on the orchestrator, but for each plaquette this time).

The plaquette basically need to store whatever information is sufficient to perform the above computation.

— Reply to this email directly, view it on GitHub https://github.com/QCHackers/tqec/issues/34#issuecomment-1908607179, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAKAXTCLJTBH7VJD245JB6DYQFAR3AVCNFSM6AAAAABBUJYRJOVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMYTSMBYGYYDOMJXHE . You are receiving this because you were mentioned.Message ID: @.***>

Gistbatch commented 5 months ago

I've tried to wrap my head around this but have some problems. My idea currently is to calculate the position by anchoring the top_left of the current plaquette to the top_right of the left and bottom_left of the above plaquettes. The problems are:

  1. This assumes that the plaquettes are at least rectangular. Do you think this is a valid assumption? Else, one would need to create a separate grid of qubits where you would need to explicitly anchor plaquettes to an absolute position
  2. How do we handle the 0 plaquettes? We can only know this by looking at the surrounding plaquettes and taking a guess, but these might still need to be anchored.
nelimee commented 5 months ago

I think we can restrict ourselves to rectangular plaquettes.

More complex tiling would need to also be reflected in the Template and TemplateOrchestrator classes, and we would need to represent scaled templates with something more complex than a 2-dimensional array of numbers. For the moment, I think implementing that kind of thing is a "high cost, low reward" situation as it would require to refactor most of the code and we do not need such generality for the moment.

The 0 plaquette issue seems challenging. In my opinion, we should try to solve it with cross-template information sharing. Let's take the following example to illustrate what I mean by that. image In the above image, we want the 0 plaquette that is on the same Template as the 1 plaquette to have:

Getting the y dimension is simple in this case, but the x dimension requires to be able to query the neighbouring plaquette. I think this can be done quite easily by adding a few query methods (get_neighbour(direction: Direction) -> int for example) to the TemplateOrchestrator and using them for 0 plaquettes.

Another solution is to look at the problem the other way around: instead of trying to compute the shape of 0 plaquettes, we try to position non-0 plaquettes using their neighbours. In the image above, this would translate in "trying to position 1 by using the already computed position of 4". I prefer this solution as not all 0 plaquettes have a non-zero neighbour (the top-right corner of the above image is filled with 0 plaquettes).

Nevertheless, both solutions impose some restrictions on the dimension of neighbouring plaquettes, and we do not want that in the case we try to implement.

nelimee commented 5 months ago

Thinking about it and the options we have, I think the solution given by @afowler in penultimate message is the way to go. Basically, we add 2 parameters to tqec.generation.circuit.generate_circuit:

Gistbatch commented 5 months ago

I'll try this approach. I'll hopefully have something done by the end of today.

afowler commented 5 months ago

Hi Adrien,

In your example I see templates that are neither 2kx2k nor 1x2k. There are some 1x2 and 2x2 templates. Can these all be made 1x1? What is their purpose. Also, shouldn't all plaquettes, 0 or otherwise, have the same dimensions?

Best, Austin.

On Thu, Jan 25, 2024 at 8:24 AM Adrien Suau @.***> wrote:

I think we can restrict ourselves to rectangular plaquettes.

More complex tiling would need to also be reflected in the Template and TemplateOrchestrator classes, and we would need to represent scaled templates with something more complex than a 2-dimensional array of numbers. For the moment, I think implementing that kind of thing is a "high cost, low reward" situation as it would require to refactor most of the code and we do not need such generality for the moment.

The 0 plaquette issue seems challenging. In my opinion, we should try to solve it with cross-template information sharing. Let's take the following example to illustrate what I mean by that. image.png (view on web) https://github.com/QCHackers/tqec/assets/12374487/662fb5f2-b0c2-466d-aaa5-2dce4ea5efbf In the above image, we want the 0 plaquette that is on the same Template as the 1 plaquette to have:

  • the x dimension of the 3 plaquette,
  • the y dimension of the 1 plaquette.

Getting the y dimension is simple in this case, but the x dimension requires to be able to query the neighbouring plaquette. I think this can be done quite easily by adding a few query methods (get_neighbour(direction: Direction) -> int for example) to the TemplateOrchestrator and using them for 0 plaquettes.

Another solution is to look at the problem the other way around: instead of trying to compute the shape of 0 plaquettes, we try to position non-0 plaquettes using their neighbours. In the image above, this would translate in "trying to position 1 by using the already computed position of 4". I prefer this solution as not all 0 plaquettes have a non-zero neighbour (the top-right corner of the above image is filled with 0 plaquettes).

Nevertheless, both solutions impose some restrictions on the dimension of neighbouring plaquettes, and we do not want that in the case we try to implement.

— Reply to this email directly, view it on GitHub https://github.com/QCHackers/tqec/issues/34#issuecomment-1910547737, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAKAXTATFUWVDMK24GVXU53YQKBKJAVCNFSM6AAAAABBUJYRJOVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMYTSMJQGU2DONZTG4 . You are receiving this because you were mentioned.Message ID: @.***>

nelimee commented 5 months ago

Hi, Yes these are relicates from before the corner pinning method to organise templates and that I never tried to change because the implementation was working as expected and produced correct results. They can be changed to 1x1 without any issue. I will do that on Monday.