abst 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/abst.rb +38 -0
- data/lib/config.rb +21 -0
- data/lib/include/array.rb +45 -0
- data/lib/include/bisect.rb +95 -0
- data/lib/include/cache.rb +60 -0
- data/lib/include/compatibility.rb +3 -0
- data/lib/include/complex.rb +10 -0
- data/lib/include/float.rb +19 -0
- data/lib/include/fundamental.rb +903 -0
- data/lib/include/graph.rb +11 -0
- data/lib/include/group.rb +35 -0
- data/lib/include/integer.rb +385 -0
- data/lib/include/matrix.rb +143 -0
- data/lib/include/polynomial.rb +137 -0
- data/lib/include/prime.rb +556 -0
- data/lib/include/prime_mpqs.rb +483 -0
- data/lib/include/rational.rb +155 -0
- data/lib/include/residue.rb +27 -0
- data/lib/include/ring.rb +21 -0
- data/lib/include/sequence.rb +54 -0
- data/lib/include/set.rb +67 -0
- data/lib/include/vector.rb +90 -0
- data/test/test_all.rb +15 -0
- data/test/test_array.rb +10 -0
- data/test/test_bisect.rb +43 -0
- data/test/test_combination.rb +6 -0
- data/test/test_float.rb +13 -0
- data/test/test_fundamental.rb +406 -0
- data/test/test_group.rb +10 -0
- data/test/test_integer.rb +161 -0
- data/test/test_matrix.rb +54 -0
- data/test/test_polynomial.rb +107 -0
- data/test/test_prime.rb +153 -0
- data/test/test_prime_mpqs.rb +24 -0
- data/test/test_rational.rb +33 -0
- data/test/test_sequence.rb +55 -0
- data/test/test_set.rb +36 -0
- data/test/test_vector.rb +37 -0
- metadata +98 -0
@@ -0,0 +1,137 @@
|
|
1
|
+
module Abst
|
2
|
+
module_function
|
3
|
+
|
4
|
+
class Polynomial
|
5
|
+
include Abst::Ring
|
6
|
+
|
7
|
+
class << self
|
8
|
+
attr_reader :coef_class, :zero, :one
|
9
|
+
end
|
10
|
+
|
11
|
+
attr_reader :coef
|
12
|
+
protected :coef
|
13
|
+
|
14
|
+
def initialize(coef)
|
15
|
+
@coef = coef.to_a
|
16
|
+
cutdown
|
17
|
+
end
|
18
|
+
|
19
|
+
def add_sub(op, other)
|
20
|
+
a = @coef
|
21
|
+
b = other.kind_of?(self.class.coef_class) ? [other] : other.coef
|
22
|
+
a, b = b, a if a.size < b.size
|
23
|
+
rslt_coef = a.dup
|
24
|
+
b.size.times {|i| rslt_coef[i] = rslt_coef[i].__send__(op, b[i])}
|
25
|
+
return self.class.new(rslt_coef)
|
26
|
+
end
|
27
|
+
|
28
|
+
def *(other)
|
29
|
+
other = other.kind_of?(self.class.coef_class) ? [other] : other.coef
|
30
|
+
rslt_coef = Array.new(@coef.size + other.size - 1, self.class.coef_class.zero)
|
31
|
+
|
32
|
+
@coef.size.times do |j|
|
33
|
+
other.size.times do |i|
|
34
|
+
rslt_coef[i + j] += @coef[j] * other[i]
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
return self.class.new(rslt_coef)
|
39
|
+
end
|
40
|
+
|
41
|
+
def divmod(other)
|
42
|
+
other = other.kind_of?(self.class.coef_class) ? [other] : other.coef
|
43
|
+
q = [self.class.coef_class.zero]
|
44
|
+
r = @coef.dup
|
45
|
+
|
46
|
+
lc_other = other.last
|
47
|
+
(@coef.size - other.size).downto(0) do |i|
|
48
|
+
tq, tr = r.pop.divmod(lc_other)
|
49
|
+
raise NotImplementedError unless self.class.coef_class.zero == tr
|
50
|
+
q[i] = tq
|
51
|
+
next if self.class.coef_class.zero == tq
|
52
|
+
|
53
|
+
(other.size - 1).times do |j|
|
54
|
+
r[i + j] -= tq * other[j]
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
r[0] = self.class.coef_class.zero if r.empty?
|
59
|
+
return self.class.new(q), self.class.new(r)
|
60
|
+
end
|
61
|
+
|
62
|
+
def ==(other)
|
63
|
+
other = other.kind_of?(self.class.coef_class) ? [other] : other.coef
|
64
|
+
return @coef == other
|
65
|
+
end
|
66
|
+
|
67
|
+
def degree
|
68
|
+
return -INFINITY if 1 == @coef.size and @coef[0] == self.class.coef_class.zero
|
69
|
+
return @coef.size - 1
|
70
|
+
end
|
71
|
+
|
72
|
+
# leading coefficient
|
73
|
+
def lc
|
74
|
+
return @coef.last
|
75
|
+
end
|
76
|
+
|
77
|
+
def eval(x)
|
78
|
+
rslt = @coef.last
|
79
|
+
(@coef.size - 2).downto(0) do |i|
|
80
|
+
rslt = rslt * x + @coef[i]
|
81
|
+
end
|
82
|
+
|
83
|
+
return rslt
|
84
|
+
end
|
85
|
+
|
86
|
+
def normalize!
|
87
|
+
raise NotImplementedError
|
88
|
+
end
|
89
|
+
|
90
|
+
def normalize
|
91
|
+
return self.dup.normalize!
|
92
|
+
end
|
93
|
+
|
94
|
+
# delete last zero-entries
|
95
|
+
def cutdown
|
96
|
+
zero = self.class.coef_class.zero
|
97
|
+
|
98
|
+
return if zero != @coef.last
|
99
|
+
|
100
|
+
# find last non-zero entry
|
101
|
+
idx = 0
|
102
|
+
(@coef.size - 2).downto(1) do |i|
|
103
|
+
if @coef[i] != zero
|
104
|
+
idx = i
|
105
|
+
break
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
@coef[idx + 1, @coef.size] = []
|
110
|
+
end
|
111
|
+
|
112
|
+
def to_a
|
113
|
+
return @coef.dup
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
# Param:: immutable class coef_class
|
118
|
+
def create_polynomial(coef_class, coef = nil)
|
119
|
+
poly = Class.new(Polynomial) do
|
120
|
+
@coef_class = coef_class
|
121
|
+
@zero = self.new([coef_class.zero]).freeze
|
122
|
+
@one = self.new([coef_class.one]).freeze
|
123
|
+
end
|
124
|
+
|
125
|
+
return poly.new(coef) if coef
|
126
|
+
return poly
|
127
|
+
end
|
128
|
+
|
129
|
+
alias Polynomial create_polynomial
|
130
|
+
module_function :Polynomial
|
131
|
+
|
132
|
+
# Param::
|
133
|
+
# Return::
|
134
|
+
def root_mod_p
|
135
|
+
raise NotImplementedError
|
136
|
+
end
|
137
|
+
end
|
@@ -0,0 +1,556 @@
|
|
1
|
+
module Abst
|
2
|
+
module_function
|
3
|
+
|
4
|
+
#
|
5
|
+
# Cache
|
6
|
+
#
|
7
|
+
|
8
|
+
# precompute primes by eratosthenes
|
9
|
+
def precompute_primes
|
10
|
+
primes = eratosthenes_sieve(PRIME_CACHE_LIMIT).to_a
|
11
|
+
|
12
|
+
Dir::mkdir(DATA_DIR) unless FileTest.exist?(DATA_DIR)
|
13
|
+
open(PRIMES_LIST, "w") {|io| io.write(primes.map(&:to_s).join("\n"))}
|
14
|
+
|
15
|
+
return primes
|
16
|
+
end
|
17
|
+
|
18
|
+
def load_precomputed_primes
|
19
|
+
open(PRIMES_LIST) {|io| return io.read.split("\n").map(&:to_i)}
|
20
|
+
end
|
21
|
+
|
22
|
+
$primes = nil
|
23
|
+
def primes_list
|
24
|
+
return $primes if $primes
|
25
|
+
|
26
|
+
# precomputed?
|
27
|
+
if FileTest.exist?(PRIMES_LIST)
|
28
|
+
$primes = load_precomputed_primes
|
29
|
+
else
|
30
|
+
$primes = precompute_primes
|
31
|
+
end
|
32
|
+
|
33
|
+
def $primes.include?(n)
|
34
|
+
return Bisect.index(self, n)
|
35
|
+
end
|
36
|
+
|
37
|
+
$primes.freeze
|
38
|
+
|
39
|
+
return $primes
|
40
|
+
end
|
41
|
+
|
42
|
+
#
|
43
|
+
# primality test
|
44
|
+
#
|
45
|
+
|
46
|
+
# Param:: positive integer n
|
47
|
+
# positive integer base
|
48
|
+
# Return:: boolean whether n passes a pseudoprime test for the base or not
|
49
|
+
# When n and base are not relatively prime, this algorithm
|
50
|
+
# may judge a prime number n to be a composite number
|
51
|
+
def pseudoprime_test(n, base)
|
52
|
+
return power(base, n - 1, n) == 1
|
53
|
+
end
|
54
|
+
|
55
|
+
# Param:: positive odd integer n
|
56
|
+
# positive integer b
|
57
|
+
# integer e and k s.t. n = 2 ** e * k and k is odd.
|
58
|
+
# Return:: boolean whether n passes a strong pseudoprime test for the base b or not
|
59
|
+
# When n and b are not relatively prime, this algorithm
|
60
|
+
# may judge a prime number n to be a composite number
|
61
|
+
def strong_pseudoprime_test(n, b, e = nil, k = nil)
|
62
|
+
n_minus_1 = n - 1
|
63
|
+
|
64
|
+
unless e
|
65
|
+
e = 0
|
66
|
+
e += 1 while 0 == n_minus_1[e]
|
67
|
+
k = n_minus_1 >> e
|
68
|
+
end
|
69
|
+
|
70
|
+
z = power(b, k, n)
|
71
|
+
|
72
|
+
return true if 1 == z or n_minus_1 == z
|
73
|
+
(e - 1).times do
|
74
|
+
z = z ** 2 % n
|
75
|
+
return true if z == n_minus_1
|
76
|
+
end
|
77
|
+
|
78
|
+
return false
|
79
|
+
end
|
80
|
+
|
81
|
+
# Miller-Rabin pseudo-primality test
|
82
|
+
# Param:: odd integer n >= 3
|
83
|
+
# Return:: boolean whether n passes trials times random base strong pseudoprime test or not
|
84
|
+
# integer witness (or nil) if return_witness
|
85
|
+
def miller_rabin(n, trials = 20, return_witness = false)
|
86
|
+
# Precomputation
|
87
|
+
n_minus_1 = n - 1
|
88
|
+
e = 0
|
89
|
+
e += 1 while 0 == n_minus_1[e]
|
90
|
+
k = n_minus_1 >> e
|
91
|
+
|
92
|
+
trials.times do
|
93
|
+
base = rand(n - 2) + 2
|
94
|
+
unless strong_pseudoprime_test(n, base, e, k)
|
95
|
+
return return_witness ? [false, base] : false
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
return return_witness ? [true, nil] : true
|
100
|
+
end
|
101
|
+
|
102
|
+
# Primality test
|
103
|
+
# Param:: positive integer n > 2
|
104
|
+
# factor is factorization of n - 1
|
105
|
+
# Return:: boolean whether n is prime or not
|
106
|
+
def n_minus_1(n, factor = nil)
|
107
|
+
factor = factorize(n - 1) unless factor
|
108
|
+
factor.shift if 2 == factor[0][0]
|
109
|
+
|
110
|
+
n_1 = n - 1
|
111
|
+
half_n_1 = n_1 >> 1
|
112
|
+
|
113
|
+
primes = primes_list.each
|
114
|
+
find_base = proc do
|
115
|
+
b = primes.next
|
116
|
+
until (t = power(b, half_n_1, n)) == n_1
|
117
|
+
return false unless t == 1
|
118
|
+
b = primes.next
|
119
|
+
end
|
120
|
+
b
|
121
|
+
end
|
122
|
+
|
123
|
+
base = find_base.call
|
124
|
+
factor.each do |prime, e|
|
125
|
+
while power(base, half_n_1 / prime, n) == n_1
|
126
|
+
base = find_base.call
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
return true
|
131
|
+
end
|
132
|
+
|
133
|
+
# Primality test
|
134
|
+
# Param:: positive integer n
|
135
|
+
# Return:: boolean whether n is prime or not
|
136
|
+
def apr(n)
|
137
|
+
raise NotImplementedError
|
138
|
+
end
|
139
|
+
|
140
|
+
# Param:: positive integer n
|
141
|
+
# Return:: boolean whether n is prime or not
|
142
|
+
def prime?(n)
|
143
|
+
if n <= 3
|
144
|
+
return false if n <= 1
|
145
|
+
return true
|
146
|
+
end
|
147
|
+
|
148
|
+
if n <= primes_list.last
|
149
|
+
return Bisect.index(primes_list, n) ? true : false
|
150
|
+
end
|
151
|
+
|
152
|
+
factor = trial_division(n, 257)[0]
|
153
|
+
return factor[0][0] == n unless factor.empty?
|
154
|
+
|
155
|
+
if n < 341_550_071_728_321
|
156
|
+
[2, 3, 5, 7, 11, 13, 17].each do |i|
|
157
|
+
return false unless strong_pseudoprime_test(n, i)
|
158
|
+
end
|
159
|
+
return true
|
160
|
+
end
|
161
|
+
|
162
|
+
return false unless miller_rabin(n)
|
163
|
+
return n_minus_1(n)
|
164
|
+
end
|
165
|
+
|
166
|
+
# Lucas-Lehmer primality test
|
167
|
+
# Param:: odd prime p
|
168
|
+
# Return:: boolean whether M(p) == 2**p - 1 is prime or not
|
169
|
+
# there M(p) means p-th Mersenne number
|
170
|
+
def lucas_lehmer(p)
|
171
|
+
s = 4
|
172
|
+
m = (1 << p) - 1
|
173
|
+
(p - 2).times {s = (s * s - 2) % m}
|
174
|
+
return 0 == s
|
175
|
+
end
|
176
|
+
|
177
|
+
#
|
178
|
+
# factorization
|
179
|
+
#
|
180
|
+
|
181
|
+
# Param:: positive integer n >= 2
|
182
|
+
# positive integer limit
|
183
|
+
# Return:: factorization up to limit and remainder of n i.e.
|
184
|
+
# [[[a, b], [c, d], ...], r] s.t.
|
185
|
+
# n == a**b * c**d * ... * r, (r have no factor less than or equal to limit ** 2)
|
186
|
+
def trial_division(n, limit = INFINITY)
|
187
|
+
factor = []
|
188
|
+
lim = [limit, isqrt(n)].min
|
189
|
+
|
190
|
+
divide = lambda do |d|
|
191
|
+
n /= d
|
192
|
+
div_count = 1
|
193
|
+
loop do
|
194
|
+
q, r = n.divmod(d)
|
195
|
+
break unless 0 == r
|
196
|
+
|
197
|
+
n = q
|
198
|
+
div_count += 1
|
199
|
+
end
|
200
|
+
|
201
|
+
factor.push([d, div_count])
|
202
|
+
lim = [lim, isqrt(n)].min
|
203
|
+
|
204
|
+
lim < d
|
205
|
+
end
|
206
|
+
|
207
|
+
(plist = primes_list).each do |d|
|
208
|
+
break if lim < d
|
209
|
+
break if 0 == n % d and divide.call(d)
|
210
|
+
end
|
211
|
+
|
212
|
+
if plist.last < lim
|
213
|
+
d = plist.last - plist.last % 30 - 1
|
214
|
+
while d <= lim
|
215
|
+
# [2, 6, 4, 2, 4, 2, 4, 6] are difference of [1, 7, 11, 13, 17, 19, 23, 29]
|
216
|
+
# which are prime bellow 30 == 2 * 3 * 5 except 2, 3, 5
|
217
|
+
[2, 6, 4, 2, 4, 2, 4, 6].each do |diff|
|
218
|
+
d += diff
|
219
|
+
break if 0 == n % d and divide.call(d)
|
220
|
+
end
|
221
|
+
end
|
222
|
+
end
|
223
|
+
|
224
|
+
# n is prime?
|
225
|
+
if 1 < n and isqrt(n) <= lim
|
226
|
+
factor.push([n, 1])
|
227
|
+
n = 1
|
228
|
+
end
|
229
|
+
return factor, n
|
230
|
+
end
|
231
|
+
|
232
|
+
# Param:: positive integer n
|
233
|
+
# Return:: factor a and b (a <= b) if found else false
|
234
|
+
def differences_of_squares(n, limit = 1_000_000)
|
235
|
+
sqrt = isqrt(n)
|
236
|
+
dx = (sqrt << 1) + 1
|
237
|
+
dy = 1
|
238
|
+
r = sqrt ** 2 - n
|
239
|
+
terms = 0
|
240
|
+
|
241
|
+
# find x and y s.t. x**2 - y**2 == n
|
242
|
+
loop do
|
243
|
+
while 0 < r
|
244
|
+
r -= dy
|
245
|
+
dy += 2
|
246
|
+
end
|
247
|
+
|
248
|
+
break if 0 == r
|
249
|
+
|
250
|
+
r += dx
|
251
|
+
dx += 2
|
252
|
+
|
253
|
+
terms += 1
|
254
|
+
return false if limit == terms
|
255
|
+
end
|
256
|
+
|
257
|
+
return (dx - dy) >> 1, (dx + dy - 2) >> 1
|
258
|
+
end
|
259
|
+
|
260
|
+
# Param:: positive integer n
|
261
|
+
# integer c which is used recurrence formula x ** 2 + c (mod n)
|
262
|
+
# integer s starting value of the recurrence formula
|
263
|
+
# integer max number of trials
|
264
|
+
# Return:: a factor f (1 < f < n) if found else nil
|
265
|
+
def pollard_rho(n, c = 1, s = 2, max = 10_000)
|
266
|
+
u = s
|
267
|
+
v = (s ** 2 + c) % n
|
268
|
+
range = 1
|
269
|
+
product = 1
|
270
|
+
terms = 0
|
271
|
+
|
272
|
+
loop do
|
273
|
+
range.times do
|
274
|
+
v = (v ** 2 + c) % n
|
275
|
+
temp = product * (u - v) % n
|
276
|
+
if 0 == temp
|
277
|
+
g = lehmer_gcd(n, product)
|
278
|
+
return (1 < g) ? g : nil
|
279
|
+
end
|
280
|
+
product = temp
|
281
|
+
terms += 1
|
282
|
+
|
283
|
+
if terms & 1023 == 0
|
284
|
+
g = lehmer_gcd(n, product)
|
285
|
+
return g if 1 < g
|
286
|
+
return nil if max <= terms
|
287
|
+
end
|
288
|
+
end
|
289
|
+
|
290
|
+
# reset
|
291
|
+
u = v
|
292
|
+
range <<= 1
|
293
|
+
range.times { v = (v ** 2 + c) % n }
|
294
|
+
end
|
295
|
+
end
|
296
|
+
|
297
|
+
# Param:: positive integer n
|
298
|
+
# positive integer bound <= PRIME_CACHE_LIMIT
|
299
|
+
# positive integer m (2 <= m < n)
|
300
|
+
# Return:: a factor f (1 < f < n) if found else nil
|
301
|
+
def p_minus_1(n, bound = 10_000, m = 2)
|
302
|
+
plist = primes_list
|
303
|
+
|
304
|
+
p = nil
|
305
|
+
old_m = m
|
306
|
+
old_i = i = -1
|
307
|
+
|
308
|
+
loop do
|
309
|
+
i += 1
|
310
|
+
p = plist[i]
|
311
|
+
break if nil == p or bound < p
|
312
|
+
|
313
|
+
# Compute power
|
314
|
+
p_pow = p
|
315
|
+
lim = bound / p
|
316
|
+
p_pow *= p while p_pow <= lim
|
317
|
+
m = power(m, p_pow, n)
|
318
|
+
|
319
|
+
next unless 15 == i & 15
|
320
|
+
|
321
|
+
# Compute GCD
|
322
|
+
g = lehmer_gcd(m - 1, n)
|
323
|
+
if 1 == g
|
324
|
+
old_m = m
|
325
|
+
old_i = i
|
326
|
+
next
|
327
|
+
end
|
328
|
+
return g unless n == g
|
329
|
+
break
|
330
|
+
end
|
331
|
+
|
332
|
+
if nil == p or bound < p
|
333
|
+
return nil if 0 == i & 15
|
334
|
+
|
335
|
+
g = lehmer_gcd(m - 1, n)
|
336
|
+
return nil if 1 == g
|
337
|
+
return g unless n == g
|
338
|
+
end
|
339
|
+
|
340
|
+
# Backtrack
|
341
|
+
i = old_i
|
342
|
+
m = old_m
|
343
|
+
|
344
|
+
loop do
|
345
|
+
i += 1
|
346
|
+
p_pow = p = plist[i]
|
347
|
+
|
348
|
+
loop do
|
349
|
+
m = power(m, p, n)
|
350
|
+
g = lehmer_gcd(m - 1, n)
|
351
|
+
if 1 == g
|
352
|
+
p_pow *= p
|
353
|
+
break if bound < p_pow
|
354
|
+
next
|
355
|
+
end
|
356
|
+
return nil if n == g
|
357
|
+
return g unless 1 == g
|
358
|
+
end
|
359
|
+
end
|
360
|
+
end
|
361
|
+
|
362
|
+
# Param:: integer n
|
363
|
+
# boolean return_hash
|
364
|
+
# Return:: prime factorization of n s.t. [[p_1, e_1], [p_2, e_2], ...]
|
365
|
+
# n == p_1**e_1 * p_2**e_2 * ... (p_1 < p_2 < ...)
|
366
|
+
# if |n| <= 1 then return [[n, 1]].
|
367
|
+
# if n < 0 then [-1, 1] is added as a factor.
|
368
|
+
def factorize(n, return_hash = false)
|
369
|
+
unless return_hash
|
370
|
+
return factorize(n, true).to_a.sort
|
371
|
+
end
|
372
|
+
|
373
|
+
factor = Hash.new(0)
|
374
|
+
if n <= 1
|
375
|
+
return {n => 1} if -1 <= n
|
376
|
+
n = -n
|
377
|
+
factor[-1] = 1
|
378
|
+
end
|
379
|
+
|
380
|
+
found_factor, n = trial_division(n, td_lim = 10_000)
|
381
|
+
found_factor.each {|k, v| factor[k] += v}
|
382
|
+
td_lim_square = td_lim ** 2
|
383
|
+
|
384
|
+
check_finish = lambda do
|
385
|
+
if n <= td_lim_square or prime?(n)
|
386
|
+
factor[n] += 1 unless 1 == n
|
387
|
+
return true
|
388
|
+
end
|
389
|
+
return false
|
390
|
+
end
|
391
|
+
|
392
|
+
divide = lambda do |f|
|
393
|
+
f.size.times do |i|
|
394
|
+
d = f[i][0]
|
395
|
+
loop do
|
396
|
+
q, r = n.divmod(d)
|
397
|
+
break unless 0 == r
|
398
|
+
n = q
|
399
|
+
f[i][1] += 1
|
400
|
+
end
|
401
|
+
end
|
402
|
+
|
403
|
+
return f
|
404
|
+
end
|
405
|
+
|
406
|
+
return factor if check_finish.call
|
407
|
+
|
408
|
+
# pollard_rho
|
409
|
+
loop do
|
410
|
+
c = nil
|
411
|
+
loop do
|
412
|
+
c = rand(n - 3) + 1
|
413
|
+
break unless c.square?
|
414
|
+
end
|
415
|
+
s = rand(n)
|
416
|
+
f = pollard_rho(n, c, s, 50_000)
|
417
|
+
break unless f
|
418
|
+
|
419
|
+
# f is prime?
|
420
|
+
n /= f
|
421
|
+
if f <= td_lim_square or prime?(f)
|
422
|
+
f = divide.call([[f, 1]])
|
423
|
+
else
|
424
|
+
f = divide.call(factorize(f))
|
425
|
+
end
|
426
|
+
|
427
|
+
f.each {|k, v| factor[k] += v}
|
428
|
+
return factor if check_finish.call
|
429
|
+
end
|
430
|
+
|
431
|
+
# MPQS
|
432
|
+
loop do
|
433
|
+
f = mpqs(n)
|
434
|
+
break unless f
|
435
|
+
|
436
|
+
# f is prime?
|
437
|
+
n /= f
|
438
|
+
if f <= td_lim_square or prime?(f)
|
439
|
+
f = divide.call([[f, 1]])
|
440
|
+
else
|
441
|
+
f = divide.call(factorize(f))
|
442
|
+
end
|
443
|
+
|
444
|
+
f.each {|k, v| factor[k] += v}
|
445
|
+
return factor if check_finish.call
|
446
|
+
end
|
447
|
+
|
448
|
+
raise [factor, n].to_s
|
449
|
+
end
|
450
|
+
|
451
|
+
#
|
452
|
+
# generation
|
453
|
+
#
|
454
|
+
|
455
|
+
def eratosthenes_sieve(n)
|
456
|
+
return Enumerator.new(self, :eratosthenes_sieve, n) unless block_given?
|
457
|
+
|
458
|
+
return if n < 2
|
459
|
+
|
460
|
+
yield 2
|
461
|
+
return if 2 == n
|
462
|
+
|
463
|
+
yield 3
|
464
|
+
|
465
|
+
# make list for sieve
|
466
|
+
sieve_len_max = (n + 1) >> 1
|
467
|
+
sieve = [true, false, true]
|
468
|
+
sieve_len = 3
|
469
|
+
k = 5
|
470
|
+
i = 2
|
471
|
+
while sieve_len < sieve_len_max
|
472
|
+
if sieve[i]
|
473
|
+
yield k
|
474
|
+
sieve_len *= k
|
475
|
+
if sieve_len_max < sieve_len
|
476
|
+
sieve_len /= k
|
477
|
+
# adjust sieve list length
|
478
|
+
sieve *= sieve_len_max / sieve_len
|
479
|
+
sieve += sieve[0...(sieve_len_max - sieve.size)]
|
480
|
+
sieve_len = sieve_len_max
|
481
|
+
else
|
482
|
+
sieve *= k
|
483
|
+
end
|
484
|
+
|
485
|
+
i.step(sieve_len - 1, k) do |j|
|
486
|
+
sieve[j] = false
|
487
|
+
end
|
488
|
+
end
|
489
|
+
|
490
|
+
k += 2
|
491
|
+
i += 1
|
492
|
+
end
|
493
|
+
|
494
|
+
# sieve
|
495
|
+
limit = (isqrt(n) - 1) >> 1
|
496
|
+
while i <= limit
|
497
|
+
if sieve[i]
|
498
|
+
yield k = (i << 1) + 1
|
499
|
+
j = (k ** 2) >> 1
|
500
|
+
while j < sieve_len_max
|
501
|
+
sieve[j] = false
|
502
|
+
j += k
|
503
|
+
end
|
504
|
+
end
|
505
|
+
|
506
|
+
i += 1
|
507
|
+
end
|
508
|
+
|
509
|
+
# output result
|
510
|
+
limit = (n - 1) >> 1
|
511
|
+
while i <= limit
|
512
|
+
yield((i << 1) + 1) if sieve[i]
|
513
|
+
i += 1
|
514
|
+
end
|
515
|
+
end
|
516
|
+
|
517
|
+
# Param:: integer n
|
518
|
+
# Return:: The least prime greater than n
|
519
|
+
def next_prime(n)
|
520
|
+
return Bisect.find_gt(primes_list, n) if n < primes_list.last
|
521
|
+
|
522
|
+
n += (n.even? ? 1 : 2)
|
523
|
+
n += 2 until prime?(n)
|
524
|
+
|
525
|
+
return n
|
526
|
+
end
|
527
|
+
|
528
|
+
def phi(n)
|
529
|
+
return 1 if 1 == n
|
530
|
+
return n - 1 if prime?(n)
|
531
|
+
|
532
|
+
return factorize(n).inject(1) {|r, i| r * i[0] ** (i[1] - 1) * (i[0] - 1)}
|
533
|
+
end
|
534
|
+
end
|
535
|
+
|
536
|
+
class Range
|
537
|
+
def each_prime()
|
538
|
+
return Enumerator.new(self, :each_prime) unless block_given?
|
539
|
+
|
540
|
+
primes = Abst.primes_list
|
541
|
+
|
542
|
+
max = last + (exclude_end? ? -1 : 0)
|
543
|
+
if (first <= primes.last)
|
544
|
+
a = Bisect.bisect_left(primes, first)
|
545
|
+
a.upto(primes.size - 1) do |i|
|
546
|
+
return if max < primes[i]
|
547
|
+
yield primes[i]
|
548
|
+
end
|
549
|
+
end
|
550
|
+
|
551
|
+
s = primes.last + 2
|
552
|
+
s.step(max, 2) do |i|
|
553
|
+
yield i if prime?(i)
|
554
|
+
end
|
555
|
+
end
|
556
|
+
end
|