abst 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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