Skip to content

Create plaquette from RPNG string#411

Merged
giangiac merged 29 commits intotqec:mainfrom
giangiac:feature/generate-plaquette-from-rpng
Dec 18, 2024
Merged

Create plaquette from RPNG string#411
giangiac merged 29 commits intotqec:mainfrom
giangiac:feature/generate-plaquette-from-rpng

Conversation

@giangiac
Copy link
Copy Markdown
Contributor

@giangiac giangiac commented Dec 4, 2024

See issue #410 in the tqec repo.

This PR includes:

  • a function to validate the RPNG string
  • a function that generates the plaquette given the RPNG string
  • [for a future PR] a generic and documented interface, so that users will be able to implement their own translation if they want

Example of a RPNG string and description of the format:

-z1- -z2- -z3- -z4-
rpng rpng rpng rpng

(r) data qubit reset basis or h or -
(p) data basis for the controlled operation (x means CNOT controlled on the ancilla and targeting the data qubit, y means CY, z means CZ)
(n) time step (positive integers, all distinct, typically in 1-5)
(g) data qubit measure basis or h or -

Assumptions on the circuit:

  • if not otherwise stated, a basis can be {x,y,z}
  • the ancilla is always initialized in $\ket{+}$ and measured in the X basis
  • the ancilla is always the control qubit for the CNOT, CY, or CZ gates

@nelimee nelimee added enhancement New feature or request, may not be in the task flow backend Issue pertaining to the Python backend (tqec package) labels Dec 4, 2024
@nelimee nelimee linked an issue Dec 4, 2024 that may be closed by this pull request
@nelimee nelimee added this to the Spatial junctions milestone Dec 4, 2024
@afowler
Copy link
Copy Markdown

afowler commented Dec 4, 2024 via email

@giangiac
Copy link
Copy Markdown
Contributor Author

giangiac commented Dec 5, 2024

@nelimee I am not sure why the CI/CD is failing.

Also, I am thinking if it is worth merging with the canonical form of the circuits expressed as RPNG strings, leaving the general interface for custom compilation for another PR.

@inmzhang
Copy link
Copy Markdown
Contributor

inmzhang commented Dec 5, 2024

Hi Gian,

I am not sure why the CI/CD is failing.

You need to install and run the pre-commit hooks locally. And the deploy failure is because you did not create the branch under the tqec repository but use your fork instead, it will cause permission issue.

Also, I am thinking if it is worth merging with the canonical form of the circuits expressed as RPNG strings, leaving the general interface for custom compilation for another PR.

In my opinion, they should be in separate PR.

@nelimee
Copy link
Copy Markdown
Contributor

nelimee commented Dec 5, 2024

A few preliminary notes on the current state of the implementation:

  • The functions are too complex. There are too much if/else branches, too much "magic" (e.g., v[0] could be renamed r in most cases, to make it easier to read).
  • I think that a dataclass with some methods would be perfect to wrap one RPNG representation. The dataclass would be responsible to validate that the provided RPNG string is locally valid (i.e. that we have correct values for R, P and G) and would provide methods to ease the global validation (e.g., a property n returning the timestep at which the 2-qubit gate is scheduled).
  • The dataclass could also help for circuit generation, for example by returning the correct reset/measurement/computation gates using methods.

@nelimee nelimee mentioned this pull request Dec 5, 2024
@giangiac
Copy link
Copy Markdown
Contributor Author

giangiac commented Dec 5, 2024

I am not sure why the CI/CD is failing.

You need to install and run the pre-commit hooks locally. And the deploy failure is because you did not create the branch under the tqec repository but use your fork instead, it will cause permission issue.

Would you suggest creating a new branch in the official tqec repo, merge my fork there, and then create a PR internal to tqec?
In general I would find it more convenient to work directly in the tqec repo, but didn't know if that's a good practice.

@giangiac
Copy link
Copy Markdown
Contributor Author

giangiac commented Dec 5, 2024

A few preliminary notes on the current state of the implementation:

  • The functions are too complex. There are too much if/else branches, too much "magic" (e.g., v[0] could be renamed r in most cases, to make it easier to read).
  • I think that a dataclass with some methods would be perfect to wrap one RPNG representation. The dataclass would be responsible to validate that the provided RPNG string is locally valid (i.e. that we have correct values for R, P and G) and would provide methods to ease the global validation (e.g., a property n returning the timestep at which the 2-qubit gate is scheduled).
  • The dataclass could also help for circuit generation, for example by returning the correct reset/measurement/computation gates using methods.

Thanks for the early feedback, Adrien.

I can wrap the rpng strings into a dataclass to facilitate querying the values of interest.
Is the idea to facilitate writing custom circuits from the rpng?
Or do you think it would affect how the rest of the backend uses it?
(in my mind we just need the plaquette given a valid rpng string)

I'll include the validation inside that class, but would not mind keeping its "complex" implementation for the moment (there is no urgency here and no risk of computational slowdowns).

@nelimee
Copy link
Copy Markdown
Contributor

