Rydberg devices and operations

Due to the nature of the QRydDemo hardware based on Rydberg atoms, QRydDemo quantum computing devices can have special capabilities that are 'not' present in all universal quantum computers.

The devices can have two-dimensional grids of optical tweezer-positions and different two-dimensional grids can be calibrated. A tweezer-position is a physical spot that can be populated by a qubit. Not every tweezer position needs to be filled by a qubit and qubit can be moved between tweezer positions. Note that all functionality described here is a preview and does not represent a finalized QRydDemo design.

Special operations

To support the full flexibility of the QRydDemo devices, four additional qoqo operations are provided PragmaChangeQRydLayout, PragmaSwitchDeviceLayout, PragmaShiftQRydQubit and PragmaShiftQubitsTweezers. PragmaChangeQRydLayout allows a quantum circuit to change between predefined calibrated optical tweezer positions. It indexes the layouts by integer. A similar operation, but meant for TweezerDevice and TweezerMutableDevice, is PragmaSwitchDeviceLayout, which indexes the new layout via a string. PragmaShiftQRydQubit allows a quantum circuit to shift a qubit from one tweezer position to another. PragmaShiftQubitsTweezers is the equivalent operation meant to be used with TweezerDevice and TweezerMutableDevice.

   from qoqo import Circuit
   from qoqo_qryd.pragma_operations import PragmaChangeQRydLayout, PragmaShiftQRydQubit, PragmaSwitchDeviceLayout, PragmaShiftQubitsTweezers

   circuit = Circuit()
   # Switch to predefined layout 1
   circuit += PragmaChangeQRydLayout(new_layout=1).to_pragma_change_device()
   # Switch to predefined layout "triangle"
   circuit += PragmaSwitchDeviceLayout(new_layout="triangle").to_pragma_change_device()
   # Shift qubit 0 to tweezer position: row 0, column 1 and qubit 1 to postion row 1, column 1
   circuit += PragmaShiftQRydQubit(new_positions={0: (0,1), 1: (1,1)}).to_pragma_change_device()
   # Shift the qubit state present in tweezer 0 to tweezer 1, and the qubit state present in tweezer 2 to tweezer 3
   circuit += PragmaShiftQubitsTweezers(shifts=[(0, 1), (2, 3)]).to_pragma_change_device()
   ()

QRyd and Tweezer devices

Each type of QRydDemo hardware or Simulator device can be represented by either the QRydDevice or the TweezerDevice classes. The available hardware operations are defined in the devices. They save the 2D connectivity and can be queried for the availability of certain gate operations on the qubit. At the moment the most general example Device class is FirstDevice, that can be used for simulations. Other available devices include TweezerMutableDevice, which works by first defining the underlying tweezer structure and then populate it with qubits as needed. TweezerDevice works in a similar way. The main difference is it does not allow any setting of the Tweezer information. This should be obtained via the .from_api() call (see the WebAPI section).

The fundamental gates that are available on the QRydDemo devices are the following qoqo operations: RotateX, RotateY, RotateZ, RotateXY, PauliX, PauliY, PauliZ, PhaseShiftState1 , SqrtPauliX, InvSqrtPauliX, PhaseShiftedControlledZ and PhaseShiftedControlledPhase. The single-qubit gates are assumed to be available on all qubits. The PhaseShiftedControlledZ and PhaseShiftedControlledPhase are available between a subset of qubit pairs. The PhaseShiftedControlledZ is a ControlledPauliZ gate that also applies single qubit phases whereas the PhaseShiftedControlledPhase is equivalent to PhaseShiftedControlledZ but with a variable phase rotation. The phase shifts can in principle be device dependent.

The devices can optionally contain the controlled_z_phase_relation and controlled_phase_phase_relation parameters that define the phase shift relations of the two-qubit gates for the device. The first parameter can also be set explicitly by putting a string defining a float value as input.

   from qoqo_qryd.qryd_devices import FirstDevice
   from qoqo_qryd.tweezer_devices import TweezerMutableDevice
   import numpy as np

   # Create a FirstDevice
   first_device = FirstDevice(
      # The number of tweezer position rows in the 2D Grid is fixed
      number_rows=2,
      # The number of tweezer position  columns in the 2D grid is also fixed
      number_columns=4,
      # As not all tweezer positions must be filled, the number of positions
      # occupied by qubits per row is fixed
      qubits_per_row=[2, 2],
      # The (model) physical distance between rows is fixed
      row_distance=1.0,
      # The initial layout (layout number 0 for PragmaChangeQRydLayout) is defined 
      # by the physical positions of the tweezers in each row
      initial_layout=np.array([
         [0.0, 1.0, 2.0, 3.0],
         [0.0, 1.0, 2.0, 3.0]]),
      # The phase shift value related to the PhaseShiftedControlledZ gate
      # Using a string that defines a relation is also possible
      controlled_z_phase_relation="0.23",
      # The relation to use for the PhaseShiftedControlledPhase phase shift value
      controlled_phase_phase_relation="DefaultRelation"
   )

   # Print the two-qubit-operation connectivity graph of the device
   print(first_device.two_qubit_edges())

   # Create a TweezerMutableDevice
   tweezer_device = TweezerMutableDevice(
      # The phase shift value related to the PhaseShiftedControlledZ gate
      # Using a string that defines a relation is also possible
      controlled_z_phase_relation="0.23",
      # The relation to use for the PhaseShiftedControlledPhase phase shift value
      controlled_phase_phase_relation="DefaultRelation"
   )

   # Add a tweezer layout to the device
   tweezer_device.add_layout(name="triangle")

   # Set single-qubit tweezer gate time information on the new layout
   tweezer_device.set_tweezer_single_qubit_gate_time(
      hqslang="PhaseShiftState1",
      tweezer=0,
      gate_time=0.23,
      layout="triangle",
   )

   # Populate the newly set tweezer with qubit indexed as 0
   tweezer_device.add_qubit_tweezer_mapping(
      qubit=0,
      tweezer=0,
   )

   # Print the available layouts of the device
   print(tweezer_device.available_layouts())

SimulatorBackend

The SimulatorBackend of qoqo-qryd can execute qoqo QuantumPrograms depending on the provided devices. At the moment only the FirstDevice is available for the QRydDemo project. Executing a circuit with the SimulatorBackend initialized by the FirstDevice corresponds to running a simulation of the QuantumProgram which validates that only operations available in FirstDevice are used.

   from qoqo_qryd.qryd_devices import FirstDevice
   from qoqo_qryd import SimulatorBackend
   import numpy as np
   # Create a FirstDevice
   device = FirstDevice(
      # The number of tweezer position rows in the 2D Grid is fixed
      number_rows=2,
      # The number of tweezer position  columns in the 2D grid is also fixed
      number_columns=4,
      # As not all tweezer positions must be filled, the number of positions
      # occupied by qubits per row is fixed
      qubits_per_row=[2, 2],
      # The (model) physical distance between rows is fixed
      row_distance=1.0,
      # The initial layout (layout number 0 for PragmaChangeQRydLayout) is defined 
      # by the physical positions of the tweezers in each row
      initial_layout=np.array([
         [0.0, 1.0, 2.0, 3.0],
         [0.0, 1.0, 2.0, 3.0]]))

   # Initialize Backend
   backend = SimulatorBackend(device)