carl  24.04
Computer ARithmetic Library
Monomial.cpp
Go to the documentation of this file.
1 
2 /**
3  * @file MonomialPool.cpp
4  * @author Florian Corzilius <corzilius@cs.rwth-aachen.de>
5  */
6 
7 #include "Monomial.h"
8 #include "MonomialPool.h"
10 
11 namespace carl
12 {
14  CARL_LOG_TRACE("carl.core.monomial", "Freeing " << *this);
16  }
18  {
19  ///@todo this should work on the shared_ptr directly. Then we could directly return this shared_ptr instead of the ugly copying.
20  CARL_LOG_FUNC("carl.core.monomial", mExponents << ", " << v);
21  auto it = std::find(mExponents.cbegin(), mExponents.cend(), v);
22 
23  if (it == mExponents.cend())
24  {
25  std::vector<std::pair<Variable, exponent>> exps(this->mExponents);
26  return MonomialPool::getInstance().create(std::move(exps), mTotalDegree);
27  }
28  if (mExponents.size() == 1) return nullptr;
29 
30  std::size_t tDeg = mTotalDegree - it->second;
31  Content newExps(mExponents.begin(), it);
32  it++;
33  newExps.insert(newExps.end(), it, mExponents.end());
34  return MonomialPool::getInstance().create( std::move(newExps), tDeg );
35  }
36 
38  {
39  auto it = std::find(mExponents.cbegin(), mExponents.cend(), v);
40  if(it == mExponents.cend()) return false;
41  else {
42  Content newExps;
43  // If the exponent is one, the variable does not occur in the new monomial.
44  if(it->second == 1) {
45  if(it != mExponents.begin()) {
46  newExps.assign(mExponents.begin(), it);
47  }
48  newExps.insert(newExps.end(), it+1,mExponents.end());
49  } else {
50  // We have to decrease the exponent of the variable by one.
51  newExps.assign(mExponents.begin(), mExponents.end());
52  newExps[uint(it - mExponents.begin())].second -= 1;
53  }
54  if (newExps.empty())
55  {
56  res = nullptr;
57  }
58  else
59  {
60  res = createMonomial(std::move(newExps), exponent(mTotalDegree - 1));
61  }
62 
63  CARL_LOG_TRACE("carl.core.monomial", *this << " / " << v << " = " << res);
64  return true;
65  }
66  }
67 
68  bool Monomial::divide(const Monomial::Arg& m, Monomial::Arg& res) const
69  {
70  if (!m) {
72  CARL_LOG_TRACE("carl.core.monomial", *this << " / " << m << " = " << res);
73  return true;
74  }
75  if(m->mTotalDegree > mTotalDegree || m->mExponents.size() > mExponents.size())
76  {
77  // Division will fail.
78  CARL_LOG_TRACE("carl.core.monomial", *this << " / " << m << " fails");
79  return false;
80  }
81  Content newExps;
82 
83  // Linear, as we expect small monomials.
84  auto itright = m->mExponents.begin();
85  for(auto itleft = mExponents.begin(); itleft != mExponents.end(); ++itleft)
86  {
87  // Done with division
88  if(itright == m->mExponents.end())
89  {
90  // Insert remaining part
91  newExps.insert(newExps.end(), itleft, mExponents.end());
92  res = MonomialPool::getInstance().create( std::move(newExps), uint(mTotalDegree - m->mTotalDegree) );
93  CARL_LOG_TRACE("carl.core.monomial", *this << " / " << m << " = " << res);
94  return true;
95  }
96  // Variable is present in both monomials.
97  if(itleft->first == itright->first)
98  {
99  if (itleft->second < itright->second)
100  {
101  // Underflow, itright->exp was larger than itleft->exp.
102  CARL_LOG_TRACE("carl.core.monomial", *this << " / " << m << " fails");
103  return false;
104  }
105  std::size_t newExp = itleft->second - itright->second;
106  if(newExp > 0)
107  {
108  newExps.emplace_back(itleft->first, newExp);
109  }
110  itright++;
111  }
112  // Variable is not present in lhs, division fails.
113  else if(itleft->first > itright->first)
114  {
115  CARL_LOG_TRACE("carl.core.monomial", *this << " / " << m << " fails");
116  return false;
117  }
118  else
119  {
120  assert(itleft->first < itright->first);
121  newExps.emplace_back(*itleft);
122  }
123  }
124  // If there remain variables in the m, it fails.
125  if(itright != m->mExponents.end())
126  {
127  CARL_LOG_TRACE("carl.core.monomial", *this << " / " << m << " fails");
128  return false;
129  }
130  if (newExps.empty())
131  {
132  CARL_LOG_TRACE("carl.core.monomial", *this << " / " << m << " fails");
133  res = nullptr;
134  return true;
135  }
136  res = MonomialPool::getInstance().create( std::move(newExps), std::size_t(mTotalDegree - m->mTotalDegree) );
137  CARL_LOG_TRACE("carl.core.monomial", *this << " / " << m << " = " << res);
138  return true;
139  }
140 
142  if (mTotalDegree % 2 == 1) return nullptr;
143  Content newExps;
144  for (const auto& it: mExponents) {
145  if (it.second % 2 == 1) return nullptr;
146  newExps.emplace_back(it.first, it.second / 2);
147  }
148  return createMonomial(std::move(newExps), mTotalDegree / 2);
149  }
150 
151  Monomial::Arg Monomial::lcm(const std::shared_ptr<const Monomial>& lhs, const std::shared_ptr<const Monomial>& rhs)
152  {
153  if (!lhs && !rhs) return nullptr;
154  if (!lhs) return rhs;
155  if (!rhs) return lhs;
156  CARL_LOG_FUNC("carl.core.monomial", lhs << ", " << rhs);
157  assert(lhs->is_consistent());
158  assert(rhs->is_consistent());
159 
160  Content newExps;
161  std::size_t expsum = lhs->tdeg() + rhs->tdeg();
162  // Linear, as we expect small monomials.
163  auto itright = rhs->mExponents.cbegin();
164  auto leftEnd = lhs->mExponents.cend();
165  auto rightEnd = rhs->mExponents.cend();
166  for(auto itleft = lhs->mExponents.cbegin(); itleft != leftEnd;)
167  {
168  // Done on right
169  if(itright == rightEnd)
170  {
171  // Insert remaining part
172  newExps.insert(newExps.end(), itleft, lhs->mExponents.end());
173  std::shared_ptr<const Monomial> result = MonomialPool::getInstance().create( std::move(newExps), expsum );
174  CARL_LOG_TRACE("carl.core.monomial", "Result: " << result);
175  return result;
176  }
177  // Variable is present in both monomials.
178  if(itleft->first == itright->first)
179  {
180  std::size_t newExp = std::max(itleft->second, itright->second);
181  newExps.emplace_back(itleft->first, newExp);
182  expsum -= std::min(itleft->second, itright->second);
183  ++itright;
184  ++itleft;
185  }
186  // Variable is not present in lhs, dividing lcm yields variable will not occur in result
187 
188  else if(itleft->first > itright->first)
189  {
190  newExps.push_back(*itright);
191  ++itright;
192  }
193  else
194  {
195  assert(itleft->first < itright->first);
196  newExps.push_back(*itleft);
197  ++itleft;
198  }
199  }
200  // Insert remaining part
201  newExps.insert(newExps.end(), itright, rhs->mExponents.end());
202  std::shared_ptr<const Monomial> result = MonomialPool::getInstance().create( std::move(newExps), expsum );
203  CARL_LOG_TRACE("carl.core.monomial", "Result: " << result);
204  return result;
205  }
206 
208  {
209  CARL_LOG_FUNC("carl.core.monomial", mExponents << ", " << mTotalDegree << ", " << mHash);
210  if (mTotalDegree < 1) return false;
211  std::size_t tdegree = 0;
212  for(const auto& ve : mExponents)
213  {
214  if (ve.second <= 0) {
215  CARL_LOG_TRACE("carl.core.monomial", "Degree is zero.");
216  return false;
217  }
218  tdegree += ve.second;
219  }
220  if (tdegree != mTotalDegree) {
221  CARL_LOG_TRACE("carl.core.monomial", "Wrong total degree.");
222  return false;
223  }
224  if (!std::is_sorted(mExponents.begin(), mExponents.end(), [](const std::pair<Variable, exponent>& p1, const std::pair<Variable, exponent>& p2){ return p1.first < p2.first; })) {
225  CARL_LOG_TRACE("carl.core.monomial", "Is not sorted.");
226  return false;
227  }
228  return true;
229  }
230 
232  {
233  assert( (&lhs != &rhs) || (lhs.id() == rhs.id()) );
234  assert((lhs.id() != 0) && (rhs.id() != 0));
235  if (lhs.id() == rhs.id()) return CompareResult::EQUAL;
236  auto lhsit = lhs.mExponents.begin();
237  auto rhsit = rhs.mExponents.begin();
238  auto lhsend = lhs.mExponents.end();
239  auto rhsend = rhs.mExponents.end();
240  while (lhsit != lhsend) {
241  if (rhsit == rhsend)
242  return CompareResult::GREATER;
243  //which variable occurs first
244  if (lhsit->first == rhsit->first) {
245  //equal variables
246  if (lhsit->second > rhsit->second)
247  return CompareResult::LESS;
248  if (lhsit->second < rhsit->second)
249  return CompareResult::GREATER;
250  } else {
251  return (lhsit->first < rhsit->first) ? CompareResult::LESS : CompareResult::GREATER;
252  }
253  ++lhsit;
254  ++rhsit;
255  }
256  assert(rhsit != rhsend);
257  return CompareResult::LESS;
258  }
259 
261  {
262  if(!lhs)
263  return rhs;
264  if(!rhs)
265  return lhs;
266  assert( rhs->tdeg() > 0 );
267  assert( lhs->tdeg() > 0 );
268  assert(lhs->is_consistent());
269  assert(rhs->is_consistent());
270  Monomial::Content newExps;
271  newExps.reserve(lhs->exponents().size() + rhs->exponents().size());
272 
273  // Linear, as we expect small monomials.
274  auto itleft = lhs->begin();
275  auto itright = rhs->begin();
276  while( itleft != lhs->end() && itright != rhs->end() )
277  {
278  // Variable is present in both monomials.
279  if(itleft->first == itright->first)
280  {
281  newExps.emplace_back( itleft->first, itleft->second + itright->second);
282  ++itleft;
283  ++itright;
284  }
285  // Variable is not present in lhs, we have to insert var-exp pair from rhs.
286  else if(itleft->first > itright->first)
287  {
288  newExps.emplace_back( itright->first, itright->second );
289  ++itright;
290  }
291  // Variable is not present in rhs, we have to insert var-exp pair from lhs.
292  else
293  {
294  newExps.emplace_back( itleft->first, itleft->second );
295  ++itleft;
296  }
297  }
298  // Insert remaining.
299  if( itleft != lhs->end() )
300  newExps.insert(newExps.end(), itleft, lhs->end());
301  else if( itright != rhs->end() )
302  newExps.insert(newExps.end(), itright, rhs->end());
303  Monomial::Arg result = createMonomial(std::move(newExps), lhs->tdeg() + rhs->tdeg());
304  CARL_LOG_TRACE("carl.core.monomial", lhs << " * " << rhs << " = " << result);
305  if (result) assert(lhs->tdeg() + rhs->tdeg() == result->tdeg());
306  return result;
307  }
308 
310  {
311  if (!lhs) {
312  return createMonomial(rhs, 1);
313  }
314  Monomial::Content newExps;
315  // Linear, as we expect small monomials.
316  bool inserted = false;
317  for (const auto& p: *lhs) {
318  if (inserted) newExps.push_back(p);
319  else if (p.first < rhs) newExps.push_back(p);
320  else if (p.first == rhs) {
321  newExps.emplace_back(rhs, p.second + 1);
322  inserted = true;
323  } else if (p.first > rhs) {
324  newExps.emplace_back(rhs, 1);
325  newExps.push_back(p);
326  inserted = true;
327  }
328  }
329  if (!inserted) newExps.emplace_back(rhs, 1);
330 
331  Monomial::Arg result = createMonomial(std::move(newExps), lhs->tdeg() + 1);
332  CARL_LOG_TRACE("carl.core.monomial", lhs << " * " << rhs << " = " << result);
333  assert(result);
334  assert(lhs->tdeg() + 1 == result->tdeg());
335  return result;
336  }
337 
339  return rhs * lhs;
340  }
341 
343  {
344  if (lhs == rhs) {
345  // Return lhs^2
346  return createMonomial(Monomial::Content({{lhs, 2}}), exponent(2));
347  }
348  if (lhs > rhs) std::swap(lhs, rhs);
349  // Return lhs * rhs
350  return createMonomial(Monomial::Content({{lhs, 1}, {rhs, 1}}), exponent(2));
351  }
352 
353  Monomial::Arg pow(Variable v, std::size_t exp) {
354  return createMonomial(v, exp);
355  }
356 }
A small wrapper that configures logging for carl.
#define CARL_LOG_FUNC(channel, args)
Definition: carl-logging.h:46
#define CARL_LOG_TRACE(channel, msg)
Definition: carl-logging.h:44
carl is the main namespace for the library.
Monomial::Arg createMonomial(T &&... t)
Definition: MonomialPool.h:168
std::uint64_t uint
Definition: numbers.h:16
void swap(Variable &lhs, Variable &rhs)
Definition: Variables.h:202
std::size_t exponent
Type of an exponent.
Definition: Monomial.h:29
Interval< Number > exp(const Interval< Number > &i)
Definition: Exponential.h:10
Interval< Number > operator*(const Interval< Number > &lhs, const Interval< Number > &rhs)
Operator for the multiplication of two intervals.
Definition: operators.h:386
CompareResult
Definition: CompareResult.h:12
@ GREATER
Definition: SignCondition.h:15
Interval< Number > pow(const Interval< Number > &i, Integer exp)
Definition: Power.h:11
A Variable represents an algebraic variable that can be used throughout carl.
Definition: Variable.h:85
The general-purpose monomials.
Definition: Monomial.h:59
std::size_t mTotalDegree
Some applications performance depends on getting the degree of monomials very fast.
Definition: Monomial.h:76
std::shared_ptr< const Monomial > Arg
Definition: Monomial.h:62
static Monomial::Arg lcm(const Monomial::Arg &lhs, const Monomial::Arg &rhs)
Calculates the least common multiple of two monomial pointers.
Definition: Monomial.cpp:151
bool is_consistent() const
Checks if the monomial is consistent.
Definition: Monomial.cpp:207
Content mExponents
A vector of variable exponent pairs (v_i^e_i) with nonzero exponents.
Definition: Monomial.h:74
std::vector< std::pair< Variable, std::size_t > > Content
Definition: Monomial.h:63
std::size_t id() const
Return the id of this monomial.
Definition: Monomial.h:177
static CompareResult lexicalCompare(const Monomial &lhs, const Monomial &rhs)
This method performs a lexical comparison as defined in , page 47.
Definition: Monomial.cpp:231
std::size_t mHash
Cached hash.
Definition: Monomial.h:80
bool divide(Variable v, Monomial::Arg &res) const
Divides the monomial by a variable v.
Definition: Monomial.cpp:37
Monomial::Arg sqrt() const
Calculates and returns the square root of this monomial, iff the monomial is a square as checked by i...
Definition: Monomial.cpp:141
Monomial::Arg drop_variable(Variable v) const
For a monomial m = Prod( x_i^{e_i} ) * v^e, divides m by v^e.
Definition: Monomial.cpp:17
Monomial::Arg create(Variable _var, exponent _exp)
Creates a monomial from a variable and an exponent.
void free(const Monomial *m)
Definition: MonomialPool.h:136
static MonomialPool & getInstance()
Returns the single instance of this class by reference.
Definition: Singleton.h:45