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,38 @@
1
+ require_relative 'include/compatibility'
2
+
3
+ module Abst
4
+ ABST_ROOT = File.dirname(__FILE__) + '/'
5
+
6
+ # Integer block byte size
7
+ BASE_BYTE = 1.size
8
+ INFINITY = Float::INFINITY
9
+
10
+ I = Complex::I
11
+ end
12
+
13
+ require_relative 'config'
14
+
15
+ require_relative 'include/bisect'
16
+ require_relative 'include/cache'
17
+
18
+ require_relative 'include/group'
19
+ require_relative 'include/ring'
20
+
21
+ require_relative 'include/array'
22
+ require_relative 'include/complex'
23
+ require_relative 'include/float'
24
+ require_relative 'include/fundamental'
25
+ require_relative 'include/graph'
26
+ require_relative 'include/integer'
27
+ require_relative 'include/prime'
28
+ require_relative 'include/prime_mpqs'
29
+ require_relative 'include/rational'
30
+ require_relative 'include/residue'
31
+ require_relative 'include/sequence'
32
+ require_relative 'include/set'
33
+
34
+ require_relative 'include/vector'
35
+ require_relative 'include/polynomial'
36
+ require_relative 'include/matrix'
37
+
38
+ include Abst if Abst::AUTO_INCLUDE
@@ -0,0 +1,21 @@
1
+ module Abst
2
+ # Precompute primes under the value
3
+ PRIME_CACHE_LIMIT = 1_000_000
4
+
5
+ # System cache files will be created in this directory
6
+ DATA_DIR = ABST_ROOT + 'data/'
7
+
8
+ # User cache files will be created in this directory
9
+ CACHE_DIR = ABST_ROOT + 'cache/'
10
+
11
+ # Cache primes
12
+ PRIMES_LIST = DATA_DIR + 'primes_list'
13
+
14
+ # Bit size of Fixnum
15
+ # integer e s.t. (2 ** e) is not Fixnum and (2 ** e - 1) is Fixnum
16
+ FIXNUM_BIT_SIZE = 30
17
+
18
+ THREAD_NUM = defined?(JRUBY_VERSION) ? 6 : 1
19
+
20
+ AUTO_INCLUDE = false
21
+ end
@@ -0,0 +1,45 @@
1
+ class Array
2
+ def each_coefficient(init = nil)
3
+ return Enumerator.new(self, :each_coefficient, init) unless block_given?
4
+
5
+ init = Array.new(self.size, 0) unless init
6
+ current = init.dup
7
+
8
+ loop do
9
+ yield current.dup
10
+
11
+ # next coef
12
+ self.size.times do |i|
13
+ if self[i] == current[i]
14
+ return if i == self.size - 1
15
+ current[i] = 0
16
+ else
17
+ current[i] += 1
18
+ break
19
+ end
20
+ end
21
+ end
22
+ end
23
+
24
+ def to_set(sortable = true, &compare)
25
+ return SortableSet.new(self, &compare) if sortable
26
+ return Set.new(self)
27
+ end
28
+
29
+ # to_vector
30
+ def to_v(coef_class = nil)
31
+ vector = Abst::Vector(coef_class || self[0].class, self.size)
32
+ return vector.new(self)
33
+ end
34
+
35
+ # to_matrix
36
+ def to_m(coef_class = nil)
37
+ matrix = Abst::Matrix(coef_class || self[0][0].class, self.size, self[0].size)
38
+ return matrix.new(self)
39
+ end
40
+
41
+ # Create integer from factorization of it
42
+ def to_i
43
+ return self.map{|p, e| p ** e}.inject(&:*)
44
+ end
45
+ end
@@ -0,0 +1,95 @@
1
+ module Bisect
2
+ module_function
3
+
4
+ def bisect_left(list, item, lo = 0, hi = list.size)
5
+ if block_given?
6
+ while lo < hi
7
+ i = (lo + hi - 1) >> 1
8
+
9
+ if 0 <= yield(list[i], item)
10
+ hi = i
11
+ else
12
+ lo = i + 1
13
+ end
14
+ end
15
+ else
16
+ while lo < hi
17
+ i = (lo + hi - 1) >> 1
18
+
19
+ if 0 <= (list[i] <=> item)
20
+ hi = i
21
+ else
22
+ lo = i + 1
23
+ end
24
+ end
25
+ end
26
+
27
+ return hi
28
+ end
29
+
30
+ def bisect_right(list, item, lo = 0, hi = list.size)
31
+ if block_given?
32
+ while lo < hi
33
+ i = (lo + hi - 1) >> 1
34
+
35
+ if 0 < yield(list[i], item)
36
+ hi = i
37
+ else
38
+ lo = i + 1
39
+ end
40
+ end
41
+ else
42
+ while lo < hi
43
+ i = (lo + hi - 1) >> 1
44
+
45
+ if 0 < (list[i] <=> item)
46
+ hi = i
47
+ else
48
+ lo = i + 1
49
+ end
50
+ end
51
+ end
52
+
53
+ return lo
54
+ end
55
+
56
+ def insert_left(list, item, lo = 0, hi = list.size, &block)
57
+ i = bisect_left(list, item, lo, hi, &block)
58
+ list.insert(i, item)
59
+ end
60
+
61
+ def insert_right(list, item, lo = 0, hi = list.size, &block)
62
+ i = bisect_right(list, item, lo, hi, &block)
63
+ list.insert(i, item)
64
+ end
65
+
66
+ # Locate the leftmost value exactly equal to item
67
+ def index(list, item, &block)
68
+ i = bisect_left(list, item, &block)
69
+ return list[i] == item ? i : nil
70
+ end
71
+
72
+ # Find rightmost value less than item
73
+ def find_lt(list, item, &block)
74
+ i = bisect_left(list, item, &block)
75
+ return list[i - 1] unless 0 == i
76
+ end
77
+
78
+ # Find rightmost value less than or equal to item
79
+ def find_le(list, item, &block)
80
+ i = bisect_right(list, item, &block)
81
+ return list[i - 1] unless 0 == i
82
+ end
83
+
84
+ # Find leftmost value greater than item
85
+ def find_gt(list, item, &block)
86
+ i = bisect_right(list, item, &block)
87
+ return list[i] unless list.size == i
88
+ end
89
+
90
+ # Find leftmost item greater than or equal to item
91
+ def find_ge(list, item, &block)
92
+ i = bisect_left(list, item, &block)
93
+ return list[i] unless list.size == i
94
+ end
95
+ end
@@ -0,0 +1,60 @@
1
+ module Abst
2
+ class Cache
3
+ PREFIX = 'abst_cache_'
4
+ CACHE_DIR = CACHE_DIR
5
+
6
+ def self.mkdir(dir)
7
+ pdir = File.dirname(dir)
8
+ mkdir(pdir) unless FileTest.exist?(pdir)
9
+ Dir::mkdir(dir)
10
+ end
11
+
12
+ def self.[]=(cache_id, data)
13
+ if nil == data
14
+ delete(cache_id)
15
+ return
16
+ end
17
+
18
+ path = get_path(cache_id)
19
+ dir = File.dirname(path)
20
+
21
+ mkdir(dir) unless FileTest.exist?(dir)
22
+ open(path, "w") {|io| Marshal.dump(data, io)}
23
+ end
24
+
25
+ def self.[](cache_id)
26
+ path = get_path(cache_id)
27
+
28
+ return nil unless FileTest.exist?(path)
29
+ open(path) {|io| return Marshal.load(io)}
30
+ end
31
+
32
+ def self.delete(cache_id)
33
+ path = get_path(cache_id)
34
+
35
+ File.delete(path) if FileTest.exist?(path)
36
+ end
37
+
38
+ def self.clear
39
+ raise NotImplementedError
40
+ end
41
+
42
+ def self.exist?(cache_id)
43
+ return FileTest.exist?(get_path(cache_id))
44
+ end
45
+
46
+ def self.get_path(cache_id)
47
+ cache_id = cache_id.to_s
48
+ unless /^[a-z0-9_]+$/ =~ cache_id
49
+ raise ArgumentError, "Invalid cache_id. (Only a-z 0-9 and _ are available)"
50
+ end
51
+
52
+ return self::CACHE_DIR + self::PREFIX + cache_id
53
+ end
54
+ end
55
+
56
+ class SystemCache < Cache
57
+ PREFIX = ''
58
+ CACHE_DIR = DATA_DIR
59
+ end
60
+ end
@@ -0,0 +1,3 @@
1
+ class Float
2
+ INFINITY = 1 / 0.0 unless defined?(INFINITY)
3
+ end
@@ -0,0 +1,10 @@
1
+ class Complex
2
+ def self.one
3
+ return Complex(1, 0)
4
+ end
5
+
6
+ def self.zero
7
+ return Complex(0, 0)
8
+ end
9
+ end
10
+
@@ -0,0 +1,19 @@
1
+ class Float
2
+ def self.one
3
+ return 1.0
4
+ end
5
+
6
+ def self.zero
7
+ return 0.0
8
+ end
9
+
10
+ def inverse
11
+ return 1.0 / self
12
+ end
13
+
14
+ # Return:: formatted string
15
+ def to_fs
16
+ return self.to_s.gsub(/(?<=\d)(?=(\d\d\d)+\.)/, ' ')
17
+ end
18
+ end
19
+
@@ -0,0 +1,903 @@
1
+ module Abst
2
+ module_function
3
+
4
+ # Right-Left Binary Power
5
+ # Param:: group element g
6
+ # integer n
7
+ # Euclidean domain element mod
8
+ # Return:: g ** n % mod
9
+ def right_left_power(g, n, mod = nil)
10
+ rslt = g.class.one
11
+ return rslt if 0 == n
12
+
13
+ if n < 0
14
+ n = -n
15
+ g **= (-1)
16
+ end
17
+
18
+ g %= mod if mod
19
+
20
+ loop do
21
+ rslt *= g if n.odd?
22
+ rslt %= mod if mod
23
+
24
+ n >>= 1
25
+ break if 0 == n
26
+
27
+ g = g ** 2
28
+ g %= mod if mod
29
+ end
30
+
31
+ return rslt
32
+ end
33
+
34
+ # Left-Right Binary Power
35
+ # Param:: group element g
36
+ # integer n
37
+ # Euclidean domain element mod
38
+ # Return:: g ** n % mod
39
+ def left_right_power(g, n, mod = nil)
40
+ return g.class.one if 0 == n
41
+
42
+ if n < 0
43
+ n = -n
44
+ g **= (-1)
45
+ end
46
+
47
+ g %= mod if mod
48
+ e = ilog2(n)
49
+
50
+ rslt = g
51
+ while 0 != e
52
+ e -= 1
53
+
54
+ rslt *= rslt
55
+ rslt %= mod if mod
56
+
57
+ if 1 == n[e]
58
+ rslt *= g
59
+ rslt %= mod if mod
60
+ end
61
+ end
62
+
63
+ return rslt
64
+ end
65
+ alias power left_right_power
66
+ module_function :power
67
+
68
+ # Left-Right Base 2**k Power
69
+ # Param:: group element g
70
+ # integer n
71
+ # Euclidean domain element mod
72
+ # base bit size k
73
+ # Return:: g ** n % mod
74
+ def left_right_base2k_power(g, n, mod = nil, k = nil)
75
+ rslt = g.class.one
76
+ return rslt if 0 == n
77
+
78
+ # Initialize
79
+ if n < 0
80
+ n = -n
81
+ g **= (-1)
82
+ end
83
+
84
+ g %= mod if mod
85
+
86
+ unless k
87
+ e = ilog2(n)
88
+ optim = [0, 8, 24, 69, 196, 538, 1433, 3714]
89
+
90
+ if e <= optim.last
91
+ k = Bisect.bisect_left(optim, e)
92
+ else
93
+ k = optim.size
94
+ k += 1 until e <= k * (k + 1) * (1 << (k << 1)) / ((1 << (k + 1)) - k - 2)
95
+ end
96
+ end
97
+
98
+ # convert n into base 2**k
99
+ digits = []
100
+ mask = (1 << k) - 1
101
+ until 0 == n
102
+ digits.unshift(n & mask)
103
+ n >>= k
104
+ end
105
+
106
+ # Precomputations
107
+ z_powers = [nil, g]
108
+ g_square = g * g
109
+ g_square %= mod if mod
110
+ 3.step((1 << k) - 1, 2) do |i|
111
+ z_powers[i] = z_powers[i - 2] * g_square
112
+ z_powers[i] %= mod if mod
113
+ end
114
+
115
+ digits.each do |a|
116
+ # Multiply
117
+ if 0 == a
118
+ k.times do
119
+ rslt = rslt ** 2
120
+ rslt %= mod if mod
121
+ end
122
+ else
123
+ t = 0
124
+ t += 1 while 0 == a[t]
125
+ a >>= t if 0 < t
126
+
127
+ (k - t).times do
128
+ rslt = rslt ** 2
129
+ rslt %= mod if mod
130
+ end
131
+ rslt *= z_powers[a]
132
+ rslt %= mod if mod
133
+ t.times do
134
+ rslt = rslt ** 2
135
+ rslt %= mod if mod
136
+ end
137
+ end
138
+ end
139
+
140
+ return rslt
141
+ end
142
+
143
+ # GCD
144
+ # Param:: a and b are member of a Euclidean domain
145
+ # Return:: gcd of a and b
146
+ def gcd(a, b)
147
+ until b.zero?
148
+ a, b = b, a % b
149
+ end
150
+
151
+ return a
152
+ end
153
+
154
+ def lcm(a, b)
155
+ return a * b / gcd(a, b)
156
+ end
157
+
158
+ # Param:: integer a, b
159
+ # Return:: gcd of a and b
160
+ def lehmer_gcd(a, b)
161
+ a = -a if a < 0
162
+ b = -b if b < 0
163
+ a, b = b, a if a < b
164
+
165
+ until 0 == b
166
+ return gcd(a, b) if b.instance_of?(Fixnum)
167
+
168
+ # Get most significant digits of a and b
169
+ shift_size = (a < b ? b : a).bit_size - FIXNUM_BIT_SIZE
170
+ a_ = a >> shift_size
171
+ b_ = b >> shift_size
172
+
173
+ _A = 1
174
+ _B = 0 # a_ == msd(a) * _A + msd(b) * _B
175
+ _C = 0
176
+ _D = 1 # b_ == msd(a) * _C + msd(b) * _D
177
+
178
+ # Always
179
+ # a_ + _B <= msd(a * _A + b * _B) < a_ + _A AND
180
+ # b_ + _C <= msd(a * _C + b * _D) < a_ + _D
181
+ # OR
182
+ # a_ + _B > msd(a * _A + b * _B) >= a_ + _A AND
183
+ # b_ + _C > msd(a * _C + b * _D) >= a_ + _D
184
+
185
+ # Test quotient
186
+ until 0 == b_ + _C or 0 == b_ + _D
187
+ q1 = (a_ + _A) / (b_ + _C)
188
+ q2 = (a_ + _B) / (b_ + _D)
189
+ break if q1 != q2
190
+
191
+ # Euclidean step
192
+ _A, _C = _C, _A - q1 * _C
193
+ _B, _D = _D, _B - q1 * _D
194
+ a_, b_ = b_, a_ - q1 * b_
195
+ end
196
+
197
+ # Multi-precision step
198
+ if 0 == _B
199
+ a, b = b, a % b
200
+ else
201
+ a, b = a * _A + b * _B, a * _C + b * _D
202
+ end
203
+ end
204
+
205
+ return a
206
+ end
207
+
208
+ # Binary GCD
209
+ # Param:: integer a, b
210
+ # Return:: gcd of a and b
211
+ def binary_gcd(a, b)
212
+ a = -a if a < 0
213
+ b = -b if b < 0
214
+ a, b = b, a if a < b
215
+ return a if 0 == b
216
+
217
+ # Reduce size once
218
+ a, b = b, a % b
219
+ return a if 0 == b
220
+
221
+ # Compute powers of 2
222
+ k = 0
223
+ k += 1 while 0 == a[k] and 0 == b[k]
224
+ if 0 < k
225
+ a >>= k
226
+ b >>= k
227
+ end
228
+
229
+ # Remove initial power of 2
230
+ a >>= 1 while a.even?
231
+ b >>= 1 while b.even?
232
+
233
+ loop do
234
+ # Subtract (Here a and b are both odd.)
235
+ t = a - b
236
+ return a << k if 0 == t
237
+
238
+ count = 0
239
+ count += 1 while 0 == t[count]
240
+ t >>= count
241
+
242
+ (0 < t) ? a = t : b = -t
243
+ end
244
+ end
245
+
246
+ # Param:: a and b are member of a Euclidean domain
247
+ # Return:: (u, v, d) s.t. a*u + b*v = gcd(a, b) = d
248
+ def extended_gcd(a, b)
249
+ u0 = a.class.one
250
+ u1 = a.class.zero
251
+
252
+ return u0, u1, a if b.zero?
253
+
254
+ d0 = a # d0 = a * u0 + b * v0
255
+ d1 = b # d1 = a * u1 + b * v1
256
+
257
+ loop do
258
+ q, r = d0.divmod(d1)
259
+
260
+ return u1, (d1 - a * u1) / b, d1 if r.zero?
261
+
262
+ d0, d1 = d1, r
263
+ u0, u1 = u1, u0 - q * u1
264
+ end
265
+ end
266
+
267
+ # Param:: non-negative integer a, b
268
+ # Return:: (u, v, d) s.t. a*u + b*v = gcd(a, b) = d
269
+ def extended_lehmer_gcd(a, b)
270
+ d0 = a
271
+ u0 = 1 # d0 = a * u0 + b * v0
272
+ d1 = b
273
+ u1 = 0 # d1 = a * u1 + b * v1
274
+
275
+ loop do
276
+ if d1.instance_of?(Fixnum)
277
+ _u, _v, d = extended_gcd(d0, d1)
278
+
279
+ # here
280
+ # d == _u * d0 + _v * d1
281
+ # d0 == u0 * a + v0 * b
282
+ # d1 == u1 * a + v1 * b
283
+
284
+ u = _u * u0 + _v * u1
285
+ v = (d - u * a) / b
286
+
287
+ return u, v, d
288
+ end
289
+
290
+ # Get most significant digits of d0 and d1
291
+ shift_size = (d0 < d1 ? d1 : d0).bit_size - FIXNUM_BIT_SIZE
292
+ a_ = d0 >> shift_size
293
+ b_ = d1 >> shift_size
294
+
295
+ # Initialize (Here a_ and b_ are next value of d0, d1)
296
+ _A = 1
297
+ _B = 0 # a_ == msd(d0) * _A + msd(d1) * _B
298
+ _C = 0
299
+ _D = 1 # b_ == msd(d0) * _C + msd(d1) * _D
300
+
301
+ # Test Quotient
302
+ until 0 == b_ + _C or 0 == b_ + _D
303
+ q1 = (a_ + _B) / (b_ + _D)
304
+ q2 = (a_ + _A) / (b_ + _C)
305
+ break if q1 != q2
306
+
307
+ # Euclidean step
308
+ _A, _C = _C, _A - q1 * _C
309
+ _B, _D = _D, _B - q1 * _D
310
+ a_, b_ = b_, a_ - q1 * b_
311
+ end
312
+
313
+ # Multi-precision step
314
+ if 0 == _B
315
+ q, r = d0.divmod(d1)
316
+ d0, d1 = d1, r
317
+ u0, u1 = u1, u0 - q * u1
318
+ else
319
+ d0, d1 = d0 * _A + d1 * _B, d0 * _C + d1 * _D
320
+ u0, u1 =u0 * _A + u1 * _B, u0 * _C + u1 * _D
321
+ end
322
+ end
323
+ end
324
+
325
+ # Param:: non-negative integer a, b
326
+ # Return:: (u, v, d) s.t. a*u + b*v = gcd(a, b) = d
327
+ def extended_binary_gcd(a, b)
328
+ if a < b
329
+ a, b = b, a
330
+ exchange_flag_1 = true
331
+ end
332
+
333
+ if 0 == b
334
+ return 0, 1, a if exchange_flag_1
335
+ return 1, 0, a
336
+ end
337
+
338
+ # Reduce size once
339
+ _Q, r = a.divmod(b)
340
+ if 0 == r
341
+ return 1, 0, b if exchange_flag_1
342
+ return 0, 1, b
343
+ end
344
+ a, b = b, r
345
+
346
+ # Compute power of 2
347
+ _K = 0
348
+ _K += 1 while 0 == a[_K] and 0 == b[_K]
349
+ if 0 < _K
350
+ a >>= _K
351
+ b >>= _K
352
+ end
353
+
354
+ if b.even?
355
+ a, b = b, a
356
+ exchange_flag_2 = true
357
+ end
358
+
359
+ # Initialize
360
+ u = 1
361
+ d = a # d == a * u + b * v, (v = 0)
362
+ u_ = 0
363
+ d_ = b # d_ == a * u_ + b * v_, (v_ = 1)
364
+
365
+ # Remove intial power of 2
366
+ while d.even?
367
+ d >>= 1
368
+ u += b if u.odd?
369
+ u >>= 1
370
+ end
371
+
372
+ loop do
373
+ # Substract
374
+ next_u = u - u_
375
+ next_d = d - d_ # next_d == a * next_u + b * next_v
376
+ next_u += b if next_u < 0
377
+
378
+ break if 0 == next_d
379
+
380
+ # Remove powers of 2
381
+ while next_d.even?
382
+ next_d >>= 1
383
+ next_u += b if next_u.odd?
384
+ next_u >>= 1
385
+ end
386
+
387
+ if 0 < next_d
388
+ u = next_u
389
+ d = next_d
390
+ else
391
+ u_ = b - next_u
392
+ d_ = -next_d
393
+ end
394
+ end
395
+
396
+ v = (d - a * u) / b
397
+
398
+ u, v = v, u if exchange_flag_2
399
+ d <<= _K
400
+ u, v = v, u - v * _Q
401
+ u, v = v, u if exchange_flag_1
402
+
403
+ return u, v, d
404
+ end
405
+
406
+ # Param:: integer n
407
+ # positive integer mod which is reratively prime with n
408
+ # Return:: inverse of n modulo mod. (1 <= inverse < mod)
409
+ def inverse(n, mod)
410
+ u, _, d = extended_gcd(n, mod)
411
+
412
+ raise ArgumentError, 'n and mod must be reratively prime.' unless 1 == d
413
+
414
+ return u % mod
415
+ end
416
+
417
+ # Chinese Remainder Theorem using Algorithm 1.3.12 of [CCANT]
418
+ # Param:: array of pair integer s.t. [[x_1, m_1], [x_2, m_2], ... , [x_k, m_k]]
419
+ # m_i are pairwise coprime
420
+ # Return:: integer x s.t. x = x_i (mod m_i) for all i
421
+ # and 0 <= x < m_1 * m_2 * ... * m_k
422
+ # Example: chinese_remainder_theorem([(1,2),(2,3),(3,5)]) return 23
423
+ def chinese_remainder_theorem(list)
424
+ x, m = list.shift
425
+
426
+ list.each do |xi, mi|
427
+ u, v, = extended_gcd(m, mi)
428
+ x = u * m * xi + v * mi * x
429
+ m *= mi
430
+ x %= m
431
+ end
432
+
433
+ return x
434
+ end
435
+
436
+ # Param:: integer a, b, a_, b_ s.t. (real number x s.t. a/b <= x <= a_/b_)
437
+ # Return:: continueed fraction expansion of x
438
+ # and lower and upper bounds for this next partial quotient.
439
+ # Format: [[continueed fraction expansion...], [lower, upper]]
440
+ def continued_fraction(a, b, a_, b_)
441
+ # Initialize
442
+ q = q_ = nil
443
+ rslt = []
444
+
445
+ until 0 == b or 0 == b_
446
+ # Euclidean step
447
+ q, r = a.divmod(b)
448
+
449
+ r_ = a_ - b_ * q
450
+ if r_ < 0 or b_ <= r_
451
+ q_ = a_ / b_
452
+ break
453
+ end
454
+
455
+ rslt.push(q)
456
+ a , b = b , r
457
+ a_, b_ = b_, r_
458
+ end
459
+
460
+ if 0 == b
461
+ return rslt, [] if 0 == b_
462
+ return rslt, [a_ / b_, INFINITY]
463
+ end
464
+
465
+ return rslt, [a / b, INFINITY] if 0 == b_
466
+
467
+ q, q_ = q_, q if q > q_
468
+ return rslt, [q, q_]
469
+ end
470
+
471
+ # Param:: odd prime p
472
+ # Return:: primitive root modulo p
473
+ def primitive_root(p)
474
+ p_m1 = p - 1
475
+ check_order = factorize(p_m1)
476
+ check_order.shift
477
+ half_p_m1 = p_m1 >> 1
478
+ check_order.map!{|f| half_p_m1 / f.first}
479
+
480
+ a = 1
481
+ loop do
482
+ a += 1
483
+
484
+ next unless -1 == kronecker_symbol(a, p)
485
+ check = true
486
+ check_order.each do |e|
487
+ if p_m1 == power(a, e, p)
488
+ check = false
489
+ break
490
+ end
491
+ end
492
+
493
+ return a if check
494
+ end
495
+ end
496
+
497
+ # Param:: integer n, m
498
+ # Return:: kronecker symbol (n|m)
499
+ def kronecker_symbol(n, m)
500
+ if 0 == m
501
+ return (-1 == n or 1 == n) ? 1 : 0
502
+ end
503
+
504
+ return 0 if n.even? and m.even?
505
+
506
+ m8 = [0, 1, 0, -1, 0, -1, 0, 1]
507
+
508
+ # Remove 2's from m
509
+ count = 0
510
+ count += 1 while 0 == m[count]
511
+ m >>= count
512
+ rslt = count.even? ? 1 : m8[n & 7]
513
+
514
+ if m < 0
515
+ m = -m
516
+ rslt = -rslt if n < 0
517
+ end
518
+ n %= m
519
+
520
+ until 0 == n
521
+ count = 0
522
+ count += 1 while 0 == n[count]
523
+ n >>= count
524
+ rslt *= m8[m & 7] if count.odd?
525
+
526
+ # Apply reciprocity
527
+ rslt = -rslt if 1 == n[1] and 1 == m[1]
528
+ n, m = m % n, n
529
+ end
530
+
531
+ return (1 == m) ? rslt : 0
532
+ end
533
+ alias legendre_symbol kronecker_symbol
534
+ alias jacobi_symbol kronecker_symbol
535
+ module_function :jacobi_symbol, :legendre_symbol
536
+
537
+ # Param:: integer n
538
+ # odd prime p
539
+ # positive integer exp
540
+ # (if 1 < exp then n must be relatively prime with p)
541
+ # Return:: the square root of n mod (p ** exp) if exists else nil
542
+ def mod_sqrt(n, p, exp = 1, return_list = false)
543
+ if 1 < exp or return_list
544
+ x = mod_sqrt(n, p)
545
+ return x unless x
546
+ return [x] if 1 == exp
547
+ raise ArgumentError, "if 1 < exp then n must be relatively prime with p" if 0 == x
548
+
549
+ rslt = [x] if return_list
550
+ p_power = p
551
+ z = extended_lehmer_gcd(x << 1, p)[0]
552
+ (exp - 1).times do
553
+ x += (n - x ** 2) / p_power * z % p * p_power
554
+ p_power *= p
555
+ rslt.push(x) if return_list
556
+ end
557
+
558
+ return return_list ? rslt : x
559
+ end
560
+
561
+ unless (k = kronecker_symbol(n, p)) == 1
562
+ return nil if -1 == k
563
+ return 0
564
+ end
565
+
566
+ if 0 < p & 6
567
+ return power(n, (p >> 2) + 1, p) if p[1] == 1
568
+ n %= p
569
+ x = power(n, (p >> 3) + 1, p)
570
+ return x if x ** 2 % p == n
571
+ return x * power(2, p >> 2, p) % p
572
+ end
573
+
574
+ # get q and e s.t. p - 1 == 2**e * q with q odd
575
+ e = 0
576
+ q = p - 1
577
+ e += 1 while 0 == q[e]
578
+ q >>= e
579
+
580
+ # Find generator
581
+ g = 2
582
+ g += 1 until -1 == kronecker_symbol(g, p)
583
+ z = power(g, q, p) # |<z>| == 2 ** e
584
+
585
+ # Initialize
586
+ temp = power(n, q >> 1, p)
587
+ x = n * temp % p # n ** ((q + 1) / 2) mod p
588
+ b = x * temp % p # n ** q mod p
589
+
590
+ # always
591
+ # n * b == x ** 2
592
+ until 1 == b
593
+ # Find exponent f s.t. b ** (2 ** f) == 1 (mod p)
594
+ f = 0
595
+ b_ = b
596
+ until 1 == b_
597
+ b_ = b_ ** 2 % p
598
+ f += 1
599
+ end
600
+
601
+ # Reduce exponent
602
+ (e - f - 1).times { z = z ** 2 % p }
603
+ e = f
604
+ x = x * z % p
605
+ z = z ** 2 % p
606
+ b = b * z % p
607
+ end
608
+
609
+ return x
610
+ end
611
+
612
+ # Param:: positive integer d
613
+ # prime number p (d < p)
614
+ # Return:: integer solution (x, y) to the Diophantine equation
615
+ # x ** 2 + d * y ** 2 = p if exists else nil
616
+ def cornacchia(d, p)
617
+ return nil if -1 == kronecker_symbol(-d, p)
618
+
619
+ # Compute square root
620
+ x0 = mod_sqrt(-d, p)
621
+ x0 = p - x0 if x0 <= p >> 1
622
+ a = p
623
+ b = x0
624
+ border = isqrt(p)
625
+
626
+ # Euclidean algorithm
627
+ while border < b
628
+ a, b = b, a % b
629
+ end
630
+
631
+ # Test solution
632
+ c, r = (p - b ** 2).divmod(d)
633
+ return nil if 0 != r
634
+
635
+ q = c.square?
636
+ return nil unless q
637
+
638
+ return [b, q]
639
+ end
640
+
641
+ # Param:: d is a negative integer s.t. d = 0 or 1 mod 4
642
+ # prime number p (|d| < 4p)
643
+ # Return:: integer solution (x, y) to the Diophantine equation
644
+ # x ** 2 + |d| * y ** 2 = 4p if exists else nil
645
+ def modified_cornacchia(d, p)
646
+ # Case p == 2
647
+ if 2 == p
648
+ return nil unless q = (d + 8).square?
649
+ return q, 1
650
+ end
651
+
652
+ # Test if residue
653
+ return nil if -1 == kronecker_symbol(d, p)
654
+
655
+ # Compute square root
656
+ x0 = mod_sqrt(d, p)
657
+ x0 = p - x0 if 0 != x0 - d % 2
658
+
659
+ a = p << 1
660
+ b = x0
661
+ l = isqrt(p << 2)
662
+
663
+ # Euclidean algorithm
664
+ a, b = b, a % b while b < l
665
+
666
+ # Test solution
667
+ c, r = (4 * p - b**2).divmod(-d)
668
+ return nil if 0 != r
669
+ return nil unless q = c.square?
670
+ return b, q
671
+ end
672
+
673
+ # Integer Square Root
674
+ # Param:: positive integer n
675
+ # Return:: integer part of the square root of n
676
+ # i.e. the number m s.t. m ** 2 <= n < (m + 1) ** 2
677
+ def isqrt(n)
678
+ x = 1 << ((ilog2(n) >> 1) + 1)
679
+
680
+ loop do
681
+ # Newtonian step
682
+ next_x = (x + n / x) >> 1
683
+ return x if x <= next_x
684
+
685
+ x = next_x
686
+ end
687
+ end
688
+
689
+ # Integer Power Root
690
+ # Param:: positive integer n
691
+ # positive integer pow
692
+ # Return:: integer part of the power root of n
693
+ # i.e. the number m s.t. m ** pow <= n < (m + 1) ** pow
694
+ # if return_power is true then return n ** pow
695
+ def iroot(n, pow, return_power = false)
696
+ # get integer e s.t. (2 ** (e - 1)) ** pow <= n < (2 ** e) ** pow
697
+ e = ilog2(n) / pow + 1 # == Rational(ilog2(n) + 1, pow).ceil
698
+
699
+ x = 1 << e # == 2 ** e
700
+ z = nil
701
+ q = n >> (e * (pow - 1)) # == n / (x ** (pow - 1))
702
+
703
+ loop do
704
+ # Newtonian step
705
+ x += (q - x) / pow
706
+ z = x ** (pow - 1)
707
+ q = n / z
708
+
709
+ break if x <= q
710
+ end
711
+
712
+ return x, x * z if return_power
713
+ return x
714
+ end
715
+
716
+ # Param:: positive integer n > 1
717
+ # Return:: p if n is of the form p^k with p prime else false
718
+ def prime_power?(n)
719
+ if n.even?
720
+ return n.power_of?(2) ? 2 : false
721
+ end
722
+
723
+ p = n
724
+ loop do
725
+ rslt, witness = miller_rabin(p, 10, true)
726
+ if rslt
727
+ # Final test
728
+ redo unless prime?(p)
729
+ return n.power_of?(p) ? p : false
730
+ end
731
+
732
+ d = lehmer_gcd(power(witness, p, p) - witness, p)
733
+ return false if 1 == d or d == p
734
+ p = d
735
+ end
736
+ end
737
+
738
+ # Param:: positive integer n
739
+ # boolean largest_exp
740
+ # Return:: integer x, k s.t. n == x ** k
741
+ # if n == 1 then x, k == 1, 1
742
+ # (2 <= k if exist else x, k == n, 1)
743
+ # if largest_exp is true then return largest k
744
+ def power_detection(n, largest_exp = true)
745
+ x, k = n, 1
746
+
747
+ limit = ilog2(n)
748
+ (2..limit).each_prime do |exp|
749
+ break if limit < exp
750
+
751
+ root, pow = iroot(n, exp, true)
752
+ if pow == n
753
+ return root, exp unless largest_exp
754
+
755
+ n = x = root
756
+ k *= exp
757
+ limit = ilog2(n)
758
+ redo
759
+ end
760
+ end
761
+
762
+ return x, k
763
+ end
764
+
765
+ # Param:: positive integer n
766
+ # Return:: integer e s.t. 2 ** e <= n < 2 ** (e + 1)
767
+ def ilog2(n)
768
+ bits = (n.size - BASE_BYTE) << 3
769
+ return bits + Bisect.bisect_right(powers_of_2, n >> bits) - 1
770
+ end
771
+
772
+ $powers_of_2 = nil
773
+ # Return:: array power of 2 s.t. [1, 2, 4, 8, 16, 32, ...]
774
+ def powers_of_2
775
+ unless $powers_of_2
776
+ $powers_of_2 = [1]
777
+ ((BASE_BYTE << 3) - 1).times do |i|
778
+ $powers_of_2[i + 1] = $powers_of_2[i] << 1
779
+ end
780
+ end
781
+
782
+ return $powers_of_2
783
+ end
784
+
785
+ # Param:: positive integer m
786
+ # Return:: continued fraction of sqrt m
787
+ # [n, [a_1, a_2, ..., a_i]] s.t. sqrt m = n + frac{1}{a1 + frac{1}{a2 + ...}}
788
+ # n is integer part and a_1...a_i are repeating part
789
+ # Example::continued_fraction_of_sqrt(2) -> [1, [2]]
790
+ # continued_fraction_of_sqrt(3) -> [1, [1, 2]]
791
+ # continued_fraction_of_sqrt(4) -> [2, []]
792
+ def continued_fraction_of_sqrt(m)
793
+ if r = m.square?
794
+ return [r, []]
795
+ end
796
+
797
+ # Initialize
798
+ rslt = [isqrt(m), []]
799
+
800
+ a = 1
801
+ _B = b = -rslt[0]
802
+ c = 1
803
+
804
+ loop do
805
+ # inverse
806
+ a, b, c = a * c, -b * c, a**2 * m - b**2
807
+
808
+ # reduction
809
+ t = gcd(gcd(a, b), c)
810
+ a /= t
811
+ b /= t
812
+ c /= t
813
+
814
+ t = (isqrt(m * a ** 2) + b) / c
815
+ rslt[1].push(t)
816
+ b -= c * t
817
+
818
+ return rslt if 1 == a and _B == b and 1 == c
819
+ end
820
+ end
821
+
822
+ # Param:: positive non-square integer n
823
+ # Return:: least positive integer a, b s.t. a**2 - n * b**2 == 1 or -1
824
+ def bhaskara_brouncker(n)
825
+ t = sqrt = isqrt(n)
826
+ u, u1 = 0, sqrt
827
+ c, c1 = 1, n - sqrt ** 2
828
+ a, a1 = 1, sqrt
829
+ b, b1 = 0, 1
830
+
831
+ until 1 == c1
832
+ t = (sqrt + u1) / c1
833
+ u1, u = t * c1 - u1, u1
834
+ c1, c = c + t * (u - u1), c1
835
+ a1, a = a + t * a1, a1
836
+ b1, b = b + t * b1, b1
837
+ end
838
+
839
+ return a1, b1
840
+ end
841
+
842
+ # primitive Pythagorean number
843
+ # Param:: integer max_c
844
+ # Return:: array of primitive Pythagorean numbers s.t. [[a, b, c], ...]
845
+ # a**2 + b**2 == c**2 and a < b < c <= max_c
846
+ def pythagorean(max_c)
847
+ return Enumerator.new(self, :pythagorean, max_c) unless block_given?
848
+ return [] if max_c <= 4
849
+
850
+ 1.upto(isqrt(max_c - 1)) do |m|
851
+ mm = m ** 2
852
+ s = m.even? ? 1 : 2
853
+ s.step(m, 2) do |n|
854
+ next unless gcd(m, n) == 1
855
+
856
+ nn = n ** 2
857
+ c = mm + nn
858
+ break if max_c < c
859
+
860
+ a = mm - nn
861
+ b = (m * n) << 1
862
+ a, b = b, a if b < a
863
+
864
+ yield [a, b, c]
865
+ end
866
+ end
867
+ end
868
+
869
+ # Param:: positive integer n
870
+ # Return:: the value of moebius function for n
871
+ def mobius(n)
872
+ return 1 if 1 == n
873
+ return 0 unless n.squarefree?
874
+ return factorize(n).size.odd? ? -1 : 1
875
+ end
876
+ alias moebius mobius
877
+
878
+ # Param:: Integer base (2 <= base < p)
879
+ # Integer m (2 <= m < p)
880
+ # prime p
881
+ # Return:: Integer e s.t. base ** e == m (mod p)
882
+ def dlog_rho(base, m, p)
883
+ raise NotImplementedError
884
+ end
885
+
886
+ # Param:: Integer base (2 <= base < p)
887
+ # Integer m (2 <= m < p)
888
+ # prime p
889
+ # Return:: Integer e s.t. base ** e == m (mod p)
890
+ def dlog_icm(base, m, p)
891
+ # Select factor base
892
+
893
+ # Select smooth elements on factor base
894
+
895
+ # Solve DL of factor base for base
896
+
897
+ # Find smooth element h s.t. h == m * base ** f where f is integer
898
+
899
+ # Solve DL of h for factor base
900
+
901
+ raise NotImplementedError
902
+ end
903
+ end