Skip to content

Commit e905323

Browse files
chloeimbadamant-pwn
authored andcommitted
Update factorization.md
I have made some editorial changes to the article. This should make reading more clear and improve understanding.
1 parent 5f2c0fc commit e905323

File tree

1 file changed

+53
-57
lines changed

1 file changed

+53
-57
lines changed

src/algebra/factorization.md

Lines changed: 53 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -5,22 +5,22 @@ tags:
55

66
# Integer factorization
77

8-
In this article we list several algorithms for factorizing integers, each of them can be both fast and also slow (some slower than others) depending on their input.
8+
In this article we list several algorithms for the factorization of integers, each of which can be either fast or varying levels of slow depending on their input.
99

10-
Notice, if the number that you want to factorize is actually a prime number, most of the algorithms, especially Fermat's factorization algorithm, Pollard's p-1, Pollard's rho algorithm will run very slow.
11-
So it makes sense to perform a probabilistic (or a fast deterministic) [primality test](primality_tests.md) before trying to factorize the number.
10+
Notice, if the number that you want to factorize is actually a prime number, most of the algorithms will run very slowly. This is especially true forFermat's factorization algorithm, Pollard's p-1.
11+
Therefore, it makes the most sense to perform a probabilistic (or a fast deterministic) [primality test](primality_tests.md) before trying to factorize the number.
1212

1313
## Trial division
1414

1515
This is the most basic algorithm to find a prime factorization.
1616

