Skip to content

Idiomatic addition circuit #983

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

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
113 changes: 99 additions & 14 deletions qualtran/bloqs/arithmetic/addition.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
"## `Add`\n",
"An n-bit addition gate.\n",
"\n",
"Implements $U|a\\rangle|b\\rangle \\rightarrow |a\\rangle|a+b\\rangle$ using $4n - 4 T$ gates.\n",
"Implements $U|a\\rangle|b\\rangle \\rightarrow |a\\rangle|a+b\\rangle$ using $n-1$ AND gates.\n",
"\n",
"#### Parameters\n",
" - `a_dtype`: Quantum datatype used to represent the integer a.\n",
Expand All @@ -49,9 +49,81 @@
" - `b`: A b_dtype.bitsize-sized input/output register (register b above). \n",
"\n",
"#### References\n",
" - [Halving the cost of quantum addition](https://arxiv.org/abs/1709.06648). \n"
" - [Halving the cost of quantum addition](https://arxiv.org/abs/1709.06648). Gidney 2018. The construction used in this bloq, evolved from [2].\n",
" - [A new quantum ripple-carry addition circuit](https://arxiv.org/abs/quant-ph/0410184). Cuccaro et. al. 2004.\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "263c1c98-db09-4a11-bf1b-dc7426c66fce",
"metadata": {},
"outputs": [],
"source": [
"from qualtran import BloqBuilder\n",
"from qualtran.bloqs.arithmetic.addition import IdiomaticAdd, _LeftAddPart, _RightAddPart"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "f30f4130-5d5b-489a-8ed9-50902ec15431",
"metadata": {},
"outputs": [],
"source": [
"bb = BloqBuilder()\n",
"c = bb.add_register('c', 1)\n",
"i = bb.add_register('i', 1)\n",
"t = bb.add_register('t', 1)\n",
"c, i, t, cc = bb.add(_LeftAddPart(), c=c, i=i, t=t)\n",
"c, i, t = bb.add(_RightAddPart(), c=c, i=i, t=t, cc=cc)\n",
"cbloq = bb.finalize(c=c, i=i, t=t)\n",
"show_bloq(cbloq, 'musical_score')"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "13bc1255-8e3c-49f6-8c1f-c174ae64cdc8",
"metadata": {},
"outputs": [],
"source": [
"show_bloq(cbloq.flatten_once(lambda b: True), 'musical_score')"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "77d8cfcf-bae6-4420-a145-729622da23e0",
"metadata": {},
"outputs": [],
"source": [
"m = IdiomaticAdd(5)\n",
"cm = m.decompose_bloq()\n",
"show_bloq(cm, 'musical_score')"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "08645d99-8f4e-4324-9028-9401911228c7",
"metadata": {},
"outputs": [],
"source": [
"%time\n",
"m = IdiomaticAdd(10_000)\n",
"cbloq = m.decompose_bloq()\n",
"print(cbloq._binst_graph.number_of_nodes())"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "42153aa5-d2fa-46a7-b2f1-9720ef5db669",
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "code",
"execution_count": null,
Expand Down Expand Up @@ -95,7 +167,17 @@
},
"outputs": [],
"source": [
"add_large = Add(QUInt(bitsize=64))"
"add_large = Add(QUInt(bitsize=5000))"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "cbc705bc-b7cb-4f32-b3ba-0410f45f15cb",
"metadata": {},
"outputs": [],
"source": [
"add_large.decompose_bloq()"
]
},
{
Expand All @@ -116,7 +198,10 @@
"execution_count": null,
"id": "e5b746c1",
"metadata": {
"collapsed": false
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
"outputs": [],
"source": [
Expand Down Expand Up @@ -337,7 +422,7 @@
{
"cell_type": "code",
"execution_count": null,
"id": "cd255bf9",
"id": "47b4b6d7",
"metadata": {
"cq.autogen": "AddK.bloq_doc.py"
},
Expand All @@ -348,7 +433,7 @@
},
{
"cell_type": "markdown",
"id": "7538f9a5",
"id": "7152a86b",
"metadata": {
"cq.autogen": "AddK.example_instances.md"
},
Expand All @@ -359,7 +444,7 @@
{
"cell_type": "code",
"execution_count": null,
"id": "4305289f",
"id": "a50b7ae4",
"metadata": {
"cq.autogen": "AddK.add_k"
},
Expand All @@ -372,7 +457,7 @@
{
"cell_type": "code",
"execution_count": null,
"id": "f6048819",
"id": "7f7e9c09",
"metadata": {
"cq.autogen": "AddK.add_k_small"
},
Expand All @@ -384,7 +469,7 @@
{
"cell_type": "code",
"execution_count": null,
"id": "b67fd469",
"id": "802f8da2",
"metadata": {
"cq.autogen": "AddK.add_k_large"
},
Expand All @@ -395,7 +480,7 @@
},
{
"cell_type": "markdown",
"id": "b8b04228",
"id": "21737304",
"metadata": {
"cq.autogen": "AddK.graphical_signature.md"
},
Expand All @@ -406,7 +491,7 @@
{
"cell_type": "code",
"execution_count": null,
"id": "e93e7f2e",
"id": "1849daf3",
"metadata": {
"cq.autogen": "AddK.graphical_signature.py"
},
Expand All @@ -419,7 +504,7 @@
},
{
"cell_type": "markdown",
"id": "13552795",
"id": "83759458",
"metadata": {
"cq.autogen": "AddK.call_graph.md"
},
Expand All @@ -430,7 +515,7 @@
{
"cell_type": "code",
"execution_count": null,
"id": "d8d6584e",
"id": "a3c60bc5",
"metadata": {
"cq.autogen": "AddK.call_graph.py"
},
Expand Down Expand Up @@ -471,7 +556,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.11.7"
"version": "3.11.8"
}
},
"nbformat": 4,
Expand Down
77 changes: 77 additions & 0 deletions qualtran/bloqs/arithmetic/addition.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@
)
from qualtran.bloqs import util_bloqs
from qualtran.bloqs.basic_gates import CNOT, XGate
from qualtran.bloqs.mcmt import MultiTargetCNOT
from qualtran.bloqs.mcmt.and_bloq import And
from qualtran.bloqs.mcmt.multi_control_multi_target_pauli import MultiControlX
from qualtran.cirq_interop import decompose_from_cirq_style_method
Expand All @@ -73,6 +74,82 @@
from qualtran.symbolics import SymbolicInt


@frozen
class _LeftAddPart(Bloq):
"""The 'left' part of the addition building block from the reference, figure 2."""

@property
def signature(self) -> Signature:
return Signature(
[
Register('c', QUInt(1)),
Register('i', QUInt(1)),
Register('t', QUInt(1)),
Register('out', QUInt(1), side=Side.RIGHT),
]
)

def build_composite_bloq(self, bb: 'BloqBuilder', c, i, t) -> Dict[str, 'SoquetT']:
c, [i, t] = bb.add(MultiTargetCNOT(2), ctrl=c, targets=[i, t])
[i, t], out = bb.add(And(), ctrl=[i, t])
c, out = bb.add(CNOT(), ctrl=c, target=out)
return {'c': c, 'i': i, 't': t, 'out': out}


@frozen
class _RightAddPart(Bloq):
"""The 'right' part of the addition building block from the reference, figure 2."""

@property
def signature(self) -> 'Signature':
return Signature(
[
Register('c', QUInt(1)),
Register('i', QUInt(1)),
Register('t', QUInt(1)),
Register('cc', QUInt(1), side=Side.LEFT),
]
)

def build_composite_bloq(self, bb: 'BloqBuilder', c, i, t, cc) -> Dict[str, 'SoquetT']:
c, cc = bb.add(CNOT(), ctrl=c, target=cc)
i, t = bb.add(And().adjoint(), ctrl=[i, t], target=cc)
c, i = bb.add(CNOT(), ctrl=c, target=i)
i, t = bb.add(CNOT(), ctrl=i, target=t)
return {'c': c, 'i': i, 't': t}


@frozen
class IdiomaticAdd(Bloq):
"""An addition circuit; follows figure 1"""

n: 'SymbolicInt'

@property
def signature(self) -> Signature:
return Signature([Register('a', QUInt(self.n)), Register('b', QUInt(self.n))])

def build_composite_bloq(self, bb: 'BloqBuilder', a, b) -> Dict[str, 'SoquetT']:
a_bits = bb.split(a)
b_bits = bb.split(b)
anc = bb.allocate(1)
ancs = [anc]

for i in range(self.n):
ancs[-1], a_bits[i], b_bits[i], anc = bb.add(
_LeftAddPart(), c=ancs[-1], i=a_bits[i], t=b_bits[i]
)
ancs.append(anc)

for i in range(self.n - 1, -1, -1):
ancs[i], a_bits[i], b_bits[i] = bb.add(
_RightAddPart(), c=ancs[i], i=a_bits[i], t=b_bits[i], cc=ancs[i + 1]
)

bb.free(ancs[0])
return {'a': bb.join(a_bits), 'b': bb.join(b_bits)}


@frozen
class Add(Bloq):
r"""An n-bit addition gate.
Expand Down
4 changes: 3 additions & 1 deletion qualtran/bloqs/mcmt/multi_control_multi_target_pauli.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,9 @@ class MultiTargetCNOT(GateWithRegisters):

@cached_property
def signature(self) -> Signature:
return Signature.build(control=1, targets=self.bitsize)
return Signature(
[Register('ctrl', QBit()), Register('targets', QBit(), shape=(self.bitsize,))]
)

def decompose_from_registers(
self,
Expand Down
Loading