Skip to content

Commit

Permalink
Add more arithmetic gates.
Browse files Browse the repository at this point in the history
  • Loading branch information
fdmalone committed Oct 8, 2023
1 parent ecdacc5 commit 4f990dc
Show file tree
Hide file tree
Showing 4 changed files with 277 additions and 7 deletions.
3 changes: 3 additions & 0 deletions dev_tools/autogenerate-bloqs-notebooks.py
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,9 @@
BloqNbSpec(qualtran.bloqs.arithmetic_test._make_square),
BloqNbSpec(qualtran.bloqs.arithmetic_test._make_sum_of_squares),
BloqNbSpec(qualtran.bloqs.arithmetic_test._make_greater_than),
BloqNbSpec(qualtran.bloqs.arithmetic_test._make_greater_than_constant),
BloqNbSpec(qualtran.bloqs.arithmetic_test._make_equals_a_constant),
BloqNbSpec(qualtran.bloqs.arithmetic_test._make_to_contiguous_index),
BloqNbSpec(qualtran.bloqs.arithmetic_test._make_scale_int_by_real),
BloqNbSpec(qualtran.bloqs.arithmetic_test._make_multiply_two_reals),
BloqNbSpec(qualtran.bloqs.arithmetic_test._make_square_real_number),
Expand Down
113 changes: 112 additions & 1 deletion qualtran/bloqs/arithmetic.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,6 @@
"Implements $U|a\\rangle|b\\rangle|0\\rangle \\rightarrow\n",
"|a\\rangle|b\\rangle|a > b\\rangle$ using $8n T$ gates.\n",
"\n",
"\n",
"#### Parameters\n",
" - `bitsize`: Number of bits used to represent the two integers a and b. \n",
"\n",
Expand Down Expand Up @@ -361,6 +360,118 @@
"bloq = SquareRealNumber(bitsize=10)\n",
"show_bloq(bloq)"
]
},
{
"cell_type": "markdown",
"id": "c63ef890",
"metadata": {
"cq.autogen": "_make_greater_than_constant.md"
},
"source": [
"## `GreaterThanConstant`\n",
"Implements $U_a|x\\rangle = U_a|x\\rangle|z\\rangle = |x\\rangle |z ^ (x > a)\\rangle\"\n",
"\n",
"#### Parameters\n",
" - `bitsize`: bitsize of x register.\n",
" - `val`: integer to compare x against (a above.) \n",
"\n",
"#### Registers\n",
" - `- x`: Register to compare against val.\n",
" - `- result`: Register to hold result of comparison.\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "e03bf9e1",
"metadata": {
"cq.autogen": "_make_greater_than_constant.py"
},
"outputs": [],
"source": [
"from qualtran.bloqs.arithmetic import GreaterThanConstant\n",
"\n",
"bloq = GreaterThanConstant(bitsize=4, val=13)\n",
"show_bloq(bloq)"
]
},
{
"cell_type": "markdown",
"id": "c317ee1b",
"metadata": {
"cq.autogen": "_make_equals_a_constant.md"
},
"source": [
"## `EqualsAConstant`\n",
"Implements $U_a|x\\rangle = U_a|x\\rangle|z\\rangle = |x\\rangle |z ^ (x == a)\\rangle\"\n",
"\n",
"#### Parameters\n",
" - `bitsize`: bitsize of x register.\n",
" - `val`: integer to compare x against (a above.) \n",
"\n",
"#### Registers\n",
" - `- x`: Register to compare against val.\n",
" - `- result`: Register to hold result of comparison.\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "ad925b70",
"metadata": {
"cq.autogen": "_make_equals_a_constant.py"
},
"outputs": [],
"source": [
"from qualtran.bloqs.arithmetic import EqualsAConstant\n",
"\n",
"bloq = EqualsAConstant(bitsize=4, val=13)\n",
"show_bloq(bloq)"
]
},
{
"cell_type": "markdown",
"id": "3aeab187",
"metadata": {
"cq.autogen": "_make_to_contiguous_index.md"
},
"source": [
"## `ToContiguousIndex`\n",
"Build a contiguous register s from mu and nu.\n",
"\n",
"$$\n",
" s = \\nu (\\nu + 1) / 2 + \\mu\n",
"$$\n",
"\n",
"Assuming nu is zero indexed (in contrast to the THC paper which assumes 1,\n",
"hence the slightly different formula).\n",
"\n",
"#### Parameters\n",
" - `bitsize`: number of bits for mu and nu registers.\n",
" - `s_bitsize`: Number of bits for contiguous register. \n",
"\n",
"Registers\n",
" - mu, nu: input registers\n",
" - s: output contiguous register\n",
"\n",
"#### References\n",
"(Even more efficient quantum computations of chemistry through tensor hypercontraction)[https://arxiv.org/pdf/2011.03494.pdf] Eq. 29.\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "6ba10227",
"metadata": {
"cq.autogen": "_make_to_contiguous_index.py"
},
"outputs": [],
"source": [
"from qualtran.bloqs.arithmetic import ToContiguousIndex\n",
"\n",
"bloq = ToContiguousIndex(bitsize=4, s_bitsize=8)\n",
"show_bloq(bloq)"
]
}
],
"metadata": {
Expand Down
126 changes: 120 additions & 6 deletions qualtran/bloqs/arithmetic.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,10 @@
# See the License for the specific language governing permissions and
# limitations under the License.

from typing import Optional, Set, Tuple, TYPE_CHECKING
from functools import cached_property
from typing import Dict, Optional, Set, Tuple, TYPE_CHECKING, Union

import sympy
from attrs import frozen
from cirq_ft import TComplexity

Expand Down Expand Up @@ -421,7 +423,6 @@ class GreaterThan(Bloq):
Implements $U|a\rangle|b\rangle|0\rangle \rightarrow
|a\rangle|b\rangle|a > b\rangle$ using $8n T$ gates.
Args:
bitsize: Number of bits used to represent the two integers a and b.
Expand All @@ -445,10 +446,123 @@ def pretty_name(self) -> str:
return "a gt b"

def t_complexity(self):
# TODO Determine precise clifford count and/or ignore.
# See: https://github.com/quantumlib/cirq-qubitization/issues/219
# See: https://github.com/quantumlib/cirq-qubitization/issues/217
return TComplexity(t=8 * self.bitsize)

def bloq_counts(
self, ssa: Optional['SympySymbolAllocator'] = None
) -> Set[Tuple[Union[int, sympy.Expr], Bloq]]:
return {(8*self.bitsize, TGate())}


@frozen
class GreaterThanConstant(Bloq):
r"""Implements $U_a|x\rangle = U_a|x\rangle|z\rangle = |x\rangle |z ^ (x > a)\rangle"
Args:
bitsize: bitsize of x register.
val: integer to compare x against (a above.)
Registers:
- x: Register to compare against val.
- result: Register to hold result of comparison.
"""

bitsize: int
val: int

@cached_property
def signature(self) -> Signature:
return Signature.build(x=self.bitsize, result=1)

def t_complexity(self):
return TComplexity(t=4 * self.bitsize)

def bloq_counts(
self, ssa: Optional['SympySymbolAllocator'] = None
) -> Set[Tuple[Union[int, sympy.Expr], Bloq]]:
return {(4*self.bitsize, TGate())}


@frozen
class EqualsAConstant(Bloq):
r"""Implements $U_a|x\rangle = U_a|x\rangle|z\rangle = |x\rangle |z ^ (x == a)\rangle"
Args:
bitsize: bitsize of x register.
val: integer to compare x against (a above.)
Registers:
- x: Register to compare against val.
- result: Register to hold result of comparison.
"""

bitsize: int
val: int

@cached_property
def signature(self) -> Signature:
return Signature.build(x=self.bitsize, result=1)

def t_complexity(self):
return TComplexity(t=4 * self.bitsize)

def bloq_counts(
self, ssa: Optional['SympySymbolAllocator'] = None
) -> Set[Tuple[Union[int, sympy.Expr], Bloq]]:
return {(4*self.bitsize, TGate())}


@frozen
class ToContiguousIndex(Bloq):
r"""Build a contiguous register s from mu and nu.
$$
s = \nu (\nu + 1) / 2 + \mu
$$
Assuming nu is zero indexed (in contrast to the THC paper which assumes 1,
hence the slightly different formula).
Args:
bitsize: number of bits for mu and nu registers.
s_bitsize: Number of bits for contiguous register.
Registers
- mu, nu: input registers
- s: output contiguous register
References:
(Even more efficient quantum computations of chemistry through
tensor hypercontraction)[https://arxiv.org/pdf/2011.03494.pdf] Eq. 29.
"""

bitsize: int
s_bitsize: int

@cached_property
def signature(self) -> Signature:
return Signature(
[
Register("mu", bitsize=self.bitsize),
Register("nu", bitsize=self.bitsize),
Register("s", bitsize=self.s_bitsize),
]
)

def on_classical_vals(
self, mu: 'ClassicalValT', nu: 'ClassicalValT'
) -> Dict[str, 'ClassicalValT']:
return {'mu': mu, 'nu': nu, 's': nu * (nu + 1) // 2 + mu}

def bloq_counts(
self, ssa: Optional['SympySymbolAllocator'] = None
) -> Set[Tuple[Union[int, sympy.Expr], Bloq]]:
return {(4 * (self.bitsize**2 + self.bitsize - 1), TGate())}

def t_complexity(self) -> 'cirq_ft.TComplexity':
num_toffoli = self.bitsize**2 + self.bitsize - 1
return TComplexity(t=4 * num_toffoli)

def bloq_counts(self, ssa: Optional['SympySymbolAllocator'] = None) -> Set[Tuple[int, Bloq]]:
return {(8 * self.bitsize, TGate())}
num_toffoli = self.bitsize**2 + self.bitsize - 1
return {(num_toffoli, TGate())}
42 changes: 42 additions & 0 deletions qualtran/bloqs/arithmetic_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,17 @@
from qualtran import BloqBuilder, Register
from qualtran.bloqs.arithmetic import (
Add,
EqualsAConstant,
GreaterThan,
GreaterThanConstant,
MultiplyTwoReals,
OutOfPlaceAdder,
Product,
ScaleIntByReal,
Square,
SquareRealNumber,
SumOfSquares,
ToContiguousIndex,
)
from qualtran.testing import execute_notebook

Expand Down Expand Up @@ -56,6 +59,20 @@ def _make_greater_than():

return GreaterThan(bitsize=4)

def _make_greater_than_constant():
from qualtran.bloqs.arithmetic import GreaterThanConstant

return GreaterThanConstant(bitsize=4, val=13)

def _make_equals_a_constant():
from qualtran.bloqs.arithmetic import EqualsAConstant

return EqualsAConstant(bitsize=4, val=13)

def _make_to_contiguous_index():
from qualtran.bloqs.arithmetic import ToContiguousIndex

return ToContiguousIndex(bitsize=4, s_bitsize=8)

def _make_scale_int_by_real():
from qualtran.bloqs.arithmetic import ScaleIntByReal
Expand Down Expand Up @@ -155,6 +172,31 @@ def test_greater_than():
q0, q1, anc = bb.add(GreaterThan(bitsize), a=q0, b=q1, result=anc)
cbloq = bb.finalize(a=q0, b=q1, result=anc)

def test_greater_than_constant():
bb = BloqBuilder()
bitsize = 5
q0 = bb.add_register('x', bitsize)
anc = bb.add_register('result', 1)
q0, anc = bb.add(GreaterThanConstant(bitsize, 17), x=q0, result=anc)
cbloq = bb.finalize(x=q0, result=anc)

def test_equals_a_constant():
bb = BloqBuilder()
bitsize = 5
q0 = bb.add_register('x', bitsize)
anc = bb.add_register('result', 1)
q0, anc = bb.add(EqualsAConstant(bitsize, 17), x=q0, result=anc)
cbloq = bb.finalize(x=q0, result=anc)

def test_to_contiguous_index():
bb = BloqBuilder()
bitsize = 5
q0 = bb.add_register('mu', bitsize)
q1 = bb.add_register('nu', bitsize)
out = bb.add_register('s', 1)
q0, q1, out = bb.add(ToContiguousIndex(bitsize, 2*bitsize), mu=q0, nu=q1, s=out)
cbloq = bb.finalize(mu=q0, nu=q1, s=out)


def test_notebook():
execute_notebook('arithmetic')

0 comments on commit 4f990dc

Please sign in to comment.