6 * @author Sebastian Junges
9 #include "Buchberger.h"
11 #include <carl-arith/poly/umvpoly/functions/SPolynomial.h>
18 * Calculate the Groebner basis
20 template<class Polynomial, template<typename> class AddingPolicy>
21 void Buchberger<Polynomial, AddingPolicy>::calculate(const std::list<Polynomial>& scheduledForAdding)
23 CARL_LOG_INFO("carl.gb.buchberger", "Calculate gb");
24 for(unsigned i = 0; i < pGb->getGenerators().size(); ++i)
26 mGbElementsIndices.push_back(i);
30 for(const Polynomial& newPol : scheduledForAdding)
34 CARL_LOG_INFO("carl.gb.buchberger", "Added a constant polynomial.");
41 //As long as unprocessed pairs exist..
44 while(!pCritPairs->empty())
46 // Takes the next pair scheduled
47 SPolPair critPair = pCritPairs->pop();
48 assert( critPair.mP1 < pGb->getGenerators().size() );
49 assert( critPair.mP2 < pGb->getGenerators().size() );
50 CARL_LOG_DEBUG("carl.gb.buchberger", "Calculate SPol for: " << pGb->getGenerators()[critPair.mP1] << ", " << pGb->getGenerators()[critPair.mP2]);
51 // Calculates the S-Polynomial
52 assert( pGb->getGenerators()[critPair.mP1].nr_terms() != 0 );
53 assert( pGb->getGenerators()[critPair.mP2].nr_terms() != 0 );
54 Polynomial spol = carl::SPolynomial(pGb->getGenerators()[critPair.mP1], pGb->getGenerators()[critPair.mP2]);
55 spol.setReasons(pGb->getGenerators()[critPair.mP1].getReasons() | pGb->getGenerators()[critPair.mP2].getReasons());
56 CARL_LOG_DEBUG("carl.gb.buchberger", "SPol: " << spol);
57 // Schedules the S-polynomial for reduction
58 Reductor<Polynomial, Polynomial> reductor(*pGb, spol);
59 // Does a full reduction on this
60 Polynomial remainder = reductor.fullReduce();
61 CARL_LOG_DEBUG("carl.gb.buchberger", "Remainder of SPol: " << remainder);
62 // If it is not zero, we should add this one to our GB
63 if(!is_zero(remainder))
65 // If it is constant, we are done and can return {1} as GB.
66 if(remainder.is_constant())
69 pGb->addGenerator(remainder.normalize());
75 // divide the polynomial through the leading coefficient.
77 if(addToGb(remainder.normalize())) break;
82 mGbElementsIndices.clear();
88 * Updating the critical pairs based on the added generator.
91 template<class Polynomial, template<typename> class AddingPolicy>
92 void Buchberger<Polynomial, AddingPolicy>::update(const size_t index)
95 std::vector<Polynomial>& generators = pGb->getGenerators();
96 assert(generators.size() > index);
97 assert(!generators[index].is_constant());
98 auto jEnd = mGbElementsIndices.end();
100 std::unordered_map<size_t, SPolPair> spairs;
101 std::vector<size_t> primelist;
102 for(auto jt = mGbElementsIndices.begin(); jt != jEnd; ++jt)
104 // TODO why do we update if otherIndex is something constant?!
105 size_t otherIndex = *jt;
106 assert(generators.size() > otherIndex);
107 uint oideg = generators[otherIndex].lmon() ? generators[otherIndex].lmon()->tdeg() : 0;
108 SPolPair sp(otherIndex, index, Monomial::lcm(generators[index].lmon(), generators[otherIndex].lmon()));
109 if(sp.mLcm->tdeg() == generators[index].lmon()->tdeg() + oideg)
111 // *generators[index].lmon( ), *generators[otherIndex].lmon( ) are prime.
112 primelist.push_back(otherIndex);
114 spairs.emplace(otherIndex, sp);
118 pCritPairs->elimMultiples(generators[index].lmon(), spairs);
119 // pCritPairs->elimMultiples(generators[index].lmon(), index, spairs);
121 removeBuchbergerTriples(spairs, primelist);
123 // Pairs which are primes don't have to be added according to Buchbergers first criterion
124 for(std::vector<size_t>::const_iterator pt = primelist.begin(); pt != primelist.end(); ++pt)
129 // We add the critical pairs to our tree of pairs
130 std::list<SPolPair> critPairsList;
132 std::transform(spairs.begin(), spairs.end(), std::back_inserter(critPairsList), [](std::pair<size_t, SPolPair> val)
136 pCritPairs->push(critPairsList);
138 std::vector<size_t> tempIndices;
139 jEnd = mGbElementsIndices.end();
140 for(auto jt = mGbElementsIndices.begin(); jt != jEnd; ++jt)
142 if(!generators[*jt].lmon()->divisible(generators[index].lmon()))
144 tempIndices.push_back(*jt);
148 pGb->eliminateGenerator(*jt);
152 mGbElementsIndices.swap(tempIndices);
153 // We add the currently added polynomial to our GB.
154 mGbElementsIndices.push_back(index);
157 template<class Polynomial, template<typename> class AddingPolicy>
158 void Buchberger<Polynomial, AddingPolicy>::removeBuchbergerTriples(std::unordered_map<size_t, SPolPair>& spairs, std::vector<size_t>& primelist)
160 auto it = spairs.begin();
162 if(!primelist.empty())
164 auto primes = primelist.begin();
165 while(it != spairs.end())
167 if(it->first == *primes)
170 //if there are no primes left, we can stop this check
171 if(primes == primelist.end())
179 for(std::unordered_map<size_t, SPolPair>::const_iterator jt = spairs.begin(); jt != it; ++jt)
181 if(it->second.mLcm->divisible(jt->second.mLcm))
183 it = spairs.erase(it);
191 std::unordered_map<size_t, SPolPair>::const_iterator jt = it;
192 for(++jt; jt != spairs.end(); ++jt)
194 if(it->second.mLcm->divisible(jt->second.mLcm))
196 it = spairs.erase(it);
207 // same as above, but now without prime-skipping.
208 while(it != spairs.end())
210 bool elim = false; //critPair.print(std::cout);
211 for(std::unordered_map<size_t, SPolPair>::const_iterator jt = spairs.begin(); jt != it; ++jt)
213 if(it->second.mLcm->divisible(jt->second.mLcm))
215 it = spairs.erase(it);
222 std::unordered_map<size_t, SPolPair>::const_iterator jt = it;
223 for(++jt; jt != spairs.end(); ++jt)
225 if(it->second.mLcm->divisible(jt->second.mLcm))
227 it = spairs.erase(it);