How to format and export control solutions for hardware implementation

Prepare optimized controls for hardware implementation

Boulder Opal provides flexible optimization tools to obtain robust model-based or model-free optimized controls. These controls are returned as dictionaries, making them easy to integrate into most experimental workflows. In some cases, however, the control outputs may need to be adapted. In this notebook, we demonstrate how to transform optimized controls into a hardware-ready form and export the result.

Summary workflow

1. Obtain or import optimized controls

Optimized controls can be obtained from Boulder Opal's optimization tools. In the example below we import the control generated in this user guide.

For model-based optimization, the optimization result is obtained from calculations of the following form, where the output_node_names include the controls:

optimization_result = bo.run_optimization(
    cost_node_name="infidelity",
    output_node_names=["alpha", "gamma"],
    graph=graph,
)

In this instance, the controls are extracted using optimization_result["output"]["alpha"] for the control labeled alpha. The optimized pulse is represented as a dictionary, which includes the keys values and durations and their values are 1D NumPy arrays.

For automated optimization, the controls are returned as a NumPy array with a pre-defined duration and segment_count.

2. Ensure that the sampling rate is hardware-compatible

To implement a control pulse in a hardware device, we need to make sure that the pulse segment durations match the sampling rate of the corresponding arbitrary waveform generator (AWG). This can be enforced in the optimization design, as shown in our notebook for robust single qubit gates on IBM devices. If the optimized pulse segments are coarser than the AWG time resolution (dt), you will need to subdivide the pulse into an integer number of dt, when possible, or you can filter and discretize the pulse appropriately within your optimization.

3. Format the control pulses for the target hardware

Different devices have different input format requirements. The optimized control type can be manipulated or the format transformed (for instance taking real and imaginary parts).

4. Export the controls

Finally, the controls can be saved to your preferred file type, for example JSON, CSV or pickle. The saved controls are then ready to be imported and applied on your hardware.

Example: Formatting and exporting a model-based optimized control pulse

We present a detailed example of how to export an optimized control in a format that is ready for hardware implementation.

Specifically, we consider a pulse optimized for trapped ions by following the How to optimize error-robust Mølmer–Sørensen gates for trapped ions user guide. We first load the pre-saved model-based optimization result from the boulderopal.run_optimization function, and extract the control pulse ion_drive. Next, we adapt the 3.125 µs resolution of the control pulse to match a 1 µs pulse sampling period requirement for the pulse generation hardware. Finally, we extract the real and imaginary parts of the pulse and export them to the CSV file format.

# Import the relevant packages
import csv
import jsonpickle
import numpy as np
import boulderopal as bo


def load_variable(file_name):
    """
    Load a variable from a file encoded with jsonpickle.
    """
    with open(file_name, "r+") as file:
        return jsonpickle.decode(file.read())
# Import and extract the control pulse
optimization_result = load_variable("resources/ion_optimization_result")
control_pulse = optimization_result["output"]["ion_drive"]
original_sampling_period = control_pulse["durations"][0]
print("Original sampling period (s):", original_sampling_period)

# Repeat the pulse values to match the target sampling period
target_sampling_period = 1e-6
scaling = original_sampling_period / target_sampling_period
control_pulse_values = np.repeat(control_pulse["values"], scaling)
control_pulse_duration = np.sum(control_pulse["durations"])
print(
    f"{len(control_pulse_values)} segments matches the target "
    f"{control_pulse_duration / target_sampling_period:.1f} samples for a "
    f"{control_pulse_duration * 1e6:.1f} µs pulse."
)

# Take the real and imaginary parts of the control pulse values
control_pulse_values = [np.real(control_pulse_values), np.imag(control_pulse_values)]

# Export the controls to CSV, with real and imaginary arrays on subsequent lines
save_filename = "resources/exported_pulse.csv"
with open(save_filename, "w", newline="") as f:
    writer = csv.writer(f)
    writer.writerows(control_pulse_values)

# Reload pulse data and check that it is unchanged
with open(save_filename, newline="") as file:
    data = list(csv.reader(file))
real_data = np.array(data[0], dtype=np.float64)
imag_data = np.array(data[1], dtype=np.float64)
print(
    "Pulse data is accurately reloaded:",
    np.all(real_data == control_pulse_values[0]),
    np.all(imag_data == control_pulse_values[1]),
)
Original sampling period (s): 3.125e-06
192 segments matches the target 200.0 samples for a 200.0 µs pulse.
Pulse data is accurately reloaded: True True

Was this useful?

cta background

New to Boulder Opal?

Get access to everything you need to automate and optimize quantum hardware performance at scale.