Skip to content

Commit 1da6f23

Browse files
committed
planted noisy kXOR algorithm
1 parent 3117a84 commit 1da6f23

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

55 files changed

+14300
-19
lines changed

dev_tools/qualtran_dev_tools/notebook_specs.py

+56
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,9 @@
9090
import qualtran.bloqs.gf_arithmetic.gf2_multiplication
9191
import qualtran.bloqs.gf_arithmetic.gf2_square
9292
import qualtran.bloqs.hamiltonian_simulation.hamiltonian_simulation_by_gqsp
93+
import qualtran.bloqs.max_k_xor_sat
94+
import qualtran.bloqs.max_k_xor_sat.arithmetic
95+
import qualtran.bloqs.max_k_xor_sat.guided_hamiltonian
9396
import qualtran.bloqs.mcmt.and_bloq
9497
import qualtran.bloqs.mcmt.controlled_via_and
9598
import qualtran.bloqs.mcmt.ctrl_spec_and
@@ -859,6 +862,58 @@
859862
),
860863
]
861864

865+
# --------------------------------------------------------------------------
866+
# ----- Quartic Speedups paper ------------------------------------------
867+
# --------------------------------------------------------------------------
868+
ALGO_QUARTIC_SPEEDUPS = [
869+
# ----- Preliminaries ------------------------------------------
870+
NotebookSpecV2(
871+
title='Guided (sparse) Hamiltonian Problem',
872+
module=qualtran.bloqs.max_k_xor_sat.guided_hamiltonian.guided_hamiltonian,
873+
bloq_specs=[
874+
qualtran.bloqs.max_k_xor_sat.guided_hamiltonian.guided_hamiltonian._GUIDED_HAMILTONIAN_DOC,
875+
qualtran.bloqs.max_k_xor_sat.guided_hamiltonian.guided_hamiltonian._GUIDED_HAMILTONIAN_PHASE_ESTIMATION_DOC,
876+
],
877+
),
878+
NotebookSpecV2(
879+
title='Arithmetic Primitives',
880+
module=qualtran.bloqs.max_k_xor_sat.arithmetic,
881+
bloq_specs=[
882+
qualtran.bloqs.max_k_xor_sat.arithmetic.sort_in_place._SORT_IN_PLACE_DOC,
883+
qualtran.bloqs.max_k_xor_sat.arithmetic.symmetric_difference._SYMMETRIC_DIFFERENCE_DOC,
884+
qualtran.bloqs.max_k_xor_sat.arithmetic.has_duplicates._HAS_DUPLICATES_DOC,
885+
],
886+
),
887+
# ----- Algorithm ------------------------------------------
888+
NotebookSpecV2(
889+
title='kXOR: Instance load Oracles',
890+
module=qualtran.bloqs.max_k_xor_sat.load_kxor_instance,
891+
bloq_specs=[qualtran.bloqs.max_k_xor_sat.load_kxor_instance._LOAD_INSTANCE_DOC],
892+
),
893+
NotebookSpecV2(
894+
title='Noisy kXOR: Guiding State',
895+
module=qualtran.bloqs.max_k_xor_sat.guiding_state,
896+
bloq_specs=[
897+
qualtran.bloqs.max_k_xor_sat.guiding_state._SIMPLE_GUIDING_STATE_DOC,
898+
qualtran.bloqs.max_k_xor_sat.guiding_state._GUIDING_STATE_DOC,
899+
],
900+
),
901+
NotebookSpecV2(
902+
title='Noisy kXOR: Block-encoding the Kikuchi Matrix',
903+
module=qualtran.bloqs.max_k_xor_sat.kikuchi_block_encoding,
904+
bloq_specs=[
905+
qualtran.bloqs.max_k_xor_sat.kikuchi_adjacency_matrix._KIKUCHI_MATRIX_ENTRY_DOC,
906+
qualtran.bloqs.max_k_xor_sat.kikuchi_adjacency_list._KIKUCHI_NONZERO_INDEX_DOC,
907+
qualtran.bloqs.max_k_xor_sat.kikuchi_block_encoding._KIKUCHI_HAMILTONIAN_DOC,
908+
],
909+
),
910+
NotebookSpecV2(
911+
title='Algorithm: Planted Noise kXOR',
912+
module=qualtran.bloqs.max_k_xor_sat.planted_noisy_kxor,
913+
bloq_specs=[qualtran.bloqs.max_k_xor_sat.planted_noisy_kxor._PLANTED_NOISY_KXOR_DOC],
914+
),
915+
]
916+
862917
NB_BY_SECTION = [
863918
('Basic Gates', BASIC_GATES),
864919
('Chemistry', CHEMISTRY),
@@ -867,5 +922,6 @@
867922
('GF Arithmetic', GF_ARITHMETIC),
868923
('Rotations', ROT_QFT_PE),
869924
('Block Encoding', BLOCK_ENCODING),
925+
('Paper: Quartic Quantum Speedups for Planted Inference', ALGO_QUARTIC_SPEEDUPS),
870926
('Other', OTHER),
871927
]

