Skip to content

Commit

Permalink
Merge branch 'main' into sparse
Browse files Browse the repository at this point in the history
  • Loading branch information
charlesyuan314 authored Jul 17, 2024
2 parents c888899 + 7f3e929 commit c2ad903
Show file tree
Hide file tree
Showing 16 changed files with 625 additions and 47 deletions.
11 changes: 11 additions & 0 deletions dev_tools/autogenerate-bloqs-notebooks-v2.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@
from qualtran_dev_tools.jupyter_autogen import NotebookSpecV2, render_notebook

import qualtran.bloqs.arithmetic.addition
import qualtran.bloqs.arithmetic.bitwise
import qualtran.bloqs.arithmetic.permutation
import qualtran.bloqs.arithmetic.sorting
import qualtran.bloqs.arithmetic.subtraction
Expand Down Expand Up @@ -337,6 +338,11 @@
qualtran.bloqs.arithmetic.addition._ADD_K_DOC,
],
),
NotebookSpecV2(
title='Negation',
module=qualtran.bloqs.arithmetic.negate,
bloq_specs=[qualtran.bloqs.arithmetic.negate._NEGATE_DOC],
),
NotebookSpecV2(
title='Subtraction',
module=qualtran.bloqs.arithmetic.subtraction,
Expand Down Expand Up @@ -395,6 +401,11 @@
qualtran.bloqs.arithmetic.permutation._PERMUTATION_CYCLE_DOC,
],
),
NotebookSpecV2(
title='Bitwise Operations',
module=qualtran.bloqs.arithmetic.bitwise,
bloq_specs=[qualtran.bloqs.arithmetic.bitwise._XOR_DOC],
),
]

