Skip to content
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

ControlledAddOrSubtract Bloq #1145

Merged
merged 14 commits into from
Jul 23, 2024
Merged
7 changes: 7 additions & 0 deletions dev_tools/autogenerate-bloqs-notebooks-v2.py
Original file line number Diff line number Diff line change
Expand Up @@ -348,6 +348,13 @@
module=qualtran.bloqs.arithmetic.subtraction,
bloq_specs=[qualtran.bloqs.arithmetic.subtraction._SUB_DOC],
),
NotebookSpecV2(
title='Controlled Add-or-Subtract',
module=qualtran.bloqs.arithmetic.controlled_add_or_subtract,
bloq_specs=[
qualtran.bloqs.arithmetic.controlled_add_or_subtract._CONTROLLED_ADD_OR_SUBTRACT_DOC
],
),
NotebookSpecV2(
title='Multiplication',
module=qualtran.bloqs.arithmetic.multiplication,
Expand Down
1 change: 1 addition & 0 deletions docs/bloqs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ Bloqs Library
arithmetic/addition.ipynb
arithmetic/negate.ipynb
arithmetic/subtraction.ipynb
arithmetic/controlled_add_or_subtract.ipynb
arithmetic/multiplication.ipynb
arithmetic/comparison.ipynb
arithmetic/sorting.ipynb
Expand Down
4 changes: 2 additions & 2 deletions qualtran/bloqs/arithmetic/addition.py
Original file line number Diff line number Diff line change
Expand Up @@ -516,8 +516,8 @@ def get_ctrl_system(
def _add_ctrled(
bb: 'BloqBuilder', ctrl_soqs: Sequence['SoquetT'], in_soqs: Dict[str, 'SoquetT']
) -> Tuple[Iterable['SoquetT'], Iterable['SoquetT']]:
ctrl, x = bb.add_t(bloq, ctrls=ctrl_soqs[0], **in_soqs)
return (ctrl,), (x,)
ctrls, x = bb.add_t(bloq, ctrls=np.asarray(ctrl_soqs), **in_soqs)
return np.asarray(ctrls).tolist(), (x,)
Comment on lines +533 to +534
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

was this a bug? is there a test that would have caught it?

actually: what's going on here? the conditions above exclude any situation in where there is more than one SoquetT being passed in. For this bloq, that one SoquetT is an array of soquets

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It fails on test_tensor:

            for li in reg.all_idxs():
>               idxed_soq = in_soq[li]
E               IndexError: too many indices for array: array is 0-dimensional, but 1 were indexed


return bloq, _add_ctrled

Expand Down
181 changes: 181 additions & 0 deletions qualtran/bloqs/arithmetic/controlled_add_or_subtract.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
{
"cells": [
{
"cell_type": "markdown",
"id": "3f5866ad",
"metadata": {
"cq.autogen": "title_cell"
},
"source": [
"# Controlled Add-or-Subtract"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "2cd93efb",
"metadata": {
"cq.autogen": "top_imports"
},
"outputs": [],
"source": [
"from qualtran import Bloq, CompositeBloq, BloqBuilder, Signature, Register\n",
"from qualtran import QBit, QInt, QUInt, QAny\n",
"from qualtran.drawing import show_bloq, show_call_graph, show_counts_sigma\n",
"from typing import *\n",
"import numpy as np\n",
"import sympy\n",
"import cirq"
]
},
{
"cell_type": "markdown",
"id": "bab535ef",
"metadata": {
"cq.autogen": "ControlledAddOrSubtract.bloq_doc.md"
},
"source": [
"## `ControlledAddOrSubtract`\n",
"Transforms |1>|a>|b> to |1>|a>|b + a> and |0>|a>|b> to |0>|a>|b - a>\n",
"\n",
"Given two numbers `a`, `b` and a control bit `ctrl`, this bloq computes:\n",
"- the sum `b + a` when `ctrl=1`,\n",
"- the difference `b - a` when `ctrl=0`,\n",
"and stores it in the second register (`b`).\n",
"\n",
"This uses a controlled `Negate` followed by an uncontrolled `Add`,\n",
"which has half the T-cost of a controlled `Add`.\n",
"\n",
"#### Registers\n",
" - `ctrl`: a single control bit\n",
" - `a`: an integer value.\n",
" - `b`: an integer value. If it is not big enough to store the result, the most significant bits are dropped. \n",
"\n",
"#### References\n",
" - [Compilation of Fault-Tolerant Quantum Heuristics for Combinatorial Optimization](https://arxiv.org/abs/2007.07391). Sanders et. al. Section II-A-1, Algorithm 1.\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "759a4cb5",
"metadata": {
"cq.autogen": "ControlledAddOrSubtract.bloq_doc.py"
},
"outputs": [],
"source": [
"from qualtran.bloqs.arithmetic.controlled_add_or_subtract import ControlledAddOrSubtract"
]
},
{
"cell_type": "markdown",
"id": "e2e9a2be",
"metadata": {
"cq.autogen": "ControlledAddOrSubtract.example_instances.md"
},
"source": [
"### Example Instances"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "77844520",
"metadata": {
"cq.autogen": "ControlledAddOrSubtract.ctrl_add_or_sub_unsigned"
},
"outputs": [],
"source": [
"ctrl_add_or_sub_unsigned = ControlledAddOrSubtract(QUInt(8), QUInt(8))"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "871ae83f",
"metadata": {
"cq.autogen": "ControlledAddOrSubtract.ctrl_add_or_sub_signed"
},
"outputs": [],
"source": [
"ctrl_add_or_sub_signed = ControlledAddOrSubtract(QInt(8), QInt(8))"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "0df1d5cb",
"metadata": {
"cq.autogen": "ControlledAddOrSubtract.ctrl_add_or_sub_signed_symb"
},
"outputs": [],
"source": [
"import sympy\n",
"\n",
"n = sympy.Symbol(\"n\")\n",
"ctrl_add_or_sub_signed_symb = ControlledAddOrSubtract(QInt(n), QInt(n))"
]
},
{
"cell_type": "markdown",
"id": "a4f0e47e",
"metadata": {
"cq.autogen": "ControlledAddOrSubtract.graphical_signature.md"
},
"source": [
"#### Graphical Signature"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "76c8da21",
"metadata": {
"cq.autogen": "ControlledAddOrSubtract.graphical_signature.py"
},
"outputs": [],
"source": [
"from qualtran.drawing import show_bloqs\n",
"show_bloqs([ctrl_add_or_sub_unsigned, ctrl_add_or_sub_signed, ctrl_add_or_sub_signed_symb],\n",
" ['`ctrl_add_or_sub_unsigned`', '`ctrl_add_or_sub_signed`', '`ctrl_add_or_sub_signed_symb`'])"
]
},
{
"cell_type": "markdown",
"id": "a0d571ad",
"metadata": {
"cq.autogen": "ControlledAddOrSubtract.call_graph.md"
},
"source": [
"### Call Graph"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "eb6944d0",
"metadata": {
"cq.autogen": "ControlledAddOrSubtract.call_graph.py"
},
"outputs": [],
"source": [
"from qualtran.resource_counting.generalizers import ignore_split_join\n",
"ctrl_add_or_sub_unsigned_g, ctrl_add_or_sub_unsigned_sigma = ctrl_add_or_sub_unsigned.call_graph(max_depth=1, generalizer=ignore_split_join)\n",
"show_call_graph(ctrl_add_or_sub_unsigned_g)\n",
"show_counts_sigma(ctrl_add_or_sub_unsigned_sigma)"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"name": "python"
}
},
"nbformat": 4,
"nbformat_minor": 5
}
100 changes: 100 additions & 0 deletions qualtran/bloqs/arithmetic/controlled_add_or_subtract.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
# Copyright 2024 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from functools import cached_property
from typing import TYPE_CHECKING, Union

from attrs import field, frozen

from qualtran import Bloq, bloq_example, BloqDocSpec, QBit, QInt, QMontgomeryUInt, QUInt, Signature
from qualtran.bloqs.arithmetic import Add
from qualtran.bloqs.basic_gates import OnEach, XGate

if TYPE_CHECKING:
from qualtran import BloqBuilder, Soquet, SoquetT


@frozen
class ControlledAddOrSubtract(Bloq):
"""Transforms |1>|a>|b> to |1>|a>|b + a> and |0>|a>|b> to |0>|a>|b - a>

Given two numbers `a`, `b` and a control bit `ctrl`, this bloq computes:
- the sum `b + a` when `ctrl=1`,
- the difference `b - a` when `ctrl=0`,
and stores it in the second register (`b`).

This uses a controlled `Negate` followed by an uncontrolled `Add`,
which has half the T-cost of a controlled `Add`.

Registers:
ctrl: a single control bit
a: an integer value.
b: an integer value. If it is not big enough to store the result,
the most significant bits are dropped.

References:
[Compilation of Fault-Tolerant Quantum Heuristics for Combinatorial Optimization](https://arxiv.org/abs/2007.07391).
Sanders et. al. Section II-A-1, Algorithm 1.
"""

a_dtype: Union[QInt, QUInt, QMontgomeryUInt] = field()
b_dtype: Union[QInt, QUInt, QMontgomeryUInt] = field()

@b_dtype.default
def b_dtype_default(self):
return self.a_dtype

@cached_property
def signature(self) -> Signature:
return Signature.build_from_dtypes(ctrl=QBit(), a=self.a_dtype, b=self.b_dtype)

def build_composite_bloq(
self, bb: 'BloqBuilder', ctrl: 'Soquet', a: 'Soquet', b: 'Soquet'
) -> dict[str, 'SoquetT']:
ctrl = bb.add(XGate(), q=ctrl)
ctrl, b = bb.add(OnEach(self.b_dtype.num_qubits, XGate()).controlled(), ctrl=ctrl, q=b)

a, b = bb.add(Add(self.a_dtype, self.b_dtype), a=a, b=b)

ctrl, b = bb.add(OnEach(self.b_dtype.num_qubits, XGate()).controlled(), ctrl=ctrl, q=b)
ctrl = bb.add(XGate(), q=ctrl)

return {'ctrl': ctrl, 'a': a, 'b': b}


@bloq_example
def _ctrl_add_or_sub_unsigned() -> ControlledAddOrSubtract:
ctrl_add_or_sub_unsigned = ControlledAddOrSubtract(QUInt(8), QUInt(8))
return ctrl_add_or_sub_unsigned


@bloq_example
def _ctrl_add_or_sub_signed() -> ControlledAddOrSubtract:
ctrl_add_or_sub_signed = ControlledAddOrSubtract(QInt(8), QInt(8))
return ctrl_add_or_sub_signed


@bloq_example
def _ctrl_add_or_sub_signed_symb() -> ControlledAddOrSubtract:
import sympy

n = sympy.Symbol("n")
ctrl_add_or_sub_signed_symb = ControlledAddOrSubtract(QInt(n), QInt(n))
return ctrl_add_or_sub_signed_symb


_CONTROLLED_ADD_OR_SUBTRACT_DOC = BloqDocSpec(
bloq_cls=ControlledAddOrSubtract,
import_line='from qualtran.bloqs.arithmetic.controlled_add_or_subtract import ControlledAddOrSubtract',
examples=[_ctrl_add_or_sub_unsigned, _ctrl_add_or_sub_signed, _ctrl_add_or_sub_signed_symb],
)
Loading
Loading