1717
We divide by each possible divisor $d$.
18-
We can notice, that it is impossible that all prime factors of a composite number $n$ are bigger than $\sqrt{n}$.
18+
It can be observed that it is impossible for all prime factors of a composite number $n$ to be bigger than $\sqrt{n}$.
1919
Therefore, we only need to test the divisors $2 \le d \le \sqrt{n}$, which gives us the prime factorization in $O(\sqrt{n})$.
2020
(This is [pseudo-polynomial time](https://en.wikipedia.org/wiki/Pseudo-polynomial_time), i.e. polynomial in the value of the input but exponential in the number of bits of the input.)
2121

22-
The smallest divisor has to be a prime number.
23-
We remove the factor from the number, and repeat the process.
22+
The smallest divisor must be a prime number.
23+
We remove the factored number, and continue the process.
2424
If we cannot find any divisor in the range $[2; \sqrt{n}]$, then the number itself has to be prime.
2525

2626
```{.cpp file=factorization_trial_division1}
@@ -41,10 +41,9 @@ vector<long long> trial_division1(long long n) {
4141
### Wheel factorization
4242
4343
This is an optimization of the trial division.
44-
The idea is the following.
45-
Once we know that the number is not divisible by 2, we don't need to check every other even number.
44+
Once we know that the number is not divisible by 2, we don't need to check other even numbers.
4645
This leaves us with only $50\%$ of the numbers to check.
47-
After checking 2, we can simply start with 3 and skip every other number.
46+
After checking 2, and determining it is an odd number, we can simply start with 3 and only count other odd numbers.
4847
4948
```{.cpp file=factorization_trial_division2}
5049
vector<long long> trial_division2(long long n) {
@@ -65,17 +64,16 @@ vector<long long> trial_division2(long long n) {
6564
}
6665
```
6766

68-
This method can be extended.
67+
This method can be extended further.
6968
If the number is not divisible by 3, we can also ignore all other multiples of 3 in the future computations.
7069
So we only need to check the numbers $5, 7, 11, 13, 17, 19, 23, \dots$.
7170
We can observe a pattern of these remaining numbers.
7271
We need to check all numbers with $d \bmod 6 = 1$ and $d \bmod 6 = 5$.
7372
So this leaves us with only $33.3\%$ percent of the numbers to check.
74-
We can implement this by checking the primes 2 and 3 first, and then start checking with 5 and alternatively skip 1 or 3 numbers.
73+
We can implement this by checking the primes 2 and 3 first, and upon discovering they are not divisible by said numbers, check 5.
7574

76-
We can extend this even further.
7775
Here is an implementation for the prime number 2, 3 and 5.
78-
It's convenient to use an array to store how much we have to skip.
76+
A convenient way to store skippable numbers is with an array.
7977

8078
```{.cpp file=factorization_trial_division3}
8179
vector<long long> trial_division3(long long n) {
@@ -102,13 +100,12 @@ vector<long long> trial_division3(long long n) {
102100
}
103101
```
104102
105-
If we extend this further with more primes, we can even reach better percentages.
106-
However, also the skip lists will get a lot bigger.
103+
If we continue exending this method to include even more primes, better percentages can be reached, but the skip lists will become larger.
107104
108105
### Precomputed primes
109106
110-
Extending the wheel factorization with more and more primes will leave exactly the primes to check.
111-
So a good way of checking is just to precompute all prime numbers with the [Sieve of Eratosthenes](sieve-of-eratosthenes.md) until $\sqrt{n}$ and test them individually.
107+
The further we extend the wheel factorization method, we will only be left with prime numbers to check.
108+
A good way of checking this is to precompute all prime numbers with the [Sieve of Eratosthenes](sieve-of-eratosthenes.md) until $\sqrt{n}$, and test them individually.
112109
113110
```{.cpp file=factorization_trial_division4}
114111
vector<long long> primes;
@@ -135,7 +132,7 @@ We can write an odd composite number $n = p \cdot q$ as the difference of two sq
135132

136133
$$n = \left(\frac{p + q}{2}\right)^2 - \left(\frac{p - q}{2}\right)^2$$
137134

138-
Fermat's factorization method tries to exploit the fact, by guessing the first square $a^2$, and check if the remaining part $b^2 = a^2 - n$ is also a square number.
135+
Fermat's factorization method tries to exploit this fact by guessing the first square $a^2$, and checking if the remaining part, $b^2 = a^2 - n$, is also a square number.
139136
If it is, then we have found the factors $a - b$ and $a + b$ of $n$.
140137

141138
```cpp
@@ -152,12 +149,12 @@ int fermat(int n) {
152149
}
153150
```
154151
155-
Notice, this factorization method can be very fast, if the difference between the two factors $p$ and $q$ is small.
152+
This factorization method can be very fast if the difference between the two factors $p$ and $q$ is small.
156153
The algorithm runs in $O(|p - q|)$ time.
157-
However since it is very slow, once the factors are far apart, it is rarely used in practice.
154+
In practice though, this method is rarely used. Once factors become further apart, it is extremely slow.
158155
159-
However there are still a huge number of optimizations for this approach.
160-
E.g. by looking at the squares $a^2$ modulo a fixed small number, you can notice that you don't have to look at certain values $a$ since they cannot produce a square number $a^2 - n$.
156+
However, there are still a large number of optimization options regarding this approach.
157+
By looking at the squares $a^2$ modulo, a fixed small number, it can be observed that certain values don't have to be viewed, $a$ since they cannot produce a square number $a^2 - n$.
161158
162159
163160
## Pollard's $p - 1$ method { data-toc-label="Pollard's <script type='math/tex'>p - 1</script> method" }
@@ -190,11 +187,11 @@ $$M = \prod_{\text{prime } q \le B} q^{\lfloor \log_q B \rfloor}$$
190187
191188
Notice, if $p-1$ divides $M$ for all prime factors $p$ of $n$, then $\gcd(a^M - 1, n)$ will just be $n$.
192189
In this case we don't receive a factor.
193-
Therefore we will try to perform the $\gcd$ multiple time, while we compute $M$.
190+
Therefore, we will try to perform the $\gcd$ multiple time, while we compute $M$.
194191
195192
Some composite numbers don't have $B$-powersmooth factors for small $B$.
196-
E.g. the factors of the composite number $100~000~000~000~000~493 = 763~013 \cdot 131~059~365~961$ are $190~753$-powersmooth and $1~092~161~383$-powersmooth.
197-
We would have to choose $B >= 190~753$ to factorize the number.
193+
Meaning, the factors of the composite number $100~000~000~000~000~493 = 763~013 \cdot 131~059~365~961$ are $190~753$-powersmooth and $1~092~161~383$-powersmooth.
194+
We will have to choose $B >= 190~753$ to factorize the number.
198195
199196
In the following implementation we start with $B = 10$ and increase $B$ after each each iteration.
200197
@@ -228,55 +225,55 @@ long long pollards_p_minus_1(long long n) {
228225
229226
```
230227

231-
Notice, this is a probabilistic algorithm.
232-
It can happen that the algorithm doesn't find a factor.
228+
Observe that this is a probabilistic algorithm.
229+
A consequence of this is that there is a possibility of the algorithm being unable to find a factor at all.
233230

234231
The complexity is $O(B \log B \log^2 n)$ per iteration.
235232

236233
## Pollard's rho algorithm
237234

238-
Another factorization algorithm from John Pollard.
235+
Pollard's Rho Algorithm is yet another factorization algorithm from John Pollard.
239236

240237
Let the prime factorization of a number be $n = p q$.
241238
The algorithm looks at a pseudo-random sequence $\{x_i\} = \{x_0,~f(x_0),~f(f(x_0)),~\dots\}$ where $f$ is a polynomial function, usually $f(x) = (x^2 + c) \bmod n$ is chosen with $c = 1$.
242239

243-
Actually we are not very interested in the sequence $\{x_i\}$, we are more interested in the sequence $\{x_i \bmod p\}$.
244-
Since $f$ is a polynomial function and all the values are in the range $[0;~p)$ this sequence will begin to cycle sooner or later.
245-
The **birthday paradox** actually suggests, that the expected number of elements is $O(\sqrt{p})$ until the repetition starts.
246-
If $p$ is smaller than $\sqrt{n}$, the repetition will start very likely in $O(\sqrt[4]{n})$.
240+
In this instance, we are not interested in the sequence $\{x_i\}$.
241+
We are more interested in the sequence $\{x_i \bmod p\}$.
242+
Since $f$ is a polynomial function, and all the values are in the range $[0;~p)$, this sequence will eventually begin to cycle.
243+
The **birthday paradox** actually suggests that the expected number of elements is $O(\sqrt{p})$ until the repetition starts.
244+
If $p$ is smaller than $\sqrt{n}$, the repetition will likely start in $O(\sqrt[4]{n})$.
247245

248246
Here is a visualization of such a sequence $\{x_i \bmod p\}$ with $n = 2206637$, $p = 317$, $x_0 = 2$ and $f(x) = x^2 + 1$.
249247
From the form of the sequence you can see very clearly why the algorithm is called Pollard's $\rho$ algorithm.
250248

251249
<center>![Pollard's rho visualization](pollard_rho.png)</center>
252250

253-
There is still one big open question.
254-
We don't know $p$ yet, so how can we argue about the sequence $\{x_i \bmod p\}$?
251+
Yet, there is still an open question.
252+
If don't know $p$ yet, how can we argue the sequence $\{x_i \bmod p\}$?
255253

256254
It's actually quite easy.
257255
There is a cycle in the sequence $\{x_i \bmod p\}_{i \le j}$ if and only if there are two indices $s, t \le j$ such that $x_s \equiv x_t \bmod p$.
258256
This equation can be rewritten as $x_s - x_t \equiv 0 \bmod p$ which is the same as $p ~|~ \gcd(x_s - x_t, n)$.
259257

260258
Therefore, if we find two indices $s$ and $t$ with $g = \gcd(x_s - x_t, n) > 1$, we have found a cycle and also a factor $g$ of $n$.
261-
Notice that it is possible that $g = n$.
262-
In this case we haven't found a proper factor, and we have to repeat the algorithm with different parameter (different starting value $x_0$, different constant $c$ in the polynomial function $f$).
259+
It is possible that $g = n$.
260+
In this case we haven't found a proper factor, so we must repeat the algorithm with a different parameter (different starting value $x_0$, different constant $c$ in the polynomial function $f$).
263261

264262
To find the cycle, we can use any common cycle detection algorithm.
265263

266264
### Floyd's cycle-finding algorithm
267265

268-
This algorithm finds a cycle by using two pointers.
269-
These pointers move over the sequence at different speeds.
270-
In each iteration the first pointer advances to the next element, but the second pointer advances two elements.
271-
It's not hard to see, that if there exists a cycle, the second pointer will make at least one full cycle and then meet the first pointer during the next few cycle loops.
266+
This algorithm finds a cycle by using two pointers moving over the sequence at differing speeds.
267+
During each iteration, the first pointer will advance one element over, while the second pointer advances to every other element.
268+
Using this idea it is easy to observe that if there is a cycle, at some point the second pointer will come around to meet the first one during the loops.
272269
If the cycle length is $\lambda$ and the $\mu$ is the first index at which the cycle starts, then the algorithm will run in $O(\lambda + \mu)$ time.
273270

274-
This algorithm is also known as the [Tortoise and Hare algorithm](../others/tortoise_and_hare.md), based on the tale in which a tortoise (here a slow pointer) and a hare (here a faster pointer) make a race.
271+
This algorithm is also known as the [Tortoise and Hare algorithm](../others/tortoise_and_hare.md), based on the tale in which a tortoise (the slow pointer) and a hare (the faster pointer) have a race.
275272

276-
It is actually possible to determine the parameter $\lambda$ and $\mu$ using this algorithm (also in $O(\lambda + \mu)$ time and $O(1)$ space), but here is just the simplified version for finding the cycle at all.
277-
The algorithm and returns true as soon as it detects a cycle.
278-
If the sequence doesn't have a cycle, then the function will never stop.
279-
However this cannot happen during Pollard's rho algorithm.
273+
It is actually possible to determine the parameter $\lambda$ and $\mu$ using this algorithm (also in $O(\lambda + \mu)$ time and $O(1)$ space).
274+
When a cycle is detected, the algorithm will return 'True'.
275+
If the sequence doesn't have a cycle, then the function will loop endlessly.
276+
However, using Pollard's Rho Algorithm, this can be prevented.
280277

281278
```text
282279
function floyd(f, x0):
@@ -290,8 +287,8 @@ function floyd(f, x0):
290287

291288
### Implementation
292289

293-
First here is a implementation using the **Floyd's cycle-finding algorithm**.
294-
The algorithm runs (usually) in $O(\sqrt[4]{n} \log(n))$ time.
290+
First, here is an implementation using the **Floyd's cycle-finding algorithm**.
291+
The algorithm generally runs in $O(\sqrt[4]{n} \log(n))$ time.
295292

296293
```{.cpp file=pollard_rho}
297294
long long mult(long long a, long long b, long long mod) {
@@ -353,16 +350,15 @@ long long mult(long long a, long long b, long long mod) {
353350

354351
Alternatively you can also implement the [Montgomery multiplication](montgomery_multiplication.md).
355352

356-
As already noticed above: if $n$ is composite and the algorithm returns $n$ as factor, you have to repeat the procedure with different parameter $x_0$ and $c$.
353+
As stated previously, if $n$ is composite and the algorithm returns $n$ as factor, you have to repeat the procedure with different parameters $x_0$ and $c$.
357354
E.g. the choice $x_0 = c = 1$ will not factor $25 = 5 \cdot 5$.
358-
The algorithm will just return $25$.
359-
However the choice $x_0 = 1$, $c = 2$ will factor it.
355+
The algorithm will return $25$.
356+
However, the choice $x_0 = 1$, $c = 2$ will factor it.
360357

361358
### Brent's algorithm
362359

363-
Brent uses a similar algorithm as Floyd.
364-
It also uses two pointer.
365-
But instead of advancing the pointers by one and two respectably, we advance them in powers of two.
360+
Brent implements a similar method to Floyd, using two pointers.
361+
The difference being that instead of advancing the pointers by one and two places respectively, they are advanced by powers of two.
366362
As soon as $2^i$ is greater than $\lambda$ and $\mu$, we will find the cycle.
367363

368364
```text
@@ -380,12 +376,12 @@ function floyd(f, x0):
380376
return true
381377
```
382378

383-
Brent's algorithm also runs in linear time, but is usually faster than Floyd's algorithm, since it uses less evaluations of the function $f$.
379+
Brent's algorithm also runs in linear time, but is generally faster than Floyd's, since it uses less evaluations of the function $f$.
384380

385381
### Implementation
386382

387-
The straightforward implementation using Brent's algorithms can be speeded up by noticing, that we can omit the terms $x_l - x_k$ if $k < \frac{3 \cdot l}{2}$.
388-
Also, instead of performing the $\gcd$ computation at every step, we multiply the terms and do it every few steps and backtrack if we overshoot.
383+
The straightforward implementation of Brent's algorithm can be sped up by omitting the terms $x_l - x_k$ if $k < \frac{3 \cdot l}{2}$.
384+
In addition, instead of performing the $\gcd$ computation at every step, we multiply the terms every few steps and backtrack if overshot.
389385

390386
```{.cpp file=pollard_rho_brent}
391387
long long brent(long long n, long long x0=2, long long c=1) {
@@ -422,7 +418,7 @@ long long brent(long long n, long long x0=2, long long c=1) {
422418
}
423419
```
424420
425-
The combination of a trial division for small prime numbers together with Brent's version of Pollard's rho algorithm will make a very powerful factorization algorithm.
421+
The combination of a trial division for small prime numbers together with Brent's version of Pollard's rho algorithm makes a very powerful factorization algorithm.
426422
427423
## Practice Problems
428424

0 commit comments

Comments
 (0)