-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathCRT_polynomial_multiplication.sf
79 lines (54 loc) · 1.67 KB
/
CRT_polynomial_multiplication.sf
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
#!/usr/bin/ruby
# Polynomial multiplication, using the Chinese Remainder Theorem (CRT).
# Reference:
# Lecture 14, Week 8 (2hrs) - Towards polynomial factorization
# https://youtube.com/watch?v=KNyHz0eoAMA (from 1 hour and 7 minutes)
func CRT (*congruences) {
var c = 0
var m = congruences.lcm { _[1] }
for a,n in (congruences) {
var t = m/n
var u = (t * invmod(t, n))
c += ((a.lift*u) % m)
}
return (c % m)
}
func poly_height(x) {
x.coeffs.map { .tail.abs }.max
}
func CRT_poly_mul(a,b) {
var c_height = 2*(poly_height(a) * poly_height(b) * min(a.coeffs.len, b.coeffs.len))
var m = 1
var P = []
Math.seq(3, {.tail.next_prime}).each {|p|
m *= p
P << p
break if (m > c_height)
}
var c = lift(CRT(P.map{|p| [Mod(a,p) * Mod(b,p), p] }...))
var t = (m>>1)
return Poly(c.coeffs.map_2d {|x,y| [x, (y > t) ? (y-m) : y] })
}
func CRT_poly_mul_space_optimized(a,b) {
var c_height = 2*(poly_height(a) * poly_height(b) * min(a.coeffs.len, b.coeffs.len))
var m = 1
var c = [0, 1]
Math.seq(3, {.tail.next_prime}).each {|p|
m *= p
c = [CRT(c, [Mod(a,p)*Mod(b,p), p]), m]
break if (m > c_height)
}
c = c[0].lift
var t = (m>>1)
return Poly(c.coeffs.map_2d {|x,y| [x, (y > t) ? (y-m) : y] })
}
assert_eq(CRT([2, 3], [3, 5], [2, 7]), 23)
var x = Poly(1)
assert_eq(CRT_poly_mul(3*x - 4, 6*x + 5), (3*x - 4)*(6*x + 5))
var a = (17*x**3 + 7*x**2 - x + 65)
var b = (34*x**4 - 23*x**2 + 8*x - 12)
say (a*b)
say CRT_poly_mul(a,b)
say CRT_poly_mul_space_optimized(a,b)
__END__
578*x^7 + 238*x^6 - 425*x^5 + 2185*x^4 - 125*x^3 - 1587*x^2 + 532*x - 780