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

SelectSwapQROM revamp and upgrades #986

Merged
merged 12 commits into from
May 28, 2024

Conversation

tanujkhattar
Copy link
Collaborator

@tanujkhattar tanujkhattar commented May 22, 2024

Fixes #108
Partially addresses #368
Fixes #78

We still need an adjoint bloq for QROMs to make the complexity for clean ancilla version match that of the paper, and I haven't implemented the optimization to save one target register from https://quantum-journal.org/papers/q-2019-12-02-208/pdf/

This PR introduces major revamp to SelectSwapQROM and some upgrades to QROM. I'll add more detailed description soon

image image

@fdmalone


@cirq.value_equality(distinct_child_types=True)
@attrs.frozen
class QROMABC(abc.ABC):
Copy link
Collaborator

Choose a reason for hiding this comment

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

QROMInterface or something else, I'm not mad on ABC

Copy link
Collaborator

Choose a reason for hiding this comment

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

BaseQROM or _BaseQROM or QROMBase

@cirq.value_equality(distinct_child_types=True)
@attrs.frozen
class QROMABC(abc.ABC):
r"""Bloq to load `data[l]` in the target register when the selection stores an index `l`.
Copy link
Collaborator

Choose a reason for hiding this comment

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

See #988 for including the abstract base class docs in a notebook somewhere.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

done

|d_L[s_1, s_2, \dots, s_k]\rangle
$$

There two high level parameters that control the behavior of a QROM are -
Copy link
Collaborator

Choose a reason for hiding this comment

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

nit: There -> The


There two high level parameters that control the behavior of a QROM are -

1. Shape of the classical dataset to be loaded ($\text{data.shape} = (S_1, S_2, ..., S_K)$).
Copy link
Collaborator

Choose a reason for hiding this comment

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

nit: The shape, The number

Copy link
Collaborator

Choose a reason for hiding this comment

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

nit: datasets

to build the QROM.

### Shape of the classical dataset to be loaded.
QROM bloq supports loading multidimensional classical datasets. In order to load a data
Copy link
Collaborator

Choose a reason for hiding this comment

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

Not The or A

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Can you clarify?

Copy link
Collaborator

Choose a reason for hiding this comment

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

I'm not sure anymore lol. I think it's was meant to be nit: The (or A) QROM bloq supports...

registers with bitsizes $(p, q, r, s)$ where
$p,q,r,s=\log_2{P}, \log_2{Q}, \log_2{R}, \log_2{S}$.

In general, to load K dimensional data, we use K named selection registers `(selection0,
Copy link
Collaborator

Choose a reason for hiding this comment

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

nit: $K$ etc


If you have multiple classical datasets `(data_1, data_2, data_3, ..., data_L)` to be loaded
and each of them has the same shape `(data_1.shape == data_2.shape == ... == data_L.shape)`
and different target bitsizes `(b_1, b_2, ..., b_L)`, then one construct a single classical
Copy link
Collaborator

Choose a reason for hiding this comment

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

nit: constructs

- `data.shape == data_1.shape == data_2.shape == ... == data_L` and
- `data[idx] = f'{data_1[idx]!0{b_1}b}' + f'{data_2[idx]!0{b_2}b}' + ... + f'{data_L[idx]!0{b_L}b}'`

Thus, the target bitsize of the merged dataset is $b = b_1 + b_2 + \dots + b_L$ and clifford
Copy link
Collaborator

Choose a reason for hiding this comment

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

nit: the clifford cost

- `data[idx] = f'{data_1[idx]!0{b_1}b}' + f'{data_2[idx]!0{b_2}b}' + ... + f'{data_L[idx]!0{b_L}b}'`

Thus, the target bitsize of the merged dataset is $b = b_1 + b_2 + \dots + b_L$ and clifford
cost of loading merged dataset scales as
Copy link
Collaborator

Choose a reason for hiding this comment

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

nit: the merged



@bloq_example
def _qroam_symb_dirty() -> SelectSwapQROM:
Copy link
Collaborator

Choose a reason for hiding this comment

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

I think for the purposes of exposition it would be helpful to add a 1D example with the symbols matching those from the screenshotted costs.

)
for didx, data in enumerate([[[1, 2, 3, 4, 5]], [[1, 2, 3], [3, 2, 1]]])
for block_size in [None, 1, 2, 3]
for block_size in [None, 0, 1]
Copy link
Collaborator

Choose a reason for hiding this comment

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

Did this get slower?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

no, the different is that we now specify log_block_size instead of block_size; where block_size = 2**log_block_size.

"\n",
"The `SelectSwapQROM` is a hybrid of the following two existing primitives:\n",
"\n",
" * Unary Iteration based `QROM` requires O(N) T-gates to load `N` data\n",
Copy link
Collaborator

Choose a reason for hiding this comment

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

This doesn't format well in the notebook.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

fixed

Copy link
Collaborator

@fdmalone fdmalone left a comment

Choose a reason for hiding this comment

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

Awesome! Should we just rename it QROAM at this point?

@@ -54,7 +52,7 @@ def _to_tuple(x: Iterable[NDArray]) -> Sequence[NDArray]:

@cirq.value_equality()
@attrs.frozen
class QROM(UnaryIterationGate):
class QROM(QROMABC, UnaryIterationGate):
Copy link
Collaborator

@fdmalone fdmalone May 23, 2024

Choose a reason for hiding this comment

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

Would it make sense to ever just have a single QROM bloq where you'd get QROAM if block_size > 1, or would it make things more complicated.

from qualtran.simulation.classical_sim import ClassicalValT
from qualtran.symbolics import bit_length, is_symbolic, shape, Shaped, SymbolicInt

QROMT = TypeVar('QROMT', bound='QROMABC')
Copy link
Collaborator

Choose a reason for hiding this comment

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

QROM_T?

@mpharrigan
Copy link
Collaborator

related #699

@tanujkhattar
Copy link
Collaborator Author

I've rewritten the docs on qrom base and derived classes and used the docs from base class in the notebooks for derived classes. I think we can still continue to improve the docs, but I'll go ahead and merge this for now.

@tanujkhattar tanujkhattar enabled auto-merge (squash) May 28, 2024 19:45
@tanujkhattar tanujkhattar merged commit cdf09f2 into quantumlib:main May 28, 2024
7 checks passed
@fdmalone
Copy link
Collaborator

@tanujkhattar I remember discussing this at the time, but what's the origin in the factor of 2 difference between the ceiling term when comparing Theorem 1 and 2, I think this is not related to the inverse right?

@tanujkhattar
Copy link
Collaborator Author

Cost for the dirty ancilla case (Theorem 1) matches the Appendix A formula (2 QROMs + 4 SwapWithZero's)

Cost for the clean ancilla case is different because we need

  1. QROM + QROM.adjoint()
  2. SwapWithZero + SwapWithZero.adjoint()

Our implementation assumes that the clean ancilla are freed up as part of the decomposition. In their implementation, they only count the cost of computing the table lookup; and measure the clean ancilla in X basis and keep the measurement results around as part of a deferred uncomputation strategy. Once the QROM needs to be uncomputed, these measurement results are used along with measurement based uncomputation of table lookup described in Appendix C.

Therefore, they essentially don't incur any cost for QROM.adjoint() and SwapWithZero.adjoint() -- therefore we have a 2x overhead in the total cost compared to their cost.

@fdmalone
Copy link
Collaborator

Thank you!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
3 participants