-
Notifications
You must be signed in to change notification settings - Fork 59
Implement PRODUCT decomposition #1542
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
base: main
Are you sure you want to change the base?
Conversation
Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA). View this failed invocation of the CLA check for more information. For the most up to date status, view the checks section at the bottom of the pull request. |
@NoureldinYosri can you take a look Ideally, we'd be adding new decompositions using the idiomatic qualtran style ( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@christopherkang thank you for your contribution. I see that you styled your code in the same way as the other bloqs in the file which is great ... however this file was written in the early days of Qualtran and now we have new ways for doing things. please use the examples I left to remodel your code
@@ -343,6 +351,51 @@ def build_call_graph(self, ssa: 'SympySymbolAllocator') -> 'BloqCountDictT': | |||
# See: https://github.com/quantumlib/Qualtran/issues/217 | |||
num_toff = 2 * self.a_bitsize * self.b_bitsize - max(self.a_bitsize, self.b_bitsize) | |||
return {Toffoli(): num_toff} | |||
|
|||
def decompose_from_registers( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
please use the idiomatic way of defining the construction instead of the legacy way... the idiomatic way makes the construction more readable. you can use this as an example
Qualtran/qualtran/bloqs/arithmetic/comparison.py
Lines 988 to 1006 in 60037bc
def build_composite_bloq( | |
self, bb: 'BloqBuilder', x: 'Soquet', y: 'Soquet', target: 'Soquet' | |
) -> Dict[str, 'SoquetT']: | |
if is_symbolic(self.bitsize): | |
raise DecomposeTypeError(f"Cannot decompose {self} with symbolic `bitsize`.") | |
cvs: Union[list[int], HasLength] | |
if isinstance(self.bitsize, int): | |
cvs = [0] * self.bitsize | |
else: | |
cvs = HasLength(self.bitsize) | |
x, y = bb.add(Xor(self.dtype), x=x, y=y) | |
y_split = bb.split(y) | |
y_split, target = bb.add(MultiControlX(cvs=cvs), controls=y_split, target=target) | |
y = bb.join(y_split, self.dtype) | |
x, y = bb.add(Xor(self.dtype), x=x, y=y) | |
return {'x': x, 'y': y, 'target': target} |
@@ -119,6 +120,94 @@ def test_product(): | |||
num_toff = 2 * bitsize * mbits - max(bitsize, mbits) | |||
assert t_complexity(cbloq) == TComplexity(t=4 * num_toff) | |||
|
|||
def test_product_gates(): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we have methods that do most of the testing, you can use these as example
Qualtran/qualtran/bloqs/mod_arithmetic/mod_subtraction_test.py
Lines 209 to 248 in 60037bc
@pytest.mark.parametrize('cv', range(2)) | |
@pytest.mark.parametrize('dtype', [QUInt, QMontgomeryUInt]) | |
@pytest.mark.parametrize( | |
['prime', 'bitsize'], [(p, n) for p in (13, 17, 23) for n in range(p.bit_length(), 10)] | |
) | |
def test_cmodsub_decomposition(cv, dtype, bitsize, prime): | |
b = CModSub(dtype(bitsize), prime, cv) | |
qlt_testing.assert_valid_bloq_decomposition(b) | |
@pytest.mark.parametrize('cv', range(2)) | |
@pytest.mark.parametrize('dtype', [QUInt, QMontgomeryUInt]) | |
@pytest.mark.parametrize( | |
['prime', 'bitsize'], [(p, n) for p in (13, 17, 23) for n in range(p.bit_length(), 10)] | |
) | |
def test_cmodsub_bloq_counts(cv, dtype, bitsize, prime): | |
b = CModSub(dtype(bitsize), prime, cv) | |
qlt_testing.assert_equivalent_bloq_counts(b) | |
@pytest.mark.slow | |
@pytest.mark.parametrize('cv', range(2)) | |
@pytest.mark.parametrize('dtype', [QUInt, QMontgomeryUInt]) | |
@pytest.mark.parametrize( | |
['prime', 'bitsize'], [(p, n) for p in (13, 17) for n in range(p.bit_length(), 6)] | |
) | |
def test_cmodsub_classical_action(cv, dtype, bitsize, prime): | |
b = CModSub(dtype(bitsize), prime, cv) | |
qlt_testing.assert_consistent_classical_action(b, ctrl=range(2), x=range(prime), y=range(prime)) | |
@pytest.mark.slow | |
@pytest.mark.parametrize('prime', (10**9 + 7, 10**9 + 9)) | |
@pytest.mark.parametrize('bitsize', (32, 33)) | |
def test_cmodsub_classical_action_large(bitsize, prime): | |
b = CModSub(QMontgomeryUInt(bitsize), prime) | |
rng = np.random.default_rng(13324) | |
qlt_testing.assert_consistent_classical_action( | |
b, ctrl=(1,), x=rng.choice(prime, 5).tolist(), y=rng.choice(prime, 5).tolist() | |
) |
I have performed a quick implementation of the
PRODUCT
function using the implementation suggested in https://arxiv.org/pdf/2007.07391 (page 69).This addresses issue #485.
Some notes:
AND
bloq. It is important to use theAND
bloq because theAND.adjoint
natively allows us to uncompute without additional Toffoli complexity (by using the strategies from Gidney)