Send a job to Fresnel
Fresnel is Pasqal’s state of the art neutral-atom QPU available on the cloud.
You can use the cloud SDK to send a job to Fresnel just like you did for an emulator in the previous section.
However there are a few hardware constraints to keep in mind before sending a job for execution on a real QPU. Some additional validation rules are checked on your sequence before it is scheduled:
- the channels defined in your sequence must match with channels available on the device
- your register must derive from a register layout
- the register must verify the constraints of the hardware: minimum spacing, atom count, etc.
Get the Fresnel specs
The specifications of our QPUs are accessible via the SDK which will let you build a pulser Device
object that you can use to design your pulser Sequence
.
from pulser.json.abstract_repr.deserializer import deserialize_devicefrom pasqal_cloud import SDK
project_id = "your_project_id"# Replace this value by your project_id on the Pasqal platform.username = "your_username"# Replace this value by your username or email on the Pasqal platform.
# Initialize the cloud clientsdk = SDK(username=username, project_id=project_id)
specs = sdk.get_device_specs_dict()# Build a device object to describe the specs of our "Fresnel" QPUdevice = deserialize_device(specs["FRESNEL"])
Inspect the newly build device
object, this describes all the constraints of the hardware and will help you design your sequence. Refer to the pulser documentation on devices (external)
for more details.
Build your register
You need to define both a register and a layout before proceeding. The register specify where atoms will be arranged, while the layout specifies the positioning of traps necessary to capture and structure these atoms within the register.
For details on layouts, see the Pulser documentation (external) .
Pre-calibrated layouts
The device defines a list of pre-calibrated layouts (external) . You can build your register out of one of these layouts.
This is the recommended option because it will improve the performance of the QPU
-
Option 1: Define your register using pre-calibrated layouts:
Inspect the layouts available on Fresnel and define your register from this layout. Check the pulser documentation for more information on how to do that.
Example:
# let's say we are interested in the first layout available on the devicelayout = device.pre_calibrated_layouts[0]# Select traps 1, 3 and 5 of the layout to define the registertraps = [1,3,5]register = layout.define_register(*traps)# You can draw the resulting register to verify it matches your expectationsregister.draw()
Arbitrary layouts
If pre-calibrated layouts do not satisfy the requirements of your experiment, you can create a custom layout.
For any given arbitrary register, a neutral-atom QPU will place traps according to the layout, which must then undergo calibration. Since each calibration requires time, it is generally advisable to reuse an existing calibrated layout whenever possible
-
Option 2: Automatically derive a layout from your defined register
This option allows for the automatic generation of a layout based on a specified register. However, for large registers, this process may yield sub-optimal solutions due to limitations in the algorithm used to create the layout.
qubits = {"q0": (0, 0),"q1": (0, 10),"q2": (8, 2),"q3": (1, 15),"q4": (-10, -3),"q5": (-8, 5),}register = Register(qubits).with_automatic_layout(device) -
Option 3: Define your register using a manually defined layout
- Create an arbitrary layout with 20 traps randomly positioned in a 2D plane
import numpy as np# Generating random coordinatesnp.random.seed(301122) # Keeps results consistent between runstraps = np.random.randint(0, 30, size=(20, 2))traps = traps - np.mean(traps, axis=0)# Creating the layoutlayout = RegisterLayout(traps, slug="random_20")- Define your register with specific trap IDs
trap_ids = [4, 8, 19, 0]reg1 = layout.define_register(*trap_ids, qubit_ids=["a", "b", "c", "d"])reg1.draw()
Design your sequence
Once you have defined your register you can now create a Sequence
object using the Fresnel device and register. Refer to the Pulser documentation (external)
to design your sequence.
# Assuming `device` is the pulser Device object# And `register` is the register defined from one of the layout of the device# Build a pulser sequenceseq = Sequence(register, device)# Now design your sequence by defining variables, adding pulses, ...
Send the job for execution
Once you have designed your sequence, you can serialize it and send it for execution.
Before sending a job to Fresnel you can try validating your sequence by targeting an emulator backend first. You can do this by targeting our device EMU_FRESNEL
within the SDK, your sequence will be run on an emulator but is validated server-side using the same criteria as a job scheduled for Fresnel.
from pasqal_cloud import SDK, EmulatorTypesdk = SDK( ...)jobs = [{"runs": 100}]batch = sdk.create_batch( seq.to_abstract_repr(), jobs, emulator=EmulatorType.EMU_FRESNEL)
If your batch is successful after this, it should be ready for execution on Fresnel.
# Create a batch of 1 job with 100 runsjobs = [{"runs": 100}]
# Simply omit the `emulator` arguments to target Fresnelfresnel_batch = sdk.create_batch(seq.to_abstract_repr(), jobs)