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

Create KaliskiModInverse #1464

Merged
merged 14 commits into from
Oct 30, 2024
Merged

Create KaliskiModInverse #1464

merged 14 commits into from
Oct 30, 2024

Conversation

NoureldinYosri
Copy link
Contributor

@NoureldinYosri NoureldinYosri commented Oct 11, 2024

Implemented Kaliski modular inversion from appendix C5 https://arxiv.org/abs/2302.06639. The Toffoli complexity is $26n^2 + 7n - 1$ is higher than the formula in Litenski of $26n^2 + 2n$ because litenski drops constant factors in his estimates ... but these constant factors get multiplied by 2n (the number of iterations).

That's the cost of a single iteration is $13n + 3$ but litenski calculates it as $13n$

@NoureldinYosri NoureldinYosri changed the title Create KaliskiModInverse [Draft] Create KaliskiModInverse Oct 11, 2024
@NoureldinYosri NoureldinYosri changed the title [Draft] Create KaliskiModInverse Create KaliskiModInverse Oct 21, 2024
@NoureldinYosri NoureldinYosri marked this pull request as ready for review October 21, 2024 22:01
Copy link
Collaborator

@mpharrigan mpharrigan left a comment

Choose a reason for hiding this comment

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

generally lgtm, but curious to hear your response to my comment

qualtran/bloqs/mod_arithmetic/mod_division_test.py Outdated Show resolved Hide resolved
Comment on lines 452 to 484
a = b = 0
assert m == 0
m ^= f & (v == 0)
f ^= m

a ^= f & (u % 2 == 0)
m ^= f & (a == 0) & (v % 2 == 0)
b ^= a
b ^= m

t = (u > v) & (b == 0) & f
a ^= t
m ^= t

if a:
u, v = v, u
r, s = s, r

if f and b == 0:
v -= u
s += r

b ^= m
b ^= a
if f:
assert v % 2 == 0, f'{u=} {v=} {r=} {s=} {a=} {b=} {m=} {f=}'
v >>= 1
r = (r << 1) % self.mod
if a:
u, v = v, u
s, r = r, s
a ^= s == 0
return {'u': u, 'v': v, 'r': r, 's': s, 'a': a, 'b': b, 'm': m, 'f': f}
Copy link
Collaborator

Choose a reason for hiding this comment

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

This is a broader comment, but attaching it to these lines since this is the place where it's most acute.

Is this just a transcription of the individual bloq operations? ideally the classical implementation would be inspectably-correct so that we can write effective unit tests against it. If possible, we would like to avoid a unit test where one inscrutable routine produces the same output as another inscrutable routine (although this is better than nothing!). Some concrete suggestions and requests:

  • Can we have a unit test that proves that the bloqs in this PR are computing a modular inverse? You can take a bunch of numbers, run them through the bloq simulator, and assert that x * (x^-1) = 1 or use pow(x, -1, p) to validate the output.
  • Maybe some inline comments in this on_classical_vals. Presumably there's some method to this madness :)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The reason I wrote it like this is that I didn't want to write individual tests for the _KaliskiIterationStepX bloqs. Instead I prefered a blackbox style test where I test the thing that we will actually use KaliskiModInverse which produces two register, the first has the modular inverse and the second has the ancillas. The problem here is that the value in the ancilla register is not trivial.

Reimplementing this by calling the individual _KaliskiIterationStepX.on_each is not a good idea since that will make the test useless. The test now compares the output of _KaliskiIteration.on_classical_data with the output of the individual steps. but if _KaliskiIteration.on_classical_data calls those steps then the test becomes useless.


Can we have a unit test that proves that the bloqs in this PR are computing a modular inverse?

That's what test_kaliski_mod_inverse_classical_action does. The modular inverse in motegomry form is such that $x_m x_m^{-1} = (x R) (x^{-1} R) R^{-1} = R = 2^{n} \mod p$ rather than $1$; it also comes from the identity $a_m \cdot b_m = (a \cdot b)_m$. I made the test clearer.

Screenshot from 2024-10-29 10-42-51

Maybe some inline comments in this on_classical_vals. Presumably there's some method to this madness

I added a docstring explaining what happens here.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Maybe some inline comments in this on_classical_vals. Presumably there's some method to this madness

nvm I updated the method to follow the pseudocode of the original algorithm from Fig7b in https://arxiv.org/abs/2001.09580 which is alot more readable

Copy link
Collaborator

@mpharrigan mpharrigan left a comment

Choose a reason for hiding this comment

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

Thanks for the changes! I agree with all the motivation and blackbox style testing. Good to know you already had a "systems test" and even better to see it written out in a readable way now.

@mpharrigan mpharrigan merged commit b3e0748 into quantumlib:main Oct 30, 2024
8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants