question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

[BUG] `qml.draw` fails for templates without a custom `adjoint` method (`expansion_strategy=None`)

See original GitHub issue

Expected behavior

dev = qml.device("default.qubit", wires=2)

@qml.qnode(dev)
def qpe_circuit():
    qml.adjoint(qml.QuantumPhaseEstimation)(
        qml.PauliX.matrix,
        target_wires=[0],
        estimation_wires=[1],
    )
    return qml.state()

print(qml.draw(qpe_circuit)())

Executes correctly.

Actual behavior

An error is raised:

~/xanadu/pennylane/pennylane/circuit_drawer/representation_resolver.py in element_representation(self, element, wire)
    487             return self.output_representation(element, wire)
    488 
--> 489         return self.operator_representation(element, wire)

~/xanadu/pennylane/pennylane/circuit_drawer/representation_resolver.py in operator_representation(self, op, wire)
    420         elif len(qml.math.shape(op.data[0])) != 0:
    421             print(name)
--> 422             representation = name + RepresentationResolver._format_matrix_arguments(
    423                 op.data, "M", self.matrix_cache
    424             )

TypeError: unsupported operand type(s) for +: 'NoneType' and 'str'

Additional information

The issue seems to arise with any template that doesn’t define the adjoint method. The specific line in the traceback errors out because a QuantumTape object is being processed and it doesn’t have a name attribute defined.

When expansion_strategy=device is set, drawing concludes successfully and draws the circuit as expected.

Source code

No response

Tracebacks

No response

System information

Name: PennyLane
Version: 0.20.0.dev0
Summary: PennyLane is a Python quantum machine learning library by Xanadu Inc.
Home-page: https://github.com/XanaduAI/pennylane
Author: 
Author-email: 
License: Apache License 2.0
Location: /home/antal/xanadu/pennylane
Requires: numpy, scipy, networkx, autograd, toml, appdirs, semantic_version, autoray, cachetools, pennylane-lightning
Required-by: PennyLane-Cirq, PennyLane-Orquestra, PennyLane-SF, pennylane-qulacs, PennyLane-IonQ, amazon-braket-pennylane-plugin, PennyLane-Honeywell, PennyLane-qiskit, PennyLane-AQT, PennyLane-Qchem, PennyLane-PQ, PennyLane-Forest, PennyLane-Lightning, PennyLane-qsharp
Platform info:           Linux-5.11.0-40-generic-x86_64-with-glibc2.10
Python version:          3.8.5
Numpy version:           1.21.4
Scipy version:           1.7.3
Installed devices:
- cirq.mixedsimulator (PennyLane-Cirq-0.17.1)
- cirq.pasqal (PennyLane-Cirq-0.17.1)
- cirq.qsim (PennyLane-Cirq-0.17.1)
- cirq.qsimh (PennyLane-Cirq-0.17.1)
- cirq.simulator (PennyLane-Cirq-0.17.1)
- orquestra.forest (PennyLane-Orquestra-0.15.0)
- orquestra.ibmq (PennyLane-Orquestra-0.15.0)
- orquestra.qiskit (PennyLane-Orquestra-0.15.0)
- orquestra.qulacs (PennyLane-Orquestra-0.15.0)
- strawberryfields.fock (PennyLane-SF-0.16.0.dev0)
- strawberryfields.gaussian (PennyLane-SF-0.16.0.dev0)
- strawberryfields.gbs (PennyLane-SF-0.16.0.dev0)
- strawberryfields.remote (PennyLane-SF-0.16.0.dev0)
- strawberryfields.tf (PennyLane-SF-0.16.0.dev0)
- qulacs.simulator (pennylane-qulacs-0.17.0.dev0)
- ionq.qpu (PennyLane-IonQ-0.17.0.dev0)
- ionq.simulator (PennyLane-IonQ-0.17.0.dev0)
- braket.aws.qubit (amazon-braket-pennylane-plugin-1.4.1.dev0)
- braket.local.qubit (amazon-braket-pennylane-plugin-1.4.1.dev0)
- honeywell.hqs (PennyLane-Honeywell-0.16.0.dev0)
- qiskit.aer (PennyLane-qiskit-0.18.0.dev0)
- qiskit.basicaer (PennyLane-qiskit-0.18.0.dev0)
- qiskit.ibmq (PennyLane-qiskit-0.18.0.dev0)
- aqt.noisy_sim (PennyLane-AQT-0.18.0)
- aqt.sim (PennyLane-AQT-0.18.0)
- projectq.classical (PennyLane-PQ-0.18.0.dev0)
- projectq.ibm (PennyLane-PQ-0.18.0.dev0)
- projectq.simulator (PennyLane-PQ-0.18.0.dev0)
- forest.numpy_wavefunction (PennyLane-Forest-0.18.0.dev0)
- forest.qvm (PennyLane-Forest-0.18.0.dev0)
- forest.wavefunction (PennyLane-Forest-0.18.0.dev0)
- lightning.qubit (PennyLane-Lightning-0.19.0.dev0)
- microsoft.QuantumSimulator (PennyLane-qsharp-0.19.0)
- default.gaussian (PennyLane-0.20.0.dev0)
- default.mixed (PennyLane-0.20.0.dev0)
- default.qubit (PennyLane-0.20.0.dev0)
- default.qubit.autograd (PennyLane-0.20.0.dev0)
- default.qubit.jax (PennyLane-0.20.0.dev0)
- default.qubit.tf (PennyLane-0.20.0.dev0)
- default.qubit.torch (PennyLane-0.20.0.dev0)
- default.tensor (PennyLane-0.20.0.dev0)
- default.tensor.tf (PennyLane-0.20.0.dev0)


