docs/hardware/pasqal/getting_started.ipynb fails to execute in Google Colab
Description of the issue
The cirq-pasqal getting_started.ipynb notebook calls cirq.optimize_for_target_gateset which should produce a circuit that validates w/r to pasqal device, but this fails when run on https://colab.research.google.com/ notebook.
The same notebook passes if run on a local Debian Linux OS. This seems to be cause by different round-off errors of the CPUs, which lead to differing optimized circuits.
The root cause appears to be that cirq.optimize_for_target_gateset does not ensure that for PasqalGateset the new
circuit has single-operation moments, they just happen to be so for getting_started.ipynb with a favorable round-off errors.
The optimization may also produce a moment with 2 operations, which fails validation as follows:
How to reproduce the issue
Create and run fresh colab at https://colab.research.google.com
# cell 1
!pip install "cirq_pasqal==1.4.1"
# cell 2
import cirq
import cirq_pasqal
from cirq_pasqal import TwoDQubit, PasqalVirtualDevice
p_qubits = TwoDQubit.square(6) # 6x6 square array of TwoDQubits
# Initialize and create a circuit
initial_circuit = cirq.Circuit()
initial_circuit.append(cirq.CZ(p_qubits[0], p_qubits[1]))
initial_circuit.append(cirq.Z(p_qubits[0]))
initial_circuit.append(cirq.CX(p_qubits[0], p_qubits[2]))
# Create a Pasqal device with a control radius of 2.1 (in units of the lattice spacing)
p_device = PasqalVirtualDevice(control_radius=2.1, qubits=p_qubits)
pasqal_gateset = cirq_pasqal.PasqalGateset(include_additional_controlled_ops=False)
print("INITIAL\n")
print(initial_circuit)
print()
pasqal_circuit = cirq.optimize_for_target_gateset(
initial_circuit, gateset=pasqal_gateset
)
print("OPTIMIZED\n")
print(pasqal_circuit)
print("\nVALIDATION\n")
p_device.validate_circuit(pasqal_circuit)
(0, 0): ───@───Z───@─── │ │ (1, 0): ───@───────┼─── │ (2, 0): ───────────X───
OPTIMIZED
(0, 0): ───@───Z──────────────────@───Z───────────────────── │ │ (1, 0): ───@──────────────────────┼───────────────────────── │ (2, 0): ───────────PhX(0.5)^0.5───@───PhX(-0.5)^0.5───Z^0───
VALIDATION
ValueError Traceback (most recent call last)
2 frames /usr/local/lib/python3.10/dist-packages/cirq_pasqal/pasqal_device.py in validate_circuit(self, circuit) 137 ValueError: If the given circuit can't be run on this device 138 """ --> 139 super().validate_circuit(circuit) 140 141 # Measurements must be in the last non-empty moment
/usr/local/lib/python3.10/dist-packages/cirq/devices/device.py in validate_circuit(self, circuit) 84 """ 85 for moment in circuit: ---> 86 self.validate_moment(moment) 87 88 def validate_moment(self, moment: 'cirq.Moment') -> None:
/usr/local/lib/python3.10/dist-packages/cirq_pasqal/pasqal_device.py in validate_moment(self, moment) 233 for operation in moment: 234 if not isinstance(operation.gate, cirq.MeasurementGate): --> 235 raise ValueError("Cannot do simultaneous gates. Use cirq.InsertStrategy.NEW.") 236 237 def minimal_distance(self) -> float:
ValueError: Cannot do simultaneous gates. Use cirq.InsertStrategy.NEW.
Cirq version
1.4.1
Circq cync: Goal is to enable this notebook again and make sure it works.
I am trying to understand what happened here:
This code in the main was added in pull request #6656:
# TODO(https://github.com/quantumlib/Cirq/issues/6655) - remove after fixup
pasqal_circuit = cirq.Circuit(pasqal_circuit.all_operations(),
strategy=cirq.InsertStrategy.NEW)
It was added as a workaround for the original circuit:
pasqal_circuit = cirq.optimize_for_target_gateset(initial_circuit,
gateset=pasqal_gateset)
So this issue is still open to address the bug in cirq.optimize_for_target_gateset!
I will be trying to look into cirq.optimize_for_target_gateset and see.
"@pavoljuhas please correct me if there is something I am getting wrong."
The workaround in #6656 transforms pasqal_circuit so that each moment has exactly one operation.
This is ensured by cirq.InsertStrategy.NEW which tells cirq to create new moment for each operation in the phase_circuit.all_operations() sequence. Before that the moment 4 in the initial example would be
In: pasqal_circuit[4]
Out: cirq.Moment(
cirq.PhasedXPowGate(phase_exponent=-0.5, exponent=0.5).on(pasqal.TwoDQubit(2, 0)),
(cirq.Z**-1.0).on(pasqal.TwoDQubit(0, 0)),
)
which fails validation for PasqalVirtualDevice, because it requires one operations per moment (excluding measurements) - https://github.com/quantumlib/Cirq/blob/95f6a3f17a723d67927746a62992011be98b78b9/cirq-pasqal/cirq_pasqal/pasqal_device.py#L232-L235