Next: , Previous: Polynomial arithmetic, Up: Methods and functions


5.8 Rational expressions

5.8.1 The normal method

Some basic form of simplification of expressions is called for frequently. GiNaC provides the method .normal(), which converts a rational function into an equivalent rational function of the form ‘numerator/denominator’ where numerator and denominator are coprime. If the input expression is already a fraction, it just finds the GCD of numerator and denominator and cancels it, otherwise it performs fraction addition and multiplication.

.normal() can also be used on expressions which are not rational functions as it will replace all non-rational objects (like functions or non-integer powers) by temporary symbols to bring the expression to the domain of rational functions before performing the normalization, and re-substituting these symbols afterwards. This algorithm is also available as a separate method .to_rational(), described below.

This means that both expressions t1 and t2 are indeed simplified in this little code snippet:

     {
         symbol x("x");
         ex t1 = (pow(x,2) + 2*x + 1)/(x + 1);
         ex t2 = (pow(sin(x),2) + 2*sin(x) + 1)/(sin(x) + 1);
         std::cout << "t1 is " << t1.normal() << std::endl;
         std::cout << "t2 is " << t2.normal() << std::endl;
     }

Of course this works for multivariate polynomials too, so the ratio of the sample-polynomials from the section about GCD and LCM above would be normalized to P_a/P_b = (4*y+z)/(y+3*z).

5.8.2 Numerator and denominator

The numerator and denominator of an expression can be obtained with

     ex ex::numer();
     ex ex::denom();
     ex ex::numer_denom();

These functions will first normalize the expression as described above and then return the numerator, denominator, or both as a list, respectively. If you need both numerator and denominator, calling numer_denom() is faster than using numer() and denom() separately.

5.8.3 Converting to a polynomial or rational expression

Some of the methods described so far only work on polynomials or rational functions. GiNaC provides a way to extend the domain of these functions to general expressions by using the temporary replacement algorithm described above. You do this by calling

     ex ex::to_polynomial(exmap & m);
     ex ex::to_polynomial(lst & l);

or

     ex ex::to_rational(exmap & m);
     ex ex::to_rational(lst & l);

on the expression to be converted. The supplied exmap or lst will be filled with the generated temporary symbols and their replacement expressions in a format that can be used directly for the subs() method. It can also already contain a list of replacements from an earlier application of .to_polynomial() or .to_rational(), so it's possible to use it on multiple expressions and get consistent results.

The difference between .to_polynomial() and .to_rational() is probably best illustrated with an example:

     {
         symbol x("x"), y("y");
         ex a = 2*x/sin(x) - y/(3*sin(x));
         cout << a << endl;
     
         lst lp;
         ex p = a.to_polynomial(lp);
         cout << " = " << p << "\n   with " << lp << endl;
          // = symbol3*symbol2*y+2*symbol2*x
          //   with {symbol2==sin(x)^(-1),symbol3==-1/3}
     
         lst lr;
         ex r = a.to_rational(lr);
         cout << " = " << r << "\n   with " << lr << endl;
          // = -1/3*symbol4^(-1)*y+2*symbol4^(-1)*x
          //   with {symbol4==sin(x)}
     }

The following more useful example will print ‘sin(x)-cos(x)’:

     {
         symbol x("x");
         ex a = pow(sin(x), 2) - pow(cos(x), 2);
         ex b = sin(x) + cos(x);
         ex q;
         exmap m;
         divide(a.to_polynomial(m), b.to_polynomial(m), q);
         cout << q.subs(m) << endl;
     }