You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: src/algebra/factorization.md
+53-57Lines changed: 53 additions & 57 deletions
Original file line number
Diff line number
Diff line change
@@ -5,22 +5,22 @@ tags:
5
5
6
6
# Integer factorization
7
7
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.
9
9
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.
12
12
13
13
## Trial division
14
14
15
15
This is the most basic algorithm to find a prime factorization.
16
16
17
17
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}$.
19
19
Therefore, we only need to test the divisors $2 \le d \le \sqrt{n}$, which gives us the prime factorization in $O(\sqrt{n})$.
20
20
(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.)
21
21
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.
24
24
If we cannot find any divisor in the range $[2; \sqrt{n}]$, then the number itself has to be prime.
25
25
26
26
```{.cpp file=factorization_trial_division1}
@@ -41,10 +41,9 @@ vector<long long> trial_division1(long long n) {
41
41
### Wheel factorization
42
42
43
43
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.
46
45
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.
48
47
49
48
```{.cpp file=factorization_trial_division2}
50
49
vector<long long> trial_division2(long long n) {
@@ -65,17 +64,16 @@ vector<long long> trial_division2(long long n) {
65
64
}
66
65
```
67
66
68
-
This method can be extended.
67
+
This method can be extended further.
69
68
If the number is not divisible by 3, we can also ignore all other multiples of 3 in the future computations.
70
69
So we only need to check the numbers $5, 7, 11, 13, 17, 19, 23, \dots$.
71
70
We can observe a pattern of these remaining numbers.
72
71
We need to check all numbers with $d \bmod 6 = 1$ and $d \bmod 6 = 5$.
73
72
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.
75
74
76
-
We can extend this even further.
77
75
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.
79
77
80
78
```{.cpp file=factorization_trial_division3}
81
79
vector<longlong> trial_division3(long long n) {
@@ -102,13 +100,12 @@ vector<long long> trial_division3(long long n) {
102
100
}
103
101
```
104
102
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.
107
104
108
105
### Precomputed primes
109
106
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.
112
109
113
110
```{.cpp file=factorization_trial_division4}
114
111
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
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.
139
136
If it is, then we have found the factors $a - b$ and $a + b$ of $n$.
140
137
141
138
```cpp
@@ -152,12 +149,12 @@ int fermat(int n) {
152
149
}
153
150
```
154
151
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.
156
153
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.
158
155
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$.
Notice, if $p-1$ divides $M$ for all prime factors $p$ of $n$, then $\gcd(a^M - 1, n)$ will just be $n$.
192
189
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$.
194
191
195
192
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.
198
195
199
196
In the following implementation we start with $B = 10$ and increase $B$ after each each iteration.
200
197
@@ -228,55 +225,55 @@ long long pollards_p_minus_1(long long n) {
228
225
229
226
```
230
227
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.
233
230
234
231
The complexity is $O(B \log B \log^2 n)$ per iteration.
235
232
236
233
## Pollard's rho algorithm
237
234
238
-
Another factorization algorithm from John Pollard.
235
+
Pollard's Rho Algorithm is yet another factorization algorithm from John Pollard.
239
236
240
237
Let the prime factorization of a number be $n = p q$.
241
238
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$.
242
239
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})$.
247
245
248
246
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$.
249
247
From the form of the sequence you can see very clearly why the algorithm is called Pollard's $\rho$ algorithm.
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\}$?
255
253
256
254
It's actually quite easy.
257
255
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$.
258
256
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)$.
259
257
260
258
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$).
263
261
264
262
To find the cycle, we can use any common cycle detection algorithm.
265
263
266
264
### Floyd's cycle-finding algorithm
267
265
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.
272
269
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.
273
270
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.
275
272
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.
280
277
281
278
```text
282
279
function floyd(f, x0):
@@ -290,8 +287,8 @@ function floyd(f, x0):
290
287
291
288
### Implementation
292
289
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.
295
292
296
293
```{.cpp file=pollard_rho}
297
294
longlongmult(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) {
353
350
354
351
Alternatively you can also implement the [Montgomery multiplication](montgomery_multiplication.md).
355
352
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$.
357
354
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.
360
357
361
358
### Brent's algorithm
362
359
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.
366
362
As soon as $2^i$ is greater than $\lambda$ and $\mu$, we will find the cycle.
367
363
368
364
```text
@@ -380,12 +376,12 @@ function floyd(f, x0):
380
376
return true
381
377
```
382
378
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$.
384
380
385
381
### Implementation
386
382
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.
389
385
390
386
```{.cpp file=pollard_rho_brent}
391
387
longlongbrent(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) {
422
418
}
423
419
```
424
420
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.
0 commit comments