Pennylane --> IBMQ conversion error

Hi, I tried running the code from this video. When I tried to run it on a IBM device it gave me an error. The error seems to be because of the controlled Z gate that the program uses. It works fine on the pennylane simulator but when I try to use the qiskit one it breaks. Could use some help debugging.

# Put code here

import pennylane as qml
from pennylane import numpy as np

property_prices = [4, 8, 6, 3, 12, 15] # total 48 
variables_wires = [0, 1, 2, 3, 4, 5]

aux_oracle_wires = [6, 7, 8 ,9 ,10, 11]

def oracle(variables_wires, aux_oracle_wires):
    
    def add_k_fourier(k, wires):
        for j in range(len(wires)):
            qml.RZ(k * np.pi / (2**j), wires=wires[j])
            
    def value_second_sibling():
        
        qml.QFT(wires = aux_oracle_wires)
        
        for wire in variables_wires:
            qml.ctrl(add_k_fourier, control = wire)(property_prices[wire], wires = aux_oracle_wires)
            
        qml.adjoint(qml.QFT)(wires = aux_oracle_wires)
        
    value_second_sibling()
    qml.FlipSign(sum(property_prices) // 2, wires = aux_oracle_wires)
    qml.adjoint(value_second_sibling)()

dev = qml.device('qiskit.ibmq', wires=12, backend='ibmq_qasm_simulator')

@qml.qnode(dev)
def circuit():
    
    # step 1
    for wire in variables_wires:
        qml.Hadamard(wires = wire)
       
    # step 2
    oracle(variables_wires, aux_oracle_wires)
    
    # step 3
    qml.GroverOperator(wires = variables_wires)
    
    return qml.probs(wires = variables_wires)


import matplotlib.pyplot as plt

values = circuit()
plt.bar(range(len(values)), values)

If you want help with diagnosing an error, please put the full error message below:

# Put full error message here

---------------------------------------------------------------------------
KeyError                                  Traceback (most recent call last)
Cell In[5], line 3
      1 import matplotlib.pyplot as plt
----> 3 values = circuit()
      4 plt.bar(range(len(values)), values)

File ~\anaconda3\Lib\site-packages\pennylane\qnode.py:989, in QNode.__call__(self, *args, **kwargs)
    986     self.execute_kwargs.pop("mode")
    988 # pylint: disable=unexpected-keyword-arg
--> 989 res = qml.execute(
    990     (self._tape,),
    991     device=self.device,
    992     gradient_fn=self.gradient_fn,
    993     interface=self.interface,
    994     transform_program=self.transform_program,
    995     gradient_kwargs=self.gradient_kwargs,
    996     override_shots=override_shots,
    997     **self.execute_kwargs,
    998 )
   1000 res = res[0]
   1002 # convert result to the interface in case the qfunc has no parameters

File ~\anaconda3\Lib\site-packages\pennylane\interfaces\execution.py:757, in execute(tapes, device, gradient_fn, interface, transform_program, grad_on_execution, gradient_kwargs, cache, cachesize, max_diff, override_shots, expand_fn, max_expansion, device_batch_transform)
    754     raise ValueError("Gradient transforms cannot be used with grad_on_execution=True")
    756 ml_boundary_execute = _get_ml_boundary_execute(interface, _grad_on_execution)
--> 757 results = ml_boundary_execute(
    758     tapes, device, execute_fn, gradient_fn, gradient_kwargs, _n=1, max_diff=max_diff
    759 )
    761 results = batch_fn(results)
    762 return program_post_processing(results)

File ~\anaconda3\Lib\site-packages\pennylane\interfaces\autograd.py:317, in execute(tapes, device, execute_fn, gradient_fn, gradient_kwargs, _n, max_diff)
    312 # pylint misidentifies autograd.builtins as a dict
    313 # pylint: disable=no-member
    314 parameters = autograd.builtins.tuple(
    315     [autograd.builtins.list(t.get_parameters()) for t in tapes]
    316 )
--> 317 return _execute(
    318     parameters,
    319     tapes=tapes,
    320     device=device,
    321     execute_fn=execute_fn,
    322     gradient_fn=gradient_fn,
    323     gradient_kwargs=gradient_kwargs,
    324     _n=_n,
    325     max_diff=max_diff,
    326 )[0]

File ~\anaconda3\Lib\site-packages\autograd\tracer.py:48, in primitive.<locals>.f_wrapped(*args, **kwargs)
     46     return new_box(ans, trace, node)
     47 else:
---> 48     return f_raw(*args, **kwargs)

File ~\anaconda3\Lib\site-packages\pennylane\interfaces\autograd.py:378, in _execute(parameters, tapes, device, execute_fn, gradient_fn, gradient_kwargs, _n, max_diff)
    360 if logger.isEnabledFor(logging.DEBUG):
    361     logger.debug(
    362         "Entry with args=(parameters=%s, tapes=%s, device=%s, execute_fn=%s, gradient_fn=%s, gradient_kwargs=%s, _n=%s, max_diff=%s) called by=%s",
    363         parameters,
   (...)
    375         "::L".join(str(i) for i in inspect.getouterframes(inspect.currentframe(), 2)[1][1:3]),
    376     )
--> 378 res, jacs = execute_fn(tapes, **gradient_kwargs)
    380 return res, jacs

File ~\anaconda3\Lib\site-packages\pennylane\interfaces\execution.py:623, in execute.<locals>.inner_execute_with_empty_jac(tapes, **_)
    622 def inner_execute_with_empty_jac(tapes, **_):
--> 623     return (inner_execute(tapes), [])

File ~\anaconda3\Lib\site-packages\pennylane\interfaces\execution.py:255, in _make_inner_execute.<locals>.inner_execute(tapes, **_)
    253 if numpy_only:
    254     tapes = tuple(qml.transforms.convert_to_numpy_parameters(t) for t in tapes)
--> 255 return cached_device_execution(tapes)

File ~\anaconda3\Lib\site-packages\pennylane\interfaces\execution.py:377, in cache_execute.<locals>.wrapper(tapes, **kwargs)
    372         return (res, []) if return_tuple else res
    374 else:
    375     # execute all unique tapes that do not exist in the cache
    376     # convert to list as new device interface returns a tuple
--> 377     res = list(fn(tuple(execution_tapes.values()), **kwargs))
    379 final_res = []
    381 for i, tape in enumerate(tapes):

File ~\anaconda3\Lib\contextlib.py:81, in ContextDecorator.__call__.<locals>.inner(*args, **kwds)
     78 @wraps(func)
     79 def inner(*args, **kwds):
     80     with self._recreate_cm():
---> 81         return func(*args, **kwds)

File ~\anaconda3\Lib\site-packages\pennylane_qiskit\ibmq.py:91, in IBMQDevice.batch_execute(self, circuits)
     90 def batch_execute(self, circuits):  # pragma: no cover, pylint:disable=arguments-differ
---> 91     res = super().batch_execute(circuits, timeout=self.timeout_secs)
     92     if self.tracker.active:
     93         self._track_run()

File ~\anaconda3\Lib\site-packages\pennylane_qiskit\qiskit_device.py:473, in QiskitDevice.batch_execute(self, circuits, timeout)
    470 def batch_execute(self, circuits, timeout: int = None):
    471     # pylint: disable=missing-function-docstring
--> 473     compiled_circuits = self.compile_circuits(circuits)
    475     # Send the batch of circuit objects using backend.run
    476     self._current_job = self.backend.run(compiled_circuits, shots=self.shots, **self.run_args)

File ~\anaconda3\Lib\site-packages\pennylane_qiskit\qiskit_device.py:462, in QiskitDevice.compile_circuits(self, circuits)
    458 for circuit in circuits:
    459     # We need to reset the device here, else it will
    460     # not start the next computation in the zero state
    461     self.reset()
--> 462     self.create_circuit_object(circuit.operations, rotations=circuit.diagonalizing_gates)
    464     compiled_circ = self.compile()
    465     compiled_circ.name = f"circ{len(compiled_circuits)}"

File ~\anaconda3\Lib\site-packages\pennylane_qiskit\qiskit_device.py:273, in QiskitDevice.create_circuit_object(self, operations, **kwargs)
    261 """Builds the circuit objects based on the operations and measurements
    262 specified to apply.
    263 
   (...)
    269         pre-measurement into the eigenbasis of the observables.
    270 """
    271 rotations = kwargs.get("rotations", [])
--> 273 applied_operations = self.apply_operations(operations)
    275 # Rotating the state for measurement in the computational basis
    276 rotation_circuits = self.apply_operations(rotations)

File ~\anaconda3\Lib\site-packages\pennylane_qiskit\qiskit_device.py:322, in QiskitDevice.apply_operations(self, operations)
    318         par[idx] = p.tolist()
    320 operation = operation.name
--> 322 mapped_operation = self._operation_map[operation]
    324 self.qubit_state_vector_check(operation)
    326 qregs = [self._reg[i] for i in device_wires.labels]

KeyError: 'C(RZ)'

And, finally, make sure to include the versions of your packages. Specifically, show us the output of qml.about().

Name: PennyLane
Version: 0.32.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\Carter\anaconda3\Lib\site-packages
Requires: appdirs, autograd, autoray, cachetools, networkx, numpy, pennylane-lightning, requests, rustworkx, scipy, semantic-version, toml, typing-extensions
Required-by: PennyLane-Lightning, PennyLane-qiskit

Platform info: Windows-10-10.0.22621-SP0
Python version: 3.11.5
Numpy version: 1.23.5
Scipy version: 1.11.1
Installed devices:

  • default.gaussian (PennyLane-0.32.0)
  • default.mixed (PennyLane-0.32.0)
  • default.qubit (PennyLane-0.32.0)
  • default.qubit.autograd (PennyLane-0.32.0)
  • default.qubit.jax (PennyLane-0.32.0)
  • default.qubit.tf (PennyLane-0.32.0)
  • default.qubit.torch (PennyLane-0.32.0)
  • default.qutrit (PennyLane-0.32.0)
  • null.qubit (PennyLane-0.32.0)
  • lightning.qubit (PennyLane-Lightning-0.32.0)
  • qiskit.aer (PennyLane-qiskit-0.32.0)
  • qiskit.basicaer (PennyLane-qiskit-0.32.0)
  • qiskit.ibmq (PennyLane-qiskit-0.32.0)
  • qiskit.ibmq.circuit_runner (PennyLane-qiskit-0.32.0)
  • qiskit.ibmq.sampler (PennyLane-qiskit-0.32.0)
  • qiskit.remote (PennyLane-qiskit-0.32.0)

Hey @shrug001! Welcome to the forum and thanks for watching our video :smiley:

Great question. The way operators get translated from PL to Qiskit is via a dictionary lookup given the operator’s name in PL (see here for the source code). The controlled RX gate has a different name in PennyLane depending on how you define it:

>>> op = qml.CRX(0.1, wires=[0, 1])
>>> op.name
'CRX'
>>> op = qml.ctrl(qml.RX(0.1, 0), control=[1])
>>> op.name
'C(RX)'

There is a mapping for when the name is CRX, but not for C(RX) :sweat_smile:.

So, looks like you found a bug! Do you mind making a bug report on the PennyLane github?

1 Like

The bug report has been filed. Thank you very much for your help.

1 Like

When I changed the code to this:
aux_oracle_wires = [6, 7, 8 ,9 ,10, 11]

def oracle(variables_wires, aux_oracle_wires):

def add_k_fourier(k, wires,wires2, num):
    for j in range(len(wires)):
        qml.CRZ(k * np.pi / (2**j), wires=[wires2[num],wires[j]])
        
def value_second_sibling():
    
    qml.QFT(wires = aux_oracle_wires)
    
    for i in range(len(variables_wires)):
        add_k_fourier(property_prices[i],aux_oracle_wires, variables_wires, i)
        
    qml.adjoint(qml.QFT)(wires = aux_oracle_wires)
    
value_second_sibling()
qml.FlipSign(sum(property_prices) // 2, wires = aux_oracle_wires)
qml.adjoint(value_second_sibling)()

It gives me the same error even though I am not using the qml.ctrl function anymore:

KeyError Traceback (most recent call last)
Cell In[8], line 3
1 import matplotlib.pyplot as plt
----> 3 values = circuit()
4 plt.bar(range(len(values)), values)

File ~\anaconda3\Lib\site-packages\pennylane\qnode.py:989, in QNode.call(self, *args, **kwargs)
986 self.execute_kwargs.pop(“mode”)
988 # pylint: disable=unexpected-keyword-arg
→ 989 res = qml.execute(
990 (self._tape,),
991 device=self.device,
992 gradient_fn=self.gradient_fn,
993 interface=self.interface,
994 transform_program=self.transform_program,
995 gradient_kwargs=self.gradient_kwargs,
996 override_shots=override_shots,
997 **self.execute_kwargs,
998 )
1000 res = res[0]
1002 # convert result to the interface in case the qfunc has no parameters

File ~\anaconda3\Lib\site-packages\pennylane\interfaces\execution.py:757, in execute(tapes, device, gradient_fn, interface, transform_program, grad_on_execution, gradient_kwargs, cache, cachesize, max_diff, override_shots, expand_fn, max_expansion, device_batch_transform)
754 raise ValueError(“Gradient transforms cannot be used with grad_on_execution=True”)
756 ml_boundary_execute = _get_ml_boundary_execute(interface, _grad_on_execution)
→ 757 results = ml_boundary_execute(
758 tapes, device, execute_fn, gradient_fn, gradient_kwargs, _n=1, max_diff=max_diff
759 )
761 results = batch_fn(results)
762 return program_post_processing(results)

File ~\anaconda3\Lib\site-packages\pennylane\interfaces\autograd.py:317, in execute(tapes, device, execute_fn, gradient_fn, gradient_kwargs, _n, max_diff)
312 # pylint misidentifies autograd.builtins as a dict
313 # pylint: disable=no-member
314 parameters = autograd.builtins.tuple(
315 [autograd.builtins.list(t.get_parameters()) for t in tapes]
316 )
→ 317 return _execute(
318 parameters,
319 tapes=tapes,
320 device=device,
321 execute_fn=execute_fn,
322 gradient_fn=gradient_fn,
323 gradient_kwargs=gradient_kwargs,
324 _n=_n,
325 max_diff=max_diff,
326 )[0]

File ~\anaconda3\Lib\site-packages\autograd\tracer.py:48, in primitive..f_wrapped(*args, **kwargs)
46 return new_box(ans, trace, node)
47 else:
—> 48 return f_raw(*args, **kwargs)

File ~\anaconda3\Lib\site-packages\pennylane\interfaces\autograd.py:378, in _execute(parameters, tapes, device, execute_fn, gradient_fn, gradient_kwargs, _n, max_diff)
360 if logger.isEnabledFor(logging.DEBUG):
361 logger.debug(
362 “Entry with args=(parameters=%s, tapes=%s, device=%s, execute_fn=%s, gradient_fn=%s, gradient_kwargs=%s, _n=%s, max_diff=%s) called by=%s”,
363 parameters,
(…)
375 “::L”.join(str(i) for i in inspect.getouterframes(inspect.currentframe(), 2)[1][1:3]),
376 )
→ 378 res, jacs = execute_fn(tapes, **gradient_kwargs)
380 return res, jacs

File ~\anaconda3\Lib\site-packages\pennylane\interfaces\execution.py:623, in execute..inner_execute_with_empty_jac(tapes, **)
622 def inner_execute_with_empty_jac(tapes, **
):
→ 623 return (inner_execute(tapes), )

File ~\anaconda3\Lib\site-packages\pennylane\interfaces\execution.py:255, in make_inner_execute..inner_execute(tapes, **)
253 if numpy_only:
254 tapes = tuple(qml.transforms.convert_to_numpy_parameters(t) for t in tapes)
→ 255 return cached_device_execution(tapes)

File ~\anaconda3\Lib\site-packages\pennylane\interfaces\execution.py:377, in cache_execute..wrapper(tapes, **kwargs)
372 return (res, ) if return_tuple else res
374 else:
375 # execute all unique tapes that do not exist in the cache
376 # convert to list as new device interface returns a tuple
→ 377 res = list(fn(tuple(execution_tapes.values()), **kwargs))
379 final_res =
381 for i, tape in enumerate(tapes):

File ~\anaconda3\Lib\contextlib.py:81, in ContextDecorator.call..inner(*args, **kwds)
78 @wraps(func)
79 def inner(*args, **kwds):
80 with self._recreate_cm():
—> 81 return func(*args, **kwds)

File ~\anaconda3\Lib\site-packages\pennylane_qiskit\ibmq.py:91, in IBMQDevice.batch_execute(self, circuits)
90 def batch_execute(self, circuits): # pragma: no cover, pylint:disable=arguments-differ
—> 91 res = super().batch_execute(circuits, timeout=self.timeout_secs)
92 if self.tracker.active:
93 self._track_run()

File ~\anaconda3\Lib\site-packages\pennylane_qiskit\qiskit_device.py:473, in QiskitDevice.batch_execute(self, circuits, timeout)
470 def batch_execute(self, circuits, timeout: int = None):
471 # pylint: disable=missing-function-docstring
→ 473 compiled_circuits = self.compile_circuits(circuits)
475 # Send the batch of circuit objects using backend.run
476 self._current_job = self.backend.run(compiled_circuits, shots=self.shots, **self.run_args)

File ~\anaconda3\Lib\site-packages\pennylane_qiskit\qiskit_device.py:462, in QiskitDevice.compile_circuits(self, circuits)
458 for circuit in circuits:
459 # We need to reset the device here, else it will
460 # not start the next computation in the zero state
461 self.reset()
→ 462 self.create_circuit_object(circuit.operations, rotations=circuit.diagonalizing_gates)
464 compiled_circ = self.compile()
465 compiled_circ.name = f"circ{len(compiled_circuits)}"

File ~\anaconda3\Lib\site-packages\pennylane_qiskit\qiskit_device.py:273, in QiskitDevice.create_circuit_object(self, operations, **kwargs)
261 “”“Builds the circuit objects based on the operations and measurements
262 specified to apply.
263
(…)
269 pre-measurement into the eigenbasis of the observables.
270 “””
271 rotations = kwargs.get(“rotations”, )
→ 273 applied_operations = self.apply_operations(operations)
275 # Rotating the state for measurement in the computational basis
276 rotation_circuits = self.apply_operations(rotations)

File ~\anaconda3\Lib\site-packages\pennylane_qiskit\qiskit_device.py:322, in QiskitDevice.apply_operations(self, operations)
318 par[idx] = p.tolist()
320 operation = operation.name
→ 322 mapped_operation = self._operation_map[operation]
324 self.qubit_state_vector_check(operation)
326 qregs = [self._reg[i] for i in device_wires.labels]

KeyError: ‘C(RZ)’

Hey @shrug001! Thanks for making the bug report :slight_smile:

The issue still persisting probably means that another operator here is being decomposed into a problematic one (one that uses qml.ctrl somewhere) on the qasm simulator. I can’t see any operator in your updated code that decomposes into a CRZ operator when using default.qubit (i.e., not the qasm device).

Let me see what I can find out though. In the meantime, do you need to run this on the qasm simulator, or can you use a native PL simulator?

I can run this on a pennylane simulator. I just want this to be able to run on an actual quantum computer so I am testing with qiskit before I actually send a real job. It’s not urgent or anything though.

@shrug001 can you try doing this to avoid anything being decomposed into a controlled rotation gate?

@qml.qnode(dev)
@qml.compile(basis_set=["CNOT", "RZ", "RX", "RY"])
def circuit():
    
    # step 1
    for wire in variables_wires:
        qml.Hadamard(wires = wire)
       
    # step 2
    oracle(variables_wires, aux_oracle_wires)
    
    # step 3
    qml.GroverOperator(wires = variables_wires)
    
    return qml.probs(wires = variables_wires)

Let me know if this helps!

I get this error


IndexError Traceback (most recent call last)
File ~\anaconda3\Lib\site-packages\pennylane\operation.py:1032, in Operator.init(self, wires, id, *params)
1031 try:
→ 1032 wires = params[-1]
1033 params = params[:-1]

IndexError: tuple index out of range

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

ValueError Traceback (most recent call last)
Cell In[4], line 3
1 import matplotlib.pyplot as plt
----> 3 values = circuit()
4 plt.bar(range(len(values)), values)

File ~\anaconda3\Lib\site-packages\pennylane\qnode.py:974, in QNode.call(self, *args, **kwargs)
971 kwargs[“shots”] = _get_device_shots(self._original_device)
973 # construct the tape
→ 974 self.construct(args, kwargs)
976 cache = self.execute_kwargs.get(“cache”, False)
977 using_custom_cache = (
978 hasattr(cache, “getitem”)
979 and hasattr(cache, “setitem”)
980 and hasattr(cache, “delitem”)
981 )

File ~\anaconda3\Lib\site-packages\pennylane\qnode.py:872, in QNode.construct(self, args, kwargs)
869 if old_interface == “auto”:
870 self.interface = qml.math.get_interface(*args, *list(kwargs.values()))
→ 872 self._tape = make_qscript(self.func, shots)(*args, **kwargs)
873 self._qfunc_output = self.tape._qfunc_output
875 params = self.tape.get_parameters(trainable_only=False)

File ~\anaconda3\Lib\site-packages\pennylane\tape\qscript.py:1531, in make_qscript..wrapper(*args, **kwargs)
1529 def wrapper(*args, **kwargs):
1530 with AnnotatedQueue() as q:
→ 1531 result = fn(*args, **kwargs)
1533 qscript = QuantumScript.from_queue(q, shots)
1534 qscript._qfunc_output = result

File ~\anaconda3\Lib\site-packages\pennylane\transforms\qfunc_transforms.py:181, in _create_qfunc_internal_wrapper..internal_wrapper(*args, **kwargs)
178 @functools.wraps(fn)
179 def internal_wrapper(*args, **kwargs):
180 tape = make_qscript(fn)(*args, **kwargs)
→ 181 tape = tape_transform(tape, *transform_args, **transform_kwargs)
183 num_measurements = len(tape.measurements)
184 if num_measurements == 0:

File ~\anaconda3\Lib\site-packages\pennylane\transforms\qfunc_transforms.py:147, in single_tape_transform.call(self, tape, *args, **kwargs)
145 def call(self, tape, *args, **kwargs):
146 with qml.queuing.AnnotatedQueue() as q:
→ 147 self.transform_fn(tape, *args, **kwargs)
148 qs = qml.tape.QuantumScript.from_queue(q, shots=tape.shots)
149 for obj, info in q.items():

File ~\anaconda3\Lib\site-packages\pennylane\transforms\compile.py:158, in compile(tape, pipeline, basis_set, num_passes, expand_depth)
156 with QueuingManager.stop_recording():
157 if basis_set is not None:
→ 158 expanded_tape = tape.expand(
159 depth=expand_depth, stop_at=lambda obj: obj.name in basis_set
160 )
161 else:
162 # Expands out anything that is not a single operation (i.e., the templates)
163 # expand barriers when only_visual=True
164 def stop_at(obj):

File ~\anaconda3\Lib\site-packages\pennylane\tape\qscript.py:1234, in QuantumScript.expand(self, depth, stop_at, expand_measurements)
1189 def expand(self, depth=1, stop_at=None, expand_measurements=False):
1190 “”“Expand all operations to a specific depth.
1191
1192 Args:
(…)
1232 RY(0.2, wires=[‘a’])]
1233 “””
→ 1234 new_script = qml.tape.tape.expand_tape(
1235 self, depth=depth, stop_at=stop_at, expand_measurements=expand_measurements
1236 )
1237 new_script._update()
1238 return new_script

File ~\anaconda3\Lib\site-packages\pennylane\tape\tape.py:217, in expand_tape(tape, depth, stop_at, expand_measurements)
214 continue
216 # recursively expand out the newly created tape
→ 217 expanded_tape = expand_tape(obj, stop_at=stop_at, depth=depth - 1)
219 new_ops.extend(expanded_tape.operations)
220 new_measurements.extend(expanded_tape.measurements)

File ~\anaconda3\Lib\site-packages\pennylane\tape\tape.py:217, in expand_tape(tape, depth, stop_at, expand_measurements)
214 continue
216 # recursively expand out the newly created tape
→ 217 expanded_tape = expand_tape(obj, stop_at=stop_at, depth=depth - 1)
219 new_ops.extend(expanded_tape.operations)
220 new_measurements.extend(expanded_tape.measurements)

File ~\anaconda3\Lib\site-packages\pennylane\tape\tape.py:217, in expand_tape(tape, depth, stop_at, expand_measurements)
214 continue
216 # recursively expand out the newly created tape
→ 217 expanded_tape = expand_tape(obj, stop_at=stop_at, depth=depth - 1)
219 new_ops.extend(expanded_tape.operations)
220 new_measurements.extend(expanded_tape.measurements)

File ~\anaconda3\Lib\site-packages\pennylane\tape\tape.py:202, in expand_tape(tape, depth, stop_at, expand_measurements)
200 if obj.has_decomposition:
201 with QueuingManager.stop_recording():
→ 202 obj = QuantumScript(obj.decomposition(), _update=False)
203 else:
204 new_queue.append(obj)

File ~\anaconda3\Lib\site-packages\pennylane\operation.py:1257, in Operator.decomposition(self)
1245 def decomposition(self):
1246 r""“Representation of the operator as a product of other operators.
1247
1248 … math:: O = O_1 O_2 \dots O_n
(…)
1255 list[Operator]: decomposition of the operator
1256 “””
→ 1257 return self.compute_decomposition(
1258 *self.parameters, wires=self.wires, **self.hyperparameters
1259 )

File ~\anaconda3\Lib\site-packages\pennylane\ops\qubit\non_parametric_ops.py:1982, in Toffoli.compute_decomposition(wires)
1946 @staticmethod
1947 def compute_decomposition(wires):
1948 r""“Representation of the operator as a product of other operators (static method).
1949
1950 … math:: O = O_1 O_2 \dots O_n.
(…)
1979
1980 “””
1981 return [
→ 1982 Hadamard(wires=wires[2]),
1983 CNOT(wires=[wires[1], wires[2]]),
1984 qml.adjoint(T(wires=wires[2])),
1985 CNOT(wires=[wires[0], wires[2]]),
1986 T(wires=wires[2]),
1987 CNOT(wires=[wires[1], wires[2]]),
1988 qml.adjoint(T(wires=wires[2])),
1989 CNOT(wires=[wires[0], wires[2]]),
1990 T(wires=wires[2]),
1991 T(wires=wires[1]),
1992 CNOT(wires=[wires[0], wires[1]]),
1993 Hadamard(wires=wires[2]),
1994 T(wires=wires[0]),
1995 qml.adjoint(T(wires=wires[1])),
1996 CNOT(wires=[wires[0], wires[1]]),
1997 ]

File ~\anaconda3\Lib\site-packages\pennylane\operation.py:1764, in Operation.init(self, wires, id, *params)
1763 def init(self, *params, wires=None, id=None):
→ 1764 super().init(*params, wires=wires, id=id)
1766 # check the grad_recipe validity
1767 if self.grad_recipe is None:
1768 # Make sure grad_recipe is an iterable of correct length instead of None

File ~\anaconda3\Lib\site-packages\pennylane\operation.py:1036, in Operator.init(self, wires, id, *params)
1034 wires_from_args = True
1035 except IndexError as err:
→ 1036 raise ValueError(
1037 f"Must specify the wires that {type(self).name} acts on"
1038 ) from err
1040 self._num_params = len(params)
1042 # Check if the expected number of parameters coincides with the one received.
1043 # This is always true for the default Operator.num_params property, but
1044 # subclasses may overwrite it to define a fixed expected value.

ValueError: Must specify the wires that Hadamard acts on

Which is weird because I do specify the wires

@shrug001 can you attach the full code example that you’re currently working with that produces that error?

import pennylane as qml
from pennylane import numpy as np

property_prices = [4, 8, 6, 3, 12, 15] # total 48 
variables_wires = [0, 1, 2, 3, 4, 5]

aux_oracle_wires = [6, 7, 8 ,9 ,10, 11]

def oracle(variables_wires, aux_oracle_wires):
    
    def add_k_fourier(k, wires,wires2, num):
        for j in range(len(wires)):
            qml.CRZ(k * np.pi / (2**j), wires=[wires2[num],wires[j]])
            
    def value_second_sibling():
        
        qml.QFT(wires = aux_oracle_wires)
        
        for i in range(len(variables_wires)):
            add_k_fourier(property_prices[i],aux_oracle_wires, variables_wires, i)
            
        qml.adjoint(qml.QFT)(wires = aux_oracle_wires)
        
    value_second_sibling()
    qml.FlipSign(sum(property_prices) // 2, wires = aux_oracle_wires)
    qml.adjoint(value_second_sibling)()

dev = qml.device('qiskit.ibmq', wires=12, backend='ibmq_qasm_simulator')

@qml.qnode(dev)
@qml.compile(basis_set=["CNOT", "RZ", "RX", "RY"])
def circuit():
    
    # step 1
    for wire in variables_wires:
        qml.Hadamard(wires = wire)
       
    # step 2
    oracle(variables_wires, aux_oracle_wires)
    
    # step 3
    qml.GroverOperator(wires = variables_wires)
    
    return qml.probs(wires = variables_wires)


import matplotlib.pyplot as plt

values = circuit()
plt.bar(range(len(values)), values)import matplotlib.pyplot as plt

values = circuit()
plt.bar(range(len(values)), values)

ignore the second repeat of the code near the end

Hey @shrug001! Thanks. There seems to be some sort of issue here that’s caused with the choice of gate basis set and how GroverOperator gets decomposed as a result. Am looking into it!

Okay — looks like this issue has been solved here: Fix grover operator work wires by albi3ro · Pull Request #4668 · PennyLaneAI/pennylane · GitHub

To access the fix, you’ll need to install PennyLane from source:

>>> git clone https://github.com/PennyLaneAI/pennylane.git
>>> cd pennylane
>>> pip install -e .

Let me know if this helps!

Running the same code as before I now get:
C:\Users\Carter\anaconda3\Lib\site-packages\pennylane\transforms\core\transform_dispatcher.py:101: UserWarning: Decorating a QNode with @transform_fn(**transform_kwargs) has been deprecated and will be removed in a future version. Please decorate with @functools.partial(transform_fn, **transform_kwargs) instead, or call the transform directly using qnode = transform_fn(qnode, **transform_kwargs)
warnings.warn(

And the Error message:

ValueError                                Traceback (most recent call last)
Cell In[4], line 3
      1 import matplotlib.pyplot as plt
----> 3 values = circuit()
      4 plt.bar(range(len(values)), values)

File ~\anaconda3\Lib\site-packages\pennylane\qnode.py:957, in QNode.__call__(self, *args, **kwargs)
    954         kwargs["shots"] = _get_device_shots(self._original_device)
    956 # construct the tape
--> 957 self.construct(args, kwargs)
    959 cache = self.execute_kwargs.get("cache", False)
    960 using_custom_cache = (
    961     hasattr(cache, "__getitem__")
    962     and hasattr(cache, "__setitem__")
    963     and hasattr(cache, "__delitem__")
    964 )

File ~\anaconda3\Lib\site-packages\pennylane\qnode.py:847, in QNode.construct(self, args, kwargs)
    844     self.interface = qml.math.get_interface(*args, *list(kwargs.values()))
    846 with qml.queuing.AnnotatedQueue() as q:
--> 847     self._qfunc_output = self.func(*args, **kwargs)
    849 self._tape = QuantumScript.from_queue(q, shots)
    851 params = self.tape.get_parameters(trainable_only=False)

File ~\anaconda3\Lib\site-packages\pennylane\transforms\core\transform_dispatcher.py:223, in TransformDispatcher._qfunc_transform.<locals>.qfunc_transformed(*args, **kwargs)
    220     qfunc_output = qfunc(*args, **kwargs)
    222 tape = qml.tape.QuantumScript.from_queue(q)
--> 223 transformed_tapes, processing_fn = self._transform(tape, *targs, **tkwargs)
    225 if len(transformed_tapes) != 1:
    226     raise TransformError(
    227         "Impossible to dispatch your transform on quantum function, because more than "
    228         "one tape is returned"
    229     )

File ~\anaconda3\Lib\site-packages\pennylane\transforms\compile.py:164, in compile(tape, pipeline, basis_set, num_passes, expand_depth)
    162 with QueuingManager.stop_recording():
    163     if basis_set is not None:
--> 164         expanded_tape = tape.expand(
    165             depth=expand_depth, stop_at=lambda obj: obj.name in basis_set
    166         )
    167     else:
    168         # Expands out anything that is not a single operation (i.e., the templates)
    169         # expand barriers when `only_visual=True`
    170         def stop_at(obj):

File ~\anaconda3\Lib\site-packages\pennylane\tape\qscript.py:948, in QuantumScript.expand(self, depth, stop_at, expand_measurements)
    903 def expand(self, depth=1, stop_at=None, expand_measurements=False):
    904     """Expand all operations to a specific depth.
    905 
    906     Args:
   (...)
    946     RY(0.2, wires=['a'])]
    947     """
--> 948     new_script = qml.tape.tape.expand_tape(
    949         self, depth=depth, stop_at=stop_at, expand_measurements=expand_measurements
    950     )
    951     new_script._update()
    952     return new_script

File ~\anaconda3\Lib\site-packages\pennylane\tape\tape.py:218, in expand_tape(tape, depth, stop_at, expand_measurements)
    215         continue
    217 # recursively expand out the newly created tape
--> 218 expanded_tape = expand_tape(obj, stop_at=stop_at, depth=depth - 1)
    220 new_ops.extend(expanded_tape.operations)
    221 new_measurements.extend(expanded_tape.measurements)

File ~\anaconda3\Lib\site-packages\pennylane\tape\tape.py:203, in expand_tape(tape, depth, stop_at, expand_measurements)
    201 if obj.has_decomposition:
    202     with QueuingManager.stop_recording():
--> 203         obj = QuantumScript(obj.decomposition(), _update=False)
    204 else:
    205     new_queue.append(obj)

File ~\anaconda3\Lib\site-packages\pennylane\operation.py:1238, in Operator.decomposition(self)
   1226 def decomposition(self):
   1227     r"""Representation of the operator as a product of other operators.
   1228 
   1229     .. math:: O = O_1 O_2 \dots O_n
   (...)
   1236         list[Operator]: decomposition of the operator
   1237     """
-> 1238     return self.compute_decomposition(
   1239         *self.parameters, wires=self.wires, **self.hyperparameters
   1240     )

File ~\anaconda3\Lib\site-packages\pennylane\ops\qubit\non_parametric_ops.py:2229, in MultiControlledX.compute_decomposition(wires, work_wires, control_values, **kwargs)
   2226     control_values = "1" * len(control_wires)
   2228 if len(control_wires) > 2 and len(work_wires) == 0:
-> 2229     raise ValueError(
   2230         "At least one work wire is required to decompose operation: MultiControlledX"
   2231     )
   2233 flips1 = [
   2234     qml.PauliX(control_wires[i]) for i, val in enumerate(control_values) if val == "0"
   2235 ]
   2237 if len(control_wires) == 1:

ValueError: At least one work wire is required to decompose operation: MultiControlledX

For qml.about I get

Name: PennyLane
Version: 0.33.0.dev0
Summary: PennyLane is a Python quantum machine learning library by Xanadu Inc.
Home-page: https://github.com/PennyLaneAI/pennylane
Author: 
Author-email: 
License: Apache License 2.0
Location: C:\Users\Carter\anaconda3\Lib\site-packages
Requires: appdirs, autograd, autoray, cachetools, networkx, numpy, pennylane-lightning, requests, rustworkx, scipy, semantic-version, toml, typing-extensions
Required-by: PennyLane-Lightning, PennyLane-qiskit

Platform info:           Windows-10-10.0.22621-SP0
Python version:          3.11.5
Numpy version:           1.23.5
Scipy version:           1.11.1
Installed devices:
- default.gaussian (PennyLane-0.33.0.dev0)
- default.mixed (PennyLane-0.33.0.dev0)
- default.qubit (PennyLane-0.33.0.dev0)
- default.qubit.autograd (PennyLane-0.33.0.dev0)
- default.qubit.jax (PennyLane-0.33.0.dev0)
- default.qubit.legacy (PennyLane-0.33.0.dev0)
- default.qubit.tf (PennyLane-0.33.0.dev0)
- default.qubit.torch (PennyLane-0.33.0.dev0)
- default.qutrit (PennyLane-0.33.0.dev0)
- null.qubit (PennyLane-0.33.0.dev0)
- lightning.qubit (PennyLane-Lightning-0.32.0)
- qiskit.aer (PennyLane-qiskit-0.32.0)
- qiskit.basicaer (PennyLane-qiskit-0.32.0)
- qiskit.ibmq (PennyLane-qiskit-0.32.0)
- qiskit.ibmq.circuit_runner (PennyLane-qiskit-0.32.0)
- qiskit.ibmq.sampler (PennyLane-qiskit-0.32.0)
- qiskit.remote (PennyLane-qiskit-0.32.0)

I installed the preview version because for some reason the pip install -e wasn’t working

Hey @shrug001! I forgot to mention the work_wires thing :sweat_smile:. Apologies! work_wires are auxiliary wires that assist with decomposing MultiControlledX. This should work:

import pennylane as qml
from pennylane import numpy as np


property_prices = [4, 8, 6, 3, 12, 15] # total 48 
variables_wires = [0, 1, 2, 3, 4, 5]

aux_oracle_wires = [6, 7, 8 ,9 ,10, 11]

def oracle(variables_wires, aux_oracle_wires):
    
    def add_k_fourier(k, wires,wires2, num):
        for j in range(len(wires)):
            qml.CRZ(k * np.pi / (2**j), wires=[wires2[num],wires[j]])
            
    def value_second_sibling():
        
        qml.QFT(wires = aux_oracle_wires)
        
        for i in range(len(variables_wires)):
            add_k_fourier(property_prices[i],aux_oracle_wires, variables_wires, i)
            
        qml.adjoint(qml.QFT)(wires = aux_oracle_wires)
        
    value_second_sibling()
    qml.FlipSign(sum(property_prices) // 2, wires = aux_oracle_wires)
    qml.adjoint(value_second_sibling)()

#dev = qml.device('qiskit.ibmq', wires=12, backend='ibmq_qasm_simulator')
dev = qml.device('default.qubit', wires=12)

@qml.qnode(dev)
@qml.compile(basis_set=["CNOT", "RZ", "RX", "RY"])
def circuit():
    
    # step 1
    for wire in variables_wires:
        qml.Hadamard(wire)
       
    # step 2
    oracle(variables_wires, aux_oracle_wires)
    
    # step 3
    qml.GroverOperator(wires = variables_wires, work_wires=aux_oracle_wires)
    
    return qml.probs(wires = variables_wires)

values = circuit()

Let me know if that helps!

The code works for the pennylane simulator but when I try to run it with the IBMQ simulator I get this error:

KeyError                                  Traceback (most recent call last)
Cell In[4], line 3
      1 import matplotlib.pyplot as plt
----> 3 values = circuit()
      4 plt.bar(range(len(values)), values)

File ~\anaconda3\Lib\site-packages\pennylane\qnode.py:1008, in QNode.__call__(self, *args, **kwargs)
   1003     full_transform_program._set_all_argnums(
   1004         self, args, kwargs, argnums
   1005     )  # pylint: disable=protected-access
   1007 # pylint: disable=unexpected-keyword-arg
-> 1008 res = qml.execute(
   1009     (self._tape,),
   1010     device=self.device,
   1011     gradient_fn=self.gradient_fn,
   1012     interface=self.interface,
   1013     transform_program=full_transform_program,
   1014     config=config,
   1015     gradient_kwargs=self.gradient_kwargs,
   1016     override_shots=override_shots,
   1017     **self.execute_kwargs,
   1018 )
   1020 res = res[0]
   1022 # convert result to the interface in case the qfunc has no parameters

File ~\anaconda3\Lib\site-packages\pennylane\interfaces\execution.py:736, in execute(tapes, device, gradient_fn, interface, transform_program, config, grad_on_execution, gradient_kwargs, cache, cachesize, max_diff, override_shots, expand_fn, max_expansion, device_batch_transform)
    733     raise ValueError("Gradient transforms cannot be used with grad_on_execution=True")
    735 ml_boundary_execute = _get_ml_boundary_execute(interface, _grad_on_execution)
--> 736 results = ml_boundary_execute(
    737     tapes, device, execute_fn, gradient_fn, gradient_kwargs, _n=1, max_diff=max_diff
    738 )
    740 return post_processing(results)

File ~\anaconda3\Lib\site-packages\pennylane\interfaces\autograd.py:69, in execute(tapes, device, execute_fn, gradient_fn, gradient_kwargs, _n, max_diff)
     64 # pylint misidentifies autograd.builtins as a dict
     65 # pylint: disable=no-member
     66 parameters = autograd.builtins.tuple(
     67     [autograd.builtins.list(t.get_parameters()) for t in tapes]
     68 )
---> 69 return _execute(
     70     parameters,
     71     tapes=tapes,
     72     device=device,
     73     execute_fn=execute_fn,
     74     gradient_fn=gradient_fn,
     75     gradient_kwargs=gradient_kwargs,
     76     _n=_n,
     77     max_diff=max_diff,
     78 )[0]

File ~\anaconda3\Lib\site-packages\autograd\tracer.py:48, in primitive.<locals>.f_wrapped(*args, **kwargs)
     46     return new_box(ans, trace, node)
     47 else:
---> 48     return f_raw(*args, **kwargs)

File ~\anaconda3\Lib\site-packages\pennylane\interfaces\autograd.py:130, in _execute(parameters, tapes, device, execute_fn, gradient_fn, gradient_kwargs, _n, max_diff)
    112 if logger.isEnabledFor(logging.DEBUG):
    113     logger.debug(
    114         "Entry with args=(parameters=%s, tapes=%s, device=%s, execute_fn=%s, gradient_fn=%s, gradient_kwargs=%s, _n=%s, max_diff=%s) called by=%s",
    115         parameters,
   (...)
    127         "::L".join(str(i) for i in inspect.getouterframes(inspect.currentframe(), 2)[1][1:3]),
    128     )
--> 130 res, jacs = execute_fn(tapes, **gradient_kwargs)
    132 return res, jacs

File ~\anaconda3\Lib\site-packages\pennylane\interfaces\execution.py:588, in execute.<locals>.inner_execute_with_empty_jac(tapes, **_)
    587 def inner_execute_with_empty_jac(tapes, **_):
--> 588     return (inner_execute(tapes), [])

File ~\anaconda3\Lib\site-packages\pennylane\interfaces\execution.py:249, in _make_inner_execute.<locals>.inner_execute(tapes, **_)
    247 if numpy_only:
    248     tapes = tuple(qml.transforms.convert_to_numpy_parameters(t) for t in tapes)
--> 249 return cached_device_execution(tapes)

File ~\anaconda3\Lib\site-packages\pennylane\interfaces\execution.py:371, in cache_execute.<locals>.wrapper(tapes, **kwargs)
    366         return (res, []) if return_tuple else res
    368 else:
    369     # execute all unique tapes that do not exist in the cache
    370     # convert to list as new device interface returns a tuple
--> 371     res = list(fn(tuple(execution_tapes.values()), **kwargs))
    373 final_res = []
    375 for i, tape in enumerate(tapes):

File ~\anaconda3\Lib\contextlib.py:81, in ContextDecorator.__call__.<locals>.inner(*args, **kwds)
     78 @wraps(func)
     79 def inner(*args, **kwds):
     80     with self._recreate_cm():
---> 81         return func(*args, **kwds)

File ~\anaconda3\Lib\site-packages\pennylane_qiskit\ibmq.py:91, in IBMQDevice.batch_execute(self, circuits)
     90 def batch_execute(self, circuits):  # pragma: no cover, pylint:disable=arguments-differ
---> 91     res = super().batch_execute(circuits, timeout=self.timeout_secs)
     92     if self.tracker.active:
     93         self._track_run()

File ~\anaconda3\Lib\site-packages\pennylane_qiskit\qiskit_device.py:473, in QiskitDevice.batch_execute(self, circuits, timeout)
    470 def batch_execute(self, circuits, timeout: int = None):
    471     # pylint: disable=missing-function-docstring
--> 473     compiled_circuits = self.compile_circuits(circuits)
    475     # Send the batch of circuit objects using backend.run
    476     self._current_job = self.backend.run(compiled_circuits, shots=self.shots, **self.run_args)

File ~\anaconda3\Lib\site-packages\pennylane_qiskit\qiskit_device.py:462, in QiskitDevice.compile_circuits(self, circuits)
    458 for circuit in circuits:
    459     # We need to reset the device here, else it will
    460     # not start the next computation in the zero state
    461     self.reset()
--> 462     self.create_circuit_object(circuit.operations, rotations=circuit.diagonalizing_gates)
    464     compiled_circ = self.compile()
    465     compiled_circ.name = f"circ{len(compiled_circuits)}"

File ~\anaconda3\Lib\site-packages\pennylane_qiskit\qiskit_device.py:273, in QiskitDevice.create_circuit_object(self, operations, **kwargs)
    261 """Builds the circuit objects based on the operations and measurements
    262 specified to apply.
    263 
   (...)
    269         pre-measurement into the eigenbasis of the observables.
    270 """
    271 rotations = kwargs.get("rotations", [])
--> 273 applied_operations = self.apply_operations(operations)
    275 # Rotating the state for measurement in the computational basis
    276 rotation_circuits = self.apply_operations(rotations)

File ~\anaconda3\Lib\site-packages\pennylane_qiskit\qiskit_device.py:322, in QiskitDevice.apply_operations(self, operations)
    318         par[idx] = p.tolist()
    320 operation = operation.name
--> 322 mapped_operation = self._operation_map[operation]
    324 self.qubit_state_vector_check(operation)
    326 qregs = [self._reg[i] for i in device_wires.labels]

KeyError: 'C(RZ)'

Now we’re back to the original issue. That’s strange :thinking:… are you using this to ensure that things get decomposed in an ibmq-friendly way?

@qml.compile(basis_set=["CNOT", "RZ", "RX", "RY"])

yes:

import pennylane as qml
from pennylane import numpy as np

property_prices = [4, 8, 6, 3, 12, 15] # total 48 
variables_wires = [0, 1, 2, 3, 4, 5]

aux_oracle_wires = [6, 7, 8 ,9 ,10, 11]

def oracle(variables_wires, aux_oracle_wires):
    
    def add_k_fourier(k, wires,wires2, num):
        for j in range(len(wires)):
            qml.CRZ(k * np.pi / (2**j), wires=[wires2[num],wires[j]])
            
    def value_second_sibling():
        
        qml.QFT(wires = aux_oracle_wires)
        
        for i in range(len(variables_wires)):
            add_k_fourier(property_prices[i],aux_oracle_wires, variables_wires, i)
            
        qml.adjoint(qml.QFT)(wires = aux_oracle_wires)
        
    value_second_sibling()
    qml.FlipSign(sum(property_prices) // 2, wires = aux_oracle_wires)
    qml.adjoint(value_second_sibling)()

dev = qml.device('qiskit.ibmq', wires=12, backend='ibmq_qasm_simulator')
#dev = qml.device('default.qubit', wires=12)

@qml.qnode(dev)
@qml.compile(basis_set=["CNOT", "RZ", "RX", "RY"])
def circuit():
    
    # step 1
    for wire in variables_wires:
        qml.Hadamard(wires = wire)
       
    # step 2
    oracle(variables_wires, aux_oracle_wires)
    
    # step 3
    qml.GroverOperator(wires = variables_wires, work_wires=aux_oracle_wires)
    
    return qml.probs(wires = variables_wires)
import matplotlib.pyplot as plt

values = circuit()
plt.bar(range(len(values)), values)