Skip to content

Commit

Permalink
Merge branch 'main' into fix_zero_sized_registers
Browse files Browse the repository at this point in the history
  • Loading branch information
mpharrigan authored Jul 20, 2024
2 parents e8a751e + 1f47969 commit 650afab
Show file tree
Hide file tree
Showing 35 changed files with 2,108 additions and 99 deletions.
25 changes: 22 additions & 3 deletions dev_tools/autogenerate-bloqs-notebooks-v2.py
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,10 @@
NotebookSpecV2(
title='Hadamard',
module=qualtran.bloqs.basic_gates.hadamard,
bloq_specs=[qualtran.bloqs.basic_gates.hadamard._HADAMARD_DOC],
bloq_specs=[
qualtran.bloqs.basic_gates.hadamard._HADAMARD_DOC,
qualtran.bloqs.basic_gates.hadamard._CHADAMARD_DOC,
],
),
NotebookSpecV2(
title='CNOT',
Expand All @@ -145,6 +148,14 @@
module=qualtran.bloqs.basic_gates.s_gate,
bloq_specs=[qualtran.bloqs.basic_gates.s_gate._S_GATE_DOC],
),
NotebookSpecV2(
title='Y Gate',
module=qualtran.bloqs.basic_gates.y_gate,
bloq_specs=[
qualtran.bloqs.basic_gates.y_gate._Y_GATE_DOC,
qualtran.bloqs.basic_gates.y_gate._CY_GATE_DOC,
],
),
NotebookSpecV2(
title='And',
module=qualtran.bloqs.mcmt.and_bloq,
Expand Down Expand Up @@ -346,7 +357,10 @@
NotebookSpecV2(
title='Subtraction',
module=qualtran.bloqs.arithmetic.subtraction,
bloq_specs=[qualtran.bloqs.arithmetic.subtraction._SUB_DOC],
bloq_specs=[
qualtran.bloqs.arithmetic.subtraction._SUB_DOC,
qualtran.bloqs.arithmetic.subtraction._SUB_FROM_DOC,
],
),
NotebookSpecV2(
title='Multiplication',
Expand All @@ -359,6 +373,7 @@
qualtran.bloqs.arithmetic.multiplication._SCALE_INT_BY_REAL_DOC,
qualtran.bloqs.arithmetic.multiplication._MULTIPLY_TWO_REALS_DOC,
qualtran.bloqs.arithmetic.multiplication._SQUARE_REAL_NUMBER_DOC,
qualtran.bloqs.arithmetic.multiplication._INVERT_REAL_NUMBER_DOC,
],
),
NotebookSpecV2(
Expand Down Expand Up @@ -404,7 +419,10 @@
NotebookSpecV2(
title='Bitwise Operations',
module=qualtran.bloqs.arithmetic.bitwise,
bloq_specs=[qualtran.bloqs.arithmetic.bitwise._XOR_DOC],
bloq_specs=[
qualtran.bloqs.arithmetic.bitwise._XOR_DOC,
qualtran.bloqs.arithmetic.bitwise._BITWISE_NOT_DOC,
],
),
]

Expand Down Expand Up @@ -621,6 +639,7 @@
qualtran.bloqs.block_encoding.product._PRODUCT_DOC,
qualtran.bloqs.block_encoding.linear_combination._LINEAR_COMBINATION_DOC,
qualtran.bloqs.block_encoding.phase._PHASE_DOC,
qualtran.bloqs.block_encoding.sparse_matrix._SPARSE_MATRIX_DOC,
],
directory=f'{SOURCE_DIR}/bloqs/block_encoding/',
),
Expand Down
3 changes: 3 additions & 0 deletions dev_tools/requirements/deps/runtime.txt
Original file line number Diff line number Diff line change
Expand Up @@ -32,4 +32,7 @@ qsharp-widgets
# serialization
protobuf

# typing
typing_extensions>=4.10.0

