3 * @file: RationalFunction.tpp
4 * @author: Sebastian Junges
5 * @author: Florian Corzilius
7 * @since March 16, 2014
10 #include "RationalFunction.h"
12 #include <carl-arith/poly/umvpoly/functions/LCM.h>
16 template<typename Pol, bool AS>
17 RationalFunction<Pol, AS> RationalFunction<Pol, AS>::derivative(const Variable& x, unsigned nth) const {
20 return RationalFunction<Pol, AS>(0);
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));
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));
42 if (nominatorAsPolynomial() == denominatorAsPolynomial()) {
43 mPolynomialQuotient.reset();
44 mNumberQuotient = std::move(CoeffType(1));
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;
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();
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()) {
79 this->mNumberQuotient -= rhs.mNumberQuotient;
81 this->mNumberQuotient += rhs.mNumberQuotient;
83 } else if (this->is_constant()) {
84 CoeffType c = this->mNumberQuotient;
90 } else if (rhs.is_constant()) {
92 return *this -= rhs.mNumberQuotient;
94 return *this += rhs.mNumberQuotient;
96 mIsSimplified = false;
97 if (denominatorAsPolynomial().is_constant() && rhs.denominatorAsPolynomial().is_constant()) {
98 mPolynomialQuotient->first *= rhs.denominatorAsPolynomial().constant_part();
100 mPolynomialQuotient->first -= rhs.nominatorAsPolynomial() * denominatorAsPolynomial().constant_part();
102 mPolynomialQuotient->first += rhs.nominatorAsPolynomial() * denominatorAsPolynomial().constant_part();
103 mPolynomialQuotient->second *= rhs.denominatorAsPolynomial().constant_part();
105 if (denominatorAsPolynomial().is_constant()) {
106 // TODO use more efficient elimination
107 mPolynomialQuotient->first *= rhs.denominatorAsPolynomial();
109 mPolynomialQuotient->first -= rhs.nominatorAsPolynomial() * denominatorAsPolynomial().constant_part();
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();
117 mPolynomialQuotient->first -= rhs.nominatorAsPolynomial() * denominatorAsPolynomial();
119 mPolynomialQuotient->first += rhs.nominatorAsPolynomial() * denominatorAsPolynomial();
120 mPolynomialQuotient->second *= rhs.denominatorAsPolynomial().constant_part();
122 Pol leastCommonMultiple(std::move(carl::lcm(this->denominatorAsPolynomial(), rhs.denominatorAsPolynomial())));
124 mPolynomialQuotient->first = std::move(this->nominatorAsPolynomial() * quotient(leastCommonMultiple, this->denominatorAsPolynomial()) - rhs.nominatorAsPolynomial() * quotient(leastCommonMultiple, rhs.denominatorAsPolynomial()));
126 mPolynomialQuotient->first = std::move(this->nominatorAsPolynomial() * quotient(leastCommonMultiple, this->denominatorAsPolynomial()) + rhs.nominatorAsPolynomial() * quotient(leastCommonMultiple, rhs.denominatorAsPolynomial()));
128 mPolynomialQuotient->second = std::move(leastCommonMultiple);
131 eliminateCommonFactor(!AS);
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))))));
144 mIsSimplified = false;
146 mPolynomialQuotient->first -= std::move(rhs * denominatorAsPolynomial());
148 mPolynomialQuotient->first += std::move(rhs * denominatorAsPolynomial());
149 eliminateCommonFactor(!AS);
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);
159 resultNum *= CoeffType(get_denom(c));
161 resultNum -= CoeffType(get_num(c));
163 resultNum += CoeffType(get_num(c));
164 *this = std::move(RationalFunction<Pol, AS>(std::move(resultNum), std::move(Pol(CoeffType(get_denom(c))))));
167 mIsSimplified = false;
169 mPolynomialQuotient->first -= std::move(rhs * denominatorAsPolynomial());
171 mPolynomialQuotient->first += std::move(rhs * denominatorAsPolynomial());
172 eliminateCommonFactor(!AS);
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()) {
181 this->mNumberQuotient -= rhs;
183 this->mNumberQuotient += rhs;
186 mIsSimplified = false;
188 mPolynomialQuotient->first -= std::move(rhs * denominatorAsPolynomial());
190 mPolynomialQuotient->first += std::move(rhs * denominatorAsPolynomial());
191 eliminateCommonFactor(!AS);
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;
200 } else if (this->is_constant()) {
201 CoeffType c(this->mNumberQuotient);
204 } else if (rhs.is_constant()) {
205 return *this *= rhs.mNumberQuotient;
207 mIsSimplified = false;
208 mPolynomialQuotient->first *= rhs.nominatorAsPolynomial();
209 mPolynomialQuotient->second *= rhs.denominatorAsPolynomial();
210 eliminateCommonFactor(!AS);
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;
219 resultNum *= CoeffType(get_num(c));
220 *this = std::move(RationalFunction<Pol, AS>(std::move(resultNum), std::move(Pol(CoeffType(get_denom(c))))));
223 mIsSimplified = false;
224 mPolynomialQuotient->first *= rhs;
225 eliminateCommonFactor(!AS);
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);
235 resultNum *= CoeffType(get_num(c));
236 *this = std::move(RationalFunction<Pol, AS>(std::move(resultNum), std::move(Pol(CoeffType(get_denom(c))))));
239 mIsSimplified = false;
240 mPolynomialQuotient->first *= rhs;
241 eliminateCommonFactor(!AS);
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;
252 mIsSimplified = false;
253 mPolynomialQuotient->first *= rhs;
254 eliminateCommonFactor(!AS);
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);
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;
268 } else if (this->is_constant()) {
269 CoeffType c(this->mNumberQuotient);
270 *this = rhs.inverse();
272 } else if (rhs.is_constant()) {
273 return *this /= rhs.mNumberQuotient;
275 mIsSimplified = false;
276 if (carl::is_one(rhs.denominatorAsPolynomial())) {
277 return *this /= rhs.nominatorAsPolynomial();
279 mPolynomialQuotient->first *= rhs.denominatorAsPolynomial();
280 mPolynomialQuotient->second *= rhs.nominatorAsPolynomial();
281 eliminateCommonFactor(!AS);
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);
290 resultNum *= CoeffType(get_denom(c));
291 *this = std::move(RationalFunction<Pol, AS>(std::move(Pol(CoeffType(get_num(c)))), std::move(resultNum)));
294 mIsSimplified = false;
295 if (rhs.is_constant()) {
296 mPolynomialQuotient->first /= rhs.constant_part();
298 mPolynomialQuotient->second *= rhs;
299 eliminateCommonFactor(!AS);
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);
310 resultNum *= CoeffType(get_denom(c));
311 *this = RationalFunction<Pol, AS>(Pol(CoeffType(get_num(c))), std::move(resultNum));
314 mIsSimplified = false;
315 mPolynomialQuotient->second *= rhs;
316 eliminateCommonFactor(!AS);
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);
326 mIsSimplified = false;
327 mPolynomialQuotient->first /= rhs;
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;
337 mIsSimplified = false;
338 mPolynomialQuotient->first /= rhs;
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;
350 if (rhs.is_constant())
352 return lhs.nominatorAsPolynomial() == rhs.nominatorAsPolynomial() && lhs.denominatorAsPolynomial() == rhs.denominatorAsPolynomial();
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;
363 if (rhs.is_constant())
365 return lhs.nominatorAsPolynomial() * rhs.denominatorAsPolynomial() < rhs.nominatorAsPolynomial() * lhs.denominatorAsPolynomial();
368 template<typename Pol, bool AS>
369 std::string RationalFunction<Pol, AS>::toString(bool infix, bool friendlyNames) const {
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);
374 if (denominator().is_one()) {
375 return numeratorString;
379 return "(" + numeratorString + ")/(" + denominatorString + ")";
381 return "(/ " + numeratorString + " " + denominatorString + ")";
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() << ")";