Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add pauli_rep properties for common static gates #6243

Open
dwierichs opened this issue Sep 9, 2024 · 7 comments
Open

Add pauli_rep properties for common static gates #6243

dwierichs opened this issue Sep 9, 2024 · 7 comments
Labels
enhancement ✨ New feature or request

Comments

@dwierichs
Copy link
Contributor

Feature details

The pauli_rep property allows to represent an operator as a PauliSentence instance.
Currently, it is mostly implemented for qml.X, qml.Y, qml.Z and for operator math classes.
It would be great to have pauli_rep attributes for, e.g., Clifford gates (Hadamard, S, CNOT), but also for other ops.
This would simplify manipulation of qml.pauli objects.

This came up while writing this demo, where we currently have to do

new_op = qml.CNOT([0, 1]) @ original_op @ qml.CNOT([0, 1])
new_op = qml.pauli_decompose(new_op.matrix())

i.e., we have to go via the dense matrix representation to obtain the new operator. With qml.CNOT.pauli_rep implemented, we could stay in the more efficient Pauli representation.

Implementation

Basically trivial, as far as I can tell.

How important would you say this feature is?

1: Not important. Would be nice to have.

Additional information

No response

@dwierichs dwierichs added the enhancement ✨ New feature or request label Sep 9, 2024
@ldi18
Copy link
Contributor

ldi18 commented Nov 4, 2024

Hi, I’d like to work on this issue as my first contribution.

ldi18 pushed a commit to ldi18/pennylane that referenced this issue Nov 5, 2024
@dwierichs
Copy link
Contributor Author

Hi @ldi18,
That's great to hear!
Let me start an internal discussion to see which operators should be included in this, and which constraints might apply.
I'll get back to you asap.

@dwierichs
Copy link
Contributor Author

Hey @ldi18
we'd be happy for you to contribute this feature.
I think a nice goal could be to include a Pauli representation for all gates in pennylane/ops/qubit/non_parametric_ops.py, and if you'd like you could also tackle pennylane/ops/qubit/parametric_ops_single_qubit.py.
After discussing internally, it would be favourable to evaluate the Pauli representations lazily, i.e., only when they are needed and not when the Operation is created, in order to avoid overhead for unrelated workflows.
Let me know in case you require any help with this. :)
As this is your first contribution, it will probably be helpful to take a look at our how-to-PR page.

@ldi18
Copy link
Contributor

ldi18 commented Nov 7, 2024

Hi @dwierichs ,
I implemented Pauli representations for all ops in non_parametric_ops and parametric_ops_single_qubit as for the Hadamard gate here:

@property
def _pauli_rep(self):
    if self._pauli_rep_cached is None:
        self._pauli_rep_cached = qml.pauli.PauliSentence(
            {
                qml.pauli.PauliWord({self.wires[0]: "X"}): INV_SQRT2,
                qml.pauli.PauliWord({self.wires[0]: "Z"}): INV_SQRT2,
            }
        )
    return self._pauli_rep_cached

def __init__(self, wires: WiresLike, id: Optional[str] = None):
    super().__init__(wires=wires, id=id)
    self._pauli_rep_cached = None

I defined the test

def test(gate):
    dim = gate.matrix().shape[0]
    if dim == 2:
        id_str = 'I(0)'
    if dim == 4:
        id_str = 'I(0)@I(1)'
    gate_in_pauli_decomp = eval(str(gate.pauli_rep).replace('\n', ' ').replace('I', id_str)).matrix()
    return np.allclose(gate.matrix(), gate_in_pauli_decomp)

All ops pass the test, but only if I comment out the assignment in the operator constructor as shown below:

class Operator(abc.ABC, meta class=ABCCaptureMeta):
...
...
    def __init__(
        self,
        *params: TensorLike,
        wires: Optional[WiresLike] = None,
        id: Optional[str] = None,
    ):
        # pylint: disable=too-many-branches

        self._name: str = self.__class__.__name__  #: str: name of the operator
        self._id: str = id
        
        # Can this be commented out?
        # self._pauli_rep: Optional[qml.pauli.PauliSentence] = (
        #     None  # Union[PauliSentence, None]: Representation of the operator as a pauli sentence, if applicable
        # )
...
...)

Would it cause any issues elsewhere when I just remove the part I commented out above? To check this I tried running the tests as described in https://docs.pennylane.ai/en/stable/development/guide/tests.html . Actually this returns 11 errors, even for the current version in the GitHub - without any changes from me.

Is this a problem with my testing environment or just normal? I'd just create a pull request now so that you can have a look.

@dwierichs
Copy link
Contributor Author

dwierichs commented Nov 7, 2024

Hi @ldi18
That sounds great!
So we do not want to have any breaking change with the Operator API here. What I would suggest is trying to modify (instead of remove) the logic in Operator such that it is more permissive and allows you to do what you are already doing with the newly added (nice and lazy :) ) method. Probably you want to overwrite the property pauli_rep rather than _pauli_rep, no? :)
Then you can also just use the existing _pauli_rep attribute instead of _pauli_rep_cached

ldi18 pushed a commit to ldi18/pennylane that referenced this issue Nov 9, 2024
ldi18 pushed a commit to ldi18/pennylane that referenced this issue Nov 10, 2024
@ldi18
Copy link
Contributor

ldi18 commented Nov 10, 2024

Hi @dwierichs,

