346 lines
20 KiB
Plaintext
346 lines
20 KiB
Plaintext
{
|
||
"cells": [
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"# Example: QAOA as QiskitPattern\n",
|
||
"\n",
|
||
"This tutorial will be demonstation of creating QAOA as QiskitPattern as well as migration guide on how you can replicate IBM Quantum QAOA custom runtime program.\n",
|
||
"\n",
|
||
"Let's first get information on what is QAOA runtime program and what inputs and outputs it has. We will not be implementing full set of input/outputs, but we will cover most important ones. Later on we can recover full functionality if needed.\n",
|
||
"\n",
|
||
"**Description**: Qiskit Runtime QAOA program.\n",
|
||
"\n",
|
||
"\n",
|
||
"**Inputs**:\n",
|
||
"\n",
|
||
"| name | type | description |\n",
|
||
"| ---- | ---- | ----------- |\n",
|
||
"|initial_point|[array,string]|Initial parameters of the ansatz. Can be an array or the string ``'random'`` to choose random initial parameters. The type must be numpy.ndarray or str.|\n",
|
||
"|operator|object|The cost Hamiltonian, consisting of Pauli I and Z operators, whose smallest eigenvalue we're trying to find. The type must be a PauliSumOp.|\n",
|
||
"|method|str|The classical optimizer used to update the parameters in each iteration. Per default, COBYLA|\n",
|
||
"|ansatz|QuantumCircuit|Ansatz for optimization|\n",
|
||
"\n",
|
||
"**Return values**\n",
|
||
"\n",
|
||
"| name | type | description |\n",
|
||
"| ---- | ---- | ----------- |\n",
|
||
"|optimal_point|array|The optimal parameter values found during the optimization.|\n",
|
||
"|optimal_value|number|The smallest value found during the optimization. Equal to the ``eigenvalue`` attribute.|\n",
|
||
"\n",
|
||
"We will also add optional `QiskitRuntimeService` as an argument to use that to access real devices.\n"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"With that information we can start drafting our pattern implementation in `qaoa.py` file.\n",
|
||
"\n",
|
||
"What our pattern should do:\n",
|
||
"\n",
|
||
"1. parse input arguments\n",
|
||
"2. create run_qaoa function that accepts estimator instance, creates VQE and runs calculation\n",
|
||
"3. decide which sampler to use and run vqe\n",
|
||
" - if runtime service was passed then create a session and run `run_qaoa` function\n",
|
||
" - if runtime service was not passed then use stantard qiskit sampler\n",
|
||
"4. save results from qaoa\n",
|
||
"\n",
|
||
"Roughly our QAOA pattern will look like this. Full code can be found in [qaoa.py](./source_files/qaoa/qaoa.py) file.\n",
|
||
"\n",
|
||
"```python\n",
|
||
"# qaoa.py\n",
|
||
"\n",
|
||
"import ...\n",
|
||
"\n",
|
||
"def run_qaoa(\n",
|
||
" ansatz: QuantumCircuit,\n",
|
||
" estimator: BaseEstimator,\n",
|
||
" operator: PauliSumOp,\n",
|
||
" initial_point: np.array,\n",
|
||
" method: str\n",
|
||
"):\n",
|
||
" return minimize(cost_func, initial_point, args=(ansatz, operator, estimator), method=method)\n",
|
||
"\n",
|
||
"\n",
|
||
"arguments = get_arguments()\n",
|
||
"service = arguments.get(\"service\")\n",
|
||
"operator = arguments.get(\"operator\")\n",
|
||
"initial_point = arguments.get(\"initial_point\")\n",
|
||
"ansatz = arguments.get(\"ansatz\", 1)\n",
|
||
"...\n",
|
||
"if service is not None:\n",
|
||
" # if we have service we need to open a session and create sampler\n",
|
||
" service = arguments.get(\"service\") \n",
|
||
" backend = arguments.get(\"backend\", \"ibmq_qasm_simulator\")\n",
|
||
" with Session(service=service, backend=backend) as session:\n",
|
||
" estimator = Estimator(session=session, options=options)\n",
|
||
"else:\n",
|
||
" # if we do not have a service let's use standart local sampler\n",
|
||
" estimator = QiskitEstimator()\n",
|
||
"\n",
|
||
"result = run_qaoa(ansatz, estimator, operator, initial_point, \"COBYLA\")\n",
|
||
" \n",
|
||
"save_result({\n",
|
||
" \"optimal_point\": result.x.tolist(),\n",
|
||
" \"optimal_value\": result.fun\n",
|
||
"})\n",
|
||
"```"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"At this point we have our pattern implemented. Now we need to actually run it. But before let's prepare input arguments from our QAOA pattern."
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 1,
|
||
"metadata": {},
|
||
"outputs": [
|
||
{
|
||
"data": {
|
||
"text/html": [
|
||
"<pre style=\"word-wrap: normal;white-space: pre;background: #fff0;line-height: 1.1;font-family: "Courier New",Courier,monospace\"> ┌─────────────┐ ┌──────────────┐ ┌──────────────┐\n",
|
||
"q_0: ┤ U3(π/2,0,π) ├─■──────────────────────────────■──────────────────────────────■──────────────────────────────■─────────────┤ Rx(2.0*β[0]) ├─■──────────────■──────────────────────────────■──────────────────────────────■─────────────┤ Rx(2.0*β[1]) ├\n",
|
||
" ├─────────────┤ │ZZ(2.0*γ[0]) ┌──────────────┐ │ │ │ └──────────────┘ │ZZ(2.0*γ[1]) │ ┌──────────────┐ │ │ └──────────────┘\n",
|
||
"q_1: ┤ U3(π/2,0,π) ├─■─────────────┤ Rx(2.0*β[0]) ├─┼──────────────────────────────┼──────────────────────────────┼──────────────────────────────■──────────────┼─────────────┤ Rx(2.0*β[1]) ├─┼──────────────────────────────┼─────────────────────────────\n",
|
||
" ├─────────────┤ └──────────────┘ │ZZ(2.0*γ[0]) ┌──────────────┐ │ │ │ZZ(2.0*γ[1]) ├──────────────┤ │ │ \n",
|
||
"q_2: ┤ U3(π/2,0,π) ├────────────────────────────────■─────────────┤ Rx(2.0*β[0]) ├─┼──────────────────────────────┼─────────────────────────────────────────────■─────────────┤ Rx(2.0*β[1]) ├─┼──────────────────────────────┼─────────────────────────────\n",
|
||
" ├─────────────┤ └──────────────┘ │ZZ(2.0*γ[0]) ┌──────────────┐ │ └──────────────┘ │ZZ(2.0*γ[1]) ┌──────────────┐ │ \n",
|
||
"q_3: ┤ U3(π/2,0,π) ├───────────────────────────────────────────────────────────────■─────────────┤ Rx(2.0*β[0]) ├─┼────────────────────────────────────────────────────────────────────────────■─────────────┤ Rx(2.0*β[1]) ├─┼─────────────────────────────\n",
|
||
" ├─────────────┤ └──────────────┘ │ZZ(2.0*γ[0]) ┌──────────────┐ └──────────────┘ │ZZ(2.0*γ[1]) ┌──────────────┐\n",
|
||
"q_4: ┤ U3(π/2,0,π) ├──────────────────────────────────────────────────────────────────────────────────────────────■─────────────┤ Rx(2.0*β[0]) ├──────────────────────────────────────────────────────────────────────────────■─────────────┤ Rx(2.0*β[1]) ├\n",
|
||
" └─────────────┘ └──────────────┘ └──────────────┘</pre>"
|
||
],
|
||
"text/plain": [
|
||
" ┌─────────────┐ ┌──────────────┐ ┌──────────────┐\n",
|
||
"q_0: ┤ U3(π/2,0,π) ├─■──────────────────────────────■──────────────────────────────■──────────────────────────────■─────────────┤ Rx(2.0*β[0]) ├─■──────────────■──────────────────────────────■──────────────────────────────■─────────────┤ Rx(2.0*β[1]) ├\n",
|
||
" ├─────────────┤ │ZZ(2.0*γ[0]) ┌──────────────┐ │ │ │ └──────────────┘ │ZZ(2.0*γ[1]) │ ┌──────────────┐ │ │ └──────────────┘\n",
|
||
"q_1: ┤ U3(π/2,0,π) ├─■─────────────┤ Rx(2.0*β[0]) ├─┼──────────────────────────────┼──────────────────────────────┼──────────────────────────────■──────────────┼─────────────┤ Rx(2.0*β[1]) ├─┼──────────────────────────────┼─────────────────────────────\n",
|
||
" ├─────────────┤ └──────────────┘ │ZZ(2.0*γ[0]) ┌──────────────┐ │ │ │ZZ(2.0*γ[1]) ├──────────────┤ │ │ \n",
|
||
"q_2: ┤ U3(π/2,0,π) ├────────────────────────────────■─────────────┤ Rx(2.0*β[0]) ├─┼──────────────────────────────┼─────────────────────────────────────────────■─────────────┤ Rx(2.0*β[1]) ├─┼──────────────────────────────┼─────────────────────────────\n",
|
||
" ├─────────────┤ └──────────────┘ │ZZ(2.0*γ[0]) ┌──────────────┐ │ └──────────────┘ │ZZ(2.0*γ[1]) ┌──────────────┐ │ \n",
|
||
"q_3: ┤ U3(π/2,0,π) ├───────────────────────────────────────────────────────────────■─────────────┤ Rx(2.0*β[0]) ├─┼────────────────────────────────────────────────────────────────────────────■─────────────┤ Rx(2.0*β[1]) ├─┼─────────────────────────────\n",
|
||
" ├─────────────┤ └──────────────┘ │ZZ(2.0*γ[0]) ┌──────────────┐ └──────────────┘ │ZZ(2.0*γ[1]) ┌──────────────┐\n",
|
||
"q_4: ┤ U3(π/2,0,π) ├──────────────────────────────────────────────────────────────────────────────────────────────■─────────────┤ Rx(2.0*β[0]) ├──────────────────────────────────────────────────────────────────────────────■─────────────┤ Rx(2.0*β[1]) ├\n",
|
||
" └─────────────┘ └──────────────┘ └──────────────┘"
|
||
]
|
||
},
|
||
"execution_count": 1,
|
||
"metadata": {},
|
||
"output_type": "execute_result"
|
||
}
|
||
],
|
||
"source": [
|
||
"import numpy as np\n",
|
||
"\n",
|
||
"from qiskit.circuit.library import QAOAAnsatz\n",
|
||
"from qiskit.quantum_info import SparsePauliOp\n",
|
||
"\n",
|
||
"from qiskit_ibm_runtime import QiskitRuntimeService\n",
|
||
"\n",
|
||
"\n",
|
||
"operator = SparsePauliOp.from_list(\n",
|
||
" [(\"IIIZZ\", 1), (\"IIZIZ\", 1), (\"IZIIZ\", 1), (\"ZIIIZ\", 1)]\n",
|
||
")\n",
|
||
"ansatz = QAOAAnsatz(operator, reps=2)\n",
|
||
"ansatz = ansatz.decompose(reps=3)\n",
|
||
"ansatz.draw(fold=-1)"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 2,
|
||
"metadata": {},
|
||
"outputs": [
|
||
{
|
||
"data": {
|
||
"text/plain": [
|
||
"{'initial_point': None,\n",
|
||
" 'ansatz': <qiskit.circuit.quantumcircuit.QuantumCircuit at 0x7fd0b0e45310>,\n",
|
||
" 'operator': SparsePauliOp(['IIIZZ', 'IIZIZ', 'IZIIZ', 'ZIIIZ'],\n",
|
||
" coeffs=[1.+0.j, 1.+0.j, 1.+0.j, 1.+0.j]),\n",
|
||
" 'service': None,\n",
|
||
" 'backend': 'ibmq_qasm_simulator'}"
|
||
]
|
||
},
|
||
"execution_count": 2,
|
||
"metadata": {},
|
||
"output_type": "execute_result"
|
||
}
|
||
],
|
||
"source": [
|
||
"USE_RUNTIME_SERVICE = False\n",
|
||
"\n",
|
||
"service = None\n",
|
||
"if USE_RUNTIME_SERVICE:\n",
|
||
" service = QiskitRuntimeService(\n",
|
||
" channel='ibm_quantum',\n",
|
||
" instance='ibm-q/open/main',\n",
|
||
" token='<insert your token>'\n",
|
||
" )\n",
|
||
"backend = None\n",
|
||
"\n",
|
||
"input_arguments = {\n",
|
||
" \"initial_point\": None,\n",
|
||
" \"ansatz\": ansatz,\n",
|
||
" \"operator\": operator,\n",
|
||
" \"service\": service,\n",
|
||
" \"backend\": backend,\n",
|
||
"}\n",
|
||
"input_arguments"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 3,
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"from qiskit_serverless import ServerlessClient\n",
|
||
"import os"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 4,
|
||
"metadata": {},
|
||
"outputs": [
|
||
{
|
||
"data": {
|
||
"text/plain": [
|
||
"<ServerlessProvider: gateway-provider>"
|
||
]
|
||
},
|
||
"execution_count": 4,
|
||
"metadata": {},
|
||
"output_type": "execute_result"
|
||
}
|
||
],
|
||
"source": [
|
||
"serverless = ServerlessClient(\n",
|
||
" token=os.environ.get(\"GATEWAY_TOKEN\", \"awesome_token\"),\n",
|
||
" host=os.environ.get(\"GATEWAY_HOST\", \"http://localhost:8000\"),\n",
|
||
")\n",
|
||
"serverless"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 5,
|
||
"metadata": {},
|
||
"outputs": [
|
||
{
|
||
"data": {
|
||
"text/plain": [
|
||
"'qaoa'"
|
||
]
|
||
},
|
||
"execution_count": 5,
|
||
"metadata": {},
|
||
"output_type": "execute_result"
|
||
}
|
||
],
|
||
"source": [
|
||
"from qiskit_serverless import QiskitFunction\n",
|
||
"\n",
|
||
"function = QiskitFunction(\n",
|
||
" title=\"qaoa\", entrypoint=\"qaoa.py\", working_dir=\"./source_files/qaoa/\", dependencies=[\"qiskit_aer\"]\n",
|
||
")\n",
|
||
"\n",
|
||
"serverless.upload(function)"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 6,
|
||
"metadata": {},
|
||
"outputs": [
|
||
{
|
||
"data": {
|
||
"text/plain": [
|
||
"<Job | a55283e5-cfc9-4c6d-8bbb-fc7216d41a47>"
|
||
]
|
||
},
|
||
"execution_count": 6,
|
||
"metadata": {},
|
||
"output_type": "execute_result"
|
||
}
|
||
],
|
||
"source": [
|
||
"job = serverless.run(\"qaoa\", arguments=input_arguments)\n",
|
||
"job"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 7,
|
||
"metadata": {},
|
||
"outputs": [
|
||
{
|
||
"data": {
|
||
"text/plain": [
|
||
"'QUEUED'"
|
||
]
|
||
},
|
||
"execution_count": 7,
|
||
"metadata": {},
|
||
"output_type": "execute_result"
|
||
}
|
||
],
|
||
"source": [
|
||
"job.status()"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 8,
|
||
"metadata": {},
|
||
"outputs": [
|
||
{
|
||
"data": {
|
||
"text/plain": [
|
||
"{'optimal_point': [3.6344694882728,\n",
|
||
" 1.9051953195174722,\n",
|
||
" 2.5515024534598467,\n",
|
||
" 2.701136388288486],\n",
|
||
" 'optimal_value': -3.2939248998743915}"
|
||
]
|
||
},
|
||
"execution_count": 8,
|
||
"metadata": {},
|
||
"output_type": "execute_result"
|
||
}
|
||
],
|
||
"source": [
|
||
"job.result()"
|
||
]
|
||
}
|
||
],
|
||
"metadata": {
|
||
"kernelspec": {
|
||
"display_name": "Python 3 (ipykernel)",
|
||
"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.10.14"
|
||
}
|
||
},
|
||
"nbformat": 4,
|
||
"nbformat_minor": 4
|
||
}
|