-
Notifications
You must be signed in to change notification settings - Fork 0
/
polynomial_division.py
79 lines (67 loc) · 2.31 KB
/
polynomial_division.py
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
import copy
import itertools
from classes.polynomial import Polynomial
from classes.polyterm import lcm
def euclidean_division(Dividende: Polynomial, Divisor: Polynomial) -> tuple[Polynomial, Polynomial]:
"""Returns Euclidean division's quotient and rest for univariate polynomials."""
assert Dividende.dim() == Divisor.dim() == 1
assert Divisor != Polynomial()
q = Polynomial()
r = Dividende.copy()
while r != Polynomial() and r.deg() >= Divisor.deg():
t = r.lead() / Divisor.lead() # Divide the leading terms
q += t
r -= Divisor * t
return (q, r)
def s_poly(poly1, poly2):
"""Calculate the S-polynomial for poly1 and poly2."""
mylcm = lcm(poly1.lead(), poly2.lead())
s = mylcm * (poly1 / poly1.lead() - poly2 / poly2.lead())
return s
def multidiv(poly: Polynomial, Polys: list[Polynomial]):
"""Mutlivariate multi division from this video https://youtu.be/xP9dM06JeoA."""
n = len(Polys)
Q = [Polynomial()] * n
r = Polynomial()
p = poly.copy()
i = 0
while p != 0:
if p.lead().divisible_by(Polys[i].lead()):
t = p.lead() / Polys[i].lead()
Q[i] += t
p -= t * Polys[i]
i = 0
i += 1
if i == n:
r += p.lead()
p -= p.lead()
i = 0
return r, Q
def buchberger(Polys: list[Polynomial]):
"""Buchberger's Algorithm from this video https://youtu.be/KzT2S9er93k"""
G = copy.deepcopy(Polys)
pairs = list(itertools.combinations(G, 2)) # replace list by set for unordered
while pairs:
p, q = pairs.pop()
s = s_poly(p, q)
r, _ = multidiv(s, G)
if r != 0:
for g in G:
pairs.append((g, r)) # append for list, add for set
G.append(r)
return G
def reduce_GB(G):
"""Reduces a Groebner basis so that the leading terms of the basis don't divide each other."""
temp = copy.deepcopy(G)
G_minimal = []
while temp:
p = temp.pop()
if not any([p.lead().divisible_by(q.lead()) for q in temp + G_minimal]):
G_minimal.append(p)
n = len(G_minimal)
G_reduced = []
for i in range(n):
r, _ = multidiv(G_minimal[i], G_minimal[:i] + G_minimal[i + 1 :])
if r != 0:
G_reduced.append(r)
return G_reduced