1 | /*
|
---|
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
|
---|
3 | * contributor license agreements. See the NOTICE file distributed with
|
---|
4 | * this work for additional information regarding copyright ownership.
|
---|
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
|
---|
6 | * (the "License"); you may not use this file except in compliance with
|
---|
7 | * the License. You may obtain a copy of the License at
|
---|
8 | *
|
---|
9 | * http://www.apache.org/licenses/LICENSE-2.0
|
---|
10 | *
|
---|
11 | * Unless required by applicable law or agreed to in writing, software
|
---|
12 | * distributed under the License is distributed on an "AS IS" BASIS,
|
---|
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
---|
14 | * See the License for the specific language governing permissions and
|
---|
15 | * limitations under the License.
|
---|
16 | */
|
---|
17 | package agents.anac.y2019.harddealer.math3.primes;
|
---|
18 |
|
---|
19 | import java.util.ArrayList;
|
---|
20 | import java.util.List;
|
---|
21 |
|
---|
22 | import agents.anac.y2019.harddealer.math3.util.FastMath;
|
---|
23 |
|
---|
24 | /**
|
---|
25 | * Implementation of the Pollard's rho factorization algorithm.
|
---|
26 | * @since 3.2
|
---|
27 | */
|
---|
28 | class PollardRho {
|
---|
29 |
|
---|
30 | /**
|
---|
31 | * Hide utility class.
|
---|
32 | */
|
---|
33 | private PollardRho() {
|
---|
34 | }
|
---|
35 |
|
---|
36 | /**
|
---|
37 | * Factorization using Pollard's rho algorithm.
|
---|
38 | * @param n number to factors, must be > 0
|
---|
39 | * @return the list of prime factors of n.
|
---|
40 | */
|
---|
41 | public static List<Integer> primeFactors(int n) {
|
---|
42 | final List<Integer> factors = new ArrayList<Integer>();
|
---|
43 |
|
---|
44 | n = SmallPrimes.smallTrialDivision(n, factors);
|
---|
45 | if (1 == n) {
|
---|
46 | return factors;
|
---|
47 | }
|
---|
48 |
|
---|
49 | if (SmallPrimes.millerRabinPrimeTest(n)) {
|
---|
50 | factors.add(n);
|
---|
51 | return factors;
|
---|
52 | }
|
---|
53 |
|
---|
54 | int divisor = rhoBrent(n);
|
---|
55 | factors.add(divisor);
|
---|
56 | factors.add(n / divisor);
|
---|
57 | return factors;
|
---|
58 | }
|
---|
59 |
|
---|
60 | /**
|
---|
61 | * Implementation of the Pollard's rho factorization algorithm.
|
---|
62 | * <p>
|
---|
63 | * This implementation follows the paper "An improved Monte Carlo factorization algorithm"
|
---|
64 | * by Richard P. Brent. This avoids the triple computation of f(x) typically found in Pollard's
|
---|
65 | * rho implementations. It also batches several gcd computation into 1.
|
---|
66 | * <p>
|
---|
67 | * The backtracking is not implemented as we deal only with semi-primes.
|
---|
68 | *
|
---|
69 | * @param n number to factor, must be semi-prime.
|
---|
70 | * @return a prime factor of n.
|
---|
71 | */
|
---|
72 | static int rhoBrent(final int n) {
|
---|
73 | final int x0 = 2;
|
---|
74 | final int m = 25;
|
---|
75 | int cst = SmallPrimes.PRIMES_LAST;
|
---|
76 | int y = x0;
|
---|
77 | int r = 1;
|
---|
78 | do {
|
---|
79 | int x = y;
|
---|
80 | for (int i = 0; i < r; i++) {
|
---|
81 | final long y2 = ((long) y) * y;
|
---|
82 | y = (int) ((y2 + cst) % n);
|
---|
83 | }
|
---|
84 | int k = 0;
|
---|
85 | do {
|
---|
86 | final int bound = FastMath.min(m, r - k);
|
---|
87 | int q = 1;
|
---|
88 | for (int i = -3; i < bound; i++) { //start at -3 to ensure we enter this loop at least 3 times
|
---|
89 | final long y2 = ((long) y) * y;
|
---|
90 | y = (int) ((y2 + cst) % n);
|
---|
91 | final long divisor = FastMath.abs(x - y);
|
---|
92 | if (0 == divisor) {
|
---|
93 | cst += SmallPrimes.PRIMES_LAST;
|
---|
94 | k = -m;
|
---|
95 | y = x0;
|
---|
96 | r = 1;
|
---|
97 | break;
|
---|
98 | }
|
---|
99 | final long prod = divisor * q;
|
---|
100 | q = (int) (prod % n);
|
---|
101 | if (0 == q) {
|
---|
102 | return gcdPositive(FastMath.abs((int) divisor), n);
|
---|
103 | }
|
---|
104 | }
|
---|
105 | final int out = gcdPositive(FastMath.abs(q), n);
|
---|
106 | if (1 != out) {
|
---|
107 | return out;
|
---|
108 | }
|
---|
109 | k += m;
|
---|
110 | } while (k < r);
|
---|
111 | r = 2 * r;
|
---|
112 | } while (true);
|
---|
113 | }
|
---|
114 |
|
---|
115 | /**
|
---|
116 | * Gcd between two positive numbers.
|
---|
117 | * <p>
|
---|
118 | * Gets the greatest common divisor of two numbers, using the "binary gcd" method,
|
---|
119 | * which avoids division and modulo operations. See Knuth 4.5.2 algorithm B.
|
---|
120 | * This algorithm is due to Josef Stein (1961).
|
---|
121 | * </p>
|
---|
122 | * Special cases:
|
---|
123 | * <ul>
|
---|
124 | * <li>The result of {@code gcd(x, x)}, {@code gcd(0, x)} and {@code gcd(x, 0)} is the value of {@code x}.</li>
|
---|
125 | * <li>The invocation {@code gcd(0, 0)} is the only one which returns {@code 0}.</li>
|
---|
126 | * </ul>
|
---|
127 | *
|
---|
128 | * @param a first number, must be ≥ 0
|
---|
129 | * @param b second number, must be ≥ 0
|
---|
130 | * @return gcd(a,b)
|
---|
131 | */
|
---|
132 | static int gcdPositive(int a, int b){
|
---|
133 | // both a and b must be positive, it is not checked here
|
---|
134 | // gdc(a,0) = a
|
---|
135 | if (a == 0) {
|
---|
136 | return b;
|
---|
137 | } else if (b == 0) {
|
---|
138 | return a;
|
---|
139 | }
|
---|
140 |
|
---|
141 | // make a and b odd, keep in mind the common power of twos
|
---|
142 | final int aTwos = Integer.numberOfTrailingZeros(a);
|
---|
143 | a >>= aTwos;
|
---|
144 | final int bTwos = Integer.numberOfTrailingZeros(b);
|
---|
145 | b >>= bTwos;
|
---|
146 | final int shift = FastMath.min(aTwos, bTwos);
|
---|
147 |
|
---|
148 | // a and b >0
|
---|
149 | // if a > b then gdc(a,b) = gcd(a-b,b)
|
---|
150 | // if a < b then gcd(a,b) = gcd(b-a,a)
|
---|
151 | // so next a is the absolute difference and next b is the minimum of current values
|
---|
152 | while (a != b) {
|
---|
153 | final int delta = a - b;
|
---|
154 | b = FastMath.min(a, b);
|
---|
155 | a = FastMath.abs(delta);
|
---|
156 | // for speed optimization:
|
---|
157 | // remove any power of two in a as b is guaranteed to be odd throughout all iterations
|
---|
158 | a >>= Integer.numberOfTrailingZeros(a);
|
---|
159 | }
|
---|
160 |
|
---|
161 | // gcd(a,a) = a, just "add" the common power of twos
|
---|
162 | return a << shift;
|
---|
163 | }
|
---|
164 | }
|
---|