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.
@@ -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