Devices and Compilation
Initializing a quantum device
Section titled “Initializing a quantum device”Each Device in QoolQit wraps a Pulser (external) device and defines the hardware characteristics that the program will be compiled to and later executed on.
from qoolqit import MockDevice, AnalogDevice, DigitalAnalogDevice
# An example of a mock device with no hardware constraintsdevice_ideal = MockDevice()
# An example of a real devicedevice_real = AnalogDevice()
# An example of a real device with digital-analog capabilities.device_real_digital = DigitalAnalogDevice()Besides available default devices, relevant for QPU emulation, new QPU devices can be: - imported remotely - created from custom Pulser devices
Fetching a QoolQit device from a connection
Section titled “Fetching a QoolQit device from a connection”Depending on your provider you might have different QPUs available to launch your quantum program to.
The list of available ones can be fetched through the specific connection handler object, with the generic connection.fetch_available_devices() method.
For the Pasqal Cloud service, for example, creating a QoolQit device from a connection object, simply reads as:
from pulser_pasqal import PasqalCloudfrom qoolqit import Device
connection = PasqalCloud()print(connection.fetch_available_devices())
# fetch QoolQit devicefresnel_device = Device.from_connection(connection=connection, name="FRESNEL"){'FRESNEL': FRESNEL}FRESNEL: └── max_duration: 332.43763968 └── max_amplitude: 0.20412370086269147 └── max_abs_detuning: 1.134020560348286 └── min_distance: 1.0 └── max_radial_distance: 9.2Create a QoolQit device from a Pulser device
Section titled “Create a QoolQit device from a Pulser device”A custom QoolQit device can also be built straight from any Pulser device, with any desired specification. Please, refer to Pulser documentation (external) to learn how to make a custom device.
from dataclasses import replacefrom pulser import AnalogDevicefrom qoolqit import Device
# Converting the pulser Device object into a VirtualDevice objectVirtualAnalog = AnalogDevice.to_virtual()# Replacing desired valuesModdedAnalogDevice = replace(VirtualAnalog, max_radial_distance=100, max_sequence_duration=7000)
# Wrap a Pulser device object into a QoolQit Devicemod_analog_device = Device(pulser_device=ModdedAnalogDevice)AnalogDevice: └── max_duration: 387.84391296 └── max_amplitude: 0.22680411206965717 └── max_abs_detuning: 2.268041120696572 └── min_distance: 1.0 └── max_radial_distance: 20.0Compilation
Section titled “Compilation”Once a QuantumProgram is defined and a Device is selected one can proceed with the compilation by means of the method compile_to. This method will execute what has been discussed in the introduction mapping adimensional parameters to physical quantities according to specific default rules.
from qoolqit import PiecewiseLinearfrom qoolqit import Register, Drive, QuantumProgramfrom qoolqit import AnalogDevice
# Defining the Drivewf0 = PiecewiseLinear([1.0, 2.0, 1.0], [0.0, 0.5, 0.5, 0.0])wf1 = PiecewiseLinear([1.0, 2.0, 1.0], [-1.0, -1.0, 1.0, 1.0])drive = Drive(amplitude = wf0, detuning = wf1)
# Defining the Registercoords = [(0.0, 0.0), (0.0, 1.0), (1.0, 0.0), (1.0, 1.0)]register = Register.from_coordinates(coords)
# Creating the Programprogram = QuantumProgram(register, drive)device = AnalogDevice()
# Compilation to AnalogDeviceprogram.compile_to(device)Quantum Program:| Register(n_qubits = 4)| Drive(duration = 4.000)| Compiled: True| Device: AnalogDeviceNow that the program has been compiled, we can inspect the compiled sequence, which is an instance of a Pulser Sequence.
pulser_sequence = program.compiled_sequenceFinally, we can draw both the original program and the compiled sequence.
program.draw()program.draw(compiled = True)Special compilation: maximum allowed duration
Section titled “Special compilation: maximum allowed duration”Whenever possible, the compilation step in QoolQit will simply take care of mapping the input quantum program into real hardware instructions. In other words, ratios between energies (interactions and drive) and time will be preserved (see compilation rationale). However, in some applications, one may be interested in separating time from the compilation step. For example, in adiabatic protocols, one simply seeks to rescale the duration of a quantum program to the maximum value allowed by the specific hardware.
To do so, set the corresponding flag at compilation:
# Compilation to AnalogDevice max durationprogram.compile_to(device, device_max_duration_ratio=1.0)program.draw(compiled = True)As anticipated, this flag will decouple time from the compilation, letting the user set a time relative to the maximum allowed by the selected device. Moreover, as a drive's amplitude/detuning can be composed by many waveforms, this feature will rescale them preserving their relative durations.
Finally, it is important to highlight that:
