PennyLaneAI / pennylane

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.
https://pennylane.ai
Apache License 2.0
2.34k stars 600 forks source link

[BUG] string wires do not work with qml.measure #5205

Open KetpuntoG opened 8 months ago

KetpuntoG commented 8 months ago

Expected behavior

This toy example should return [1,0]

import pennylane as qml

dev = qml.device("default.qubit")

@qml.qnode(dev)
def circuit():
  qml.measure(wires = "my wire")
  return qml.probs(wires = "my wire")

circuit()

Actual behavior

---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
[<ipython-input-13-83a443119fbf>](https://32r9uqi4lvj-496ff2e9c6d22116-0-colab.googleusercontent.com/outputframe.html?vrz=colab_20240212-060142_RC00_606195215#) in <cell line: 10>()
      8   return qml.probs(wires = "my wire")
      9 
---> 10 circuit()

3 frames
[/usr/local/lib/python3.10/dist-packages/pennylane/transforms/defer_measurements.py](https://32r9uqi4lvj-496ff2e9c6d22116-0-colab.googleusercontent.com/outputframe.html?vrz=colab_20240212-060142_RC00_606195215#) in defer_measurements(tape, **kwargs)
    226     control_wires = {}
    227     cur_wire = (
--> 228         max(tape.wires) + 1 if reused_measurement_wires or any_repeated_measurements else None
    229     )
    230 

TypeError: can only concatenate str (not "int") to str

Additional information

No response

Source code

No response

Tracebacks

No response

System information

Name: PennyLane
Version: 0.34.0
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: /usr/local/lib/python3.10/dist-packages
Requires: appdirs, autograd, autoray, cachetools, networkx, numpy, pennylane-lightning, requests, rustworkx, scipy, semantic-version, toml, typing-extensions
Required-by: PennyLane-Lightning

Platform info:           Linux-6.1.58+-x86_64-with-glibc2.35
Python version:          3.10.12
Numpy version:           1.25.2
Scipy version:           1.11.4
Installed devices:
- default.gaussian (PennyLane-0.34.0)
- default.mixed (PennyLane-0.34.0)
- default.qubit (PennyLane-0.34.0)
- default.qubit.autograd (PennyLane-0.34.0)
- default.qubit.jax (PennyLane-0.34.0)
- default.qubit.legacy (PennyLane-0.34.0)
- default.qubit.tf (PennyLane-0.34.0)
- default.qubit.torch (PennyLane-0.34.0)
- default.qutrit (PennyLane-0.34.0)
- null.qubit (PennyLane-0.34.0)
- lightning.qubit (PennyLane-Lightning-0.34.0)

Existing GitHub issues

mudit2812 commented 8 months ago

This is because defer_measurements doesn't support custom wire labels. The two routes to resolution for this bug are:

trbromley commented 8 months ago

@mudit2812 don't we have a PR open to support custom wire labels with deferred measurements?

mudit2812 commented 8 months ago

@mudit2812 don't we have a PR open to support custom wire labels with deferred measurements?

I have a prototype sitting around. There are a lot of sharp bits with that implementation, so I want to create a fresh PR with a better implementation.

Vitalii4as commented 8 months ago

Hi, I have the same error trying to use CRY, QubitUnitary, ControlledQubitUnitary (and probably some others are affected as well) with named wires.

Code to reproduce

import pennylane as qml
dev = qml.device("default.qubit", wires=["wire1", "wire2"])

@qml.qnode(dev)
def test():
    m_0 = qml.measure("wire1")

    qml.cond(m_0 == 0, qml.CRY)(0.5, wires=["wire1","wire2"])

    return qml.probs(wires="wire1")

test()

Error log

ypeError                                 Traceback (most recent call last)
Cell In[18], line 12
      8     qml.cond(m_0 == 0, qml.CRY)(0.5, wires=["wire1","wire2"])
     10     return qml.probs(wires="wire1")
---> 12 test()

File /opt/.qbraid/environments/qbraid_000000/pyenv/lib/python3.11/site-packages/pennylane/qnode.py:1039, in QNode.__call__(self, *args, **kwargs)
   1034         full_transform_program._set_all_argnums(
   1035             self, args, kwargs, argnums
   1036         )  # pylint: disable=protected-access
   1038 # pylint: disable=unexpected-keyword-arg
-> 1039 res = qml.execute(
   1040     (self._tape,),
   1041     device=self.device,
   1042     gradient_fn=self.gradient_fn,
   1043     interface=self.interface,
   1044     transform_program=full_transform_program,
   1045     config=config,
   1046     gradient_kwargs=self.gradient_kwargs,
   1047     override_shots=override_shots,
   1048     **self.execute_kwargs,
   1049 )
   1051 res = res[0]
   1053 # convert result to the interface in case the qfunc has no parameters

File /opt/.qbraid/environments/qbraid_000000/pyenv/lib/python3.11/site-packages/pennylane/interfaces/execution.py:632, 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, device_vjp)
    627     if not device_batch_transform:
    628         warnings.warn(
    629             "device batch transforms cannot be turned off with the new device interface.",
    630             UserWarning,
    631         )
--> 632     tapes, post_processing = transform_program(tapes)
    633 else:
    634     # TODO: Remove once old device are removed
    635     tapes, program_post_processing = transform_program(tapes)

File /opt/.qbraid/environments/qbraid_000000/pyenv/lib/python3.11/site-packages/pennylane/transforms/core/transform_program.py:435, in TransformProgram.__call__(self, tapes)
    433 if self._argnums is not None and self._argnums[i] is not None:
    434     tape.trainable_params = self._argnums[i][j]
--> 435 new_tapes, fn = transform(tape, *targs, **tkwargs)
    436 execution_tapes.extend(new_tapes)
    438 fns.append(fn)

File /opt/.qbraid/environments/qbraid_000000/pyenv/lib/python3.11/site-packages/pennylane/transforms/defer_measurements.py:228, in defer_measurements(tape, **kwargs)
    224 # Apply controlled operations to store measurement outcomes and replace
    225 # classically controlled operations
    226 control_wires = {}
    227 cur_wire = (
--> 228     max(tape.wires) + 1 if reused_measurement_wires or any_repeated_measurements else None
    229 )
    231 for op in tape.operations:
    232     if isinstance(op, MidMeasureMP):

TypeError: can only concatenate str (not "int") to str
mudit2812 commented 8 months ago

Relevant PR for fix: #4625

mudit2812 commented 8 months ago

5280 adds a more relevant error. A more detailed fix will come soon.