MOD_ARITHMETIC = [
Expand Down
2 changes: 2 additions & 0 deletions docs/bloqs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -60,12 +60,14 @@ Bloqs Library
:caption: Arithmetic:

arithmetic/addition.ipynb
arithmetic/negate.ipynb
arithmetic/subtraction.ipynb
arithmetic/multiplication.ipynb
arithmetic/comparison.ipynb
arithmetic/sorting.ipynb
arithmetic/conversions.ipynb
arithmetic/permutation.ipynb
arithmetic/bitwise.ipynb

.. toctree::
:maxdepth: 2
Expand Down
6 changes: 5 additions & 1 deletion qualtran/_infra/data_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -221,7 +221,11 @@ def to_bits(self, x: int) -> List[int]:
def from_bits(self, bits: Sequence[int]) -> int:
"""Combine individual bits to form x"""
sign = bits[0]
x = QUInt(self.bitsize - 1).from_bits([1 - x if sign else x for x in bits[1:]])
x = (
0
if self.bitsize == 1
else QUInt(self.bitsize - 1).from_bits([1 - x if sign else x for x in bits[1:]])
)
return ~x if sign else x

def assert_valid_classical_val(self, val: int, debug_str: str = 'val'):
Expand Down
4 changes: 3 additions & 1 deletion qualtran/bloqs/arithmetic/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
# limitations under the License.

from qualtran.bloqs.arithmetic.addition import Add, AddK, OutOfPlaceAdder
from qualtran.bloqs.arithmetic.bitwise import Xor, XorK
from qualtran.bloqs.arithmetic.comparison import (
BiQubitsMixer,
EqualsAConstant,
Expand All @@ -33,7 +34,8 @@
SquareRealNumber,
SumOfSquares,
)
from qualtran.bloqs.arithmetic.negate import Negate
from qualtran.bloqs.arithmetic.sorting import BitonicSort, Comparator
from qualtran.bloqs.arithmetic.subtraction import Subtract

from ._shims import CHalf, Lt, MultiCToffoli, Negate
from ._shims import CHalf, Lt, MultiCToffoli
9 changes: 0 additions & 9 deletions qualtran/bloqs/arithmetic/_shims.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,12 +63,3 @@ class CHalf(Bloq):
@cached_property
def signature(self) -> 'Signature':
return Signature([Register('ctrl', QBit()), Register('x', QUInt(self.n))])


@frozen
class Negate(Bloq):
n: int

@cached_property
def signature(self) -> 'Signature':
return Signature([Register('x', QUInt(self.n))])
160 changes: 160 additions & 0 deletions qualtran/bloqs/arithmetic/bitwise.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
{
"cells": [
{
"cell_type": "markdown",
"id": "046f6195",
"metadata": {
"cq.autogen": "title_cell"
},
"source": [
"# Bitwise Operations"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "e7fb03a9",
"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": "18fe7319",
"metadata": {
"cq.autogen": "Xor.bloq_doc.md"
},
"source": [
"## `Xor`\n",
"Xor the value of one register into another via CNOTs.\n",
"\n",
"When both registers are in computational basis and the destination is 0,\n",
"effectively copies the value of the source into the destination.\n",
"\n",
"#### Parameters\n",
" - `dtype`: Data type of the input registers `x` and `y`. \n",
"\n",
"#### Registers\n",
" - `x`: The source register.\n",
" - `y`: The target register.\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "9304ba8f",
"metadata": {
"cq.autogen": "Xor.bloq_doc.py"
},
"outputs": [],
"source": [
"from qualtran.bloqs.arithmetic import Xor"
]
},
{
"cell_type": "markdown",
"id": "0432ed40",
"metadata": {
"cq.autogen": "Xor.example_instances.md"
},
"source": [
"### Example Instances"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "55b01f5d",
"metadata": {
"cq.autogen": "Xor.xor"
},
"outputs": [],
"source": [
"xor = Xor(QAny(4))"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "8b8090ff",
"metadata": {
"cq.autogen": "Xor.xor_symb"
},
"outputs": [],
"source": [
"xor_symb = Xor(QAny(sympy.Symbol(\"n\")))"
]
},
{
"cell_type": "markdown",
"id": "45b7826f",
"metadata": {
"cq.autogen": "Xor.graphical_signature.md"
},
"source": [
"#### Graphical Signature"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "320f183d",
"metadata": {
"cq.autogen": "Xor.graphical_signature.py"
},
"outputs": [],
"source": [
"from qualtran.drawing import show_bloqs\n",
"show_bloqs([xor, xor_symb],\n",
" ['`xor`', '`xor_symb`'])"
]
},
{
"cell_type": "markdown",
"id": "b17250e4",
"metadata": {
"cq.autogen": "Xor.call_graph.md"
},
"source": [
"### Call Graph"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "0ff8ffa9",
"metadata": {
"cq.autogen": "Xor.call_graph.py"
},
"outputs": [],
"source": [
"from qualtran.resource_counting.generalizers import ignore_split_join\n",
"xor_g, xor_sigma = xor.call_graph(max_depth=1, generalizer=ignore_split_join)\n",
"show_call_graph(xor_g)\n",
"show_counts_sigma(xor_sigma)"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"name": "python"
}
},
"nbformat": 4,
"nbformat_minor": 5
}
67 changes: 67 additions & 0 deletions qualtran/bloqs/arithmetic/bitwise.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,16 @@
from typing import cast, Dict, Optional, Set, Tuple, TYPE_CHECKING

import numpy as np
import sympy
from attrs import frozen

from qualtran import (
Bloq,
bloq_example,
BloqBuilder,
BloqDocSpec,
DecomposeTypeError,
QAny,
QBit,
QDType,
QUInt,
Expand All @@ -36,6 +40,7 @@

if TYPE_CHECKING:
from qualtran.resource_counting import BloqCountT, SympySymbolAllocator
from qualtran.simulation.classical_sim import ClassicalValT


def _cvs_converter(vv):
Expand All @@ -58,6 +63,7 @@ class XorK(SpecializedSingleQubitControlledGate):
x: A quantum register of type `self.dtype` (see above).
ctrl: A sequence of control qubits (only when `control_val` is not None).
"""

dtype: QDType
k: SymbolicInt
control_val: Optional[int] = None
Expand Down Expand Up @@ -118,3 +124,64 @@ def _cxork() -> XorK:
cxork = XorK(QUInt(8), 0b01010111).controlled()
assert isinstance(cxork, XorK)
return cxork


@frozen
class Xor(Bloq):
"""Xor the value of one register into another via CNOTs.
When both registers are in computational basis and the destination is 0,
effectively copies the value of the source into the destination.
Args:
dtype: Data type of the input registers `x` and `y`.
Registers:
x: The source register.
y: The target register.
"""

dtype: QDType

@cached_property
def signature(self) -> Signature:
return Signature.build_from_dtypes(x=self.dtype, y=self.dtype)

def build_composite_bloq(self, bb: BloqBuilder, x: Soquet, y: Soquet) -> Dict[str, SoquetT]:
if not isinstance(self.dtype.num_qubits, int):
raise DecomposeTypeError("`dtype.num_qubits` must be a concrete value.")

xs = bb.split(x)
ys = bb.split(y)

for i in range(len(xs)):
xs[i], ys[i] = bb.add_t(CNOT(), ctrl=xs[i], target=ys[i])

return {'x': bb.join(xs, dtype=self.dtype), 'y': bb.join(ys, dtype=self.dtype)}

def build_call_graph(self, ssa: 'SympySymbolAllocator') -> Set['BloqCountT']:
return {(CNOT(), self.dtype.num_qubits)}

def on_classical_vals(
self, x: 'ClassicalValT', y: 'ClassicalValT'
) -> Dict[str, 'ClassicalValT']:
return {'x': x, 'y': x ^ y}


@bloq_example
def _xor() -> Xor:
xor = Xor(QAny(4))
return xor


@bloq_example
def _xor_symb() -> Xor:
xor_symb = Xor(QAny(sympy.Symbol("n")))
return xor_symb


_XOR_DOC = BloqDocSpec(
bloq_cls=Xor,
import_line='from qualtran.bloqs.arithmetic import Xor',
examples=(_xor, _xor_symb),
)
37 changes: 35 additions & 2 deletions qualtran/bloqs/arithmetic/bitwise_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,13 @@
# 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 qualtran import QUInt
from qualtran.bloqs.arithmetic.bitwise import _cxork, _xork, XorK

import numpy as np
import pytest

from qualtran import BloqBuilder, QAny, QUInt
from qualtran.bloqs.arithmetic.bitwise import _cxork, _xor, _xor_symb, _xork, Xor, XorK
from qualtran.bloqs.basic_gates import IntEffect, IntState


def test_examples(bloq_autotester):
Expand All @@ -36,3 +41,31 @@ def test_xork_classical_sim():
ctrl_out, x_out = cbloq.call_classically(ctrl=1, x=x)
assert ctrl_out == 1
assert x_out == x ^ k


def test_xor(bloq_autotester):
bloq_autotester(_xor)


def test_xor_symb(bloq_autotester):
bloq_autotester(_xor_symb)


@pytest.mark.parametrize("dtype", [QAny(4), QUInt(4)])
@pytest.mark.parametrize("x", range(16))
@pytest.mark.parametrize("y", range(16))
def test_xor_call(dtype, x, y):
bloq = Xor(dtype)
x_out, y_out = bloq.call_classically(x=x, y=y)
assert x_out == x and y_out == x ^ y
x_out, y_out = bloq.decompose_bloq().call_classically(x=x, y=y)
assert x_out == x and y_out == x ^ y

bb = BloqBuilder()
x_soq = bb.add(IntState(x, 4))
y_soq = bb.add(IntState(y, 4))
x_soq, y_soq = bb.add_t(bloq, x=x_soq, y=y_soq)
bb.add(IntEffect(x, 4), val=x_soq)
bloq = bb.finalize(y=y_soq)

np.testing.assert_allclose(bloq.tensor_contract(), IntState(x ^ y, 4).tensor_contract())
Loading

0 comments on commit c2ad903

Please sign in to comment.