-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathbuchberger.cpp
93 lines (84 loc) · 2.68 KB
/
buchberger.cpp
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
80
81
82
83
84
85
86
87
88
89
90
91
92
93
#include "buchberger.h"
#include <algorithm>
bool decreasing_leading_term::operator()(const polynomial& p, const polynomial& q) const
{
if (p.degree() > q.degree())
return true;
else if (p.degree() < q.degree())
return false;
else {
for (int d = p.degree(); d >= 0; --d) {
if (p.coefficient(d) > q.coefficient(d))
return true;
else if (p.coefficient(d) < q.coefficient(d))
return false;
}
return false;
}
}
void reduce_mod(polynomial& p, const polynomial& q)
{
int q_deg = q.degree();
if (q_deg < 0)
return;
Z q_leading_coeff = q.coefficient(q_deg);
int initial_p_deg = p.degree();
for (int i = initial_p_deg - q_deg; i >= 0; --i) {
Z p_coeff = p.coefficient(i + q_deg);
Z quotient = p_coeff / q_leading_coeff;
if (p_coeff - quotient * q_leading_coeff < 0)
--quotient;
p -= quotient * times_x_to(q, i);
}
}
bool buchberger_search(ideal_basis& b)
{
// First try modding out any entry by following entries
for (auto i = b.begin(); i != b.end(); ++i) {
auto p = *i;
for (auto j = std::next(i); j != b.end(); ++j) {
reduce_mod(p, *j);
}
if (p != *i) {
if (p.leading_coefficient() < 0)
p.negate();
b.erase(i);
if (p != polynomial {})
b.insert(std::move(p));
return true;
}
}
// Then try raising a lower entry to match the degree of a higher entry,
// modding out, and see if we get something new; this is the generalization
// of forming the twist of pairs in the usual Buchberger algorithm.
for (auto i = b.begin(); i != b.end(); ++i) {
for (auto j = std::next(i); j != b.end(); ++j) {
polynomial p = times_x_to(*j, i->degree() - j->degree());
for (auto k = i; k != b.end(); ++k)
reduce_mod(p, *k);
if (p != polynomial {}) {
if (p.leading_coefficient() < 0)
p.negate();
b.insert(std::move(p));
return true;
}
}
}
return false;
}
void buchberger(ideal_basis& b)
{
// Remove 0 generator if present, for sanity of following code
b.erase(polynomial {});
// Make leading terms of all generators positive
while (true) {
auto i = std::find_if(b.begin(), b.end(), [](const polynomial& p) { return p.leading_coefficient() < 0; });
if (i == b.end())
break;
polynomial minus_p = -(*i);
b.erase(i);
b.insert(std::move(minus_p));
}
while (buchberger_search(b))
;
}