symath 0.1.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.
- checksums.yaml +7 -0
- data/.gitignore +12 -0
- data/.rspec +3 -0
- data/.travis.yml +7 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/Gemfile +8 -0
- data/LICENSE.txt +21 -0
- data/README.md +616 -0
- data/Rakefile +6 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/lib/symath/definition/abs.rb +48 -0
- data/lib/symath/definition/arccos.rb +25 -0
- data/lib/symath/definition/arccot.rb +23 -0
- data/lib/symath/definition/arccsc.rb +24 -0
- data/lib/symath/definition/arcsec.rb +24 -0
- data/lib/symath/definition/arcsin.rb +25 -0
- data/lib/symath/definition/arctan.rb +23 -0
- data/lib/symath/definition/bounds.rb +39 -0
- data/lib/symath/definition/codiff.rb +31 -0
- data/lib/symath/definition/constant.rb +111 -0
- data/lib/symath/definition/cos.rb +17 -0
- data/lib/symath/definition/cot.rb +17 -0
- data/lib/symath/definition/csc.rb +17 -0
- data/lib/symath/definition/curl.rb +27 -0
- data/lib/symath/definition/d.rb +62 -0
- data/lib/symath/definition/div.rb +27 -0
- data/lib/symath/definition/exp.rb +112 -0
- data/lib/symath/definition/fact.rb +55 -0
- data/lib/symath/definition/flat.rb +31 -0
- data/lib/symath/definition/function.rb +197 -0
- data/lib/symath/definition/grad.rb +23 -0
- data/lib/symath/definition/hodge.rb +23 -0
- data/lib/symath/definition/int.rb +75 -0
- data/lib/symath/definition/laplacian.rb +23 -0
- data/lib/symath/definition/lmd.rb +97 -0
- data/lib/symath/definition/ln.rb +45 -0
- data/lib/symath/definition/number.rb +51 -0
- data/lib/symath/definition/operator.rb +228 -0
- data/lib/symath/definition/sec.rb +17 -0
- data/lib/symath/definition/sharp.rb +31 -0
- data/lib/symath/definition/sin.rb +17 -0
- data/lib/symath/definition/sqrt.rb +62 -0
- data/lib/symath/definition/tan.rb +17 -0
- data/lib/symath/definition/trig.rb +95 -0
- data/lib/symath/definition/variable.rb +284 -0
- data/lib/symath/definition/xd.rb +28 -0
- data/lib/symath/definition.rb +205 -0
- data/lib/symath/equation.rb +67 -0
- data/lib/symath/fraction.rb +177 -0
- data/lib/symath/matrix.rb +252 -0
- data/lib/symath/minus.rb +125 -0
- data/lib/symath/operation/differential.rb +167 -0
- data/lib/symath/operation/distributivelaw.rb +367 -0
- data/lib/symath/operation/exterior.rb +64 -0
- data/lib/symath/operation/integration.rb +329 -0
- data/lib/symath/operation/match.rb +166 -0
- data/lib/symath/operation/normalization.rb +458 -0
- data/lib/symath/operation.rb +36 -0
- data/lib/symath/operator.rb +163 -0
- data/lib/symath/parser.rb +473 -0
- data/lib/symath/parser.y +129 -0
- data/lib/symath/poly/dup.rb +835 -0
- data/lib/symath/poly/galois.rb +621 -0
- data/lib/symath/poly.rb +142 -0
- data/lib/symath/power.rb +224 -0
- data/lib/symath/product.rb +183 -0
- data/lib/symath/sum.rb +174 -0
- data/lib/symath/type.rb +282 -0
- data/lib/symath/value.rb +372 -0
- data/lib/symath/version.rb +3 -0
- data/lib/symath/wedge.rb +48 -0
- data/lib/symath.rb +157 -0
- data/symath.gemspec +39 -0
- metadata +160 -0
@@ -0,0 +1,621 @@
|
|
1
|
+
require 'symath/poly'
|
2
|
+
|
3
|
+
module SyMath
|
4
|
+
# Class representing a galois field, i.e finite field
|
5
|
+
class Poly::Galois < Poly
|
6
|
+
attr_reader :p
|
7
|
+
|
8
|
+
# Create gl instance from dup or a gl of the same order.
|
9
|
+
def initialize(args)
|
10
|
+
if args.key?(:dup)
|
11
|
+
init_from_dup(args[:dup], args[:p])
|
12
|
+
return
|
13
|
+
end
|
14
|
+
|
15
|
+
if args.key?(:arr)
|
16
|
+
init_from_array(args[:arr], args[:p], args[:var])
|
17
|
+
return
|
18
|
+
end
|
19
|
+
|
20
|
+
raise 'Bad arguments for Poly::Galois constructor'
|
21
|
+
end
|
22
|
+
|
23
|
+
def init_from_dup(dup, p)
|
24
|
+
@arr = dup.arr.map { |t| t % p }
|
25
|
+
@p = p
|
26
|
+
@var = dup.var
|
27
|
+
end
|
28
|
+
|
29
|
+
def init_from_array(arr, p, var)
|
30
|
+
@arr = arr
|
31
|
+
@p = p
|
32
|
+
@var = var
|
33
|
+
end
|
34
|
+
|
35
|
+
# Convenience method for creating a new gl of the same order
|
36
|
+
# and the same variable
|
37
|
+
def new_gl(arr)
|
38
|
+
return SyMath::Poly::Galois.new({ :arr => arr, :p => @p, :var => @var })
|
39
|
+
end
|
40
|
+
|
41
|
+
def zero()
|
42
|
+
return new_gl([])
|
43
|
+
end
|
44
|
+
|
45
|
+
def one()
|
46
|
+
return new_gl([1])
|
47
|
+
end
|
48
|
+
|
49
|
+
def gl_x()
|
50
|
+
new_gl([1, 0])
|
51
|
+
end
|
52
|
+
|
53
|
+
# Assert that two fields have the same order
|
54
|
+
def assert_order(g)
|
55
|
+
if @p != g.p
|
56
|
+
raise 'Fields do not have the same order'
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def to_dup()
|
61
|
+
ret = @arr.map do |e|
|
62
|
+
if e <= @p / 2
|
63
|
+
e
|
64
|
+
else
|
65
|
+
e - @p
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
return SyMath::Poly::DUP.new({ :arr => ret, :var => @var })
|
70
|
+
end
|
71
|
+
|
72
|
+
def invert(a)
|
73
|
+
p = @p
|
74
|
+
raise "No inverse - #{a} and #{p} not coprime" unless a.gcd(p) == 1
|
75
|
+
|
76
|
+
return p if p == 1
|
77
|
+
|
78
|
+
m0, inv, x0 = p, 1, 0
|
79
|
+
|
80
|
+
while a > 1
|
81
|
+
inv -= (a / p) * x0
|
82
|
+
a, p = p, a % p
|
83
|
+
inv, x0 = x0, inv
|
84
|
+
end
|
85
|
+
|
86
|
+
inv += m0 if inv < 0
|
87
|
+
|
88
|
+
return inv
|
89
|
+
end
|
90
|
+
|
91
|
+
def factor_sqf()
|
92
|
+
(lc, f) = monic
|
93
|
+
|
94
|
+
if f.degree < 1
|
95
|
+
return [lc, zero]
|
96
|
+
end
|
97
|
+
|
98
|
+
factors = f.zassenhaus
|
99
|
+
|
100
|
+
return [lc, factors]
|
101
|
+
end
|
102
|
+
|
103
|
+
# Return true if polynomial is square free
|
104
|
+
def sqf_p()
|
105
|
+
(lc, f) = monic
|
106
|
+
|
107
|
+
if f.zero?
|
108
|
+
return true
|
109
|
+
else
|
110
|
+
return f.gcd(f.diff).arr == [1]
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
def sqf_list()
|
115
|
+
n = 1
|
116
|
+
sqf = false
|
117
|
+
factors = []
|
118
|
+
r = @p
|
119
|
+
|
120
|
+
(lc, f) = monic
|
121
|
+
|
122
|
+
if degree < 1
|
123
|
+
return [lc, []]
|
124
|
+
end
|
125
|
+
|
126
|
+
f = self
|
127
|
+
|
128
|
+
while true
|
129
|
+
ff = f.diff
|
130
|
+
|
131
|
+
if !ff.zero?
|
132
|
+
g = f.gcd(ff)
|
133
|
+
h = f / g
|
134
|
+
|
135
|
+
i = 1
|
136
|
+
|
137
|
+
while h.arr != [1]
|
138
|
+
gg = g.gcd(h)
|
139
|
+
hh = h / gg
|
140
|
+
|
141
|
+
if hh.degree > 0
|
142
|
+
factors << [hh, i*n]
|
143
|
+
end
|
144
|
+
|
145
|
+
g = g / gg
|
146
|
+
h = gg
|
147
|
+
i += 1
|
148
|
+
end
|
149
|
+
|
150
|
+
if g.arr == [1]
|
151
|
+
sqf = true
|
152
|
+
else
|
153
|
+
f = g
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
if !sqf
|
158
|
+
d = f.degree/r
|
159
|
+
|
160
|
+
f = new_gl((0..d).map { |i| f[i*r] })
|
161
|
+
n = n*r
|
162
|
+
else
|
163
|
+
break
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
return [lc, factors]
|
168
|
+
end
|
169
|
+
|
170
|
+
def factor()
|
171
|
+
(lc, f) = monic
|
172
|
+
|
173
|
+
if f.degree < 1
|
174
|
+
return [lc, []]
|
175
|
+
end
|
176
|
+
|
177
|
+
factors = []
|
178
|
+
|
179
|
+
f.sqf_list[1].each do |g, n|
|
180
|
+
g.factor_sqf[1].each do |h|
|
181
|
+
factors << [h, n]
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
return [lc, sort_factors_multiple(factors)]
|
186
|
+
end
|
187
|
+
|
188
|
+
# Compute f**(p**n - 1) / 2 in GF(p)[x]/(g)
|
189
|
+
# (Utility function for edf_zassenhaus)
|
190
|
+
def pow_pnm1d2(n, g, b)
|
191
|
+
f = rem(g)
|
192
|
+
h = f
|
193
|
+
r = f
|
194
|
+
|
195
|
+
(n - 1).times do
|
196
|
+
h = h.frobenius_map(g, b)
|
197
|
+
r = (r*h) % g
|
198
|
+
end
|
199
|
+
|
200
|
+
return r.pow_mod((@p - 1)/2, g)
|
201
|
+
end
|
202
|
+
|
203
|
+
def frobenius_monomial_base()
|
204
|
+
n = degree
|
205
|
+
|
206
|
+
if n == 0
|
207
|
+
return []
|
208
|
+
end
|
209
|
+
|
210
|
+
b = []
|
211
|
+
b << one
|
212
|
+
|
213
|
+
if @p < n
|
214
|
+
(1..n - 1).each do |i|
|
215
|
+
mon = b[i - 1].lshift(@p)
|
216
|
+
b << mon % self
|
217
|
+
end
|
218
|
+
elsif n > 1
|
219
|
+
b << new_gl([1, 0]).pow_mod(@p, self)
|
220
|
+
(2..n - 1).each do |i|
|
221
|
+
b << (b[i - 1]*b[1]) % self
|
222
|
+
end
|
223
|
+
end
|
224
|
+
|
225
|
+
return b
|
226
|
+
end
|
227
|
+
|
228
|
+
def frobenius_map(g, b)
|
229
|
+
f = self
|
230
|
+
m = g.degree
|
231
|
+
|
232
|
+
if f.degree >= m
|
233
|
+
f = rem(g)
|
234
|
+
end
|
235
|
+
|
236
|
+
if f.zero?
|
237
|
+
return zero
|
238
|
+
end
|
239
|
+
|
240
|
+
n = f.degree
|
241
|
+
sf = new_gl([f[-1]])
|
242
|
+
|
243
|
+
(1..n).each do |i|
|
244
|
+
sf += b[i]*f[n - i]
|
245
|
+
end
|
246
|
+
|
247
|
+
return sf
|
248
|
+
end
|
249
|
+
|
250
|
+
# Deterministic distinct degree factorization
|
251
|
+
def ddf_zassenhaus()
|
252
|
+
x = gl_x
|
253
|
+
|
254
|
+
i = 1
|
255
|
+
g = x
|
256
|
+
factors = []
|
257
|
+
|
258
|
+
f = self
|
259
|
+
b = f.frobenius_monomial_base
|
260
|
+
|
261
|
+
while 2*i <= f.degree
|
262
|
+
g = g.frobenius_map(f, b)
|
263
|
+
h = f.gcd(g - x)
|
264
|
+
|
265
|
+
if h.arr != [1]
|
266
|
+
factors << [h, i]
|
267
|
+
|
268
|
+
f = f / h
|
269
|
+
g = g % f
|
270
|
+
b = f.frobenius_monomial_base
|
271
|
+
end
|
272
|
+
|
273
|
+
i += 1
|
274
|
+
end
|
275
|
+
|
276
|
+
if f.arr != [1]
|
277
|
+
return factors + [[f, f.degree]]
|
278
|
+
else
|
279
|
+
return factors
|
280
|
+
end
|
281
|
+
end
|
282
|
+
|
283
|
+
# Generate random polynomial of degree n
|
284
|
+
def random_gl(n)
|
285
|
+
ret = [1]
|
286
|
+
(n).times { ret << rand(@p) }
|
287
|
+
return new_gl(ret)
|
288
|
+
end
|
289
|
+
|
290
|
+
# Equal degree factorization
|
291
|
+
def edf_zassenhaus(n)
|
292
|
+
factors = [self.clone]
|
293
|
+
|
294
|
+
if degree <= n
|
295
|
+
return factors
|
296
|
+
end
|
297
|
+
|
298
|
+
nn = degree / n
|
299
|
+
|
300
|
+
if @p != 2
|
301
|
+
b = frobenius_monomial_base
|
302
|
+
end
|
303
|
+
|
304
|
+
while factors.size < nn
|
305
|
+
r = random_gl(2*n - 1)
|
306
|
+
|
307
|
+
if @p == 2
|
308
|
+
h = r
|
309
|
+
|
310
|
+
(2**(n*nn - 1)).times do
|
311
|
+
r = r.pow_mod(2, self)
|
312
|
+
h += r
|
313
|
+
end
|
314
|
+
|
315
|
+
g = gcd(h)
|
316
|
+
else
|
317
|
+
h = r.pow_pnm1d2(n, self, b)
|
318
|
+
g = gcd(h - 1)
|
319
|
+
end
|
320
|
+
|
321
|
+
if g.arr != [1] and g != self
|
322
|
+
factors = g.edf_zassenhaus(n) + (self / g).edf_zassenhaus(n)
|
323
|
+
end
|
324
|
+
end
|
325
|
+
|
326
|
+
return sort_factors(factors)
|
327
|
+
end
|
328
|
+
|
329
|
+
def zassenhaus()
|
330
|
+
factors = []
|
331
|
+
|
332
|
+
ddf_zassenhaus.each do |f|
|
333
|
+
factors += f[0].edf_zassenhaus(f[1])
|
334
|
+
end
|
335
|
+
|
336
|
+
return sort_factors(factors)
|
337
|
+
end
|
338
|
+
|
339
|
+
# Extended gcd for two polynomials
|
340
|
+
def gcdex(g)
|
341
|
+
assert_order(g)
|
342
|
+
|
343
|
+
if self.zero? and g.zero?
|
344
|
+
return [one, zero, zero]
|
345
|
+
end
|
346
|
+
|
347
|
+
(p0, r0) = monic
|
348
|
+
(p1, r1) = g.monic
|
349
|
+
|
350
|
+
if zero?
|
351
|
+
return [zero, new_gl([invert(p1)]), r1]
|
352
|
+
end
|
353
|
+
|
354
|
+
if g.zero?
|
355
|
+
return [new_gl([invert(p0)]), zero, r0]
|
356
|
+
end
|
357
|
+
|
358
|
+
s0, s1 = new_gl([invert(p0)]), zero
|
359
|
+
t0, t1 = zero, new_gl([invert(p1)])
|
360
|
+
|
361
|
+
while true
|
362
|
+
(qq, rr) = r0.div(r1)
|
363
|
+
|
364
|
+
if rr.zero?
|
365
|
+
break
|
366
|
+
end
|
367
|
+
|
368
|
+
r0 = r1
|
369
|
+
(c, r1) = rr.monic
|
370
|
+
|
371
|
+
inv = invert(c)
|
372
|
+
|
373
|
+
s = s0 - s1*qq
|
374
|
+
t = t0 - t1*qq
|
375
|
+
|
376
|
+
s0 = s1
|
377
|
+
s1 = s*inv
|
378
|
+
|
379
|
+
t0 = t1
|
380
|
+
t1 = t*inv
|
381
|
+
end
|
382
|
+
|
383
|
+
return [s1, t1, r1]
|
384
|
+
end
|
385
|
+
|
386
|
+
# Divide coefficients by lc
|
387
|
+
def monic()
|
388
|
+
if zero?
|
389
|
+
return self.clone
|
390
|
+
end
|
391
|
+
|
392
|
+
c = lc
|
393
|
+
return [c, mul_ground(invert(c))]
|
394
|
+
end
|
395
|
+
|
396
|
+
def diff()
|
397
|
+
d = degree
|
398
|
+
res = @arr.each_with_index.map { |e, i| e*(d - i) % @p }
|
399
|
+
res.pop
|
400
|
+
|
401
|
+
return new_gl(res).strip!
|
402
|
+
end
|
403
|
+
|
404
|
+
def gcd(g)
|
405
|
+
assert_order(g)
|
406
|
+
|
407
|
+
f = self
|
408
|
+
# Euclidian algorithm for gcd
|
409
|
+
while !g.zero?
|
410
|
+
(f, g) = [g, f.rem(g)]
|
411
|
+
end
|
412
|
+
|
413
|
+
return f.monic[1]
|
414
|
+
end
|
415
|
+
|
416
|
+
def pow_mod(n, g)
|
417
|
+
if n == 0
|
418
|
+
return one
|
419
|
+
elsif n == 1
|
420
|
+
return self % g
|
421
|
+
elsif n == 2
|
422
|
+
return self**2 % g
|
423
|
+
end
|
424
|
+
|
425
|
+
f = self
|
426
|
+
h = one
|
427
|
+
|
428
|
+
while true
|
429
|
+
if n.odd?
|
430
|
+
h = (h*f) % g
|
431
|
+
n -= 1
|
432
|
+
end
|
433
|
+
|
434
|
+
n >>= 1
|
435
|
+
|
436
|
+
if n == 0
|
437
|
+
break
|
438
|
+
end
|
439
|
+
|
440
|
+
f = f**2 % g
|
441
|
+
end
|
442
|
+
|
443
|
+
return h
|
444
|
+
end
|
445
|
+
|
446
|
+
# Sum two polynomials
|
447
|
+
def add(g)
|
448
|
+
ret = @arr.clone
|
449
|
+
|
450
|
+
rd = degree
|
451
|
+
gd = g.degree
|
452
|
+
|
453
|
+
if gd > rd
|
454
|
+
(gd - rd).times { ret.unshift(0) }
|
455
|
+
rd += gd - rd
|
456
|
+
end
|
457
|
+
|
458
|
+
(0..gd).each do |i|
|
459
|
+
ret[rd - i] = (ret[rd - i] + g[gd - i]) % @p
|
460
|
+
end
|
461
|
+
|
462
|
+
return new_gl(ret).strip!
|
463
|
+
end
|
464
|
+
|
465
|
+
# Subtract a polynomial from this one
|
466
|
+
def sub(g)
|
467
|
+
ret = @arr.clone
|
468
|
+
|
469
|
+
rd = degree
|
470
|
+
gd = g.degree
|
471
|
+
|
472
|
+
if gd > rd
|
473
|
+
(gd - rd).times { ret.unshift(0) }
|
474
|
+
rd += gd - rd
|
475
|
+
end
|
476
|
+
|
477
|
+
(0..gd).each do |i|
|
478
|
+
ret[rd - i] = (ret[rd - i] - g[gd - i]) % @p
|
479
|
+
end
|
480
|
+
|
481
|
+
return new_gl(ret).strip!
|
482
|
+
end
|
483
|
+
|
484
|
+
def add_ground(a)
|
485
|
+
return add(new_gl([a]))
|
486
|
+
end
|
487
|
+
|
488
|
+
def sub_ground(a)
|
489
|
+
return sub(new_gl([a]))
|
490
|
+
end
|
491
|
+
|
492
|
+
# Return the negative of the polynomial
|
493
|
+
def neg()
|
494
|
+
return new_dup(@arr.map { |t| -t % @p })
|
495
|
+
end
|
496
|
+
|
497
|
+
def mul(g)
|
498
|
+
df = degree
|
499
|
+
dg = g.degree
|
500
|
+
|
501
|
+
dh = df + dg
|
502
|
+
if dh > 0
|
503
|
+
h = [0]*(dh + 1)
|
504
|
+
else
|
505
|
+
h = []
|
506
|
+
end
|
507
|
+
|
508
|
+
(0..dh).each do |i|
|
509
|
+
coeff = 0
|
510
|
+
|
511
|
+
a = [0, i - dg].max
|
512
|
+
b = [i, df].min
|
513
|
+
(a..b).each do |j|
|
514
|
+
coeff += self[j]*g[i - j]
|
515
|
+
end
|
516
|
+
|
517
|
+
h[i] = coeff % p
|
518
|
+
end
|
519
|
+
|
520
|
+
ret = new_gl(h)
|
521
|
+
ret.strip!
|
522
|
+
return ret
|
523
|
+
end
|
524
|
+
|
525
|
+
def mul_ground(a)
|
526
|
+
if a == 0
|
527
|
+
return zero
|
528
|
+
else
|
529
|
+
return new_gl(@arr.map { |e| a*e % @p})
|
530
|
+
end
|
531
|
+
end
|
532
|
+
|
533
|
+
def sqr()
|
534
|
+
d = degree
|
535
|
+
dh = 2*d
|
536
|
+
h = []
|
537
|
+
|
538
|
+
(0..dh).each do |i|
|
539
|
+
coeff = 0
|
540
|
+
|
541
|
+
jmin = [0, i - d].max
|
542
|
+
jmax = [i, d].min
|
543
|
+
|
544
|
+
n = jmax - jmin + 1
|
545
|
+
jmax = jmin + n/2 - 1
|
546
|
+
|
547
|
+
(jmin..jmax).each do |j|
|
548
|
+
coeff += self[j]*self[i - j]
|
549
|
+
end
|
550
|
+
|
551
|
+
coeff += coeff
|
552
|
+
|
553
|
+
if n.odd?
|
554
|
+
elem = self[jmax + 1]
|
555
|
+
coeff += elem**2
|
556
|
+
end
|
557
|
+
|
558
|
+
h << coeff % @p
|
559
|
+
end
|
560
|
+
|
561
|
+
return new_gl(h).strip!
|
562
|
+
end
|
563
|
+
|
564
|
+
def quo(g)
|
565
|
+
return div(g)[0]
|
566
|
+
end
|
567
|
+
|
568
|
+
def rem(f)
|
569
|
+
return div(f)[1]
|
570
|
+
end
|
571
|
+
|
572
|
+
def div(g)
|
573
|
+
assert_order(g)
|
574
|
+
|
575
|
+
df = degree
|
576
|
+
dg = g.degree
|
577
|
+
|
578
|
+
if g.zero?
|
579
|
+
raise 'Division by zero'
|
580
|
+
elsif df < dg
|
581
|
+
return [zero, self.clone]
|
582
|
+
end
|
583
|
+
|
584
|
+
inv = invert(g[0])
|
585
|
+
|
586
|
+
h = @arr.clone
|
587
|
+
dq = df - dg
|
588
|
+
dr = dg - 1
|
589
|
+
|
590
|
+
(0..df).each do |i|
|
591
|
+
coeff = h[i]
|
592
|
+
|
593
|
+
a = [0, dg - i].max
|
594
|
+
b = [df - i, dr].min
|
595
|
+
(a..b).each do |j|
|
596
|
+
coeff -= h[i + j - dg]*g[dg - j]
|
597
|
+
end
|
598
|
+
|
599
|
+
if i <= dq
|
600
|
+
coeff *= inv
|
601
|
+
end
|
602
|
+
|
603
|
+
h[i] = coeff % @p
|
604
|
+
end
|
605
|
+
|
606
|
+
return [new_gl(h[0..dq]), new_gl(h[dq + 1..-1]).strip!]
|
607
|
+
end
|
608
|
+
|
609
|
+
def lshift(n)
|
610
|
+
if zero?
|
611
|
+
return zero
|
612
|
+
else
|
613
|
+
return new_gl(@arr + [0]*n)
|
614
|
+
end
|
615
|
+
end
|
616
|
+
|
617
|
+
def to_s()
|
618
|
+
return @arr.to_s + '/' + @p.to_s
|
619
|
+
end
|
620
|
+
end
|
621
|
+
end
|