### 

- [X] I have searched exisisting GitHub issues to make sure the issue does not already exist.

Issue Analytics

  • State:closed
  • Created 2 years ago
  • Comments:5 (5 by maintainers)

github_iconTop GitHub Comments

1reaction
dime10commented, Dec 3, 2021

What if we followed case 1 and drew the tape to look as if it was its inverse? Could we get away with the user not knowing if there’s a real operation object or a tape that represents the inverse of the operation?

So like

 0: ──╭QuantumPhaseEstimation(M0)⁻¹──╭┤ State 
 1: ──╰QuantumPhaseEstimation(M0)⁻¹──╰┤ State 
M0 =
[[0 1]
 [1 0]]

The problem is that the information about the template is lost. Since the adjoint method is not defined for QuantumPhaseEstimation, the template is expanded into a tape and the adjoint is computed on the tape. All the drawer then sees is a tape with operations inside. So while in this instance the tape came from an adjointed template, it could just as well come from the manual placement of a tape in the operations list:

@qml.qnode(dev)
def tape_circuit():
    with qml.tape.QuantumTape():
        qml.Hadamard(wires=0)
        qml.CNOT(wires=[0,1])
    return qml.state()

Note that the desired behaviour you describe does happen when a template defines the adjoint method via .inv(), for example the QFT template:

@qml.qnode(dev)
def tape_circuit():
   qml.adjoint(qml.QFT)(wires=[1])
   return qml.state()

prints as:

1: ──QFT⁻¹──┤ State 

In specific, as a user, I’d expect that simply using qml.adjoint will not alter the way the circuit is being drawn. If I see QuantumPhaseEstimation, then I’d expect its inverse to pop up as a single object. If I see the decomposition of QuantumPhaseEstimation, then I’d expect a list of operations to pop up for its inverse.

So I think in addition to supporting tapes in the drawer, a fix to this bug could include defining the adjoint method for the QuantumPhaseEstimation template so that its adjoint is properly drawn.

0reactions
dime10commented, Dec 7, 2021

#1973 removed the issue for the QuantumPhaseEstimation template.

Read more comments on GitHub >

github_iconTop Results From Across the Web

No results found

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found