nelimee commented Dec 5, 2024

I can wrap the rpng strings into a dataclass to facilitate querying the values of interest.
Is the idea to facilitate writing custom circuits from the rpng?
Or do you think it would affect how the rest of the backend uses it?
(in my mind we just need the plaquette given a valid rpng string)

See for example #412. I think we need a simple and robust representation of a RPNG string, and a RPNGPlaquette, as we might have to use them in several places.

I'll include the validation inside that class, but would not mind keeping its "complex" implementation for the moment (there is no urgency here and no risk of computational slowdowns).

The problem is mostly about code reuse. I think it is better to have most of the validation code in one place, and #412 would need a little bit more flexibility, so I think we shoule have reusable structures if we can.

@giangiac
Copy link
Copy Markdown
Contributor Author

giangiac commented Dec 6, 2024

See for example #412. I think we need a simple and robust representation of a RPNG string, and a RPNGPlaquette, as we might have to use them in several places.

Thanks for the concrete example!
I adopted most of it (I am unfamiliar with the template part so I left it out) and the PR should be ready for review.

@afowler
Copy link
Copy Markdown

afowler commented Dec 10, 2024 via email

@afowler
Copy link
Copy Markdown

afowler commented Dec 11, 2024 via email

@nelimee
Copy link
Copy Markdown
Contributor

nelimee commented Dec 11, 2024

@giangiac the goal is to merge that PR as soon as possible to unlock other issues. I'll make a real full review, and we will be able to merge once the review will be addressed.

Copy link
Copy Markdown
Contributor

@nelimee nelimee left a comment

Choose a reason for hiding this comment

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

I think the main point that needs to be changed is the extraction of the Extended RPNG representation outside of the RPNG code. There are also formatting issue, you will have to run pre-commit.

Comment on lines +234 to +235
Note that the ancilla qubit is the last among the PlaquetteQubits and thus
has index 4, while the data qubits have indices 0-3.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I think that currently the standard was to have the ancilla as the first qubit (index 0). Is there any reason to change that?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Also note that plaquettes on the boundary only have 3 qubits (counting the ancilla). Having a hole in qubit indexing should not be an issue, but I would advocate for not having a hole at all.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

That's a good point.
I just noticed that if I iterate through the SquarePlaquetteQubits the iterator first goes through the data qubits and then the ancilla qubit.
I do not know the consequences of changing that behavior, so I simply adopted that convention.
In the future one may have multiple ancillas to measure a stabilizer (e.g. when connectivity is constrained) so we may have other type of issees then).

Copy link
Copy Markdown
Contributor

@nelimee nelimee Dec 11, 2024

Choose a reason for hiding this comment

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

From memory, the iteration order is very much just a detail and is not used anywhere. A good hint that the previous sentence is likely true is that the iteration order is not documented anywhere.

PS: just checked, all_qubits is only used to reduce a circuit to the plaquette's qubits by calling ScheduledCircuit.filter_by_qubits, so the specific ordering does not matter.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Shall I change the order then (first ancilla, then data)?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Ok, I just updated the PlaquetteQubits class changing the order of the fields (first syndrome_qubits, then data_qubits) and the __iter__ method.

Copy link
Copy Markdown
Contributor Author

@giangiac giangiac Dec 12, 2024

Choose a reason for hiding this comment

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

@nelimee This actually broke several CI/CD tests.
Shall we update those tests or change the way we iterate though the qubits in the RPNGDescription.get_plaquette() method?

@afowler I think it would be nice to have consistency across the codebase:
When listing the qubits in a plaquette, shall we start from the data qubits or from the ancillas?

My preference would be for data first.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Shall we update those tests or change the way we iterate though the qubits in the RPNGDescription.get_plaquette() method?

For the moment, I would take the solution that minimise the amount of code changes for this PR. If that solution is not the prefered one (ancilla qubit first or last, I have a soft preference for ancilla qubit first) then we can open a different PR to change that.

So for the moment, stick to the convention that does not break tests and minimise code changes.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Ok, I reverted the commit.
First data and then ancilla qubits.

@giangiac
Copy link
Copy Markdown
Contributor Author

I would vote against the 5-character notation. In my mind if you need to go to a circuit that cannot be expressed with the four character notation, you probably wouldn't express that circuit using plaquettes in the first place. H can be on both reset and measurement as a typical expansion of cnot into CZ can easily require H on both ends of the circuit. I think reset time should always be zero, and the measurement time should be the latest time of a gate in an entire circuit layer plus one. Best, Austin.

I am catching up with the comments and it seems that the consensus (at least among the active users @afowler @inmzhang @nelimee ) is to focus exclusively on the 4-character notation.
I will move the 5-character one to separate classes (not to lose its implementation in case of future reevaluation).

Question on N: Is it ok to assume a single digit value or shall we provide the flexibility to have a larger integer?
This may happen when gates take more than a "time step", if we describe time in terms of a certain clock.

