LunaBench: Intermediate

LunaBench offers a comprehensive suite of adjustment and configuration possibilities. From crafting custom QUBOs and Qiskit Circuits to delving into multithreading and algorithm customization, LunaBench enables you to fine-tune your dataset solving methods to your exact specifications.

This tutorial section guides you through all the configurable options available in LunaBench, complete with simple, illustrative examples for each.

Custom Quadratic Unconstrained Binary Optimization (QUBO)

QUBO is a type of optimization problem that is particularly relevant in the field of combinatorial optimization. It's especially significant for its applications in quantum computing, specifically for quantum annealers.

If you are new to QUBOs or seek a deeper understanding, a comprehensive tutorial is available here. This resource offers valuable insights into the intricacies of QUBOs and their applications in quantum computing.

Creating a dataset of QUBOs

LunaBench already encompasses a variety of optimization problems, including the Traveling Salesperson Problem (TSP) and Binary Paint Shop Problem (BPSP). However, the world of optimization challenges is vast, with countless problems that can be effectively represented through QUBO formulations. This highlights the versatility of LunaBench in addressing a wide spectrum of complex optimization scenarios.

To construct a dataset composed of QUBOs, you can easily specify "qubo" as the problem name. Then, for each instance in your dataset, provide the corresponding QUBO matrix as its value. This straightforward method allows for the efficient assembly of datasets centered around QUBO problems.

# define the problem type as qubo
problem_name = "qubo"

# define the dataset
dataset = {
    "qubo_00": {
        problem_name: [
            [2, 1],
            [1, 2]
        ]
    },
    "qubo_01": {
        problem_name: [
            [-2, 3],
            [3, -2]
        ]
    },
    "qubo_02": {
        problem_name: [
            [2, 1, 0],
            [1, 2, 1],
            [0, 1, 2]
        ]
    },
}

Customizing the output directory

LunaBench automatically creates an output directory labeled luna_results , which includes a unique identifier for each dataset and its results. However, customization of these output directories is available to better integrate with individual workflow preferences.

For this you can simply define the output path, dataset name and the result id such that you can find your solutions in {$output_path}/{$dataset_name}/solve/{$result_id}/solutions.csv .

# define the path variables
output_path = "results_tutorial"
dataset_name = "qubo_example"
result_id = "run_00"

Configuring the algorithms

Solver performance can vary significantly with different configurations. Customizability is a key feature, allowing for the fine-tuning of solver algorithms to meet specific requirements. This is achieved through the provision of additional arguments for the selected solver, organized within a dictionary. Within this structure, the keys correspond to the algorithm names, while the values are dictionaries detailing the algorithm's configuration. For instance, it's possible to specify the optimizer for the hybrid VQE algorithm according to precise preferences, among other customizable options.

# specify the algorithms with their configurations
solve_algorithms = {
    "sa": {"n_iter": 100, "n_temp_iter": 1000, "temp_start": 100},
    "vqe": {"optimizer": "COBYLA", "maxiter": 100},
}

# define the number of runs for each algorithm
n_runs = 5

Preprocessing problem instances

Preprocessing of optimization problems simplifies and streamlines the problem before solving it, leading to reduced computational time and resource usage. It helps in identifying and removing redundant constraints, variables, and simplifying the problem's structure, making the optimization process more efficient and effective.

LunaBench also offers options for preprocessing problem instances. Similar to solving algorithms, preprocessing can be specified using either a list of algorithm names or a dictionary. The preprocessing algorithms currently supported are listed on LunaBench GitHub. To get access, please contact us here.

# specify the preprocessing algorithms
preprocessing_algorithms = ["normalize_qubo"]

Running multiple algorithms in parallel

Executing a single algorithm at a time to address an instance may not efficiently leverage the computational capabilities of the hardware. As a solution, LunaBench provides the option to concurrently run multiple algorithms through multiprocessing. You can configure the maximum number of processes to run simultaneously by adjusting the process_count argument. However, it is important to consider that the overhead associated with multiprocessing could potentially slow down performance when compared to executing tasks in a single, sequential manner. You should only use this function if you know that your hardware is suitable for multiprocessing.

# specify the maximum number of parallel running algorithms
process_count = 2

Solving the dataset

After configuring all possible arguments, the dataset can be solved by running the solve_dataset function.

from lunabench import solve_dataset

