How to manage automated closed-loop hardware optimization with M-LOOP

Use external data management package for simple closed-loop optimizations

The Q-CTRL Python package contains automated closed-loop optimization tools that allow complex control optimization without requiring a complete understanding of the workings of your quantum system. These tools allow you to run optimizations incorporating input data rather than building a detailed model of all aspects of your system. However data management must be handled manually in the optimization procedure. This notebook will show how you can use the M-LOOP package to simplify management of optimization workflows.

Closed-loop optimization framework

You can use the automated closed-loop optimizers to create a closed optimization loop where the optimizer communicates with the experimental apparatus without your direct involvement. In this kind of setting, your experimental apparatus produces an initial set of results, which it sends to the optimizer. Using this information, the optimizer produces a set of improved test points that it recommends back to the experimental apparatus. The results corresponding to these test points are resent to the optimizer, and the cycle repeats itself until any of the results has a sufficiently low cost function value, or until it meets any other ending condition that you imposed. In simple cases the construction and management of the optimization loop can be handled with the open-source M-LOOP package.

Summary workflow of M-LOOP integration

1. Installation

Install the Q-CTRL Python M-LOOP package (qctrlmloop), which acts as an interface between M-LOOP and the Q-CTRL Python package.

2. Define QctrlController for use in optimization

The Q-CTRL Python M-LOOP package (which you can install with pip install qctrl-mloop) provides the QctrlController class, a controller that accepts an initial instance of the Optimizer object and then handles the subsequent calls to the experimental interface, the next steps of the automated closed-loop optimization, and the updates to the state of the Optimizer.

Using the QctrlController, you don't need to set up the optimization loop by yourself, and the optimization will run until it meets the conditions that you defined in the arguments of the controller (see the documentation of the Controller base class for a description of the options available). In this framework you can still select the optimization engine from the Q-CTRL Python package and simply pass this information to QctrlController. Note that this framework does not support experimental batching inside the optimization loop.

Worked example: Optimization over a simulated 2D landscape with M-LOOP

In practice, you would use an interface to an actual experiment to obtain the costs that correspond to each test point that the automated closed-loop optimizer requests. To keep this example simple, consider that the cost function is just a 2D parabola with a minimum at $(0,1)$, and the objective of the optimization is to find this minimum.

import numpy as np
from qctrl import Qctrl

# Start a session with the API.
qctrl = Qctrl()
import logging

# Import objects from M-LOOP and the Q-CTRL M-LOOP Python package.
from mloop.interfaces import Interface
from qctrlmloop import QctrlController

# Define the experimental interface (in this case, a parabolic cost function).
minimum = np.array([0, 1])


class CustomInterface(Interface):
    def get_next_cost_dict(self, params_dict):
        params = params_dict["params"]
        cost = sum((params - minimum) ** 2)
        return {"cost": cost}


interface = CustomInterface()

# Define initialization object for the automated closed-loop optimization.
initializer = qctrl.types.closed_loop_optimization_step.CrossEntropyInitializer(
    elite_fraction=0.2
)

# Define state object for the automated closed-loop optimization.
optimizer = qctrl.types.closed_loop_optimization_step.Optimizer(
    cross_entropy_initializer=initializer
)

# Define the controller that handles the calls to Boulder Opal.
controller = QctrlController(
    interface,
    qctrl=qctrl,
    optimizer=optimizer,
    target_cost=0.01,
    num_params=2,
    test_point_count=30,
)

# Set verbosity to the lowest possible.
# (See: https://docs.python.org/3/library/logging.html#logging-levels)
interface.log.setLevel(logging.CRITICAL)
controller.log.setLevel(logging.CRITICAL)

# Run the optimization.
controller.optimize()

# Print results.
print(f"Best cost: {controller.best_cost}")
print(f"Best parameter set: {controller.best_params}")
print(f"Minimum of the cost function: {minimum}")
INFO     M-LOOP version 3.2.1
Your task calculate_closed_loop_optimization_step has completed.

Your task calculate_closed_loop_optimization_step has completed.

Your task calculate_closed_loop_optimization_step has completed.
Best cost: 0.00870799422678118
Best parameter set: [-0.05904129  0.92773576]
Minimum of the cost function: [0 1]