Skip to content

Commit 3ce7c23

Browse files
QAOA implementation (#79)
* Sketch of first implementations * Implementation of QAOA maxcut functions * Organized code inside QAOA class Added missing functionalities (reset, cswap, input and output variables) to std_gates class * Added xy_mixer, x_mixer Added min_vertex_cover_cost, max_clique_cost Added comments * Removed two consecutive CNOTs that resulted in an identity * Small fixes to module inclusion and measurement in algorithm generation * Fixed SWAP-test * Modification after testing against qiskit QAOA tutorial * Fixed parameters indexing * Added validation on size of the graph Removed class level variables Removed unnecessary comment blocks Fixed comment which didn't match the method body removed name check in qasm variable declaration * Added references to Hamiltonian subroutine definitions * Added some unit tests Fixed constructor for QAOA * Fix for format check * More fixes for isort and mypy * Added more unit tests * Fixed unit tests * Fixed format check for unit tests * Enhanced code coverage * add: nx dependency in main package * add: all type stubs in the mypy tox cmd --------- Co-authored-by: Lorenzo Cicala <cicalalorenzo99@gmail.com>
1 parent 0938455 commit 3ce7c23

10 files changed

Lines changed: 1195 additions & 86 deletions

File tree

examples/evolutions.ipynb

Lines changed: 47 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@
3232
},
3333
{
3434
"cell_type": "code",
35-
"execution_count": null,
35+
"execution_count": 1,
3636
"id": "21685242",
3737
"metadata": {},
3838
"outputs": [],
@@ -53,7 +53,7 @@
5353
},
5454
{
5555
"cell_type": "code",
56-
"execution_count": 3,
56+
"execution_count": 2,
5757
"id": "d8527d79",
5858
"metadata": {},
5959
"outputs": [
@@ -97,7 +97,7 @@
9797
},
9898
{
9999
"cell_type": "code",
100-
"execution_count": 4,
100+
"execution_count": 3,
101101
"id": "5714c87f",
102102
"metadata": {},
103103
"outputs": [
@@ -115,7 +115,7 @@
115115
"include \"stdgates.inc\";\n",
116116
"qubit[4] qb;\n",
117117
"bit[4] cb;\n",
118-
"gate TFIM_3q_J100_h70(time) aa,ab,ac{\n",
118+
"gate TFIM_3q_j100_h70(time) aa,ab,ac{\n",
119119
"\tcnot aa, ab;\n",
120120
"\trz(2.0 * time) ab;\n",
121121
"\tcnot aa, ab;\n",
@@ -132,7 +132,7 @@
132132
"\n",
133133
"gate GQSP_1_TFIM(θa,θb,θc) aa,ab,ac,ad{\n",
134134
"\try(θa) aa;\n",
135-
"\tctrl(1) @ TFIM_3q_J100_h70(0.1) aa, ab, ac, ad;\n",
135+
"\tctrl(1) @ TFIM_3q_j100_h70(0.1) aa, ab, ac, ad;\n",
136136
"\tp(θb) aa;\n",
137137
"\try(θc) aa;\n",
138138
"}\n",
@@ -149,7 +149,7 @@
149149
"include \"stdgates.inc\";\n",
150150
"qubit[4] qb;\n",
151151
"bit[4] cb;\n",
152-
"gate TFIM_3q_J100_h70(time) aa,ab,ac{\n",
152+
"gate TFIM_3q_j100_h70(time) aa,ab,ac{\n",
153153
"\tcnot aa, ab;\n",
154154
"\trz(2.0 * time) ab;\n",
155155
"\tcnot aa, ab;\n",
@@ -166,13 +166,13 @@
166166
"\n",
167167
"gate GQSP_3_TFIM(θa,θb,θc,θd,θe,θf,θg) aa,ab,ac,ad{\n",
168168
"\try(θa) aa;\n",
169-
"\tctrl(1) @ TFIM_3q_J100_h70(0.1) aa, ab, ac, ad;\n",
169+
"\tctrl(1) @ TFIM_3q_j100_h70(0.1) aa, ab, ac, ad;\n",
170170
"\tp(θb) aa;\n",
171171
"\try(θe) aa;\n",
172-
"\tctrl(1) @ TFIM_3q_J100_h70(0.1) aa, ab, ac, ad;\n",
172+
"\tctrl(1) @ TFIM_3q_j100_h70(0.1) aa, ab, ac, ad;\n",
173173
"\tp(θc) aa;\n",
174174
"\try(θf) aa;\n",
175-
"\tctrl(1) @ TFIM_3q_J100_h70(0.1) aa, ab, ac, ad;\n",
175+
"\tctrl(1) @ TFIM_3q_j100_h70(0.1) aa, ab, ac, ad;\n",
176176
"\tp(θd) aa;\n",
177177
"\try(θg) aa;\n",
178178
"}\n",
@@ -288,7 +288,7 @@
288288
},
289289
{
290290
"cell_type": "code",
291-
"execution_count": 5,
291+
"execution_count": 4,
292292
"id": "7c651bcd",
293293
"metadata": {},
294294
"outputs": [
@@ -300,13 +300,13 @@
300300
"Trotter Decomposition - Two vs Multi-Hamiltonian\n",
301301
"----------------------------------------------------\n",
302302
"Configuration 1: Two-Hamiltonian Trotter (Suzuki)\n",
303-
"Two-Hamiltonian: 1858 characters\n",
303+
"Two-Hamiltonian: 1864 characters\n",
304304
"\tMethod: Suzuki-Trotter, Depth: 2\n",
305305
"OPENQASM 3;\n",
306306
"include \"stdgates.inc\";\n",
307307
"qubit[3] qb;\n",
308308
"bit[3] cb;\n",
309-
"gate TFIM_3q_J100_h70(time) aa,ab,ac{\n",
309+
"gate TFIM_3q_j100_h70(time) aa,ab,ac{\n",
310310
"\tcnot aa, ab;\n",
311311
"\trz(2.0 * time) ab;\n",
312312
"\tcnot aa, ab;\n",
@@ -321,7 +321,7 @@
321321
"\trx(1.4 * time) ac;\n",
322322
"}\n",
323323
"\n",
324-
"gate HeisenbergXYZ_3q_Jx100_Jy120_Jz80(time) aa,ab,ac{\n",
324+
"gate HeisenbergXYZ_3q_j_x100_j_y120_j_z80(time) aa,ab,ac{\n",
325325
"\try(pi/2) aa;\n",
326326
"\try(pi/2) ab;\n",
327327
"\tcnot aa, ab;\n",
@@ -360,9 +360,9 @@
360360
"\n",
361361
"def trot_suz_3_TFIM_HeisenbergXYZ_2(qubit[3] qubits,float time,int recursion_depth) {\n",
362362
"\tif (recursion_depth < 2){\n",
363-
"\t\tTFIM_3q_J100_h70(time/2) qb[qubits[0]],qb[qubits[1]],qb[qubits[2]];\n",
364-
"\t\tHeisenbergXYZ_3q_Jx100_Jy120_Jz80(time) qb[qubits[0]],qb[qubits[1]],qb[qubits[2]];\n",
365-
"\t\tTFIM_3q_J100_h70(time/2) qb[qubits[0]],qb[qubits[1]],qb[qubits[2]];\n",
363+
"\t\tTFIM_3q_j100_h70(time/2) qb[qubits[0]],qb[qubits[1]],qb[qubits[2]];\n",
364+
"\t\tHeisenbergXYZ_3q_j_x100_j_y120_j_z80(time) qb[qubits[0]],qb[qubits[1]],qb[qubits[2]];\n",
365+
"\t\tTFIM_3q_j100_h70(time/2) qb[qubits[0]],qb[qubits[1]],qb[qubits[2]];\n",
366366
"\t\treturn;\n",
367367
"\t}\n",
368368
"\tfloat suzuki_coeff = 1.0/(4.0 - pow(4.0, 1.0/(2.0*recursion_depth - 1.0)));\n",
@@ -377,16 +377,16 @@
377377
"\n",
378378
"\n",
379379
"Configuration 2: Multi-Hamiltonian Trotter\n",
380-
"Multi-Hamiltonian: 3342 characters\n",
380+
"Multi-Hamiltonian: 3351 characters\n",
381381
"\tHamiltonians: 3, Depth: 2\n",
382382
"\n",
383383
"Configuration 3: Linear Trotter Decomposition\n",
384-
"Linear Trotter: 1769 characters\n",
384+
"Linear Trotter: 1784 characters\n",
385385
"Method: First-order, Steps: 4\n",
386386
"Trotter Configuration Comparison:\n",
387-
"\tTwo-Hamiltonian (Suzuki): 1858 chars\n",
388-
"\tMulti-Hamiltonian: 3342 chars\n",
389-
"\tLinear decomposition: 1769 chars\n"
387+
"\tTwo-Hamiltonian (Suzuki): 1864 chars\n",
388+
"\tMulti-Hamiltonian: 3351 chars\n",
389+
"\tLinear decomposition: 1784 chars\n"
390390
]
391391
}
392392
],
@@ -492,7 +492,7 @@
492492
},
493493
{
494494
"cell_type": "code",
495-
"execution_count": 6,
495+
"execution_count": 5,
496496
"id": "4b4b3bff",
497497
"metadata": {},
498498
"outputs": [
@@ -508,19 +508,13 @@
508508
"[('Z', np.complex128(1+0j))]\n",
509509
"Pauli-Z: 508 characters\n",
510510
"Testing Random 4x4 matrix (4, 4)...\n",
511-
"[('II', np.complex128(0.4604637367120007+0.838946781387169j)), ('XI', np.complex128(0.5655598377382944+0.588833075307832j)), ('XX', np.complex128(0.4238844968885312+0.3326317061016123j)), ('IX', np.complex128(0.33106499350145013+0.33007330113196753j)), ('XY', np.complex128(-0.06002262495215413+0.2992097507618375j)), ('IY', np.complex128(-0.1797796889495182+0.20356340119461624j)), ('YI', np.complex128(-0.13521719508002197+0.19794667244217146j)), ('ZX', np.complex128(0.02442078075316162-0.23360780554666702j)), ('XZ', np.complex128(-0.18057751029366081-0.148700172760367j)), ('ZY', np.complex128(0.2184605953247674+0.03821255057383305j)), ('IZ', np.complex128(-0.095147349933698+0.07351264181838879j)), ('ZI', np.complex128(-0.11616413227155017+0.02567510247519522j)), ('YY', np.complex128(-0.05126587163767765+0.10703189572053626j)), ('YZ', np.complex128(-0.09614107149005136-0.02889548280897075j)), ('YX', np.complex128(-0.0870637778551501+0.04327330864487838j)), ('ZZ', np.complex128(0.0896637111235748-0.035398963079813106j))]\n"
512-
]
513-
},
514-
{
515-
"name": "stdout",
516-
"output_type": "stream",
517-
"text": [
518-
"Random 4x4: 2019 characters\n",
511+
"[('IX', np.complex128(0.6312692451983448+0.7062795340748755j)), ('II', np.complex128(0.3312704466731056+0.6543110856138611j)), ('XX', np.complex128(0.48885549810002155+0.46708079988828466j)), ('XI', np.complex128(0.5064276643525388+0.42560849024074227j)), ('YI', np.complex128(-0.2209432140524214-0.32680593560317794j)), ('XY', np.complex128(0.3051770998894734-0.08729195918180288j)), ('YY', np.complex128(0.22903059831001216-0.17048096768847246j)), ('ZZ', np.complex128(-0.12674613849154037+0.09991843038070033j)), ('ZI', np.complex128(-0.14733787825849548+0.023772954678058178j)), ('IY', np.complex128(-0.13339759254293293-0.04272733136592735j)), ('IZ', np.complex128(-0.018907216413733607-0.13091360941091704j)), ('ZX', np.complex128(0.007991339043142087-0.10180140392762566j)), ('ZY', np.complex128(-0.05995761592784832-0.0542893312281765j)), ('XZ', np.complex128(-0.016121493337997672+0.07795486151092063j)), ('YZ', np.complex128(0.06407397205381465+0.006693388785256826j)), ('YX', np.complex128(0.03553879879197233-0.04432680229575253j))]\n",
512+
"Random 4x4: 2023 characters\n",
519513
"\n",
520514
"Configuration 2: Operator Chain Input\n",
521515
"Testing Single Pauli chain (3 operators)...\n",
522516
"[('X', 0.5), ('Z', 0.3), ('Y', 0.2)]\n",
523-
"\tSingle Pauli: 719 characters\n",
517+
"\tSingle Pauli: 717 characters\n",
524518
"\tOperators: ['X', 'Z', 'Y']\n",
525519
"OPENQASM 3;\n",
526520
"include \"stdgates.inc\";\n",
@@ -545,7 +539,7 @@
545539
"\ty aa;\n",
546540
"}\n",
547541
"\n",
548-
"gate SEL_8998145479025848162 aa,ab,ac,ad{\n",
542+
"gate SEL_247308947824619046 aa,ab,ac,ad{\n",
549543
"\tctrl(2) @ X aa,ab,ac,ad;\n",
550544
"\tx aa;\n",
551545
"\tctrl(2) @ Z aa,ab,ac,ad;\n",
@@ -555,13 +549,13 @@
555549
"\tx ab;\n",
556550
"}\n",
557551
"\n",
558-
"gate PS_2_8654309695166846104 aa,ab,ac,ad{\n",
552+
"gate PS_2_8139876655021836051 aa,ab,ac,ad{\n",
559553
"\tPREP_3905172865891942725 aa,ab;\n",
560-
"\tSEL_8998145479025848162 aa,ab,ac,ad;\n",
554+
"\tSEL_247308947824619046 aa,ab,ac,ad;\n",
561555
"\tinv @ PREP_3905172865891942725 aa,ab;\n",
562556
"}\n",
563557
"\n",
564-
"PS_2_8654309695166846104 qb[3],qb[4],qb[0],qb[1];\n",
558+
"PS_2_8139876655021836051 qb[3],qb[4],qb[0],qb[1];\n",
565559
"cb[{3, 4}] = measure qb[{3, 4}];\n",
566560
"cb[{0, 1, 2, 3}] = measure qb[{0, 1, 2, 3}];\n",
567561
"\n",
@@ -573,9 +567,9 @@
573567
"Prep-Select Configuration Comparison:\n",
574568
"Matrix inputs:\n",
575569
"\tPauli-Z: 508 chars\n",
576-
"\tRandom 4x4: 2019 chars\n",
570+
"\tRandom 4x4: 2023 chars\n",
577571
"Operator chains:\n",
578-
"\tSingle Pauli: 719 chars\n",
572+
"\tSingle Pauli: 717 chars\n",
579573
"\tTwo-qubit Pauli: 756 chars\n"
580574
]
581575
}
@@ -681,7 +675,7 @@
681675
},
682676
{
683677
"cell_type": "code",
684-
"execution_count": null,
678+
"execution_count": 6,
685679
"id": "a44b4a64",
686680
"metadata": {},
687681
"outputs": [
@@ -698,10 +692,10 @@
698692
" Step 2: Applying GQSP...\n",
699693
" Step 3: Applying prep-select...\n",
700694
"[('Z', np.complex128(1+0j))]\n",
701-
"Integrated pipeline: 2465 characters\n",
702-
" Contains Trotter: True\n",
703-
" Contains GQSP: True\n",
704-
" Contains PrepSelect: True\n"
695+
"Integrated pipeline: 2471 characters\n",
696+
"\tContains Trotter: True\n",
697+
"\tContains GQSP: True\n",
698+
"\tContains PrepSelect: True\n"
705699
]
706700
}
707701
],
@@ -789,40 +783,19 @@
789783
},
790784
{
791785
"cell_type": "code",
792-
"execution_count": 16,
786+
"execution_count": 7,
793787
"id": "22dfb86d",
794788
"metadata": {},
795789
"outputs": [
796790
{
797-
"name": "stdout",
798-
"output_type": "stream",
799-
"text": [
800-
"OPENQASM 3;\n",
801-
"include \"stdgates.inc\";\n",
802-
"qubit[3] qb;\n",
803-
"gate Z_on_two3 aa,ab,ac{\n",
804-
"\tx ac;\n",
805-
"\tctrl(2) @ z aa, ab, ac;\n",
806-
"\tx ac;\n",
807-
"}\n",
808-
"\n",
809-
"def Grover3Z_on_two3(qubit[3] reg) {\n",
810-
"\th reg;\n",
811-
"\tfor int i in [0:2] {\n",
812-
"\t\t//Za\n",
813-
"\t\tZ_on_two3 reg[0], reg[1], reg[2];\n",
814-
"\t\th reg;\n",
815-
"\t\t//Z0\n",
816-
"\t\tx reg;\n",
817-
"\t\tctrl(2) @ z reg[0], reg[1], reg[0];\n",
818-
"\t\tx reg;\n",
819-
"\t\th reg;\n",
820-
"\t}\n",
821-
"}\n",
822-
"\n",
823-
"input angle[32] theta ;\n",
824-
"Grover3Z_on_two3(qb[{0 ,1 ,2}]);\n",
825-
"\n"
791+
"ename": "TypeError",
792+
"evalue": "GateLibrary.add_var() got an unexpected keyword argument 'type'. Did you mean 'qtype'?",
793+
"output_type": "error",
794+
"traceback": [
795+
"\u001b[31m---------------------------------------------------------------------------\u001b[39m",
796+
"\u001b[31mTypeError\u001b[39m Traceback (most recent call last)",
797+
"\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[7]\u001b[39m\u001b[32m, line 51\u001b[39m\n\u001b[32m 47\u001b[39m \u001b[38;5;28mself\u001b[39m.controlled_op(\u001b[38;5;28mself\u001b[39m.name, (qubits[-\u001b[32m1\u001b[39m], [control] + qubits[:-\u001b[32m1\u001b[39m]))\n\u001b[32m 50\u001b[39m \u001b[38;5;66;03m# Define input parameter\u001b[39;00m\n\u001b[32m---> \u001b[39m\u001b[32m51\u001b[39m theta = \u001b[43mprogram\u001b[49m\u001b[43m.\u001b[49m\u001b[43madd_var\u001b[49m\u001b[43m(\u001b[49m\u001b[33;43m\"\u001b[39;49m\u001b[33;43mtheta\u001b[39;49m\u001b[33;43m\"\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;28;43mtype\u001b[39;49m\u001b[43m=\u001b[49m\u001b[33;43m\"\u001b[39;49m\u001b[33;43minput angle[32]\u001b[39;49m\u001b[33;43m\"\u001b[39;49m\u001b[43m)\u001b[49m\n\u001b[32m 53\u001b[39m \u001b[38;5;66;03m# Apply Grover with custom gate\u001b[39;00m\n\u001b[32m 54\u001b[39m ampl.grover(Za, reg, \u001b[32m3\u001b[39m)\n",
798+
"\u001b[31mTypeError\u001b[39m: GateLibrary.add_var() got an unexpected keyword argument 'type'. Did you mean 'qtype'?"
826799
]
827800
}
828801
],
@@ -901,7 +874,7 @@
901874
],
902875
"metadata": {
903876
"kernelspec": {
904-
"display_name": "venv",
877+
"display_name": "Python 3",
905878
"language": "python",
906879
"name": "python3"
907880
},
@@ -915,7 +888,7 @@
915888
"name": "python",
916889
"nbconvert_exporter": "python",
917890
"pygments_lexer": "ipython3",
918-
"version": "3.12.8"
891+
"version": "3.13.9"
919892
}
920893
},
921894
"nbformat": 4,

examples/qaoa.ipynb

Lines changed: 522 additions & 0 deletions
Large diffs are not rendered by default.

qbraid_algorithms/qaoa/__init__.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# Copyright 2025 qBraid
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
"""
15+
Quantum Approximate Optimization Algorithm (QAOA) used to define cost and mixer Hamiltonians
16+
and generate QASM programs accordingly.
17+
"""
18+
from .qaoa import QAOA
19+
20+
__all__ = ["QAOA"]

0 commit comments

Comments
 (0)