# Note: use `pipreqs` to generate a list of dependencies based on the imports in our files.
1 change: 1 addition & 0 deletions docs/bloqs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ Bloqs Library
basic_gates/hadamard.ipynb
basic_gates/cnot.ipynb
basic_gates/s_gate.ipynb
basic_gates/y_gate.ipynb
mcmt/and_bloq.ipynb
basic_gates/states_and_effects.ipynb
swap_network/swap_network.ipynb
Expand Down
5 changes: 3 additions & 2 deletions qualtran/bloqs/arithmetic/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +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.bitwise import BitwiseNot, Xor, XorK
from qualtran.bloqs.arithmetic.comparison import (
BiQubitsMixer,
EqualsAConstant,
Expand All @@ -26,6 +26,7 @@
from qualtran.bloqs.arithmetic.conversions import SignedIntegerToTwosComplement, ToContiguousIndex
from qualtran.bloqs.arithmetic.hamming_weight import HammingWeightCompute
from qualtran.bloqs.arithmetic.multiplication import (
InvertRealNumber,
MultiplyTwoReals,
PlusEqualProduct,
Product,
Expand All @@ -36,6 +37,6 @@
)
from qualtran.bloqs.arithmetic.negate import Negate
from qualtran.bloqs.arithmetic.sorting import BitonicSort, Comparator
from qualtran.bloqs.arithmetic.subtraction import Subtract
from qualtran.bloqs.arithmetic.subtraction import Subtract, SubtractFrom

from ._shims import CHalf, Lt, MultiCToffoli
18 changes: 16 additions & 2 deletions qualtran/bloqs/arithmetic/addition.py
Original file line number Diff line number Diff line change
Expand Up @@ -129,8 +129,19 @@ def on_classical_vals(
) -> Dict[str, 'ClassicalValT']:
unsigned = isinstance(self.a_dtype, (QUInt, QMontgomeryUInt))
b_bitsize = self.b_dtype.bitsize
N = 2**b_bitsize if unsigned else 2 ** (b_bitsize - 1)
return {'a': a, 'b': int(math.fmod(a + b, N))}
N = 2**b_bitsize
if unsigned:
return {'a': a, 'b': int((a + b) % N)}

# Addition of signed integers can result in overflow. In most classical programming languages (e.g. C++)
# what happens when an overflow happens is left as an implementation detail for compiler designers.
# However for quantum subtraction the operation should be unitary and that means that the unitary of
# the bloq should be a permutation matrix.
# If we hold `a` constant then the valid range of values of `b` [-N/2, N/2) gets shifted forward or backwards
# by `a`. to keep the operation unitary overflowing values wrap around. this is the same as moving the range [0, N)
# by the same amount modulu $N$. that is add N/2 before addition and then remove it.
half_n = N >> 1
return {'a': a, 'b': int(a + b + half_n) % N - half_n}

def _circuit_diagram_info_(self, _) -> cirq.CircuitDiagramInfo:
wire_symbols = ["In(x)"] * int(self.a_dtype.bitsize)
Expand Down Expand Up @@ -188,6 +199,9 @@ def decompose_from_registers(
# reverse the order of qubits for big endian-ness.
input_bits = quregs['a'][::-1]
output_bits = quregs['b'][::-1]
if self.b_dtype.bitsize == 1:
yield CNOT().on(input_bits[0], output_bits[0])
return
ancillas = context.qubit_manager.qalloc(self.b_dtype.bitsize - 1)[::-1]
# Start off the addition by anding into the ancilla
yield And().on(input_bits[0], output_bits[0], ancillas[0])
Expand Down
7 changes: 7 additions & 0 deletions qualtran/bloqs/arithmetic/addition_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -316,6 +316,13 @@ def test_classical_add_k_unsigned(bitsize, k, x, cvs, ctrls, result):
assert bloq_classical[-1] == result


@pytest.mark.parametrize('bitsize', range(2, 5))
def test_classical_add_signed_overflow(bitsize):
bloq = Add(QInt(bitsize))
mx = 2 ** (bitsize - 1) - 1
assert bloq.call_classically(a=mx, b=mx) == (mx, -2)


# TODO: write tests for signed integer addition (subtraction)
# https://github.com/quantumlib/Qualtran/issues/606
@pytest.mark.parametrize('bitsize,k,x,cvs,ctrls,result', [(5, 2, 0, (1, 0), (1, 0), 2)])
Expand Down
113 changes: 113 additions & 0 deletions qualtran/bloqs/arithmetic/bitwise.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,119 @@
"show_call_graph(xor_g)\n",
"show_counts_sigma(xor_sigma)"
]
},
{
"cell_type": "markdown",
"id": "e31daefa",
"metadata": {
"cq.autogen": "BitwiseNot.bloq_doc.md"
},
"source": [
"## `BitwiseNot`\n",
"Flips every bit of the input register.\n",
"\n",
"#### Parameters\n",
" - `dtype`: Data type of the input register `x`. \n",
"\n",
"#### Registers\n",
" - `x`: A quantum register of type `self.dtype`.\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "b5c8e8f0",
"metadata": {
"cq.autogen": "BitwiseNot.bloq_doc.py"
},
"outputs": [],
"source": [
"from qualtran.bloqs.arithmetic.bitwise import BitwiseNot"
]
},
{
"cell_type": "markdown",
"id": "17f9af3e",
"metadata": {
"cq.autogen": "BitwiseNot.example_instances.md"
},
"source": [
"### Example Instances"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "701b7629",
"metadata": {
"cq.autogen": "BitwiseNot.bitwise_not"
},
"outputs": [],
"source": [
"bitwise_not = BitwiseNot(QUInt(4))"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "76d2c35f",
"metadata": {
"cq.autogen": "BitwiseNot.bitwise_not_symb"
},
"outputs": [],
"source": [
"n = sympy.Symbol(\"n\")\n",
"bitwise_not_symb = BitwiseNot(QUInt(n))"
]
},
{
"cell_type": "markdown",
"id": "b68ac0d3",
"metadata": {
"cq.autogen": "BitwiseNot.graphical_signature.md"
},
"source": [
"#### Graphical Signature"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "2831aab5",
"metadata": {
"cq.autogen": "BitwiseNot.graphical_signature.py"
},
"outputs": [],
"source": [
"from qualtran.drawing import show_bloqs\n",
"show_bloqs([bitwise_not, bitwise_not_symb],\n",
" ['`bitwise_not`', '`bitwise_not_symb`'])"
]
},
{
"cell_type": "markdown",
"id": "7ad37a4d",
"metadata": {
"cq.autogen": "BitwiseNot.call_graph.md"
},
"source": [
"### Call Graph"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "5b4c0241",
"metadata": {
"cq.autogen": "BitwiseNot.call_graph.py"
},
"outputs": [],
"source": [
"from qualtran.resource_counting.generalizers import ignore_split_join\n",
"bitwise_not_g, bitwise_not_sigma = bitwise_not.call_graph(max_depth=1, generalizer=ignore_split_join)\n",
"show_call_graph(bitwise_not_g)\n",
"show_counts_sigma(bitwise_not_sigma)"
]
}
],
"metadata": {
Expand Down
52 changes: 51 additions & 1 deletion qualtran/bloqs/arithmetic/bitwise.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
Soquet,
SoquetT,
)
from qualtran.bloqs.basic_gates import CNOT, XGate
from qualtran.bloqs.basic_gates import CNOT, OnEach, XGate
from qualtran.drawing import TextBox, WireSymbol
from qualtran.resource_counting.generalizers import ignore_split_join
from qualtran.symbolics import is_symbolic, SymbolicInt
Expand Down Expand Up @@ -183,3 +183,53 @@ def _xor_symb() -> Xor:
import_line='from qualtran.bloqs.arithmetic import Xor',
examples=(_xor, _xor_symb),
)


@frozen
class BitwiseNot(Bloq):
r"""Flips every bit of the input register.
Args:
dtype: Data type of the input register `x`.
Registers:
x: A quantum register of type `self.dtype`.
"""

dtype: QDType

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

def build_composite_bloq(self, bb: 'BloqBuilder', x: 'Soquet') -> dict[str, 'SoquetT']:
x = bb.add(OnEach(self.dtype.num_qubits, XGate()), q=x)
return {'x': x}

def wire_symbol(
self, reg: Optional['Register'], idx: tuple[int, ...] = tuple()
) -> 'WireSymbol':
if reg is None:
return TextBox("")

return TextBox("~x")


@bloq_example
def _bitwise_not() -> BitwiseNot:
bitwise_not = BitwiseNot(QUInt(4))
return bitwise_not


@bloq_example
def _bitwise_not_symb() -> BitwiseNot:
n = sympy.Symbol("n")
bitwise_not_symb = BitwiseNot(QUInt(n))
return bitwise_not_symb


_BITWISE_NOT_DOC = BloqDocSpec(
bloq_cls=BitwiseNot,
import_line='from qualtran.bloqs.arithmetic.bitwise import BitwiseNot',
examples=(_bitwise_not, _bitwise_not_symb),
)
44 changes: 43 additions & 1 deletion qualtran/bloqs/arithmetic/bitwise_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,16 @@
import pytest

from qualtran import BloqBuilder, QAny, QUInt
from qualtran.bloqs.arithmetic.bitwise import _xor, _xor_symb, _xork, Xor, XorK
from qualtran.bloqs.arithmetic.bitwise import (
_bitwise_not,
_bitwise_not_symb,
_xor,
_xor_symb,
_xork,
BitwiseNot,
Xor,
XorK,
)
from qualtran.bloqs.basic_gates import IntEffect, IntState


Expand Down Expand Up @@ -130,3 +139,36 @@ def test_xor_diagram():
y3: ───x⊕y───
''',
)


def test_bitwise_not_examples(bloq_autotester):
bloq_autotester(_bitwise_not)
bloq_autotester(_bitwise_not_symb)


@pytest.mark.parametrize("n", [4, 5])
def test_bitwise_not_tensor(n):
bloq = BitwiseNot(QUInt(n))

matrix = np.zeros((2**n, 2**n))
for i in range(2**n):
matrix[i, ~i] = 1

np.testing.assert_allclose(bloq.tensor_contract(), matrix)


def test_bitwise_not_diagram():
bloq = BitwiseNot(QUInt(4))
circuit = bloq.as_composite_bloq().to_cirq_circuit()
cirq.testing.assert_has_diagram(
circuit,
'''
x0: ───~x───
x1: ───~x───
x2: ───~x───
x3: ───~x───
''',
)
Loading

0 comments on commit 650afab

Please sign in to comment.