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

Implement Strong Lucas test and Baillie-PSW #323

Merged
merged 6 commits into from
Nov 13, 2024

Conversation

chiphogg
Copy link
Contributor

The Baillie-PSW is the star of the show: it's fully deterministic for
all 64-bit integers, and there are no known counterexamples of any size.
In order to reach it, we need to combine the existing Miller-Rabin test
with a Strong Lucas test, the latter of which is the "hard work" part
of this PR.

The first step is to find the right value of the "D" parameter to use:
the first from the sequence {5, -7, 9, -11, ...} whose Jacobi symbol
(see parent PR) is -1. We represent this as an uint64_t-and-bool
struct, rather than a simple int, for two reasons. First, it's easier
to write this incrementing/alternating pattern with a separate sign.
Second, when we use D.mag in calculations, it's convenient if it's
already a uint64_t like almost all of the rest of our types.

Oh --- and, this step won't work if n is a perfect square, so we add a
separate guarding step to filter this situation out.

Now for the meat of the calculation. We need to compute elements of the
Lucas Sequences, $U_k$ and $V_k$ for certain specific indices. To do
that efficiently, we use the fact that $U_1 = V_1 = 1$, and apply the
index-doubling and index-incrementing relations:

Equations for U and V

The above are derived assuming the Lucas parameters $P=1$, $Q=(1-D)/4$,
as is always done for the best-studied parameterization of Baillie-PSW.
We use a bit-representation of the desired indices to decide when to
double and when to increment, also commonly done (see the Implementation
section in the Strong Lucas reference).

Finally, we are able to combine the new Strong Lucas test with the
existing Miller-Rabin test to obtain a working Baillie-PSW test.

We use the same kinds of verification strategies for Strong Lucas and
Baillie-PSW as we used for Miller-Rabin, except that we don't test
pseudoprimes for Baillie-PSW because nobody has ever found any yet.

Helps #217.

The [Baillie-PSW] is the star of the show: it's fully deterministic for
all 64-bit integers, and there are no known counterexamples of any size.
In order to reach it, we need to combine the existing Miller-Rabin test
with a [Strong Lucas] test, the latter of which is the "hard work" part
of this PR.

The first step is to find the right value of the "D" parameter to use:
the first from the sequence {5, -7, 9, -11, ...} whose Jacobi symbol
(see parent PR) is -1.  We represent this as an `uint64_t`-and-`bool`
struct, rather than a simple `int`, for two reasons.  First, it's easier
to write this incrementing/alternating pattern with a separate sign.
Second, when we use `D.mag` in calculations, it's convenient if it's
already a `uint64_t` like almost all of the rest of our types.

Oh --- and, this step won't work if `n` is a perfect square, so we add a
separate guarding step to filter this situation out.

Now for the meat of the calculation.  We need to compute elements of the
Lucas Sequences, $U_k$ and $V_k$ for certain specific indices.  To do
that efficiently, we use the fact that $U_1 = V_1 = 1$, and apply the
index-doubling and index-incrementing relations:

![Equations for U and V](https://github.com/user-attachments/assets/8cfc1ec9-067e-4c8b-b855-9d86194f4296)

The above are derived assuming the Lucas parameters $P=1$, $Q=(1-D)/4$,
as is always done for the best-studied parameterization of Baillie-PSW.
We use a bit-representation of the desired indices to decide when to
double and when to increment, also commonly done (see the Implementation
section in the [Strong Lucas] reference).

Finally, we are able to combine the new Strong Lucas test with the
existing Miller-Rabin test to obtain a working Baillie-PSW test.

We use the same kinds of verification strategies for Strong Lucas and
Baillie-PSW as we used for Miller-Rabin, except that we don't test
pseudoprimes for Baillie-PSW because nobody has ever found any yet.

Helps #217.

[Baillie-PSW]: https://en.wikipedia.org/wiki/Baillie%E2%80%93PSW_primality_test
[Strong Lucas]: https://en.wikipedia.org/wiki/Lucas_pseudoprime#Strong_Lucas_pseudoprimes
@chiphogg chiphogg added the release notes: ♻️ lib (refactoring) Under-the-hood changes to library structure label Nov 12, 2024
The old version worked fine, but it felt a little sketchy the way we
were handling implicit conversion from a wrapped-around unsigned to a
smaller signed type.  (Note that if the signed type had been bigger, we
would silently get the wrong answer!)
It's harder to reason about a negative.  This code just reads better.
au/code/au/utility/test/probable_primes_test.cc Outdated Show resolved Hide resolved
au/code/au/utility/test/probable_primes_test.cc Outdated Show resolved Hide resolved
au/code/au/utility/test/probable_primes_test.cc Outdated Show resolved Hide resolved
au/code/au/utility/test/probable_primes_test.cc Outdated Show resolved Hide resolved
Copy link
Contributor

@geoffviola geoffviola left a comment

Choose a reason for hiding this comment

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

Very cool. Good work! 🎉

au/code/au/utility/probable_primes.hh Outdated Show resolved Hide resolved
Co-authored-by: Geoffrey Viola <[email protected]>
@chiphogg chiphogg merged commit c9bbc14 into main Nov 13, 2024
13 checks passed
@chiphogg chiphogg deleted the chiphogg/strong-lucas-baillie-psw#217 branch November 13, 2024 18:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
release notes: ♻️ lib (refactoring) Under-the-hood changes to library structure
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants