Proper way to change operations in fully constructed qnode/tape

Hi, I’m working on a project for quantum computer synthesis with ES and look for an efficient way to specifically exchange operation on different wires and different places. I looked through the docs and have some ideas how it could work, but they feel like I miss a crucial part to make it elegant. Is there a trivial way I missed doing such a transformation of operators, or do I have to glue something together till it works ?

Also, I’m thinking about changing from generator random qnodes to instantly generating random tapes to save some unneeded code. Is there a direct answer if you can do everything with tape what would be possible in qnodes or are there clear limitations why it would be a bad idea. I can solve this answers myself, but it doesn’t hurt asking if there is a clear answer to this :slight_smile:
Here is the current generator

import pennylane as qml
from pennylane import numpy as np
from pennylane.ops import CNOT


def random_qnode(num_wires, gate_set, min_depth, max_depth):
    # Create a quantum device with the specified number of wires
    dev = qml.device("default.qubit", wires=num_wires)

    # Define a quantum circuit using the PennyLane QNode decorator
    @qml.simplify
    @qml.qnode(dev)
    def circuit():
        # Randomly choose the depth of the quantum circuit
        depth = np.random.randint(min_depth, max_depth + 1)

        # Iterate over the chosen depth
        for _ in range(depth):
            # Iterate over each wire in the quantum device
            for wire in range(num_wires):
                # Randomly choose a gate from the specified gate_set
                gate_class = np.random.choice(gate_set)

                # Special case if CNOT gate is chosen
                if gate_class is CNOT:
                    # Get a list of all wires and remove the control wire
                    possible_target_wire = list(range(num_wires))
                    possible_target_wire.remove(wire)

                    # Randomly choose a target wire from the remaining wires
                    target_wire = np.random.choice(possible_target_wire)

                    # Apply CNOT gate to the chosen wire pair
                    CNOT([wire, target_wire])
                else:
                    # Apply the chosen gate to a single wire
                    gate_class(wire)

        # Return a list of expected values of PauliZ for each wire
        return qml.state()

    # Return the constructed quantum circuit
    return circuit

Here is the function which would change operations, still work in progress:

import pennylane as qml
import random
from pennylane import numpy as np


def mutation(m_qnode:qml.qnode, mutation_cap = 1):
    gates_applied = m_qnode.qtape.operations

    m_amount_nbr = random.choice(range(len(gates_applied)-mutation_cap))
    m_rows = []
    m_possible_rows = list(range(len(gates_applied)))

    for i in range(m_amount_nbr):
        rdm_possible_row = random.choice(m_possible_rows)
        m_possible_rows.remove(rdm_possible_row)

        wires = len(m_qnode.qtape.op_wires())

        #TODO code to exchange differnet parts of the given circuit

And, finally, make sure to include the versions of your packages. Specifically, show us the output of qml.about().
Name: PennyLane
Version: 0.33.0
Summary: PennyLane is a Python quantum machine learning library by Xanadu Inc.
Home-page: GitHub - PennyLaneAI/pennylane: PennyLane is a cross-platform Python library for differentiable programming of quantum computers. Train a quantum computer the same way as a neural network.
Author:
Author-email:
License: Apache License 2.0
Location: c:\users\tombi\pycharmprojects\venv\lib\site-packages
Requires: appdirs, autograd, autoray, cachetools, networkx, numpy, pennylane-lightning, requests, rustworkx, scipy, semantic-version, toml, typing-extensions
Required-by: PennyLane-Lightning

Platform info: Windows-10-10.0.22621-SP0
Python version: 3.9.13
Numpy version: 1.26.1
Scipy version: 1.11.3
Installed devices:

  • default.gaussian (PennyLane-0.33.0)
  • default.mixed (PennyLane-0.33.0)
  • default.qubit (PennyLane-0.33.0)
  • default.qubit.autograd (PennyLane-0.33.0)
  • default.qubit.jax (PennyLane-0.33.0)
  • default.qubit.legacy (PennyLane-0.33.0)
  • default.qubit.tf (PennyLane-0.33.0)
  • default.qubit.torch (PennyLane-0.33.0)
  • default.qutrit (PennyLane-0.33.0)
  • null.qubit (PennyLane-0.33.0)
  • lightning.qubit (PennyLane-Lightning-0.33.1)

Process finished with exit code 0

Hey @Cap_Cap,

I’m not sure I 100% understand what you’re trying to do, but maybe check out transpilation: qml.transforms.transpile — PennyLane 0.34.0 documentation. You can transform circuits according to a desired coupling map between qubits. If that’s not what you’re trying to do, let me know!