Skip to content

Commit 3a046cb

Browse files
MTakahashi-KWHLukeAndreesenryanhill1TheGupta2012
authored
QasmBuilder Macro (#59)
* initial commit - created first qasm file * bells inequality .qasm file update * bells inequality qasm * bern-vaz example ('1001') * load .qasm w/ pyqasm * fix * prelim autoqasm bern-vaz - needs sdk integration * pqasm loading fix * Update CONTRIBUTING.md fixed coverage report test * simple bells inequality circuit example, cleaned up * testing for bell's inequality qasm3 circuits * fix init docs & update measurement from qasm2 to qasm3 * change load_circuit to load_program, create simple jupyter notebook example for Bell's * fix QasmModoule Error * attempt to fix module import issue * formatting * fixing format issue ... hopefully * test fix * first comparision implementation of QFT * qft qasm only test and first pass at ampl amp * file structure change to prevent future merge conflicts * module compatibility correction * minor edits and acommodating to regular workflow * generated test file, demo file and fixed module init. slow progress on debugging the autoqasm closure primitives due to definement of qubit register after submodule definition * included init file for amplitude amplification * added new extensible macro generator, need work on gate parameterization, text formatting, and merging includes from gatebuilders * edits for formatting and procedural correctness * prep to ampl amplification, staging for HHL and fixes to phase est * debug and comment on qasmbuilder * checkpoint for working on HHL and debugging named and inverse operations * squashed commit for file restructure, syntax, debug, and annotation edits * cleaning up init ifles and validation edits to amp ampl * fixed module namespace conflicts and improvements to amplitude amplification * fix dangling file edits * remove remnants of autoqasm from local branch * cleaned up hamil closures and heavily improved demo qasmbuilder * eod commit, further debug on all and implementation of rodeo, both direct ancillas and mid circuit measurement * midway commit, fillout of block encoding. * eod work towards completion of prep select embedding * initial completion commit of prep select library, moving to debug and annotate * commenting and completed debug of prep block encoding * clearer directory name * eod, near completion of toeplitz and diagonal libraries * toeplitz complete, onto gqsp and loads * gqsp initial * cleanup of files and initial completion of trotter * improvements in subroutine calls and namespace fix in trotter * added multi trotter and linear trotter * building out unit tests * added and partially debugged test suite * progress towards final implementation using test driven debug * fixed doctree and ran linter * 100% test coverage, shift to load integrations and linting fixes * fixed imports to be named * aligned naming to pep 8 convention+ linting improvements * name fixes and duplicate code edited for linter * semi final commit, changeover to full pull request, addition of final grover unit test and further debugging of behavior + name fixes, and demo notebook * test fix and removal of local package requirements used for extended testing * doc build fixes * updates to function for debug +buld and new tests * update to HHL * weekend updates for local build tests 1 * fixed lint check and final test pass * minor edits, cannot fix bug in reSt with ampl amp as there is no traceback * fix unit-tests + format check * fix ci and other stuff * fix the string error --------- Co-authored-by: LukeAndreesen <[email protected]> Co-authored-by: Ryan Hill <[email protected]> Co-authored-by: Harshit Gupta <[email protected]>
1 parent 71befd3 commit 3a046cb

37 files changed

+6742
-26
lines changed

examples/bells_inequality.ipynb

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

examples/demo_hamiltonians.ipynb

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

examples/demo_qasmbuilder.ipynb

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

pyproject.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,10 +58,10 @@ multi_line_output = 3
5858
include_trailing_comma = true
5959
force_grid_wrap = 0
6060
use_parentheses = true
61-
line_length = 100
61+
line_length = 120
6262

6363
[tool.pylint.'MESSAGES CONTROL']
64-
max-line-length = 100
64+
max-line-length = 120
6565
disable = "W0108,W0511,W0401,R0902,R0903,R0913,E0401"
6666

6767
[tool.pylint.MASTER]

qbraid_algorithms/__init__.py

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,15 +24,20 @@
2424
2525
.. autosummary::
2626
:toctree: ../stubs/
27-
27+
2828
bernstein_vazirani
2929
qft
3030
iqft
3131
qpe
32+
qtran
33+
hhl
34+
evolution
35+
embedding
36+
amplitude_amplification
37+
rodeo
3238
3339
"""
3440

35-
from . import bernstein_vazirani, iqft, qft, qpe
3641
from ._version import __version__
3742

3843
__all__ = [
@@ -41,4 +46,10 @@
4146
"iqft",
4247
"bernstein_vazirani",
4348
"qpe",
49+
"qtran",
50+
'evolution',
51+
'embedding',
52+
'amplitude_amplification',
53+
'hhl',
54+
'rodeo'
4455
]
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
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+
"""
16+
Module providing Amplitude Amplification implementation.
17+
18+
Functions
19+
----------
20+
21+
.. autosummary::
22+
:toctree: ../stubs/
23+
24+
AALibrary
25+
26+
"""
27+
28+
from .amp_ampl import AALibrary
29+
30+
__all__ = [
31+
"AALibrary"
32+
]
Lines changed: 269 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,269 @@
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+
Amplitude Amplification Library for Quantum Algorithms
16+
This module implements amplitude amplification techniques for quantum algorithms,
17+
including Grover's algorithm and general amplitude amplification. It provides
18+
the `AALibrary` class, which extends `GateLibrary` to offer reusable quantum
19+
subroutines for amplifying the probability amplitudes of desired quantum states.
20+
Classes:
21+
AALibrary(GateLibrary):
22+
Implements Grover's algorithm and general amplitude amplification.
23+
Usage:
24+
- Use `grover` for unstructured search problems.
25+
- Use `amp_ampl` for general amplitude amplification with arbitrary oracles and state preparation.
26+
Notes:
27+
- The library uses subroutine-based implementations for compact qasm code generation.
28+
- Multi-controlled Z gates are used for phase inversion in the diffusion operator.
29+
- The code is designed to be extensible for other amplitude amplification algorithms.
30+
'''
31+
from typing import List
32+
33+
from qbraid_algorithms.qtran import GateBuilder, GateLibrary, std_gates
34+
35+
# TODO: once again Physics notation was originally used convert to better naming
36+
# pylint: disable=invalid-name
37+
# mypy: disable_error_code="call-arg"
38+
39+
class AALibrary(GateLibrary):
40+
"""
41+
Amplitude Amplification Library implementing Grover's algorithm and general amplitude amplification.
42+
43+
This library provides quantum algorithms for amplitude amplification, including:
44+
- Grover's algorithm for unstructured search
45+
- General amplitude amplification for arbitrary oracles
46+
47+
Both algorithms use the principle of selective phase rotation to amplify desired
48+
quantum state amplitudes while suppressing unwanted ones.
49+
"""
50+
51+
name = "AmplitudeAmplification"
52+
53+
def __init__(self, *args, **kwargs):
54+
"""Initialize the AALibrary by calling the parent GateLibrary constructor."""
55+
super().__init__(*args, **kwargs)
56+
self.name = "AmplAmp"
57+
58+
def grover(self, H, qubits: List[int], depth: int) -> None:
59+
"""
60+
Implement Grover's algorithm for quantum search.
61+
62+
Grover's algorithm provides a quadratic speedup for searching unsorted databases.
63+
It uses amplitude amplification with a specific oracle (H) to amplify the amplitude
64+
of target states while suppressing others.
65+
66+
The algorithm structure:
67+
1. Initialize qubits in superposition with Hadamard gates
68+
2. Repeat depth times:
69+
- Apply oracle H (marks target states)
70+
- Apply diffusion operator (inverts amplitudes about average)
71+
72+
Args:
73+
H: Oracle/Hamiltonian that marks target states
74+
qubits: List of qubit indices to operate on
75+
depth: Number of Grover iterations to perform
76+
"""
77+
# Generate unique subroutine name based on parameters
78+
name = f'Grover{len(qubits)}{H.name}{depth}'
79+
80+
# Check if subroutine already exists to avoid regeneration
81+
if name in self.gate_ref:
82+
qubit_list = "{" + " ,".join(str(i) for i in qubits) + "}"
83+
self.call_subroutine(name, [self.call_space.format(qubit_list)])
84+
# Alternative gate-based call (currently commented out):
85+
# self.call_gate(name, qubits[-1], qubits[:-1])
86+
return
87+
88+
# Create new gate builder for defining the subroutine
89+
gate_system = GateBuilder()
90+
std_library = gate_system.import_library(std_gates)
91+
std_library.call_space = " {}"
92+
oracle_library = gate_system.import_library(H)
93+
94+
# NOTE: Alternative gate-based implementation is commented out below.
95+
# The current subroutine approach keeps generated code compact,
96+
# whereas gates cannot use loops (would require Python loops instead).
97+
98+
# Alternative gate implementation (commented out):
99+
# std_library.begin_gate(name, qargs)
100+
# # Initial superposition
101+
# [std_library.h(i) for i in qargs]
102+
# # Grover iteration: Za -> Z0
103+
# std_library.begin_loop(depth)
104+
# std_library.comment("Za")
105+
# oracle_library.apply(qargs)
106+
# [std_library.h(i) for i in qargs]
107+
# std_library.comment("Z0")
108+
# [std_library.x(i) for i in qargs]
109+
# std_library.controlled_op("z", (qargs[-1], qargs[:-1]), n=len(qubits)-1)
110+
# [std_library.x(i) for i in qargs]
111+
# [std_library.h(i) for i in qargs]
112+
# std_library.end_loop()
113+
# std_library.end_gate()
114+
115+
# Current subroutine-based implementation
116+
register = "reg"
117+
std_library.begin_subroutine(name, [f"qubit[{len(qubits)}] {register}"])
118+
119+
# Initialize all qubits in superposition
120+
std_library.h(register)
121+
122+
# Main Grover iteration loop
123+
std_library.begin_loop(depth)
124+
125+
# Apply oracle (marks target states with phase flip)
126+
std_library.comment("Za")
127+
oracle_library.apply([f"reg[{i}]" for i in range(len(qubits))])
128+
129+
# Apply diffusion operator (inverts amplitudes about average)
130+
std_library.h(register)
131+
std_library.comment("Z0")
132+
std_library.x(register) # Flip all qubits
133+
# Multi-controlled Z gate (phase flip when all qubits are |1⟩)
134+
std_library.controlled_op("z",(f"{register}[0]", [f"{register}[{i}]" for i in range(len(qubits) - 1)]),
135+
n=len(qubits) - 1
136+
)
137+
std_library.x(register) # Flip back
138+
std_library.h(register)
139+
140+
std_library.end_loop()
141+
std_library.end_subroutine()
142+
143+
# Build and merge the subroutine into main library
144+
self.merge(*gate_system.build(), name)
145+
146+
# Call the created subroutine
147+
qubit_list = "{" + " ,".join(str(i) for i in qubits) + "}"
148+
self.call_subroutine(name, [self.call_space.format(qubit_list)])
149+
150+
def amp_ampl(self, Z, H, qubits: List[int], depth: int) -> None:
151+
"""
152+
Implement general amplitude amplification algorithm.
153+
154+
This is a generalization of Grover's algorithm that works with arbitrary
155+
oracles Z and state preparation operators H. It amplifies amplitudes of
156+
states marked by oracle Z after preparation by operator H.
157+
158+
The algorithm structure:
159+
1. Unapply state preparation Z†
160+
2. Initialize superposition
161+
3. Repeat depth times:
162+
- Apply state preparation H
163+
- Unapply oracle Z†
164+
- Apply diffusion operator Z0
165+
- Apply oracle Z
166+
167+
Args:
168+
Z: Oracle operator that marks target states
169+
H: State preparation operator
170+
qubits: List of qubit indices to operate on
171+
depth: Number of amplitude amplification iterations
172+
173+
Note:
174+
There's a bug in the original code where 'z' is used instead of 'Z'
175+
in the name generation. This is preserved to maintain exact logic.
176+
"""
177+
name = f'AmplAmp{len(qubits)}{Z.name}{depth}'
178+
179+
# Check if subroutine already exists
180+
if name in self.gate_ref:
181+
qubit_list = "{" + " ,".join(str(i) for i in qubits) + "}"
182+
self.call_subroutine(name, [self.call_space.format(qubit_list)])
183+
# Alternative gate-based call (currently commented out):
184+
# self.call_gate(name, qubits[-1], qubits[:-1])
185+
return
186+
187+
# Create new gate builder for defining the subroutine
188+
gate_system = GateBuilder()
189+
std_library = gate_system.import_library(std_gates)
190+
oracle_z = gate_system.import_library(Z)
191+
state_prep_h = gate_system.import_library(H)
192+
193+
# NOTE: Alternative gate-based implementations are commented out below.
194+
# Multiple different approaches were tried during development.
195+
196+
# Alternative gate implementation attempt 1 (commented out):
197+
# std_library.begin_gate(name, qargs)
198+
# std_library.call_space = " {} "
199+
# # Initial superposition
200+
# [std_library.h(i) for i in qargs]
201+
# # Amplitude amplification iteration
202+
# std_library.begin_loop(depth)
203+
# std_library.comment("Za")
204+
# state_prep_h.apply(qargs)
205+
# [std_library.h(i) for i in qargs]
206+
# std_library.comment("Z0")
207+
# [std_library.x(i) for i in qargs]
208+
# std_library.controlled_op("cz", (qargs[-1], qargs[:-1]), n=len(qubits)-2)
209+
# [std_library.x(i) for i in qargs]
210+
# [std_library.h(i) for i in qargs]
211+
# std_library.end_loop()
212+
# std_library.end_gate()
213+
214+
# Alternative gate implementation attempt 2 (commented out):
215+
# for _ in range(depth):
216+
# std_library.comment("Za")
217+
# oracle_z.apply(qargs)
218+
# [std_library.h(i) for i in qargs]
219+
# std_library.comment("Z0")
220+
# print((qargs[-1], qargs[:-1])) # Debug print
221+
# std_library.controlled_op("cp", (qargs[-1], qargs[:-1]), n=len(qubits)-2)
222+
# [std_library.h(i) for i in qargs]
223+
224+
# Current subroutine-based implementation
225+
register = "reg"
226+
std_library.begin_subroutine(name, [f"qubit[{len(qubits)}] {register}"])
227+
228+
# Initial unapplication of oracle (inverse preparation)
229+
oracle_z.unapply([f"reg[{i}]" for i in range(len(qubits))])
230+
231+
# Initialize superposition
232+
std_library.h(register)
233+
234+
# Main amplitude amplification loop
235+
std_library.begin_loop(depth)
236+
237+
# Apply state preparation operator
238+
std_library.comment("H")
239+
state_prep_h.apply([f"reg[{i}]" for i in range(len(qubits))])
240+
241+
# Unapply oracle (Z†)
242+
std_library.comment("Zp*")
243+
oracle_z.unapply([f"reg[{i}]" for i in range(len(qubits))])
244+
245+
# Apply diffusion operator (same as Grover)
246+
std_library.comment("Z0")
247+
std_library.x(register)
248+
std_library.controlled_op(
249+
"z",
250+
(f"{register}[0]", [f"{register}[{i}]" for i in range(len(qubits) - 1)]),
251+
n=len(qubits) - 1
252+
)
253+
std_library.x(register)
254+
255+
# Reapply oracle (Z)
256+
std_library.comment("Zp")
257+
oracle_z.apply([f"reg[{i}]" for i in range(len(qubits))])
258+
259+
std_library.end_loop()
260+
std_library.end_subroutine()
261+
262+
# Build and merge the subroutine
263+
self.merge(*gate_system.build(), name)
264+
265+
# Call the created subroutine
266+
# Alternative gate-based call (commented out):
267+
# self.call_gate(name, qubits[-1], qubits[:-1])
268+
qubit_list = "{" + " ,".join(str(i) for i in qubits) + "}"
269+
self.call_subroutine(name, [self.call_space.format(qubit_list)])
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
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+
"""
16+
Module providing Bell's Inequality experiment implementation.
17+
18+
Functions
19+
----------
20+
21+
.. autosummary::
22+
:toctree: ../stubs/
23+
24+
load_program
25+
26+
"""
27+
28+
from .bells_inequality import load_program
29+
30+
__all__ = [
31+
"load_program",
32+
]

0 commit comments

Comments
 (0)