Skip to content

ControlledOperation diagram draws exponent on the wrong qubits  #4515

Closed
@tanujkhattar

Description

@tanujkhattar

Description of the issue
When controlling an operation that has an exponent, the exponent should be drawn on the target qubit in the circuit diagram to clearly convey what's the underlying operation which is being controlled.

However, ControlledOperation's circuit drawing function has multiple bugs. The code snippet to determine the exponent index of a ControlledOperation is given below:

# Existing code snippet in  `_circuit_diagram_info_` of `ControlledOperation` to determine the `exponent_qubit_index`
exponent_qubit_index = None if sub_info.exponent_qubit_index is None else sub_info.exponent_qubit_index + 1,
  1. If the underlying operation does not specify exponent_qubit_index, then the ControlledOperation always draws the exponent on the last (largest lexicographically ordered) qubit because exponent_qubit_index stays None even though the sub_info.exponent can be non-zero.
  2. If the underlying operation does specify an exponent_qubit_index, then the ControlledOperation draws the exponent on sub_info.exponent_qubit_index + 1 instead of sub_info.exponent_qubit_index + len(self.control_values) as a result the exponent get's shifted by an incorrect value and gets drawn on one of the control qubits if the number of controls are > 1.

See the example below for more details:

How to reproduce the issue

In [2]: cirq.Circuit([
    ...:     cirq.Moment( #  First case where underlying sub operation has an exponent but it's exponent_qubit_index = None. ControlledOperation always draws the exponent on the last qubit.
    ...:         cirq.ControlledOperation(sub_operation=(cirq.X**1.5).on(cirq.LineQubit(1)),control_values=((1,), (1,), (1,)),controls=(cirq.LineQubit(3), cirq.LineQubit(0), cirq.LineQubit(2))),
    ...:     ),
    ...:     cirq.Moment(# Second case where underlying sub operation has an exponent_qubit_index = 0. ControlledOperation just shifts it by 1 instead of len(control_values).
    ...:         cirq.ControlledOperation(sub_operation=cirq.PhaseGradientGate(num_qubits=2, exponent=0.5).on(cirq.LineQubit(3), cirq.LineQubit(2)),control_values=((1,), (1,)),controls=(cirq.LineQubit(0), cirq.LineQubit(1))),
    ...:     ),
    ...: ])
Out[2]:
0: ───@────────@───────
      │        │
1: ───X────────@^0.5───
      │        │
2: ───@────────#2──────
      │        │
3: ───@^-0.5───Grad────```

Expected output of the above circuit should be:

0: ───@────────@──────────
      │        │
1: ───X^-0.5───@──────────
      │        │
2: ───@────────#2─────────
      │        │
3: ───@────────Grad^0.5───

Note that fixing this would be a breaking change for diagrams.

Also, a similar bug exists in QuirkInputRotationOperation, which always draws the exponent on qubit 0 if the underlying operation is not a ControlledOperation and hence operations like CXPowGate, which specify an explicit exponent_qubit_index but are not instances of ControlledOperation will have a wrong output.

Cirq version
0.13.0.dev

Metadata

Metadata

Assignees

Labels

kind/bug-reportSomething doesn't seem to work.triage/acceptedA consensus emerged that this bug report, feature request, or other action should be worked on

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions