854 lines
28 KiB
Plaintext
854 lines
28 KiB
Plaintext
{
|
|
"cells": [
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "b6d1e3ec",
|
|
"metadata": {},
|
|
"source": [
|
|
"{/* cspell:ignore lambdify ILOG histtype stepfilled */}\n",
|
|
"\n",
|
|
"# Higher-order binary optimization with Q-CTRL's Optimization Solver"
|
|
]
|
|
},
|
|
{
|
|
"attachments": {},
|
|
"cell_type": "markdown",
|
|
"id": "a6f69b77",
|
|
"metadata": {},
|
|
"source": [
|
|
"*Usage estimate: 24 minutes on ibm\\_fez. (NOTE: This is an estimate only. Your runtime may vary.)*"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "8bf80006",
|
|
"metadata": {},
|
|
"source": [
|
|
"## Background\n",
|
|
"\n",
|
|
"This tutorial demonstrates how to solve a higher-order binary optimization (HOBO) problem using the [Optimization Solver, a Qiskit Function by Q-CTRL Fire Opal](https://quantum.ibm.com/functions?id=a8a2b0b6-486a-41b5-8ea4-ada3b108d6b6). The example demonstrated in this tutorial is an optimization problem designed to find the ground-state energy of a random-bond 156-qubit Ising model possessing cubic terms. The Optimization Solver can be used for general optimization problems that can be defined as an objective function.\n",
|
|
"\n",
|
|
"The Optimization fully automates the hardware-aware implementation steps of solving optimization problems on quantum hardware, and by leveraging [Performance Management](https://quantum.ibm.com/functions?id=c750648c-ba44-4137-8c34-4140a3aaa7a9) for the quantum execution, it achieves accurate solutions at utility scale. For a detailed summary of the full Optimization Solver workflow and benchmarking results, refer to [the published manuscript](https://arxiv.org/abs/2406.01743).\n",
|
|
"\n",
|
|
"This tutorial walks through the following steps:\n",
|
|
"\n",
|
|
"1. Define the problem as an objective function\n",
|
|
"2. Run the hybrid algorithm using the Fire Opal Optimization Solver\n",
|
|
"3. Evaluate results"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "55b94021",
|
|
"metadata": {},
|
|
"source": [
|
|
"## Requirements\n",
|
|
"\n",
|
|
"Before starting this tutorial, ensure that you have the following installed:\n",
|
|
"\n",
|
|
"* Qiskit Functions (`pip install qiskit-ibm-catalog`)\n",
|
|
"* SymPy (`pip install sympy`)\n",
|
|
"\n",
|
|
"You will also need to get access to the Optimization Solver function. [Fill out the form](https://quantum.ibm.com/functions?id=a8a2b0b6-486a-41b5-8ea4-ada3b108d6b6) to request access."
|
|
]
|
|
},
|
|
{
|
|
"attachments": {},
|
|
"cell_type": "markdown",
|
|
"id": "7db2e559",
|
|
"metadata": {},
|
|
"source": [
|
|
"## Setup\n",
|
|
"\n",
|
|
"First, import the required packages and tools."
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 1,
|
|
"id": "c262cb27",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"# Qiskit Functions Catalog\n",
|
|
"from qiskit_ibm_catalog import QiskitFunctionsCatalog\n",
|
|
"\n",
|
|
"# SymPy tools for constructing objective function\n",
|
|
"from sympy import Poly\n",
|
|
"from sympy import symbols, srepr\n",
|
|
"\n",
|
|
"# Tools for plotting and evaluating results\n",
|
|
"import numpy as np\n",
|
|
"import matplotlib.pyplot as plt\n",
|
|
"from sympy import lambdify"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "df157bba",
|
|
"metadata": {},
|
|
"source": [
|
|
"Define your [IBM Quantum™ Platform](http://quantum.ibm.com/) credentials, which will be used throughout the tutorial to authenticate to Qiskit Runtime and Qiskit Functions."
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "b92bd67d",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"# Credentials\n",
|
|
"token = \"<YOUR_IQP_API_TOKEN>\"\n",
|
|
"hub = \"<YOUR_IQP_HUB>\"\n",
|
|
"group = \"<YOUR_IQP_GROUP>\"\n",
|
|
"project = \"<YOUR_IQP_PROJECT>\""
|
|
]
|
|
},
|
|
{
|
|
"attachments": {},
|
|
"cell_type": "markdown",
|
|
"id": "988ee237",
|
|
"metadata": {},
|
|
"source": [
|
|
"## Step 1: Define the problem as an objective function"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "6c9bffae",
|
|
"metadata": {},
|
|
"source": [
|
|
"The Optimization Solver accepts either an objective function or a graph as input. In this tutorial, the Ising spin glass minimization problem is defined as an objective function, and it has been tailored for the heavy-hex topology of IBM devices.\n",
|
|
"\n",
|
|
"Because this objective function contains cubic, quadratic, and linear terms, it falls into the HOBO class of problems, known to be considerably more complicated to solve than conventional quadratic unconstrained binary optimization (QUBO) problems.\n",
|
|
"\n",
|
|
"For detailed discussion of the construction of the problem definition and previous results obtained from the Optimization Solver refer to [this technical manuscript](https://arxiv.org/abs/2406.01743). The problem was originally defined and evaluated as part of a [paper published by Los Alamos National Laboratory](https://arxiv.org/abs/2312.00997), and it has been adapted to leverage the full device width of the 156-qubit IBM Quantum Heron processors."
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 42,
|
|
"id": "0ad66539",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"qubit_count = 156\n",
|
|
"\n",
|
|
"# Create symbolic variables to represent qubits\n",
|
|
"x = symbols([f\"x[{i}]\" for i in range(qubit_count)])\n",
|
|
"\n",
|
|
"# # Define a polynomial representing a spin glass model\n",
|
|
"spin_glass_poly = Poly(\n",
|
|
" -4 * x[0] * x[1]\n",
|
|
" - 8 * x[1] * x[2] * x[3]\n",
|
|
" + 8 * x[1] * x[2]\n",
|
|
" + 4 * x[1] * x[3]\n",
|
|
" - 4 * x[2]\n",
|
|
" + 8 * x[3] * x[4] * x[5]\n",
|
|
" - 4 * x[3] * x[5]\n",
|
|
" - 8 * x[3] * x[16] * x[23]\n",
|
|
" + 4 * x[3] * x[23]\n",
|
|
" - 2 * x[3]\n",
|
|
" - 4 * x[4]\n",
|
|
" - 8 * x[5] * x[6] * x[7]\n",
|
|
" + 8 * x[5] * x[6]\n",
|
|
" + 4 * x[5] * x[7]\n",
|
|
" - 2 * x[5]\n",
|
|
" + 8 * x[6] * x[7]\n",
|
|
" - 4 * x[6]\n",
|
|
" - 8 * x[7] * x[8] * x[9]\n",
|
|
" + 4 * x[7] * x[9]\n",
|
|
" - 8 * x[7] * x[17] * x[27]\n",
|
|
" + 4 * x[7] * x[27]\n",
|
|
" - 6 * x[7]\n",
|
|
" + 8 * x[8] * x[9]\n",
|
|
" + 8 * x[9] * x[10] * x[11]\n",
|
|
" - 4 * x[9] * x[11]\n",
|
|
" - 2 * x[9]\n",
|
|
" - 8 * x[10] * x[11]\n",
|
|
" + 4 * x[10]\n",
|
|
" - 8 * x[11] * x[12] * x[13]\n",
|
|
" + 4 * x[11] * x[13]\n",
|
|
" - 8 * x[11] * x[18] * x[31]\n",
|
|
" + 8 * x[11] * x[18]\n",
|
|
" + 4 * x[11] * x[31]\n",
|
|
" - 2 * x[11]\n",
|
|
" + 8 * x[12] * x[13]\n",
|
|
" + 8 * x[13] * x[14] * x[15]\n",
|
|
" - 4 * x[13] * x[15]\n",
|
|
" - 2 * x[13]\n",
|
|
" - 8 * x[14] * x[15]\n",
|
|
" + 4 * x[14]\n",
|
|
" - 8 * x[15] * x[19] * x[35]\n",
|
|
" + 8 * x[15] * x[19]\n",
|
|
" + 4 * x[15] * x[35]\n",
|
|
" - 2 * x[15]\n",
|
|
" + 8 * x[16] * x[23]\n",
|
|
" + 8 * x[17] * x[27]\n",
|
|
" - 4 * x[17]\n",
|
|
" + 8 * x[18] * x[31]\n",
|
|
" - 8 * x[18]\n",
|
|
" + 8 * x[19] * x[35]\n",
|
|
" - 8 * x[19]\n",
|
|
" + 4 * x[20] * x[21]\n",
|
|
" - 4 * x[20]\n",
|
|
" - 8 * x[21] * x[22] * x[23]\n",
|
|
" + 8 * x[21] * x[22]\n",
|
|
" + 4 * x[21] * x[23]\n",
|
|
" - 8 * x[21] * x[36] * x[41]\n",
|
|
" + 4 * x[21] * x[41]\n",
|
|
" - 4 * x[21]\n",
|
|
" + 8 * x[22] * x[23]\n",
|
|
" - 8 * x[22]\n",
|
|
" + 8 * x[23] * x[24] * x[25]\n",
|
|
" - 4 * x[23] * x[25]\n",
|
|
" - 10 * x[23]\n",
|
|
" - 8 * x[24] * x[25]\n",
|
|
" + 8 * x[25] * x[26] * x[27]\n",
|
|
" - 8 * x[25] * x[26]\n",
|
|
" - 4 * x[25] * x[27]\n",
|
|
" + 8 * x[25] * x[37] * x[45]\n",
|
|
" - 8 * x[25] * x[37]\n",
|
|
" - 4 * x[25] * x[45]\n",
|
|
" + 14 * x[25]\n",
|
|
" - 8 * x[26] * x[27]\n",
|
|
" + 4 * x[26]\n",
|
|
" + 8 * x[27] * x[28] * x[29]\n",
|
|
" - 4 * x[27] * x[29]\n",
|
|
" - 2 * x[27]\n",
|
|
" - 8 * x[28] * x[29]\n",
|
|
" - 8 * x[29] * x[30] * x[31]\n",
|
|
" + 4 * x[29] * x[31]\n",
|
|
" + 8 * x[29] * x[38] * x[49]\n",
|
|
" - 8 * x[29] * x[38]\n",
|
|
" - 4 * x[29] * x[49]\n",
|
|
" + 6 * x[29]\n",
|
|
" + 8 * x[30] * x[31]\n",
|
|
" - 4 * x[30]\n",
|
|
" - 8 * x[31] * x[32] * x[33]\n",
|
|
" + 4 * x[31] * x[33]\n",
|
|
" - 6 * x[31]\n",
|
|
" + 8 * x[33] * x[34] * x[35]\n",
|
|
" - 4 * x[33] * x[35]\n",
|
|
" - 8 * x[33] * x[39] * x[53]\n",
|
|
" + 8 * x[33] * x[39]\n",
|
|
" + 4 * x[33] * x[53]\n",
|
|
" - 6 * x[33]\n",
|
|
" - 8 * x[34] * x[35]\n",
|
|
" + 2 * x[35]\n",
|
|
" + 8 * x[36] * x[41]\n",
|
|
" - 8 * x[37] * x[45]\n",
|
|
" + 4 * x[37]\n",
|
|
" - 8 * x[38] * x[49]\n",
|
|
" + 4 * x[38]\n",
|
|
" + 4 * x[40] * x[41]\n",
|
|
" - 8 * x[41] * x[42] * x[43]\n",
|
|
" + 4 * x[41] * x[43]\n",
|
|
" - 8 * x[41]\n",
|
|
" + 8 * x[42] * x[43]\n",
|
|
" - 4 * x[42]\n",
|
|
" - 8 * x[43] * x[44] * x[45]\n",
|
|
" + 8 * x[43] * x[44]\n",
|
|
" + 4 * x[43] * x[45]\n",
|
|
" - 8 * x[43] * x[56] * x[63]\n",
|
|
" + 4 * x[43] * x[63]\n",
|
|
" - 6 * x[43]\n",
|
|
" - 4 * x[44]\n",
|
|
" - 8 * x[45] * x[46] * x[47]\n",
|
|
" + 4 * x[45] * x[47]\n",
|
|
" + 2 * x[45]\n",
|
|
" + 4 * x[46]\n",
|
|
" - 8 * x[47] * x[48] * x[49]\n",
|
|
" + 8 * x[47] * x[48]\n",
|
|
" + 4 * x[47] * x[49]\n",
|
|
" - 8 * x[47] * x[57] * x[67]\n",
|
|
" + 4 * x[47] * x[67]\n",
|
|
" - 2 * x[47]\n",
|
|
" - 4 * x[48]\n",
|
|
" - 8 * x[49] * x[50] * x[51]\n",
|
|
" + 8 * x[49] * x[50]\n",
|
|
" + 4 * x[49] * x[51]\n",
|
|
" - 2 * x[49]\n",
|
|
" + 8 * x[50] * x[51]\n",
|
|
" - 8 * x[50]\n",
|
|
" - 8 * x[51] * x[52] * x[53]\n",
|
|
" + 8 * x[51] * x[52]\n",
|
|
" + 4 * x[51] * x[53]\n",
|
|
" - 8 * x[51] * x[58] * x[71]\n",
|
|
" + 4 * x[51] * x[71]\n",
|
|
" - 6 * x[51]\n",
|
|
" + 8 * x[52] * x[53]\n",
|
|
" - 8 * x[52]\n",
|
|
" + 8 * x[53] * x[54] * x[55]\n",
|
|
" - 8 * x[53] * x[54]\n",
|
|
" - 4 * x[53] * x[55]\n",
|
|
" - 2 * x[53]\n",
|
|
" + 4 * x[54]\n",
|
|
" - 8 * x[55] * x[59] * x[75]\n",
|
|
" + 4 * x[55] * x[75]\n",
|
|
" - 2 * x[55]\n",
|
|
" + 8 * x[56] * x[63]\n",
|
|
" + 8 * x[57] * x[67]\n",
|
|
" - 4 * x[57]\n",
|
|
" + 8 * x[58] * x[71]\n",
|
|
" + 8 * x[59] * x[75]\n",
|
|
" - 4 * x[59]\n",
|
|
" + 4 * x[60] * x[61]\n",
|
|
" + 8 * x[61] * x[62] * x[63]\n",
|
|
" - 4 * x[61] * x[63]\n",
|
|
" + 8 * x[61] * x[76] * x[81]\n",
|
|
" - 8 * x[61] * x[76]\n",
|
|
" - 4 * x[61] * x[81]\n",
|
|
" - 8 * x[63] * x[64] * x[65]\n",
|
|
" + 8 * x[63] * x[64]\n",
|
|
" + 4 * x[63] * x[65]\n",
|
|
" - 6 * x[63]\n",
|
|
" + 8 * x[65] * x[66] * x[67]\n",
|
|
" - 8 * x[65] * x[66]\n",
|
|
" - 4 * x[65] * x[67]\n",
|
|
" - 8 * x[65] * x[77] * x[85]\n",
|
|
" + 4 * x[65] * x[85]\n",
|
|
" + 2 * x[65]\n",
|
|
" + 4 * x[66]\n",
|
|
" - 8 * x[67] * x[68] * x[69]\n",
|
|
" + 8 * x[67] * x[68]\n",
|
|
" + 4 * x[67] * x[69]\n",
|
|
" - 10 * x[67]\n",
|
|
" + 8 * x[68] * x[69]\n",
|
|
" - 4 * x[68]\n",
|
|
" + 8 * x[69] * x[70] * x[71]\n",
|
|
" - 4 * x[69] * x[71]\n",
|
|
" - 8 * x[69] * x[78] * x[89]\n",
|
|
" + 4 * x[69] * x[89]\n",
|
|
" - 6 * x[69]\n",
|
|
" + 8 * x[71] * x[72] * x[73]\n",
|
|
" - 8 * x[71] * x[72]\n",
|
|
" - 4 * x[71] * x[73]\n",
|
|
" + 2 * x[71]\n",
|
|
" - 8 * x[72] * x[73]\n",
|
|
" + 8 * x[72]\n",
|
|
" - 8 * x[73] * x[74] * x[75]\n",
|
|
" + 8 * x[73] * x[74]\n",
|
|
" + 4 * x[73] * x[75]\n",
|
|
" - 8 * x[73] * x[79] * x[93]\n",
|
|
" + 8 * x[73] * x[79]\n",
|
|
" + 4 * x[73] * x[93]\n",
|
|
" - 6 * x[73]\n",
|
|
" + 8 * x[74] * x[75]\n",
|
|
" - 4 * x[74]\n",
|
|
" - 10 * x[75]\n",
|
|
" + 4 * x[76]\n",
|
|
" + 8 * x[78] * x[89]\n",
|
|
" - 4 * x[78]\n",
|
|
" - 4 * x[79]\n",
|
|
" - 4 * x[80] * x[81]\n",
|
|
" + 4 * x[80]\n",
|
|
" - 8 * x[81] * x[82] * x[83]\n",
|
|
" + 8 * x[81] * x[82]\n",
|
|
" + 4 * x[81] * x[83]\n",
|
|
" + 8 * x[82] * x[83]\n",
|
|
" - 8 * x[82]\n",
|
|
" - 8 * x[83] * x[84] * x[85]\n",
|
|
" + 4 * x[83] * x[85]\n",
|
|
" - 8 * x[83] * x[96] * x[103]\n",
|
|
" + 4 * x[83] * x[103]\n",
|
|
" - 2 * x[83]\n",
|
|
" - 8 * x[85] * x[86] * x[87]\n",
|
|
" + 8 * x[85] * x[86]\n",
|
|
" + 4 * x[85] * x[87]\n",
|
|
" - 6 * x[85]\n",
|
|
" + 8 * x[86] * x[87]\n",
|
|
" - 4 * x[86]\n",
|
|
" - 8 * x[87] * x[88] * x[89]\n",
|
|
" + 4 * x[87] * x[89]\n",
|
|
" + 8 * x[87] * x[97] * x[107]\n",
|
|
" - 8 * x[87] * x[97]\n",
|
|
" - 4 * x[87] * x[107]\n",
|
|
" + 2 * x[87]\n",
|
|
" + 4 * x[88]\n",
|
|
" - 8 * x[89] * x[90] * x[91]\n",
|
|
" + 8 * x[89] * x[90]\n",
|
|
" + 4 * x[89] * x[91]\n",
|
|
" - 10 * x[89]\n",
|
|
" + 8 * x[90] * x[91]\n",
|
|
" - 8 * x[90]\n",
|
|
" - 8 * x[91] * x[92] * x[93]\n",
|
|
" + 4 * x[91] * x[93]\n",
|
|
" - 8 * x[91] * x[98] * x[111]\n",
|
|
" + 8 * x[91] * x[98]\n",
|
|
" + 4 * x[91] * x[111]\n",
|
|
" - 10 * x[91]\n",
|
|
" + 8 * x[92] * x[93]\n",
|
|
" - 4 * x[92]\n",
|
|
" - 8 * x[93] * x[94] * x[95]\n",
|
|
" + 4 * x[93] * x[95]\n",
|
|
" - 6 * x[93]\n",
|
|
" + 8 * x[95] * x[99] * x[115]\n",
|
|
" - 8 * x[95] * x[99]\n",
|
|
" - 4 * x[95] * x[115]\n",
|
|
" + 2 * x[95]\n",
|
|
" + 4 * x[96]\n",
|
|
" - 8 * x[97] * x[107]\n",
|
|
" + 4 * x[97]\n",
|
|
" - 4 * x[98]\n",
|
|
" - 8 * x[99] * x[115]\n",
|
|
" + 4 * x[99]\n",
|
|
" - 4 * x[100] * x[101]\n",
|
|
" + 8 * x[101] * x[102] * x[103]\n",
|
|
" - 8 * x[101] * x[102]\n",
|
|
" - 4 * x[101] * x[103]\n",
|
|
" - 8 * x[101] * x[116] * x[121]\n",
|
|
" + 8 * x[101] * x[116]\n",
|
|
" + 4 * x[101] * x[121]\n",
|
|
" + 4 * x[101]\n",
|
|
" - 8 * x[103] * x[104] * x[105]\n",
|
|
" + 4 * x[103] * x[105]\n",
|
|
" + 2 * x[103]\n",
|
|
" + 8 * x[105] * x[106] * x[107]\n",
|
|
" - 4 * x[105] * x[107]\n",
|
|
" - 8 * x[105] * x[117] * x[125]\n",
|
|
" + 4 * x[105] * x[125]\n",
|
|
" + 2 * x[105]\n",
|
|
" - 8 * x[106] * x[107]\n",
|
|
" + 4 * x[106]\n",
|
|
" + 8 * x[107] * x[108] * x[109]\n",
|
|
" - 4 * x[107] * x[109]\n",
|
|
" + 6 * x[107]\n",
|
|
" - 4 * x[108]\n",
|
|
" + 8 * x[109] * x[110] * x[111]\n",
|
|
" - 4 * x[109] * x[111]\n",
|
|
" - 8 * x[109] * x[118] * x[129]\n",
|
|
" + 4 * x[109] * x[129]\n",
|
|
" + 2 * x[109]\n",
|
|
" - 8 * x[110] * x[111]\n",
|
|
" + 4 * x[110]\n",
|
|
" - 8 * x[111] * x[112] * x[113]\n",
|
|
" + 8 * x[111] * x[112]\n",
|
|
" + 4 * x[111] * x[113]\n",
|
|
" + 2 * x[111]\n",
|
|
" + 8 * x[112] * x[113]\n",
|
|
" - 8 * x[112]\n",
|
|
" - 8 * x[113] * x[114] * x[115]\n",
|
|
" + 4 * x[113] * x[115]\n",
|
|
" - 8 * x[113] * x[119] * x[133]\n",
|
|
" + 4 * x[113] * x[133]\n",
|
|
" - 2 * x[113]\n",
|
|
" + 6 * x[115]\n",
|
|
" - 4 * x[116]\n",
|
|
" + 4 * x[118]\n",
|
|
" + 4 * x[119]\n",
|
|
" + 4 * x[120] * x[121]\n",
|
|
" - 8 * x[121] * x[122] * x[123]\n",
|
|
" + 4 * x[121] * x[123]\n",
|
|
" - 4 * x[121]\n",
|
|
" + 4 * x[122]\n",
|
|
" - 8 * x[123] * x[124] * x[125]\n",
|
|
" + 4 * x[123] * x[125]\n",
|
|
" - 8 * x[123] * x[136] * x[143]\n",
|
|
" + 4 * x[123] * x[143]\n",
|
|
" - 2 * x[123]\n",
|
|
" + 8 * x[124] * x[125]\n",
|
|
" - 4 * x[124]\n",
|
|
" + 8 * x[125] * x[126] * x[127]\n",
|
|
" - 8 * x[125] * x[126]\n",
|
|
" - 4 * x[125] * x[127]\n",
|
|
" + 2 * x[125]\n",
|
|
" - 8 * x[127] * x[128] * x[129]\n",
|
|
" + 8 * x[127] * x[128]\n",
|
|
" + 4 * x[127] * x[129]\n",
|
|
" + 8 * x[127] * x[137] * x[147]\n",
|
|
" - 8 * x[127] * x[137]\n",
|
|
" - 4 * x[127] * x[147]\n",
|
|
" - 2 * x[127]\n",
|
|
" + 8 * x[129] * x[130] * x[131]\n",
|
|
" - 4 * x[129] * x[131]\n",
|
|
" + 2 * x[129]\n",
|
|
" - 4 * x[130]\n",
|
|
" - 8 * x[131] * x[132] * x[133]\n",
|
|
" + 4 * x[131] * x[133]\n",
|
|
" - 8 * x[131] * x[138] * x[151]\n",
|
|
" + 4 * x[131] * x[151]\n",
|
|
" - 2 * x[131]\n",
|
|
" + 8 * x[133] * x[134] * x[135]\n",
|
|
" - 4 * x[133] * x[135]\n",
|
|
" + 2 * x[133]\n",
|
|
" - 8 * x[134] * x[135]\n",
|
|
" + 4 * x[134]\n",
|
|
" - 8 * x[135] * x[139] * x[155]\n",
|
|
" + 8 * x[135] * x[139]\n",
|
|
" + 4 * x[135] * x[155]\n",
|
|
" + 2 * x[135]\n",
|
|
" + 8 * x[136] * x[143]\n",
|
|
" - 4 * x[136]\n",
|
|
" + 4 * x[138]\n",
|
|
" + 8 * x[139] * x[155]\n",
|
|
" - 4 * x[139]\n",
|
|
" - 4 * x[140] * x[141]\n",
|
|
" - 8 * x[141] * x[142] * x[143]\n",
|
|
" + 8 * x[141] * x[142]\n",
|
|
" + 4 * x[141] * x[143]\n",
|
|
" + 8 * x[142] * x[143]\n",
|
|
" - 8 * x[142]\n",
|
|
" - 8 * x[143] * x[144] * x[145]\n",
|
|
" + 8 * x[143] * x[144]\n",
|
|
" + 4 * x[143] * x[145]\n",
|
|
" - 14 * x[143]\n",
|
|
" + 8 * x[144] * x[145]\n",
|
|
" - 8 * x[144]\n",
|
|
" - 8 * x[145] * x[146] * x[147]\n",
|
|
" + 8 * x[145] * x[146]\n",
|
|
" + 4 * x[145] * x[147]\n",
|
|
" - 6 * x[145]\n",
|
|
" + 8 * x[146] * x[147]\n",
|
|
" - 4 * x[146]\n",
|
|
" - 8 * x[147] * x[148] * x[149]\n",
|
|
" + 8 * x[147] * x[148]\n",
|
|
" + 4 * x[147] * x[149]\n",
|
|
" - 6 * x[147]\n",
|
|
" - 4 * x[148]\n",
|
|
" - 8 * x[149] * x[150] * x[151]\n",
|
|
" + 8 * x[149] * x[150]\n",
|
|
" + 4 * x[149] * x[151]\n",
|
|
" - 6 * x[149]\n",
|
|
" + 8 * x[151] * x[152] * x[153]\n",
|
|
" - 4 * x[151] * x[153]\n",
|
|
" + 2 * x[151]\n",
|
|
" + 8 * x[153] * x[154] * x[155]\n",
|
|
" - 8 * x[153] * x[154]\n",
|
|
" - 4 * x[153] * x[155]\n",
|
|
" + 2 * x[153]\n",
|
|
" - 8 * x[154] * x[155]\n",
|
|
" + 4 * x[154]\n",
|
|
" - 2 * x[155]\n",
|
|
" + 46,\n",
|
|
" x,\n",
|
|
" domain=\"ZZ\",\n",
|
|
")"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "ac6f36e3",
|
|
"metadata": {},
|
|
"source": [
|
|
"## Step 2: Run the hybrid algorithm using the Fire Opal Optimization Solver"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "13ba6d0c",
|
|
"metadata": {},
|
|
"source": [
|
|
"Now use the Optimization Solver Qiskit Function to run the algorithm. Behind the scenes, the Optimization Solver takes care of mapping the problem to a hybrid quantum algorithm, running the quantum circuits with error suppression, and performing the classical optimization."
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 9,
|
|
"id": "bd38bb1e",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"# Authenticate to the Qiskit Functions Catalog\n",
|
|
"catalog = QiskitFunctionsCatalog(token=token)\n",
|
|
"\n",
|
|
"# Load the function\n",
|
|
"solver = catalog.load(\"q-ctrl/optimization_solver\")"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "12cfe6f5",
|
|
"metadata": {},
|
|
"source": [
|
|
"Check to ensure that the chosen device has at least 156 qubits."
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "a27adab7",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"# Specify the target backend name\n",
|
|
"backend_name = \"<CHOOSE_A_BACKEND>\""
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "ffbe9f79",
|
|
"metadata": {},
|
|
"source": [
|
|
"The Solver accepts a string representation of the objective function."
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 43,
|
|
"id": "1834cb22",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"# Convert the objective function to string format\n",
|
|
"spin_glass_poly_as_str = srepr(spin_glass_poly)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "98213fe9",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"# Run the problem\n",
|
|
"spin_glass_job = solver.run(\n",
|
|
" problem=spin_glass_poly_as_str,\n",
|
|
" instance=hub + \"/\" + group + \"/\" + project,\n",
|
|
" run_options={\"backend_name\": backend_name},\n",
|
|
")"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "d25caa83",
|
|
"metadata": {},
|
|
"source": [
|
|
"You can use the familiar [Qiskit Serverless APIs](/docs/guides/serverless) to check your Qiskit Function workload's status:"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "77a8ded0",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"# Get job status\n",
|
|
"spin_glass_job.status()"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "7cd96271",
|
|
"metadata": {},
|
|
"source": [
|
|
"The Solver returns a dictionary with the solution and associated metadata, such as the solution bitstring, number of iterations, and mapping of variables to bitstring. For a full definition of the Solver's inputs and outputs, check out the [documentation]()."
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "bd8bd878",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"# Poll for results\n",
|
|
"result = spin_glass_job.result()"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 54,
|
|
"id": "2bddbcbc",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"# Get the final bitstring distribution and set the number of shots\n",
|
|
"distribution = result[\"final_bitstring_distribution\"]"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "50b94af2",
|
|
"metadata": {},
|
|
"source": [
|
|
"## Step 3: Evaluate results"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 31,
|
|
"id": "f6f6e93a",
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"name": "stdout",
|
|
"output_type": "stream",
|
|
"text": [
|
|
"Minimum ground state energy: -242.0\n"
|
|
]
|
|
}
|
|
],
|
|
"source": [
|
|
"# Get the solution ground state energy\n",
|
|
"print(f\"Minimum ground state energy: {result[\"solution_bitstring_cost\"]}\")"
|
|
]
|
|
},
|
|
{
|
|
"attachments": {},
|
|
"cell_type": "markdown",
|
|
"id": "733431ad",
|
|
"metadata": {},
|
|
"source": [
|
|
"The Solver found the correct solution, which was validated using classical optimization software. The complexity of this utility-scale problem requires an advanced optimization software to be solved classically, such as [IBM ILOG CPLEX Optimization Studio (CPLEX)](https://www.ibm.com/products/ilog-cplex-optimization-studio) or [Gurobi Optimization](https://www.gurobi.com/)."
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "40406a33",
|
|
"metadata": {},
|
|
"source": [
|
|
"As a visual analysis of the quality of results, you can plot the results by calculating the cost values from the bitstrings and their probabilities. For comparison, plot the results alongside a distribution of randomly sampled bitstrings, which is equivalent to a \"brute-force\" classical solution. If the algorithm consistently finds lower costs, it suggests the quantum algorithm is effectively solving the optimization problem."
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 58,
|
|
"id": "a481c257",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"def plot_cost_histogram(\n",
|
|
" costs, probabilities, distribution, qubit_count, bitstring_cost\n",
|
|
"):\n",
|
|
" \"\"\"Plots a histogram comparing the cost distributions of Q-CTRL Solver and random sampling.\"\"\"\n",
|
|
"\n",
|
|
" # Set figure DPI for higher resolution and font size for labels\n",
|
|
" plt.rcParams[\"figure.dpi\"] = 300\n",
|
|
" plt.rcParams.update({\"font.size\": 6}) # Set default font size to 6\n",
|
|
"\n",
|
|
" # Define labels and colors for the plot\n",
|
|
" labels = [\"Q-CTRL Solver\", \"Random Sampling\"]\n",
|
|
" colors = [\"#680CE9\", \"#E04542\"]\n",
|
|
"\n",
|
|
" # Calculate total shots (total number of bitstrings in the distribution)\n",
|
|
" shots = sum(distribution.values())\n",
|
|
"\n",
|
|
" # Generate random bitstrings for comparison (random sampling)\n",
|
|
" rng = np.random.default_rng(seed=0)\n",
|
|
" random_array = rng.integers(\n",
|
|
" 0, 2, size=(shots, qubit_count)\n",
|
|
" ) # Generate random bitstrings (0 or 1 for each qubit)\n",
|
|
" random_bitstrings = [\"\".join(row.astype(str)) for row in random_array]\n",
|
|
"\n",
|
|
" # Compute the cost for each random bitstring\n",
|
|
" random_costs = [bitstring_cost(k) for k in random_bitstrings]\n",
|
|
"\n",
|
|
" # Set uniform probabilities for the random sampling\n",
|
|
" random_probabilities = (\n",
|
|
" np.ones(shape=(shots,)) / shots\n",
|
|
" ) # Equal probability for each random bitstring\n",
|
|
"\n",
|
|
" # Find the minimum and maximum costs for binning the histogram\n",
|
|
" min_cost = np.min(costs)\n",
|
|
" max_cost = np.max(random_costs)\n",
|
|
"\n",
|
|
" # Create a histogram plot with a smaller figure size (4x2 inches)\n",
|
|
" fig, ax = plt.subplots(nrows=1, ncols=1, figsize=(4, 2))\n",
|
|
"\n",
|
|
" # Plot histograms for the Q-CTRL solver and random sampling costs\n",
|
|
" _, _, _ = ax.hist(\n",
|
|
" [costs, random_costs], # Data for the two histograms\n",
|
|
" np.arange(min_cost, max_cost, 2), # Bins for the histogram\n",
|
|
" weights=[\n",
|
|
" probabilities,\n",
|
|
" random_probabilities,\n",
|
|
" ], # Probabilities for each data set\n",
|
|
" label=labels, # Labels for the legend\n",
|
|
" color=colors, # Colors for each histogram\n",
|
|
" histtype=\"stepfilled\", # Filled step histogram\n",
|
|
" align=\"mid\", # Align bars to the bin center\n",
|
|
" alpha=0.8, # Transparency\n",
|
|
" )\n",
|
|
"\n",
|
|
" # Set the x and y labels for the plot\n",
|
|
" ax.set_xlabel(\"Cost\")\n",
|
|
" ax.set_ylabel(\"Probability\")\n",
|
|
"\n",
|
|
" # Add the legend to the plot\n",
|
|
" ax.legend()\n",
|
|
"\n",
|
|
" # Show the plot\n",
|
|
" plt.show()"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 59,
|
|
"id": "a2fe3966",
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"data": {
|
|
"text/plain": [
|
|
"<Image src=\"/docs/images/tutorials/solve-higher-order-binary-optimization-problems-with-q-ctrls-optimization-solver/extracted-outputs/a2fe3966-0.avif\" alt=\"Output of the previous code cell\" />"
|
|
]
|
|
},
|
|
"metadata": {},
|
|
"output_type": "display_data"
|
|
}
|
|
],
|
|
"source": [
|
|
"# Convert spin_glass_poly into a NumPy-compatible function\n",
|
|
"poly_as_numpy_function = lambdify(x, spin_glass_poly.as_expr(), \"numpy\")\n",
|
|
"\n",
|
|
"\n",
|
|
"# Function to compute the cost of a given bitstring using spin_glass_poly\n",
|
|
"def bitstring_cost(bitstring: str) -> float:\n",
|
|
" # Convert bitstring to a reversed list of integers (0s and 1s)\n",
|
|
" return float(\n",
|
|
" poly_as_numpy_function(*[int(b) for b in str(bitstring[::-1])])\n",
|
|
" )\n",
|
|
"\n",
|
|
"\n",
|
|
"# Calculate the cost of each bitstring in the distribution\n",
|
|
"costs = [bitstring_cost(k) for k, _ in distribution.items()]\n",
|
|
"\n",
|
|
"# Extract probabilities from the bitstring distribution\n",
|
|
"probabilities = np.array([v for _, v in distribution.items()])\n",
|
|
"probabilities = probabilities / sum(\n",
|
|
" probabilities\n",
|
|
") # Normalize to get probabilities\n",
|
|
"\n",
|
|
"plot_cost_histogram(\n",
|
|
" costs, probabilities, distribution, qubit_count, bitstring_cost\n",
|
|
")"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "15e35cff",
|
|
"metadata": {},
|
|
"source": [
|
|
"Since the goal of this optimization algorithm is to find the minimum ground state of the Ising model, lower values indicate better solutions. Therefore, it's visually apparent that the solutions generated by the Fire Opal Optimization Solver far outperform random selection."
|
|
]
|
|
}
|
|
],
|
|
"metadata": {
|
|
"description": "Solve a utility-scale quantum optimization problem using the Optimization Solver, A Qiskit Function by Q-CTRL Fire Opal",
|
|
"kernelspec": {
|
|
"display_name": "Python 3",
|
|
"language": "python",
|
|
"name": "python3"
|
|
},
|
|
"language_info": {
|
|
"codemirror_mode": {
|
|
"name": "ipython",
|
|
"version": 3
|
|
},
|
|
"file_extension": ".py",
|
|
"mimetype": "text/x-python",
|
|
"name": "python",
|
|
"nbconvert_exporter": "python",
|
|
"pygments_lexer": "ipython3",
|
|
"version": "3"
|
|
},
|
|
"platform": "cloud",
|
|
"title": "Higher-order binary optimization with Q-CTRL's Optimization Solver"
|
|
},
|
|
"nbformat": 4,
|
|
"nbformat_minor": 5
|
|
}
|