Polynomial Multiplication
in O(n log2n)
Meetup April 9, 2019
WHY
What Is It
O(n)
for i = 1 to n� if a > b� a += b
O(n2)
for i = 1 to n� for j = 1 to n� if a > b� a += b
O(n)
for i = 1 to n� if a < b� a += b��for i = 1 to n� if c < b� c += b
if c < d� c = sqrt(d)
O(n3)
for i = 1 to n� for j = 1 to n� for k = 1 to n� if c < b� c += b�
O(log2 n)
binarySearch(array, key, low, high): � middle = (low + high) / 2�� if array[middle] == key � return middle
elif key < array[middle]� return binarySearch(array, key, low, middle - 1)
else� return binarySearch(array, key, middle + 1, high)
Binary Search
Find 3 in 1 2 3 4 5 6 7 8 9 10
1 2 3 4 5 6 7 8 9 10
1 2 3 4
3 4
�How many times can you halve n (down to 1)? log2n
Example Graphs
Timings
N = 100 takes 1 second
How long does it take for N = 10000 (100 times more)?
O(log2n) 2s
O(n) 100s
O(n2) 10,000s (2h:46)
O(n log2n) 200s
Properties
Divide
and
Conquer
Principle
Binary Search
binarySearch(array, key, low, high): � middle = (low + high) / 2�� if array[middle] == key � return middle
elif key < array[middle]� return binarySearch(array, key, low, middle - 1)
else� return binarySearch(array, key, middle + 1, high)
Merge Sort
mergeSort(array)� first = mergeSort(array[0..n/2])� second = mergeSort(array[n/2..n])
result = []
while first.notEmpty or second.notEmpty� if first[0] < second[0]: smallest = first.removeAt(0)� else: smallest = second.removeAt(0)�� result.add(smallest)
return result
Merge Sort
O(n log2n)
Why:
�Also in general:
T(n) = 2T(n/2) + O(n) gives O(n log2n)
John Von Neumann
D&C - Because
Polynomials
Polynomials
2x2 + 5x - 1
x3 - x + 2
anxn + an-1xn-1 + … + a0x0
n is the degree
Polynomial Representation
P as coefficients:
[a0, a1, a2, ..., an]
Multiplication
(2x2 + 5x - 1)(x3 - x + 2) =
2x5 - 2x3 + 4x2 +
5x4 - 5x2 + 10x -
x3 + x - 2
= 2x5 + 5x4 - x3 - x2 + 11x - 2
Multiplication Algorithm
r = [0, 0, ...]
for i = 0 to len(a)� for j = 0 to len(b)� r[i + j] += a[i] * b[j]
O(n2)
Alternative Representation
P as values at different points:
[x1, x2, ..., xn+1]
[P(x1), P(x2), ..., P(xn+1)]
Example
P(x) = x2 + 1�x in [0, 1, 2]
P(0) = 1�P(1) = 2�P(2) = 5
Multiplication
A(x) = x + 2 A(-1) = 1 A(0) = 2 A(1) = 3
B(x) = x - 1 B(-1) = -2 B(0) = -1 B(1) = 0
C(x) = x2 + x - 2 C(-1) = -2 C(0) = -2 C(1) = 0
O(n)
Conversion Between Representation
Idea
Idea
Need an Evaluate/Interpolate method faster than O(n2).
Implement Evaluate
We'll try to solve this using D&C.
Evaluate(a, x)
a = [a0, a1, ..., an]�x = [x0, x1, ...]
How to split the problem?
Odd & Even Terms
A [a0, a1, a2, a3, ...] a0 + a1x + a2x2 + a3x3 + ...
Aeven [a0, a2, a4, ...] a0 + a2y + a4y2 + ... �Aodd [a1, a3, a5, ...] a1 + a3y + a5y2 + ...
Odd & Even Terms
A [a0, a1, a2, a3, ...] a0 + a1x + a2x2 + a3x3 + ...
Aeven [a0, a2, a4, ...] a0 + a2y + a4y2 + ... �Aodd [a1, a3, a5, ...] a1 + a3y + a5y2 + ...
�A(x) = Aeven(x2) + x * Aodd(x2)
�because
a0 + a2x2 + a4x4 + ... + xa1+ xa3x2 + xa5x4 + ...
Algorithm Attempt 1
Evaluate(a, x)� aeven = [a0, a2, a4, ...]� aodd = [a1, a3, a5, ...]� x2 = [x02, x12, x22, ...]
veven = Evaluate(aeven, x2)� vodd = Evaluate(aodd, x2)
for i = 0 to len(x)� v[i] = veven[i] + x[i] * vodd[i]
return v
Algorithm Attempt 1
Evaluate(a, x)� aeven = [a0, a2, a4, ...]� aodd = [a1, a3, a5, ...]� x2 = [x02, x12, x22, ...]
veven = Evaluate(aeven, x2)� vodd = Evaluate(aodd, x2)
for i = 0 to len(x)� v[i] = veven[i] + x[i] * vodd[i]
return v
O(n2)
Positive And Negative Points
x0, x1, x2, ..., xj, xj+1, xj+2, ...
Pick them such as:
x0 = -xj�x1 = -xj+1�x2 = -xj+2�...
Positive And Negative Points
x = 1, 2, 3, 4, ..., -1, -2, -3, -4
x2 = 1, 4, 9, 16, ..., 1, 4, 9, 16
Positive And Negative Points
x = 1, 2, 3, 4, ..., -1, -2, -3, -4
x2 = 1, 4, 9, 16, ..., 1, 4, 9, 16
also:�
A(x) = Aeven(x2) + x * Aodd(x2)
�A(-x) = Aeven(x2) - x * Aodd(x2)
Algorithm Attempt 2
Evaluate(a, x)� xhalf2 = [x02, x12, x22, ..., xj-12], j = len(x) / 2
veven = Evaluate(aeven, xhalf2)� vodd = Evaluate(aodd, xhalf2)
for i = 0 to j� v[i] = veven[i] + x[i] * vodd[i]� v[i + j] = veven[i] - x[i] * vodd[i]
return v
Algorithm Attempt 2
Evaluate(a, x)� xhalf2 = [x02, x12, x22, ..., xj-12]
veven = Evaluate(aeven, xhalf2)� vodd = Evaluate(aodd, xhalf2)
for i = 0 to j� v[i] = veven[i] + x[i] * vodd[i]� v[i + j] = veven[i] - x[i] * vodd[i]
return v
O(nlog2n)
Ideal Points
Two properties:
Is this even possible?
Complex Numbers
Basics
0
-2 -1 1 2
2i
i
-i
-2i
Basics
a
b
z
z = a + bi
Ex:
2 + 3i
0
Polar Coordinates
θ
r
z
z = r cos θ + i r sin θ
Euler
z = r eiθ
0
Polar Coordinates
θ=π
r=1
z = r cos θ + i r sin θ
Euler�
z = r eiθ
Famous formula
eiπ = -1
0
-1
Power
θ=π/4
r=1
Multiplication
z1 = r1eiθ1
z2 = r2 eiθ2
z1 * z2 = (r1r2)ei(θ1+θ2)
Raise to power
zn = rneiθn
Ex:
(eiπ/4)2 = eiπ/2 = i
0
Unit Circle
0
1
Unit circle
All points with r = 1
Roots OF unity
0
1
zn = 1
z8 = 1 has 8 solutions
ω80, ω81, ω82, ω83,...
ω81 can simply be written ω8 since the others are just its powers
Property - half are opposites
Roots OF unity
0
1
Property - the squares of ω8 values are the ω4 values
Roots OF unity
0
1
Property - the squares of ω8 values are the ω4 values
(ωn)2 = ωn/2
Property - half of these are still opposites
Bingo!
Wrapping Up
Evaluate
wd is the first d root of unity; d is the smallest power of 2 larger than the degree of a
Evaluate(a, wd)� if len(a) = 1 return a� veven = Evaluate(aeven, wd2)� vodd = Evaluate(aodd, wd2)
for i = 0 to j� v[i] = veven[i] + wdi * vodd[i]� v[i + j] = veven[i] - wdi * vodd[i]
return v
Interpolate
V = Evaluate(a, wd)
we can get a back simply doing
a = 1/d Evaluate(V, wdd-1)
Polynomial Multiplication
Multiply(a, b)
Va = Evaluate(a, wd)� Vb = Evaluate(b, wd)� � for i = 0 to len(Va)� Vc = Va[i] * Vb[i]� � c = 1/d * Evaluate(Vc, wdd-1)� return c
O(nlog2n)
Notes