abst 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|