carl  24.04
Computer ARithmetic Library
RationalFunction.tpp
Go to the documentation of this file.
1 #pragma once
2 /**
3  * @file: RationalFunction.tpp
4  * @author: Sebastian Junges
5  * @author: Florian Corzilius
6  *
7  * @since March 16, 2014
8  */
9 
10 #include "RationalFunction.h"
11 
12 #include <carl-arith/poly/umvpoly/functions/LCM.h>
13 
14 namespace carl {
15 
16 template<typename Pol, bool AS>
17 RationalFunction<Pol, AS> RationalFunction<Pol, AS>::derivative(const Variable& x, unsigned nth) const {
18  assert(nth == 1);
19  if (is_constant()) {
20  return RationalFunction<Pol, AS>(0);
21  }
22 
23  // TODO use factorization whenever possible.
24  // TODO specialize if it is just a polynomial.
25  CARL_LOG_INEFFICIENT();
26  // (u/v)' = (u'v - uv')/(v^2)
27  const auto& u = nominatorAsPolynomial();
28  const auto& v = denominatorAsPolynomial();
29  return RationalFunction<Pol, AS>(u.derivative(x) * v - u * v.derivative(x), v.pow(2));
30 }
31 
32 template<typename Pol, bool AS>
33 void RationalFunction<Pol, AS>::eliminateCommonFactor(bool _justNormalize) {
34  if (mIsSimplified) return;
35  assert(!is_constant());
36  if (carl::is_zero(nominatorAsPolynomial())) {
37  mPolynomialQuotient.reset();
38  mNumberQuotient = std::move(CoeffType(0));
39  mIsSimplified = true;
40  return;
41  }
42  if (nominatorAsPolynomial() == denominatorAsPolynomial()) {
43  mPolynomialQuotient.reset();
44  mNumberQuotient = std::move(CoeffType(1));
45  mIsSimplified = true;
46  return;
47  }
48  CoeffType cpFactorNom(std::move(nominatorAsPolynomial().coprime_factor()));
49  CoeffType cpFactorDen(std::move(denominatorAsPolynomial().coprime_factor()));
50  mPolynomialQuotient->first *= cpFactorNom;
51  mPolynomialQuotient->second *= cpFactorDen;
52  CoeffType cpFactor(std::move(cpFactorDen / cpFactorNom));
53  if (!_justNormalize && !denominatorAsPolynomial().is_constant()) {
54  carl::gcd(nominatorAsPolynomial(), denominatorAsPolynomial());
55  auto ret = carl::lazyDiv(nominatorAsPolynomial(), denominatorAsPolynomial());
56  mPolynomialQuotient->first = std::move(ret.first);
57  mPolynomialQuotient->second = std::move(ret.second);
58  CoeffType cpFactorNom(nominatorAsPolynomial().coprime_factor());
59  CoeffType cpFactorDen(denominatorAsPolynomial().coprime_factor());
60  mPolynomialQuotient->first *= cpFactorNom;
61  mPolynomialQuotient->second *= cpFactorDen;
62  cpFactor *= cpFactorDen / cpFactorNom;
63  mIsSimplified = true;
64  }
65  mPolynomialQuotient->first *= carl::get_num(cpFactor);
66  mPolynomialQuotient->second *= carl::get_denom(cpFactor);
67  if (nominatorAsPolynomial().is_constant() && denominatorAsPolynomial().is_constant()) {
68  mNumberQuotient = std::move(constant_part());
69  mPolynomialQuotient.reset();
70  mIsSimplified = true;
71  }
72 }
73 
74 template<typename Pol, bool AS>
75 template<bool byInverse>
76 RationalFunction<Pol, AS>& RationalFunction<Pol, AS>::add(const RationalFunction<Pol, AS>& rhs) {
77  if (this->is_constant() && rhs.is_constant()) {
78  if (byInverse)
79  this->mNumberQuotient -= rhs.mNumberQuotient;
80  else
81  this->mNumberQuotient += rhs.mNumberQuotient;
82  return *this;
83  } else if (this->is_constant()) {
84  CoeffType c = this->mNumberQuotient;
85  if (byInverse)
86  *this = -rhs;
87  else
88  *this = rhs;
89  return *this += c;
90  } else if (rhs.is_constant()) {
91  if (byInverse)
92  return *this -= rhs.mNumberQuotient;
93  else
94  return *this += rhs.mNumberQuotient;
95  }
96  mIsSimplified = false;
97  if (denominatorAsPolynomial().is_constant() && rhs.denominatorAsPolynomial().is_constant()) {
98  mPolynomialQuotient->first *= rhs.denominatorAsPolynomial().constant_part();
99  if (byInverse)
100  mPolynomialQuotient->first -= rhs.nominatorAsPolynomial() * denominatorAsPolynomial().constant_part();
101  else
102  mPolynomialQuotient->first += rhs.nominatorAsPolynomial() * denominatorAsPolynomial().constant_part();
103  mPolynomialQuotient->second *= rhs.denominatorAsPolynomial().constant_part();
104  } else {
105  if (denominatorAsPolynomial().is_constant()) {
106  // TODO use more efficient elimination
107  mPolynomialQuotient->first *= rhs.denominatorAsPolynomial();
108  if (byInverse)
109  mPolynomialQuotient->first -= rhs.nominatorAsPolynomial() * denominatorAsPolynomial().constant_part();
110  else
111  mPolynomialQuotient->first += rhs.nominatorAsPolynomial() * denominatorAsPolynomial().constant_part();
112  // TODO use info that it is faster
113  mPolynomialQuotient->second *= rhs.denominatorAsPolynomial();
114  } else if (rhs.denominatorAsPolynomial().is_constant()) {
115  mPolynomialQuotient->first *= rhs.denominatorAsPolynomial().constant_part();
116  if (byInverse)
117  mPolynomialQuotient->first -= rhs.nominatorAsPolynomial() * denominatorAsPolynomial();
118  else
119  mPolynomialQuotient->first += rhs.nominatorAsPolynomial() * denominatorAsPolynomial();
120  mPolynomialQuotient->second *= rhs.denominatorAsPolynomial().constant_part();
121  } else {
122  Pol leastCommonMultiple(std::move(carl::lcm(this->denominatorAsPolynomial(), rhs.denominatorAsPolynomial())));
123  if (byInverse) {
124  mPolynomialQuotient->first = std::move(this->nominatorAsPolynomial() * quotient(leastCommonMultiple, this->denominatorAsPolynomial()) - rhs.nominatorAsPolynomial() * quotient(leastCommonMultiple, rhs.denominatorAsPolynomial()));
125  } else {
126  mPolynomialQuotient->first = std::move(this->nominatorAsPolynomial() * quotient(leastCommonMultiple, this->denominatorAsPolynomial()) + rhs.nominatorAsPolynomial() * quotient(leastCommonMultiple, rhs.denominatorAsPolynomial()));
127  }
128  mPolynomialQuotient->second = std::move(leastCommonMultiple);
129  }
130  }
131  eliminateCommonFactor(!AS);
132  return *this;
133 }
134 
135 template<typename Pol, bool AS>
136 template<bool byInverse>
137 RationalFunction<Pol, AS>& RationalFunction<Pol, AS>::add(const Pol& rhs) {
138  if (this->is_constant()) {
139  CoeffType c = this->mNumberQuotient;
140  Pol resultNum(std::move(byInverse ? (rhs * CoeffType(get_denom(c)) - CoeffType(get_num(c))) : (rhs * CoeffType(get_denom(c)) + CoeffType(get_num(c)))));
141  *this = std::move(RationalFunction<Pol, AS>(std::move(resultNum), std::move(Pol(CoeffType(get_denom(c))))));
142  return *this;
143  }
144  mIsSimplified = false;
145  if (byInverse)
146  mPolynomialQuotient->first -= std::move(rhs * denominatorAsPolynomial());
147  else
148  mPolynomialQuotient->first += std::move(rhs * denominatorAsPolynomial());
149  eliminateCommonFactor(!AS);
150  return *this;
151 }
152 
153 template<typename Pol, bool AS>
154 template<bool byInverse, typename P, DisableIf<needs_cache_type<P>>>
155 RationalFunction<Pol, AS>& RationalFunction<Pol, AS>::add(Variable rhs) {
156  if (this->is_constant()) {
157  CoeffType c(this->mNumberQuotient);
158  Pol resultNum(rhs);
159  resultNum *= CoeffType(get_denom(c));
160  if (byInverse)
161  resultNum -= CoeffType(get_num(c));
162  else
163  resultNum += CoeffType(get_num(c));
164  *this = std::move(RationalFunction<Pol, AS>(std::move(resultNum), std::move(Pol(CoeffType(get_denom(c))))));
165  return *this;
166  }
167  mIsSimplified = false;
168  if (byInverse)
169  mPolynomialQuotient->first -= std::move(rhs * denominatorAsPolynomial());
170  else
171  mPolynomialQuotient->first += std::move(rhs * denominatorAsPolynomial());
172  eliminateCommonFactor(!AS);
173  return *this;
174 }
175 
176 template<typename Pol, bool AS>
177 template<bool byInverse>
178 RationalFunction<Pol, AS>& RationalFunction<Pol, AS>::add(const typename Pol::CoeffType& rhs) {
179  if (this->is_constant()) {
180  if (byInverse)
181  this->mNumberQuotient -= rhs;
182  else
183  this->mNumberQuotient += rhs;
184  return *this;
185  }
186  mIsSimplified = false;
187  if (byInverse)
188  mPolynomialQuotient->first -= std::move(rhs * denominatorAsPolynomial());
189  else
190  mPolynomialQuotient->first += std::move(rhs * denominatorAsPolynomial());
191  eliminateCommonFactor(!AS);
192  return *this;
193 }
194 
195 template<typename Pol, bool AS>
196 RationalFunction<Pol, AS>& RationalFunction<Pol, AS>::operator*=(const RationalFunction<Pol, AS>& rhs) {
197  if (this->is_constant() && rhs.is_constant()) {
198  this->mNumberQuotient *= rhs.mNumberQuotient;
199  return *this;
200  } else if (this->is_constant()) {
201  CoeffType c(this->mNumberQuotient);
202  *this = rhs;
203  return *this *= c;
204  } else if (rhs.is_constant()) {
205  return *this *= rhs.mNumberQuotient;
206  }
207  mIsSimplified = false;
208  mPolynomialQuotient->first *= rhs.nominatorAsPolynomial();
209  mPolynomialQuotient->second *= rhs.denominatorAsPolynomial();
210  eliminateCommonFactor(!AS);
211  return *this;
212 }
213 
214 template<typename Pol, bool AS>
215 RationalFunction<Pol, AS>& RationalFunction<Pol, AS>::operator*=(const Pol& rhs) {
216  if (this->is_constant()) {
217  CoeffType c = this->mNumberQuotient;
218  Pol resultNum(rhs);
219  resultNum *= CoeffType(get_num(c));
220  *this = std::move(RationalFunction<Pol, AS>(std::move(resultNum), std::move(Pol(CoeffType(get_denom(c))))));
221  return *this;
222  }
223  mIsSimplified = false;
224  mPolynomialQuotient->first *= rhs;
225  eliminateCommonFactor(!AS);
226  return *this;
227 }
228 
229 template<typename Pol, bool AS>
230 template<typename P, DisableIf<needs_cache_type<P>>>
231 RationalFunction<Pol, AS>& RationalFunction<Pol, AS>::operator*=(Variable rhs) {
232  if (this->is_constant()) {
233  CoeffType c(this->mNumberQuotient);
234  Pol resultNum(rhs);
235  resultNum *= CoeffType(get_num(c));
236  *this = std::move(RationalFunction<Pol, AS>(std::move(resultNum), std::move(Pol(CoeffType(get_denom(c))))));
237  return *this;
238  }
239  mIsSimplified = false;
240  mPolynomialQuotient->first *= rhs;
241  eliminateCommonFactor(!AS);
242  return *this;
243 }
244 
245 template<typename Pol, bool AS>
246 RationalFunction<Pol, AS>& RationalFunction<Pol, AS>::operator*=(const typename Pol::CoeffType& rhs) {
247  // TODO handle rhs == 0
248  if (this->is_constant()) {
249  this->mNumberQuotient *= rhs;
250  return *this;
251  }
252  mIsSimplified = false;
253  mPolynomialQuotient->first *= rhs;
254  eliminateCommonFactor(!AS);
255  return *this;
256 }
257 
258 template<typename Pol, bool AS>
259 RationalFunction<Pol, AS>& RationalFunction<Pol, AS>::operator*=(carl::sint rhs) {
260  return *this *= carl::rationalize<typename Pol::CoeffType>(rhs);
261 }
262 
263 template<typename Pol, bool AS>
264 RationalFunction<Pol, AS>& RationalFunction<Pol, AS>::operator/=(const RationalFunction<Pol, AS>& rhs) {
265  if (this->is_constant() && rhs.is_constant()) {
266  this->mNumberQuotient /= rhs.mNumberQuotient;
267  return *this;
268  } else if (this->is_constant()) {
269  CoeffType c(this->mNumberQuotient);
270  *this = rhs.inverse();
271  return *this *= c;
272  } else if (rhs.is_constant()) {
273  return *this /= rhs.mNumberQuotient;
274  }
275  mIsSimplified = false;
276  if (carl::is_one(rhs.denominatorAsPolynomial())) {
277  return *this /= rhs.nominatorAsPolynomial();
278  }
279  mPolynomialQuotient->first *= rhs.denominatorAsPolynomial();
280  mPolynomialQuotient->second *= rhs.nominatorAsPolynomial();
281  eliminateCommonFactor(!AS);
282  return *this;
283 }
284 
285 template<typename Pol, bool AS>
286 RationalFunction<Pol, AS>& RationalFunction<Pol, AS>::operator/=(const Pol& rhs) {
287  if (this->is_constant()) {
288  CoeffType c(this->mNumberQuotient);
289  Pol resultNum(rhs);
290  resultNum *= CoeffType(get_denom(c));
291  *this = std::move(RationalFunction<Pol, AS>(std::move(Pol(CoeffType(get_num(c)))), std::move(resultNum)));
292  return *this;
293  }
294  mIsSimplified = false;
295  if (rhs.is_constant()) {
296  mPolynomialQuotient->first /= rhs.constant_part();
297  } else {
298  mPolynomialQuotient->second *= rhs;
299  eliminateCommonFactor(!AS);
300  }
301  return *this;
302 }
303 
304 template<typename Pol, bool AS>
305 template<typename P, DisableIf<needs_cache_type<P>>>
306 RationalFunction<Pol, AS>& RationalFunction<Pol, AS>::operator/=(Variable rhs) {
307  if (this->is_constant()) {
308  CoeffType c(this->mNumberQuotient);
309  Pol resultNum(rhs);
310  resultNum *= CoeffType(get_denom(c));
311  *this = RationalFunction<Pol, AS>(Pol(CoeffType(get_num(c))), std::move(resultNum));
312  return *this;
313  }
314  mIsSimplified = false;
315  mPolynomialQuotient->second *= rhs;
316  eliminateCommonFactor(!AS);
317  return *this;
318 }
319 
320 template<typename Pol, bool AS>
321 RationalFunction<Pol, AS>& RationalFunction<Pol, AS>::operator/=(unsigned long rhs) {
322  if (this->is_constant()) {
323  this->mNumberQuotient /= CoeffType(rhs);
324  return *this;
325  }
326  mIsSimplified = false;
327  mPolynomialQuotient->first /= rhs;
328  return *this;
329 }
330 
331 template<typename Pol, bool AS>
332 RationalFunction<Pol, AS>& RationalFunction<Pol, AS>::operator/=(const typename Pol::CoeffType& rhs) {
333  if (this->is_constant()) {
334  this->mNumberQuotient /= rhs;
335  return *this;
336  }
337  mIsSimplified = false;
338  mPolynomialQuotient->first /= rhs;
339  return *this;
340 }
341 
342 template<typename Pol, bool AS>
343 bool operator==(const RationalFunction<Pol, AS>& lhs, const RationalFunction<Pol, AS>& rhs) {
344  if (lhs.is_constant()) {
345  if (rhs.is_constant())
346  return lhs.mNumberQuotient == rhs.mNumberQuotient;
347  else
348  return false;
349  }
350  if (rhs.is_constant())
351  return false;
352  return lhs.nominatorAsPolynomial() == rhs.nominatorAsPolynomial() && lhs.denominatorAsPolynomial() == rhs.denominatorAsPolynomial();
353 }
354 
355 template<typename Pol, bool AS>
356 bool operator<(const RationalFunction<Pol, AS>& lhs, const RationalFunction<Pol, AS>& rhs) {
357  if (lhs.is_constant()) {
358  if (rhs.is_constant())
359  return lhs.mNumberQuotient < rhs.mNumberQuotient;
360  else
361  return true;
362  }
363  if (rhs.is_constant())
364  return false;
365  return lhs.nominatorAsPolynomial() * rhs.denominatorAsPolynomial() < rhs.nominatorAsPolynomial() * lhs.denominatorAsPolynomial();
366 }
367 
368 template<typename Pol, bool AS>
369 std::string RationalFunction<Pol, AS>::toString(bool infix, bool friendlyNames) const {
370 
371  std::string numeratorString = is_constant() ? carl::toString(nominatorAsNumber()) : nominatorAsPolynomial().toString(infix, friendlyNames);
372  std::string denominatorString = is_constant() ? carl::toString(denominatorAsNumber()) : denominatorAsPolynomial().toString(infix, friendlyNames);
373 
374  if (denominator().is_one()) {
375  return numeratorString;
376  }
377 
378  if (infix) {
379  return "(" + numeratorString + ")/(" + denominatorString + ")";
380  } else {
381  return "(/ " + numeratorString + " " + denominatorString + ")";
382  }
383 }
384 
385 template<typename Pol, bool AS>
386 std::ostream& operator<<(std::ostream& os, const RationalFunction<Pol, AS>& rhs) {
387  if (rhs.is_constant())
388  return os << rhs.mNumberQuotient;
389  return os << "(" << rhs.nominatorAsPolynomial() << ")/(" << rhs.denominatorAsPolynomial() << ")";
390 }
391 } // namespace carl