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

Additional useful standard transforms #6130

Open
cvjjm opened this issue Aug 22, 2024 · 6 comments
Open

Additional useful standard transforms #6130

cvjjm opened this issue Aug 22, 2024 · 6 comments
Labels
enhancement ✨ New feature or request

Comments

@cvjjm
Copy link
Contributor

cvjjm commented Aug 22, 2024

Feature details

PennyLane ships a few useful transform, but some obvious one that would be nice to have are missing. These include for example transforms that:

  • Combine all all GlobalPhase gates into a single one in the end
  • Remove all GlobalPhase gates
  • Remove adjoints whenever possible, e.g., by changing the gate parameter, i.e., qml.adjoint(qml.RY)(0.2, 0)) -> qml.RY(-0.2, 0))
  • Combine powers of T gates into S gates as much as possible, i.e., TTT -> ST
  • Turn all fixed gates into some equivalent parametrized gate

While I understand that it will never be possible to cover all transforms a user could ever want, an added benefit of a slightly larger library of transforms would that there are more templates for users to start implementing their own transforms from.

Implementation

No response

How important would you say this feature is?

1: Not important. Would be nice to have.

Additional information

No response

@cvjjm cvjjm added the enhancement ✨ New feature or request label Aug 22, 2024
@josh146
Copy link
Member

josh146 commented Aug 23, 2024

Thanks @cvjjm, definitely something we want to improve down the line!

Are there any particular ones in the list that have come up which you would find useful?

@cvjjm
Copy link
Contributor Author

cvjjm commented Aug 23, 2024

They all would have been useful at some point to me and some of them I had also implemented at some point...

For the merging/deleting of the global phase I still have this code lying around:

@transform
def merge_global_phase(tape: QuantumTape, remove=False) -> (Sequence[QuantumTape], Callable):
    filtered_operations = list()

    global_phase = 0
    for operation in tape.operations:
        if isinstance(operation, qml.GlobalPhase):
            global_phase += operation.parameters[0]
        else:
            filtered_operations.append(operation)

    if remove is False and global_phase != 0:
        filtered_operations.append(qml.GlobalPhase(global_phase))

    if compatibility_mode:
        new_tape = type(tape)(filtered_operations, tape.measurements)
    else:
        new_tape = type(tape)(filtered_operations, tape.measurements, shots=tape.shots)

    def postprocessing(results):
        return np.array(results)[0]

    return [new_tape], postprocessing

@albi3ro
Copy link
Contributor

albi3ro commented Aug 23, 2024

Note that qml.simplify does simplify adjoints where possible:

@qml.simplify
@qml.qnode(qml.device('default.qubit'))
def circuit(x):
    qml.adjoint(qml.RX(x,0))
    qml.adjoint(qml.X(0))
    return qml.state()

qml.draw(circuit, level=1)(0.5)
0: ──RX(12.07)──X─┤  State

Though it will also perform other simplications.

@mudit2812
Copy link
Contributor

Note that qml.simplify does simplify adjoints where possible:

@qml.simplify
@qml.qnode(qml.device('default.qubit'))
def circuit(x):
    qml.adjoint(qml.RX(x,0))
    qml.adjoint(qml.X(0))
    return qml.state()

qml.draw(circuit, level=1)(0.5)
0: ──RX(12.07)──X─┤  State

Though it will also perform other simplications.

To avoid oversimplifying, you can also set the lazy keyword argument of qml.adjoint to False, which will cause the operators to eagerly replace Adjoint with updated parameters.

@qml.qnode(qml.device('default.qubit'))
def circuit(x):
    qml.adjoint(qml.RX(x,0), lazy=False)
    qml.adjoint(qml.X(0), lazy=False)
    return qml.state()
print(qml.draw(circuit, level=1)(0.5))
0: ──RX(-0.50)──X─┤  State

@cvjjm
Copy link
Contributor Author

cvjjm commented Sep 5, 2024

I must say that a transform with an "obscure" name such as simplify that does not really tell me what it does and potentially does things I do not want, which I then have to switch off with another option with an obscure name such as "lazy" is less useful than a collection of transforms with descriptive names (so that they can be found easily via search or by glancing over the list) that do exactly one thing and do it well, and which I can then chain together in exactly the order I want.

Here are a two more for the wish list:

  • A transform that expands all (multi) controlled operations out into with CNOT ladders
  • A transform that tries to permute commuting gates such that the same types of gates and gathered in groups so that they can be parallelized, i.e., turning
0: ─╭●─────────────────────┤  
1: ─│─────────╭●─╭●────────┤  
2: ─╰RY(0.10)─╰X─│─────────┤  
3: ──────────────╰RY(0.50)─┤ 
```
into 
```
0: ─╭●─────────────────────┤  
1: ─│─────────╭●────────╭●─┤  
2: ─╰RY(0.10)─│─────────╰X─┤  
3: ───────────╰RY(0.50)────┤  ```

Further it would be nice if the transforms would get a dedicated page in the documentation. Currently they are a bit hidden as a subsection of the API part.

@CatalinaAlbornoz
Copy link
Contributor

Hi @cvjjm , you raise some very good points. Thank you very much for these suggestions. Would any of the things in the wish list have higher priority for you than the others?

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

5 participants