WireError When Building Circuit w/ QAOA Layer

Hello! I’m trying to apply QAOA on my circuit by combining my circuit with a QAOA layer, and then applying cut_circuit. I have hit a WireError every single time, with the message saying that wires 16-36 aren’t found on the device, when I only need wire indexes from 0-15. I’ve restarted the kernel multiple times. The following is my code from my Jupyter Notebook.

import sys, pathlib, importlib
import pennylane as qml, torch
from pennylane import numpy as np

# double checking versions
print("Python executable:", sys.executable)
print("Python version   :", sys.version.split()[0])
print("PennyLane        :", qml.__version__)
print("Torch            :", torch.__version__)
from pennylane.qcut import cut_circuit
PROJECT_ROOT = pathlib.Path.cwd().resolve().parent.parent
SRC = PROJECT_ROOT / "src"
if str(SRC) not in sys.path:
    sys.path.append(str(SRC))

import circuit.quantum_galton_board as qgb
importlib.reload(qgb)

#build circuit

levels = 8
board_core = qgb.galton_template(levels, bias=0.3, coherence=True)

#QAOA layer on wires 8-15 to cut the circuit smaller

data_wires = list(range(levels, 2*levels))
def maxcut_H(ws):
    H = qml.Hamiltonian([], [])
    for i in range(len(ws)):
        for j in range(i+1, len(ws)):
            H += 0.5*(qml.Identity(0) - qml.PauliZ(ws[i]) @ qml.PauliZ(ws[j]))
    return H
cost_H = maxcut_H(data_wires)

gamma = np.array(0.8, requires_grad=True)
beta  = np.array(0.4, requires_grad=True)
def qaoa_layer():
    qml.templates.ApproxTimeEvolution(cost_H, gamma, 1)
    for w in data_wires:
        qml.RX(2*beta, wires=w)

#so now we build a new circuit with the qaoa layer

dev = qml.device("lightning.qubit", wires=2*levels, config={})

@qml.qnode(dev)
def full_circuit():
    board_core()          # queues directly on the SAME tape, wires 0..15
    qaoa_layer()
    return qml.expval(cost_H)

tape = full_circuit.construct([], {})
inner_func = full_circuit.func           # original Python function
closure    = inner_func.__closure__

#debug
offenders = [op for op in tape.operations if any(w >= 16 for w in op.wires)]
print("number of offending ops:", len(offenders))
for op in offenders[:5]:                       # print a few examples
    print(op, "   wires =", list(op.wires))

if closure is None:
    print("full_circuit has nothing.")
else:
    captured = closure[0].cell_contents
    print("captured object type:", type(captured))
    print("captured repr     :", captured)

print("Full ⟨H⟩:", full_circuit())   # outputs circuit with board_circuit + QAOA layer

This is the output along with the error message.

number of offending ops: 0
full_circuit has nothing.

---------------------------------------------------------------------------
WireError                                 Traceback (most recent call last)
Cell In[15], line 27
     24     print("captured object type:", type(captured))
     25     print("captured repr     :", captured)
---> 27 print("Full ⟨H⟩:", full_circuit()) 

File c:\Users\13174\Documents\GaltonBoard\.pixi\envs\default\Lib\site-packages\pennylane\workflow\qnode.py:922, in QNode.__call__(self, *args, **kwargs)
    919     from ._capture_qnode import capture_qnode  # pylint: disable=import-outside-toplevel
    921     return capture_qnode(self, *args, **kwargs)
--> 922 return self._impl_call(*args, **kwargs)

File c:\Users\13174\Documents\GaltonBoard\.pixi\envs\default\Lib\site-packages\pennylane\workflow\qnode.py:895, in QNode._impl_call(self, *args, **kwargs)
    892 # Calculate the classical jacobians if necessary
    893 self._transform_program.set_classical_component(self, args, kwargs)
--> 895 res = execute(
    896     (tape,),
    897     device=self.device,
    898     diff_method=self.diff_method,
    899     interface=self.interface,
    900     transform_program=self._transform_program,
    901     gradient_kwargs=self.gradient_kwargs,
    902     **self.execute_kwargs,
    903 )
    904 res = res[0]
    906 # convert result to the interface in case the qfunc has no parameters

File c:\Users\13174\Documents\GaltonBoard\.pixi\envs\default\Lib\site-packages\pennylane\workflow\execution.py:233, in execute(tapes, device, diff_method, interface, grad_on_execution, cache, cachesize, max_diff, device_vjp, postselect_mode, mcm_method, gradient_kwargs, transform_program, executor_backend)
    229 tapes, outer_post_processing = outer_transform(tapes)
    231 assert not outer_transform.is_informative, "should only contain device preprocessing"
--> 233 results = run(tapes, device, config, inner_transform)
    234 return user_post_processing(outer_post_processing(results))

File c:\Users\13174\Documents\GaltonBoard\.pixi\envs\default\Lib\site-packages\pennylane\workflow\run.py:338, in run(tapes, device, config, inner_transform_program)
    335         params = tape.get_parameters(trainable_only=False)
    336         tape.trainable_params = qml.math.get_trainable_indices(params)
--> 338 results = ml_execute(tapes, execute_fn, jpc, device=device)
    339 return results

File c:\Users\13174\Documents\GaltonBoard\.pixi\envs\default\Lib\site-packages\pennylane\workflow\interfaces\autograd.py:147, in autograd_execute(tapes, execute_fn, jpc, device)
    142 # TODO: Remove when PL supports pylint==3.3.6 (it is considered a useless-suppression) [sc-91362]
    143 # pylint: disable=no-member
    144 parameters = autograd.builtins.tuple(
    145     [autograd.builtins.list(t.get_parameters()) for t in tapes]
    146 )
