carl  24.04
Computer ARithmetic Library
Buchberger.tpp
Go to the documentation of this file.
1 
2 
3 /**
4  * @file Buchberger.tpp
5  * @ingroup gb
6  * @author Sebastian Junges
7  */
8 #pragma once
9 #include "Buchberger.h"
10 
11 #include <carl-arith/poly/umvpoly/functions/SPolynomial.h>
12 //
13 //
14 namespace carl
15 {
16 
17 /**
18  * Calculate the Groebner basis
19  */
20 template<class Polynomial, template<typename> class AddingPolicy>
21 void Buchberger<Polynomial, AddingPolicy>::calculate(const std::list<Polynomial>& scheduledForAdding)
22 {
23  CARL_LOG_INFO("carl.gb.buchberger", "Calculate gb");
24  for(unsigned i = 0; i < pGb->getGenerators().size(); ++i)
25  {
26  mGbElementsIndices.push_back(i);
27  }
28 
29  bool foundGB = false;
30  for(const Polynomial& newPol : scheduledForAdding)
31  {
32  if(addToGb(newPol))
33  {
34  CARL_LOG_INFO("carl.gb.buchberger", "Added a constant polynomial.");
35  foundGB = true;
36  break;
37  }
38  }
39 
40 
41  //As long as unprocessed pairs exist..
42  if(!foundGB)
43  {
44  while(!pCritPairs->empty())
45  {
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))
64  {
65  // If it is constant, we are done and can return {1} as GB.
66  if(remainder.is_constant())
67  {
68  pGb->clear();
69  pGb->addGenerator(remainder.normalize());
70  break;
71  }
72  else
73  {
74 
75  // divide the polynomial through the leading coefficient.
76 
77  if(addToGb(remainder.normalize())) break;
78  }
79  }
80  }
81  }
82  mGbElementsIndices.clear();
83 }
84 
85 
86 //
87 /**
88  * Updating the critical pairs based on the added generator.
89  * @param index
90  */
91 template<class Polynomial, template<typename> class AddingPolicy>
92 void Buchberger<Polynomial, AddingPolicy>::update(const size_t index)
93 {
94 
95  std::vector<Polynomial>& generators = pGb->getGenerators();
96  assert(generators.size() > index);
97  assert(!generators[index].is_constant());
98  auto jEnd = mGbElementsIndices.end();
99 
100  std::unordered_map<size_t, SPolPair> spairs;
101  std::vector<size_t> primelist;
102  for(auto jt = mGbElementsIndices.begin(); jt != jEnd; ++jt)
103  {
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)
110  {
111  // *generators[index].lmon( ), *generators[otherIndex].lmon( ) are prime.
112  primelist.push_back(otherIndex);
113  }
114  spairs.emplace(otherIndex, sp);
115  }
116 
117 
118  pCritPairs->elimMultiples(generators[index].lmon(), spairs);
119 // pCritPairs->elimMultiples(generators[index].lmon(), index, spairs);
120 
121  removeBuchbergerTriples(spairs, primelist);
122 
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)
125  {
126  spairs.erase(*pt);
127  }
128 
129  // We add the critical pairs to our tree of pairs
130  std::list<SPolPair> critPairsList;
131 
132  std::transform(spairs.begin(), spairs.end(), std::back_inserter(critPairsList), [](std::pair<size_t, SPolPair> val)
133  {
134  return val.second;
135  });
136  pCritPairs->push(critPairsList);
137 
138  std::vector<size_t> tempIndices;
139  jEnd = mGbElementsIndices.end();
140  for(auto jt = mGbElementsIndices.begin(); jt != jEnd; ++jt)
141  {
142  if(!generators[*jt].lmon()->divisible(generators[index].lmon()))
143  {
144  tempIndices.push_back(*jt);
145  }
146  else
147  {
148  pGb->eliminateGenerator(*jt);
149  }
150  }
151 
152  mGbElementsIndices.swap(tempIndices);
153  // We add the currently added polynomial to our GB.
154  mGbElementsIndices.push_back(index);
155 }
156 
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)
159 {
160  auto it = spairs.begin();
161 
162  if(!primelist.empty())
163  {
164  auto primes = primelist.begin();
165  while(it != spairs.end())
166  {
167  if(it->first == *primes)
168  {
169  ++primes;
170  //if there are no primes left, we can stop this check
171  if(primes == primelist.end())
172  {
173  break;
174  ++it;
175  }
176  }
177 
178  bool elim = false;
179  for(std::unordered_map<size_t, SPolPair>::const_iterator jt = spairs.begin(); jt != it; ++jt)
180  {
181  if(it->second.mLcm->divisible(jt->second.mLcm))
182  {
183  it = spairs.erase(it);
184  elim = true;
185  break;
186  }
187  }
188 
189  if(elim) continue;
190 
191  std::unordered_map<size_t, SPolPair>::const_iterator jt = it;
192  for(++jt; jt != spairs.end(); ++jt)
193  {
194  if(it->second.mLcm->divisible(jt->second.mLcm))
195  {
196  it = spairs.erase(it);
197  elim = true;
198  break;
199  }
200  }
201 
202  if(elim) continue;
203  ++it;
204  }
205  }
206  //TODO function
207  // same as above, but now without prime-skipping.
208  while(it != spairs.end())
209  {
210  bool elim = false; //critPair.print(std::cout);
211  for(std::unordered_map<size_t, SPolPair>::const_iterator jt = spairs.begin(); jt != it; ++jt)
212  {
213  if(it->second.mLcm->divisible(jt->second.mLcm))
214  {
215  it = spairs.erase(it);
216  elim = true;
217  break;
218  }
219  }
220  if(elim) continue;
221 
222  std::unordered_map<size_t, SPolPair>::const_iterator jt = it;
223  for(++jt; jt != spairs.end(); ++jt)
224  {
225  if(it->second.mLcm->divisible(jt->second.mLcm))
226  {
227  it = spairs.erase(it);
228  elim = true;
229  break;
230  }
231  }
232  if(elim)
233  {
234  continue;
235  }
236  else
237  {
238  ++it;
239  }
240  }
241 }
242 }