docs/bloqs/index.rst

+11
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,17 @@ Bloqs Library
132132
block_encoding/chebyshev_polynomial.ipynb
133133
block_encoding/lcu_block_encoding.ipynb
134134

135+
.. toctree::
136+
:maxdepth: 2
137+
:caption: Paper: Quartic Quantum Speedups for Planted Inference:
138+
139+
max_k_xor_sat/guided_hamiltonian/guided_hamiltonian.ipynb
140+
max_k_xor_sat/arithmetic/arithmetic.ipynb
141+
max_k_xor_sat/load_kxor_instance.ipynb
142+
max_k_xor_sat/guiding_state.ipynb
143+
max_k_xor_sat/kikuchi_block_encoding.ipynb
144+
max_k_xor_sat/planted_noisy_kxor.ipynb
145+
135146
.. toctree::
136147
:maxdepth: 2
137148
:caption: Other:

qualtran/bloqs/arithmetic/sorting.py

+6-5
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
bloq_example,
2424
BloqBuilder,
2525
BloqDocSpec,
26+
DecomposeNotImplementedError,
2627
DecomposeTypeError,
2728
QBit,
2829
QUInt,
@@ -222,8 +223,6 @@ def __attrs_post_init__(self):
222223
k = self.half_length
223224
if not is_symbolic(k):
224225
assert k >= 1, "length of input lists must be positive"
225-
# TODO(#1090) support non-power-of-two input lengths
226-
assert (k & (k - 1)) == 0, "length of input lists must be a power of 2"
227226

228227
@cached_property
229228
def signature(self) -> 'Signature':
@@ -249,14 +248,16 @@ def is_symbolic(self):
249248
def build_composite_bloq(
250249
self, bb: 'BloqBuilder', xs: 'SoquetT', ys: 'SoquetT'
251250
) -> dict[str, 'SoquetT']:
252-
if is_symbolic(self.half_length):
251+
k = self.half_length
252+
if is_symbolic(k):
253253
raise DecomposeTypeError(f"Cannot decompose symbolic {self=}")
254+
if (k & (k - 1)) == 0:
255+
# TODO(#1090) support non-power-of-two input lengths
256+
raise DecomposeNotImplementedError("length of input lists must be a power of 2")
254257

255258
assert isinstance(xs, np.ndarray)
256259
assert isinstance(ys, np.ndarray)
257260

258-
k = self.half_length
259-
260261
first_round_junk = []
261262
for i in range(k):
262263
xs[i], ys[k - 1 - i], anc = bb.add(Comparator(self.bitsize), a=xs[i], b=ys[k - 1 - i])

qualtran/bloqs/block_encoding/__init__.py

+1
Original file line numberDiff line numberDiff line change
@@ -23,5 +23,6 @@
2323
from qualtran.bloqs.block_encoding.phase import Phase
2424
from qualtran.bloqs.block_encoding.product import Product
2525
from qualtran.bloqs.block_encoding.sparse_matrix import SparseMatrix
26+
from qualtran.bloqs.block_encoding.sparse_matrix_hermitian import SparseMatrixHermitian
2627
from qualtran.bloqs.block_encoding.tensor_product import TensorProduct
2728
from qualtran.bloqs.block_encoding.unitary import Unitary

qualtran/bloqs/block_encoding/block_encoding_base.py

+8
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,14 @@ def ancilla_bitsize(self) -> SymbolicInt:
8484
def resource_bitsize(self) -> SymbolicInt:
8585
"""The number of resource qubits not counted in ancillas."""
8686