Thanks for the hint! Using pauli_rep resolved the issue in the operator class. During testing, however, test_parametric_ops:TestDecompositions:test_pc_phase_decomposition_broadcasted resulted in a shape error. Using an outer product in pauli_arithmetic.py for tensor-like phases (as in my pull request) would fix this.

My changes pass all pytest checks. Pylint still shows a few errors/warnings related to the number of parameters, but many of these also appear in the developer version without any changes from me.

@dwierichs
Copy link
Contributor Author

Hi @ldi18 ,
Nice, happy to hear this worked.
At this point it's probably best to open the pull request :)
Then we can chat concretely about more nichy test failures and CI checks like pylint.

dwierichs added a commit that referenced this issue Dec 5, 2024
**Context:**
Prior to this commit, PennyLane only allowed access to Pauli string
representations for the X, Z and Z gate via `X(0).pauli_rep`, etc. The
Pauli representations of other gates were not implemented.

**Description of the Change:**
I added the Pauli string representations for X, Y, Z, S, T, SX, SWAP,
ISWAP, ECR, SISWAP.

The correctness of each Pauli string representation is checked by
converting the returned Pauli string into a matrix and comparing it with
the respective `.matrix()` method.

(Pauli reps for parametrized ops and H were not added as they caused
problems in the CI tests.)

**Benefits:**

Pennylane now supports Pauli string decompositions for various
operators. Pauli string decompositions of products of operators with
available Pauli string decompositions can now be directly accessed.
`Example: (Hadamard(0) @ S(1) @ T(1, 2) @ SX(1) @ SWAP([0,
1])).pauli_rep`

**Related GitHub Issues:**
#6243

**Related Shortcut Stories:**
[sc-73280]

---------

Co-authored-by: Lasse Dierich <[email protected]>
Co-authored-by: David Wierichs <[email protected]>
Co-authored-by: Christina Lee <[email protected]>
Co-authored-by: ringo-but-quantum <>
Co-authored-by: Yushao Chen (Jerry) <[email protected]>
Co-authored-by: Andrija Paurevic <[email protected]>
dwierichs added a commit that referenced this issue Dec 11, 2024
…ition to PR: #6562) (#6587)

**Context:**
I added Pauli string decompositions for single qubit parametrized gates
in PR: #6562. Pennylane exploits these Pauli string representations
when, for example, computing

```python
(qml.RX(1.11, wires=0) @ qml.RY(1.23, wires=0)).matrix()
```
The example above works as intended, but

```python
(qml.RX([1.11, 2.11, 3.11], wires=0) @ qml.RY([1.23, 2.23, 3.23], wires=0)).matrix()     # shape error
```
or
```python
(qml.RX(np.array([1.11, 2.11, 3.11]), wires=0) @ qml.RY(np.array([1.23, 2.23, 3.23]), wires=0)).matrix()     # shape error
```
returns a shape error. The code above should work since `RX`and
`RY`support tensor-like (flattened) parameters as it can be seen from
```python
qml.RX([1.11, 2.11, 3.11], wires=0).matrix()    # works!
```


**Description of the Change:**

I added an outer product in `pauli_arithmetic`.

**Benefits:**
- Pauli representations can now be leveraged for the matrix conversion
of products of ops.
- A Pauli representation of the `PhaseShift gate` could be added - this
was not possible before as the `PCPhase` gate used the
`pauli_arithmetic`, which gave an error in the pytests.

**Possible Drawbacks:**
None

**Related GitHub Issues:**
#6243 and PR: #6562

---------

Co-authored-by: Lasse Dierich <[email protected]>
Co-authored-by: David Wierichs <[email protected]>
Co-authored-by: Christina Lee <[email protected]>
mudit2812 pushed a commit that referenced this issue Dec 13, 2024
…ition to PR: #6562) (#6587)

**Context:**
I added Pauli string decompositions for single qubit parametrized gates
in PR: #6562. Pennylane exploits these Pauli string representations
when, for example, computing

```python
(qml.RX(1.11, wires=0) @ qml.RY(1.23, wires=0)).matrix()
```
The example above works as intended, but

```python
(qml.RX([1.11, 2.11, 3.11], wires=0) @ qml.RY([1.23, 2.23, 3.23], wires=0)).matrix()     # shape error
```
or
```python
(qml.RX(np.array([1.11, 2.11, 3.11]), wires=0) @ qml.RY(np.array([1.23, 2.23, 3.23]), wires=0)).matrix()     # shape error
```
returns a shape error. The code above should work since `RX`and
`RY`support tensor-like (flattened) parameters as it can be seen from
```python
qml.RX([1.11, 2.11, 3.11], wires=0).matrix()    # works!
```


**Description of the Change:**

I added an outer product in `pauli_arithmetic`.

**Benefits:**
- Pauli representations can now be leveraged for the matrix conversion
of products of ops.
- A Pauli representation of the `PhaseShift gate` could be added - this
was not possible before as the `PCPhase` gate used the
`pauli_arithmetic`, which gave an error in the pytests.

**Possible Drawbacks:**
None

**Related GitHub Issues:**
#6243 and PR: #6562

---------

Co-authored-by: Lasse Dierich <[email protected]>
Co-authored-by: David Wierichs <[email protected]>
Co-authored-by: Christina Lee <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement ✨ New feature or request
Projects
None yet
Development

No branches or pull requests

2 participants