Question on the measurement time: We need to know that at the time when we generate the plaquette.
Are we going to populate the templates with Plaquette or RPNGDescription objects?

@afowler
Copy link
Copy Markdown

afowler commented Dec 11, 2024 via email

@nelimee
Copy link
Copy Markdown
Contributor

nelimee commented Dec 11, 2024

Question on N: Is it ok to assume a single digit value or shall we provide the flexibility to have a larger integer?

Let's have the simple case correct first. If we need 10+ values for N we will improve that afterwards.

Question on the measurement time: We need to know that at the time when we generate the plaquette.
Are we going to populate the templates with Plaquette or RPNGDescription objects?

Templates will return RPNG strings. These strings will be translated to Plaquette instances at circuit creation, when we will have all the global information for each round of error correction, which is needed to synchronise measurements.

@afowler
Copy link
Copy Markdown

afowler commented Dec 12, 2024 via email

@nelimee
Copy link
Copy Markdown
Contributor

nelimee commented Dec 13, 2024

Here is a proposal for the RPNG.from_string method that makes it more readable in my opinion. I am also fine with the existing code (modulus my comments), so it is up to preference.

    @staticmethod
    def _parse_or_raise(
        typ: type[RPNGCharType], char: str, pos: Literal["R", "P", "N", "G"]
    ) -> RPNGCharType:
        try:
            return typ(char)
        except ValueError as err:
            raise ValueError(
                f"Unacceptable character for the {pos} field: '{char}'."
            ) from err

    @classmethod
    def from_string(cls, rpng_string: str) -> RPNG:
        """Initialize the RPNG object from a 4-character string

        Note that any character different from a BasisEnum / ExtendedBasisEnum
        value would result in the corresponding field being None.
        """
        if len(rpng_string) != 4:
            raise ValueError("The rpng string must be exactly 4-character long.")
        r_str, p_str, n_str, g_str = tuple(rpng_string)
        # Convert the characters into the enum attributes (or raise error).
        r = RPNG._parse_or_raise(ExtendedBasisEnum, r_str, "R")
        p = RPNG._parse_or_raise(BasisEnum, p_str, "P")
        n = RPNG._parse_or_raise(int, n_str, "N")
        g = RPNG._parse_or_raise(ExtendedBasisEnum, g_str, "G")

        return cls(r, p, n, g)

The code

from tqec import RPNG

rpng = RPNG.from_string2("e---")

raises and prints to the screen

Traceback (most recent call last):
  File "/workspaces/tqec/src/tqec/plaquette/rpng.py", line 100, in _parse_or_raise
    return typ(char)
           ^^^^^^^^^
  File "/usr/local/lib/python3.12/enum.py", line 757, in __call__
    return cls.__new__(cls, value)
           ^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.12/enum.py", line 1171, in __new__
    raise ve_exc
ValueError: 'e' is not a valid ExtendedBasisEnum

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "/workspaces/tqec/main.py", line 3, in <module>
    rpng = RPNG.from_string2("e---")
           ^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/workspaces/tqec/src/tqec/plaquette/rpng.py", line 117, in from_string2
    r = RPNG._parse_or_raise(ExtendedBasisEnum, r_str, "R")
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/workspaces/tqec/src/tqec/plaquette/rpng.py", line 102, in _parse_or_raise
    raise ValueError(
ValueError: Unacceptable character for the R field: 'e'.

@giangiac
Copy link
Copy Markdown
Contributor Author

Here is a proposal for the RPNG.from_string method that makes it more readable in my opinion. I am also fine with the existing code (modulus my comments), so it is up to preference.

I am not sure how you defined RPNGCharType, but one has to include the desired behavior for - or it would not work.
What if we merge this code and leave code readability for later?

@giangiac
Copy link
Copy Markdown
Contributor Author

From my point of view, this is ready to be merged.

A few things left for future PRs:

  1. a generic and documented interface, so that users will be able to implement their own translation if they want
  2. expand the tqec documentation, for example by adding to the user_guide a new section about creating the plaquettes
  3. improve code readability (see Adrien's proposal)

Copy link
Copy Markdown
Contributor

@nelimee nelimee left a comment

Choose a reason for hiding this comment

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

Ok for me to merge that PR quickly and iterate on it. Thanks for the work :)

@nelimee
Copy link
Copy Markdown
Contributor

nelimee commented Dec 18, 2024

@giangiac do you want me to merge that PR, or are you waiting for something else to merge?

@giangiac
Copy link
Copy Markdown
Contributor Author

@giangiac do you want me to merge that PR, or are you waiting for something else to merge?

Usually, I let someone else merge my PRs, but it seems that the consensus is to merge.
So, I will go for it. :-)

@giangiac giangiac merged commit 5cb0084 into tqec:main Dec 18, 2024
@giangiac giangiac deleted the feature/generate-plaquette-from-rpng branch December 18, 2024 16:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

backend Issue pertaining to the Python backend (tqec package) enhancement New feature or request, may not be in the task flow

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Create plaquette from RPNG string

4 participants