87+
@property
88+
def ctrl_bitsize(self) -> SymbolicInt:
89+
"""The number of control qubits, useful to define optimized custom controlled circuits.
90+
91+
Usually either 0 or 1, as all other control cases can be reduced to 1.
92+
"""
93+
return 0
94+
8795
@property
8896
@abc.abstractmethod
8997
def epsilon(self) -> SymbolicFloat:
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,203 @@
1+
{
2+
"cells": [
3+
{
4+
"cell_type": "markdown",
5+
"id": "30c4ebd9",
6+
"metadata": {
7+
"cq.autogen": "title_cell"
8+
},
9+
"source": [
10+
"# Sparse Matrix (Hermitian)"
11+
]
12+
},
13+
{
14+
"cell_type": "code",
15+
"execution_count": null,
16+
"id": "e5d9072c",
17+
"metadata": {
18+
"cq.autogen": "top_imports"
19+
},
20+
"outputs": [],
21+
"source": [
22+
"from qualtran import Bloq, CompositeBloq, BloqBuilder, Signature, Register\n",
23+
"from qualtran import QBit, QInt, QUInt, QAny\n",
24+
"from qualtran.drawing import show_bloq, show_call_graph, show_counts_sigma\n",
25+
"from typing import *\n",
26+
"import numpy as np\n",
27+
"import sympy\n",
28+
"import cirq"
29+
]
30+
},
31+
{
32+
"cell_type": "markdown",
33+
"id": "9cb4d637",
34+
"metadata": {
35+
"cq.autogen": "SparseMatrixHermitian.bloq_doc.md"
36+
},
37+
"source": [
38+
"## `SparseMatrixHermitian`\n",
39+
"Hermitian Block encoding of a sparse-access Hermitian matrix.\n",
40+
"\n",
41+
"Given column and entry oracles $O_c$ and $O_A$ for an $s$-sparse Hermitian matrix\n",
42+
"$A \\in \\mathbb{C}^{2^n \\times 2^n}$, i.e. one where each row / column has exactly $s$ non-zero\n",
43+
"entries, computes a $(s, n+1, \\epsilon)$-block encoding of $A$ as follows:\n",
44+
"```\n",
45+
" ┌────┐\n",
46+
"a |0> ─┤ ├─ |0> ───────────────────────X────────────────────\n",
47+
" │ │ ┌──┐ | ┌──┐\n",
48+
" │ U │ = │ n│ ┌────┐ ┌────┐ | ┌────┐ ┌────┐ │ n│\n",
49+
"l |0^n> ─┤ A ├─ |0^n> ─┤H ├─┤ O ├─┤ ├─X──|─┤ ├─┤ O* ├─┤H ├─\n",
50+
" │ │ └──┘ | c | │ │ | | │ │ | c | └──┘\n",
51+
" │ │ └────┘ │ O │ │ | │ O* │ └────┘\n",
52+
"b |0> ─┤ ├─ |0> ────────|────┤ A ├─|──X─┤ A ├───|─────────\n",
53+
" | | ┌────┐ | | | | | ┌────┐\n",
54+
" | | | O | | | | | | | O* |\n",
55+
"j |Psi> ─┤ ├─ |Psi> ──────┤ c ├─┤ ├─X────┤ ├─┤ c ├──────\n",
56+
" └────┘ └────┘ └────┘ └────┘ └────┘\n",
57+
"```\n",
58+
"\n",
59+
"To encode a matrix of irregular dimension, the matrix should first be embedded into one of\n",
60+
"dimension $2^n \\times 2^n$ for suitable $n$.\n",
61+
"To encode a matrix where each row / column has at most $s$ non-zero entries, some zeroes should\n",
62+
"be treated as if they were non-zero so that each row / column has exactly $s$ non-zero entries.\n",
63+
"\n",
64+
"For encoding a non-hermitian matrix, or a slightly more efficient (but non Hermitian-encoding)\n",
65+
"of a matrix, use :class:`SparseMatrix` instead.\n",
66+
"\n",
67+
"#### Parameters\n",
68+
" - `col_oracle`: The column oracle $O_c$. See `RowColumnOracle` for definition.\n",
69+
" - `entry_oracle`: The entry oracle $O_A$. See `EntryOracle` for definition.\n",
70+
" - `eps`: The precision of the block encoding. \n",
71+
"\n",
72+
"#### Registers\n",
73+
" - `ctrl`: The single qubit control register. (present only if `cv` is not `None`)\n",
74+
" - `system`: The system register.\n",
75+
" - `ancilla`: The ancilla register.\n",
76+
" - `resource`: The resource register (present only if `bitsize > 0`). \n",
77+
"\n",
78+
"#### References\n",
79+
" - [Lecture Notes on Quantum Algorithms for Scientific Computation](https://arxiv.org/abs/2201.08309). Lin Lin (2022). Ch. 6.5. Proposition 6.8, Fig 6.7.\n"
80+
]
81+
},
82+
{
83+
"cell_type": "code",
84+
"execution_count": null,
85+
"id": "01cdcc22",
86+
"metadata": {
87+
"cq.autogen": "SparseMatrixHermitian.bloq_doc.py"
88+
},
89+
"outputs": [],
90+
"source": [
91+
"from qualtran.bloqs.block_encoding import SparseMatrixHermitian"
92+
]
93+
},
94+
{
95+
"cell_type": "markdown",
96+
"id": "6bd99e38",
97+
"metadata": {
98+
"cq.autogen": "SparseMatrixHermitian.example_instances.md"
99+
},
100+
"source": [
101+
"### Example Instances"
102+
]
103+
},
104+
{
105+
"cell_type": "code",
106+
"execution_count": null,
107+
"id": "8337e6aa",
108+
"metadata": {
109+
"cq.autogen": "SparseMatrixHermitian.sparse_matrix_symb_hermitian_block_encoding"
110+
},
111+
"outputs": [],
112+
"source": [
113+
"from qualtran.bloqs.block_encoding.sparse_matrix import TopLeftRowColumnOracle\n",
114+
"from qualtran.bloqs.block_encoding.sparse_matrix_hermitian import UniformSqrtEntryOracle\n",
115+
"\n",
116+
"n = sympy.Symbol('n', positive=True, integer=True)\n",
117+
"col_oracle = TopLeftRowColumnOracle(system_bitsize=n)\n",
118+
"entry_oracle = UniformSqrtEntryOracle(system_bitsize=n, entry=0.3)\n",
119+
"sparse_matrix_symb_hermitian_block_encoding = SparseMatrixHermitian(\n",
120+
" col_oracle, entry_oracle, eps=0\n",
121+
")"
122+
]
123+
},
124+
{
125+
"cell_type": "code",
126+
"execution_count": null,
127+
"id": "642141ad",
128+
"metadata": {
129+
"cq.autogen": "SparseMatrixHermitian.sparse_matrix_hermitian_block_encoding"
130+
},
131+
"outputs": [],
132+
"source": [
133+
"from qualtran.bloqs.block_encoding.sparse_matrix import TopLeftRowColumnOracle\n",
134+
"from qualtran.bloqs.block_encoding.sparse_matrix_hermitian import UniformSqrtEntryOracle\n",
135+
"\n",
136+
"col_oracle = TopLeftRowColumnOracle(system_bitsize=2)\n",
137+
"entry_oracle = UniformSqrtEntryOracle(system_bitsize=2, entry=0.3)\n",
138+
"sparse_matrix_hermitian_block_encoding = SparseMatrixHermitian(col_oracle, entry_oracle, eps=0)"
139+
]
140+
},
141+
{
142+
"cell_type": "markdown",
143+
"id": "4f3434b5",
144+
"metadata": {
145+
"cq.autogen": "SparseMatrixHermitian.graphical_signature.md"
146+
},
147+
"source": [
148+
"#### Graphical Signature"
149+
]
150+
},
151+
{
152+
"cell_type": "code",
153+
"execution_count": null,
154+
"id": "4b875699",
155+
"metadata": {
156+
"cq.autogen": "SparseMatrixHermitian.graphical_signature.py"
157+
},
158+
"outputs": [],
159+
"source": [
160+
"from qualtran.drawing import show_bloqs\n",
161+
"show_bloqs([sparse_matrix_symb_hermitian_block_encoding, sparse_matrix_hermitian_block_encoding],\n",
162+
" ['`sparse_matrix_symb_hermitian_block_encoding`', '`sparse_matrix_hermitian_block_encoding`'])"
163+
]
164+
},
165+
{
166+
"cell_type": "markdown",
167+
"id": "a0918562",
168+
"metadata": {
169+
"cq.autogen": "SparseMatrixHermitian.call_graph.md"
170+
},
171+
"source": [
172+
"### Call Graph"
173+
]
174+
},
175+
{
176+
"cell_type": "code",
177+
"execution_count": null,
178+
"id": "8128a66e",
179+
"metadata": {
180+
"cq.autogen": "SparseMatrixHermitian.call_graph.py"
181+
},
182+
"outputs": [],
183+
"source": [
184+
"from qualtran.resource_counting.generalizers import ignore_split_join\n",
185+
"sparse_matrix_symb_hermitian_block_encoding_g, sparse_matrix_symb_hermitian_block_encoding_sigma = sparse_matrix_symb_hermitian_block_encoding.call_graph(max_depth=1, generalizer=ignore_split_join)\n",
186+
"show_call_graph(sparse_matrix_symb_hermitian_block_encoding_g)\n",
187+
"show_counts_sigma(sparse_matrix_symb_hermitian_block_encoding_sigma)"
188+
]
189+
}
190+
],
191+
"metadata": {
192+
"kernelspec": {
193+
"display_name": "Python 3",
194+
"language": "python",
195+
"name": "python3"
196+
},
197+
"language_info": {
198+
"name": "python"
199+
}
200+
},
201+
"nbformat": 4,
202+
"nbformat_minor": 5
203+
}

0 commit comments

Comments
 (0)