# solve the complete dataset
solved, result_id = solve_dataset(
    problem_name=problem_name,
    dataset_name=dataset_name,
    dataset=dataset,
    solve_algorithms=solve_algorithms,
    n_runs=n_runs,
    pre_algorithms=preprocessing_algorithms,
    process_count=process_count,
    result_id=result_id,
    save_path=output_path,
)

Solving optimization problems on quantum hardware

LunaBench provides the capability to execute operations on various Quantum Computing platforms, including D-Wave Systems and IBM. To solve optimization problems hybrid algorithms such as QAOA or VQE on the IBM backend, you can include the ibm_config argument accompanied by a dictionary. This configuration should specify the token key-value pair with a personal IBM token to facilitate execution on the IBM platform. Furthermore, options to customize the channel, backend, and additional settings are available, allowing for tailored execution parameters. To execute on D-Wave Quantum Hardware, it is necessary to specify your D-Wave token within the algorithm configuration. For the execution on IBM please provide the IBM token in the algorithm configuration analogously.

# specify the algorithms with their configurations
solve_algorithms = {
    "qaoa": {
        "ibm_config": {
            "channel": "ibm_quantum",
            "backend": "ibmq_qasm_simulator",
            "token": "YOUR_IBM_TOKEN",
            "shots": 512,
        }
    },
    "dwave": {"token": "YOUR_DWAVE_TOKEN"},
}

# define the number of runs for each algorithm
n_runs = 2

# define the output path
result_id = "run_01"

# specify the maximum number of parallel running algorithms
process_count = 1

# solve the complete dataset
solved, result_id = solve_dataset(
    problem_name=problem_name,
    dataset_name=dataset_name,
    dataset=dataset,
    solve_algorithms=solve_algorithms,
    n_runs=n_runs,
    pre_algorithms=preprocessing_algorithms,
    process_count=process_count,
    result_id=result_id,
    save_path=output_path,
)

Creating a dataset of Qiskit quantum circuits

In addition to QUBOs, LunaBench also facilitates the execution of Qiskit Quantum Circuits. For executing Qiskit Circuits, the term "qiskit" is utilized as the problem_name, mirroring the approach taken with custom QUBOs in LunaBench.

# define the problem type as qiskit
problem_name = "qiskit"

Similar to QUBOs, circuits can initially be constructed and then included in the dataset dictionary under the key "circuit". The formats supported include QuantumCircuit and OpenQASM 2.0.

from qiskit import QuantumRegister, ClassicalRegister, QuantumCircuit

# create qiskit circuits
circuit_zero = QuantumCircuit(2, 2)
circuit_zero.h(0)
circuit_zero.cx(0, 1)
circuit_zero.measure([0, 1], [0, 1])

qr = QuantumRegister(3, "q")
anc = QuantumRegister(1, "ancilla")
cr = ClassicalRegister(3, "c")

circuit_one = QuantumCircuit(qr, anc, cr)
circuit_one.x(anc[0])
circuit_one.h(anc[0])
circuit_one.h(qr[0:3])
circuit_one.cx(qr[0:3], anc[0])
circuit_one.h(qr[0:3])
circuit_one.barrier(qr)
circuit_one.measure(qr, cr)

# define the dataset
dataset = {
    "circuit_00": {"circuit": circuit_zero.qasm()},
    "circuit_01": {"circuit": circuit_one},
}

Executing Qiskit Quantum Circuits

The execution algorithms for the circuit dataset can be defined using the solve_algorithms dictionary, similar to the approach taken with the dataset involving QUBOs. The implemented algorithms available for use are listed on LunaBench GitHub. To get access, please contact us here.

# specify the algorithms with their configurations
solve_algorithms = {
    "aer": {"aer_backend": "qasm_simulator"},
    "ibm": {"token": "YOUR_IBM_TOKEN", "seed_simulator": 42, "shots": 512},
}

# define the path variables
dataset_name = "circuit_example"
result_id = "run_02"

# solve the complete dataset
solved, result_id = solve_dataset(
    problem_name=problem_name,
    dataset_name=dataset_name,
    dataset=dataset,
    solve_algorithms=solve_algorithms,
    n_runs=n_runs,
    process_count=process_count,
    result_id=result_id,
    save_path=output_path,
)

Executing custom algorithms and metrics

The upcoming chapter "Expert" delves into incorporating custom algorithms and utilizing custom metrics. This section offers the flexibility to not only leverage algorithms implemented within LunaBench but also facilitates a comparative analysis of personal algorithms. Additionally, custom metrics enable an in-depth evaluation of individual problems, as well as the expansion of existing optimization challenges.

Was this page helpful?