--> 147 return _execute(parameters, tuple(tapes), execute_fn, jpc)

File c:\Users\13174\Documents\GaltonBoard\.pixi\envs\default\Lib\site-packages\autograd\tracer.py:54, in primitive.<locals>.f_wrapped(*args, **kwargs)
     52     return new_box(ans, trace, node)
     53 else:
---> 54     return f_raw(*args, **kwargs)

File c:\Users\13174\Documents\GaltonBoard\.pixi\envs\default\Lib\site-packages\pennylane\workflow\interfaces\autograd.py:184, in _execute(parameters, tapes, execute_fn, jpc)
    166 @autograd.extend.primitive
    167 def _execute(
    168     parameters,
   (...)
    171     jpc,
    172 ):
    173     """Autodifferentiable wrapper around a way of executing tapes.
    174 
    175     Args:
   (...)
    182 
    183     """
--> 184     return _to_autograd(execute_fn(tapes))

File c:\Users\13174\Documents\GaltonBoard\.pixi\envs\default\Lib\site-packages\pennylane\workflow\run.py:253, in _make_inner_execute.<locals>.inner_execute(tapes)
    244 def inner_execute(tapes: QuantumScriptBatch) -> ResultBatch:
    245     """Execution that occurs within a ML framework boundary.
    246 
    247     Closure Variables:
   (...)
    250         device (qml.devices.Device): a Pennylane device
    251     """
--> 253     transformed_tapes, transform_post_processing = inner_transform(tapes)
    255     if transformed_tapes:
    256         results = device.execute(transformed_tapes, execution_config=execution_config)

File c:\Users\13174\Documents\GaltonBoard\.pixi\envs\default\Lib\site-packages\pennylane\transforms\core\transform_program.py:501, in TransformProgram.__call__(self, *args, **kwargs)
    499 if type(args[0]).__name__ == "Jaxpr":
    500     return self.__call_jaxpr(*args, **kwargs)
--> 501 return self.__call_tapes(*args, **kwargs)

File c:\Users\13174\Documents\GaltonBoard\.pixi\envs\default\Lib\site-packages\pennylane\transforms\core\transform_program.py:431, in TransformProgram.__call_tapes(self, tapes)
    428 if argnums is not None:
    429     # pylint: disable=unsubscriptable-object
    430     tape.trainable_params = argnums[tape_idx]
--> 431 new_tapes, fn = transform(tape, *targs, **tkwargs)
    432 execution_tapes.extend(new_tapes)
    434 fns.append(fn)

File c:\Users\13174\Documents\GaltonBoard\.pixi\envs\default\Lib\site-packages\pennylane\devices\preprocess.py:150, in validate_device_wires(tape, wires, name)
    144     raise WireError(
    145         f"Cannot run circuit(s) on {name} as abstract wires are present in the device: {wires}. "
    146         f"Abstract wires are not yet supported."
    147     )
    149 if extra_wires := set(tape.wires) - set(wires):
--> 150     raise WireError(
    151         f"Cannot run circuit(s) on {name} as they contain wires "
    152         f"not found on the device: {extra_wires}"
    153     )
    155 modified = False
    156 new_ops = None

WireError: Cannot run circuit(s) on lightning.qubit as they contain wires not found on the device: {16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36}

And here are the versions of my packages.

Name: pennylane 
Version: 0.42.1 
Summary: PennyLane is a cross-platform Python library for quantum computing, quantum machine learning, and quantum chemistry. Train a quantum computer the same way as a neural network. 
Home-page:  
Author:  
Author-email:  
License-Expression: Apache-2.0 
Location: [c:\Users\13174\Documents\GaltonBoard\.pixi\envs\default\Lib\site-packages](file:///C:/Users/13174/Documents/GaltonBoard/.pixi/envs/default/Lib/site-packages) 
Requires: appdirs, autograd, autoray, cachetools, diastatic-malt, networkx, numpy, packaging, pennylane-lightning, requests, rustworkx, scipy, tomlkit, typing_extensions 
Required-by: GaltonBoard, PennyLane-qiskit, pennylane_lightning  
Platform info:           Windows-11-10.0.26100-SP0 
Python version:          3.12.11 
Numpy version:           2.3.2 
Scipy version:           1.16.1 
Installed devices: - default.clifford (pennylane-0.42.1) - default.gaussian (pennylane-0.42.1) - default.mixed (pennylane-0.42.1) - default.qubit (pennylane-0.42.1) - default.qutrit (pennylane-0.42.1)- qiskit.aer (PennyLane-qiskit-0.42.0) - qiskit.basicaer (PennyLane-qiskit-0.42.0) - qiskit.basicsim (PennyLane-qiskit-0.42.0) - qiskit.remote (PennyLane-qiskit-0.42.0)

Hi @elijiang , welcome to the Forum!

Note that you have set levels = 8 and the qubits in your device as wires=2*levels, so your qubits/wires available in your device are {0, 1, 2, ..., 15}.

What the error is telling you is that you’re using more qubits (16-36).

I can’t replicate your error since the error is coming from board_core, which comes from qgb, which you haven’t shared.
My recommendation would be to look at the code you have there and ensure that you’re only using the qubits that you have in the device.

Note that 36 qubits is very large. Unless you have a very specific architecture and smart techniques you won’t be able to simulate this.

I hope this helps!