-
Notifications
You must be signed in to change notification settings - Fork 714
QRAM template #8368
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
QRAM template #8368
Conversation
|
Hello. You may have forgotten to update the changelog!
|
doc/introduction/templates.rst
Outdated
|
|
||
| .. gallery-item:: | ||
| :description: :doc:`QRAM <../code/api/pennylane.QRAM>` | ||
| :figure: _static/templates/TODO |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TODO
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Curious how this image will be provided? Where will it come from?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Any reason we say QROM here rather than QRAM?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just using this image for now...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok I have permission from Josh and Tarik to take a shot at creating the QRAM template in inkscape. I will make one that closely matches the above.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| work_wires (Sequence[int]): the auxiliary wires used for the computation | ||
| clean (bool): if True, the work wires are not altered by operator, default is ``True`` | ||
| ..see-also:: :class:`~.QRAM`, :class:`~.QROMStatePreparation` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TODO: update name of QRAM class if needed
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done!
comp-phys-marc
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some really great work here. My initial thoughts / questions!
| for p in range(1 << k): | ||
| #change to in_wire later | ||
| parent = _node_index(k - 1, p >> 1) | ||
| if p % 2 == 0: | ||
| ops.append(qml.SWAP(wires =[self.portL_wires[parent], self._router(k, p)])) | ||
| else: | ||
| ops.append(qml.SWAP(wires =[self.portR_wires[parent], self._router(k, p)])) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there a bit of duplication of logic between here and _route_bus_down_first_k_levels?
| op0 = qml.CSWAP(wires=[d, in_w, R]) | ||
| ops.append(op0) | ||
| # dir==0 ⇒ SWAP(in, L) | ||
| op = qml.SWAP(wires=[in_w, L]) | ||
| ops.append(qml.ctrl(op, control=[d], control_values=[0])) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am not sure why we sometimes use CSWAP and sometimes use ctrl(SWAP, ...)?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If there's truly no difference we can easily replace with whatever is most efficient :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There will be no material difference. Just a matter of picking something and sticking with it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the reason we use ctrl here is because it takes control_values, right?
| # def _route_bus_down(self) -> list: | ||
| # """Route the bus from root to leaf across all levels using dir-controlled CSWAPs.""" | ||
| # ops = [] | ||
| # for k in range(self.n_k): | ||
| # for p in range(1 << k): | ||
| # in_w = self._node_in_wire(k, p) | ||
| # L = self._portL(k, p) | ||
| # R = self._portR(k, p) | ||
| # d = self._router(k, p) | ||
| # if k == 0: | ||
| # upper_ctrls, upper_vals = [], [] | ||
| # else: | ||
| # upper_ctrls = [self._router(j, p >> (k - j)) for j in range(k)] | ||
| # upper_vals = [(p >> (k - 1 - j)) & 1 for j in range(k)] | ||
| # op0 = qml.SWAP(wires=[in_w, L]) | ||
| # op1 = qml.SWAP(wires=[in_w, R]) | ||
| # ops.append( | ||
| # qml.ctrl(op0, control=[d] + upper_ctrls, control_values=[0] + upper_vals) | ||
| # if upper_ctrls | ||
| # else qml.ctrl(op0, control=[d], control_values=[0]) | ||
| # ) | ||
| # ops.append( | ||
| # qml.ctrl(op1, control=[d] + upper_ctrls, control_values=[1] + upper_vals) | ||
| # if upper_ctrls | ||
| # else qml.ctrl(op1, control=[d], control_values=[1]) | ||
| # ) | ||
| # return ops | ||
|
|
||
| # def _route_bus_up(self) -> list: | ||
| # """Inverse of `_route_bus_down`.""" | ||
| # return list(reversed(self._route_bus_down())) | ||
|
|
||
| # # ---------- Select controls---------- | ||
| # def _select_ctrls(self, s: int): | ||
| # if self.k == 0: | ||
| # return [], [] | ||
| # ctrls = list(self.select_wires) | ||
| # vals = [(s >> (self.k - 1 - j)) & 1 for j in range(self.k)] | ||
| # return ctrls, vals |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is the story / plan with all this commented out code?
| class SelectBucketBrigadeBusQRAM(qml.operation.Operation): | ||
| r"""Bucket-brigade QRAM with **explicit bus routing** using 3 qubits per node, | ||
| and an optional **select (MSB) prefix**, plus **hybrid** support. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The one part of Bucket Brigade QRAM I am still unclear about is how once we have traversed the tree and have an active path from the root to a leaf, we actually translate this to a loading of the corresponding data into the data register?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The BB QRAM undergoes three steps to query the data, including address loading, data retrieval, and address unloading. Address loading can be understood as a unitary operation that implements a transformation between binary encoding and unary encoding. Data retrieval, where the loading of the corresponding data happens, directly applies the data for each entry in the unary encoding to the corresponding location. Since unary encoding every entry in the address has seperated qubits, such loading won't affect each other. Finally the unloading of the address ``compress'' the encoding back into binary and finish the query.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks!
| portL_wires: Sequence[int], | ||
| portR_wires: Sequence[int], | ||
| *, | ||
| mode: str = "quantum", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is the benefit of hybrid mode? Is it merely a trade-off of qubit count versus speedup?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is the advantage of being able to do an access in superposition?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Basically yes, it is trade off between qubit and time
| ) | ||
|
|
||
| # ----------------------------- | ||
| # TODOs / Extensions |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are these TODOs something we can help with? How would we like to plan out and distribute this work?
|
I also just want to invite @albi3ro to share any of the thoughts she had on refactoring / structuring this code. :) |
| else: | ||
| target = self._portR(self.n_k - 1, p >> 1) | ||
| bit = self.bitstrings[p][j] | ||
| if bit == "1": |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How will the leaves' ops need to be handled once we actually have this template running on a quantum backend? Will there need to be a change?
|
Is there value in making this capture compatible? |
| ops.append(SWAP(wires=[tw, self.bus_wire[0]])) | ||
| return ops | ||
|
|
||
| # not work yet |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am curious what about this decomposition particularly doesn't work yet?
| ops += self._unmark_routers_via_bus() | ||
| return ops | ||
|
|
||
| # Not work yet |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Curious also about what in particular doesn't work about this decomposition yet.


Context: QRAM implementation based on https://arxiv.org/pdf/2502.06767
Description of the Change: Adds QRAMtemplate, tests, and documentation
Benefits:
Possible Drawbacks:
Related GitHub Issues: