This fifteenth article of the mathematical journey through open source, demonstrates the various techniques of expression simplification using Maxima.
Expression simplification can be done in a variety of ways. Let’s start with the simple ones, and then move onto more powerful ones.
Real number simplification
A simple simplification is to convert a given number into a rational number using ratsimp(). Below follows the demonstration.
$ maxima -q
(%i1) ratsimp(9);
(%o1) 9
(%i2) ratsimp(10.0);
rat: replaced 10.0 by 10/1 = 10.0
(%o2) 10
(%i3) string(ratsimp(4.2)); /* string to print it on one line */
rat: replaced 4.2 by 21/5 = 4.2
(%o3) 21/5
(%i4) string(factor(3.2)); /* string to print it on one line */
rat: replaced 3.2 by 16/5 = 3.2
(%o4) 2^4/5
(%i5) string(ratsimp(4.3333)); /* string to print it on one line */
rat: replaced 4.3333 by 43333/10000 = 4.3333
(%o5) 43333/10000
(%i6) string(ratsimp(4.3333333)); /* string to print it on one line */
rat: replaced 4.3333333 by 13/3 = 4.333333333333333
(%o6) 13/3
(%i7) quit();
Another one is to check whether a number is an integer using askinteger(). And if yes, is it an even or odd number, again using askinteger(). Moreover, asksign() checks for the sign. In case of trying these with unknown variables, Maxima would ask the user the necessary question(s) to deduce the response, and store it for future analysis. For example, askinteger(x) would ask us if x is an integer. And, if we say yes, it can then deduce many more information by itself. Below are some examples:
$ maxima -q
(%i1) askinteger(1);
(%o1) yes
(%i2) askinteger(1.0);
rat: replaced 1.0 by 1/1 = 1.0
(%o2) yes
(%i3) askinteger(1.2);
rat: replaced 1.2 by 6/5 = 1.2
(%o3) no
(%i4) askinteger(-9);
(%o4) yes
(%i5) askinteger(2/3 + 3/4 + 1/6 + 5/12);
(%o5) yes
(%i6) askinteger(-9, even);
(%o6) no
(%i7) askinteger(0, even);
(%o7) yes
(%i8) properties(x);
(%o8) []
(%i9) askinteger(x);
Is x an integer?
yes; /* This is our response */
(%o9) yes
(%i10) askinteger(x + 9);
(%o10) yes
(%i11) askinteger(2 * x, even);
(%o11) yes
(%i12) askinteger(2 * x + 1, even);
(%o12) no
(%i13) askinteger(x, even);
Is x an even number?
n; /* This is our response */
(%o13) no
(%i14) askinteger(x, odd);
(%o14) yes
(%i15) askinteger(x^3 - (x + 1)^2, even);
(%o15) no
(%i16) properties(x);
(%o16) [database info, kind(x, integer), kind(x, odd)]
(%i17) asksign((-1)^x);
(%o17) neg
(%i18) asksign((-1)^(x+1));
(%o18) pos
(%i19) asksign((-1)^x+1);
(%o19) zero
(%i20) quit();
Maxima simplification uses the concept of properties of symbols. As an example, note the properties of x in the above demonstration at %i8 and %i16.
Complex number simplification
Complex numbers have two common useful forms, namely the exponential and the circular (with sine & cosine) forms. demoivre() converts the exponential to circular form and exponentialize() does the other way round. Using expand() along with them, can simplify complicated looking expressions. Here goes few examples:
$ maxima -q
(%i1) string(demoivre(exp(%i*x^2))); /* %i is sqrt(-1) */
(%o1) %i*sin(x^2)+cos(x^2)
(%i2) string(exponentialize(a*(cos(t)))); /* %i is sqrt(-1) */
(%o2) a*(%e^(%i*t)+%e^-(%i*t))/2
(%i3) string(expand(exponentialize(a*(cos(t)+%i*sin(t))))); /* %i is sqrt(-1) */
(%o3) a*%e^(%i*t)
(%i4) quit();
Expansions and Reductions
As already seen in the previous article, expand() expands an expression completely, by default. However, it can be controlled by specifying the maximum power to which to expand for both the numerator and the denominator, respectively. Using factor() can compact the expanded expressions. Moreover, in many cases, we would like to expand it only with respect to only some variable(s). Say, (x + a + b)^2 should be expanded with respect to x. expandwrt() is meant exactly for that. One example of each of these is shown below.
$ maxima -q
(%i1) string(expand(((x+1)^2-x^2)/(x+1)^2, 2, 0));
(%o1) 2*x/(x+1)^2+1/(x+1)^2
(%i2) string(factor(((x+1)^2-x^2)/(x+1)^2));
(%o2) (2*x+1)/(x+1)^2
(%i3) string(expandwrt((x+a+b)^2,x));
(%o3) x^2+2*(b+a)*x+(b+a)^2
(%i4) quit();
Expressions containing logs, exponentials, radicals (powers) can be simplified using radcan(). Rule based simplifications can be achieved using sequential comparative simplification function scsim(). Both of these call for a few examples.
$ maxima -q
(%i1) string(radcan(exp(5 * log(x) + log(3 * exp(log(y) / 4)))));
(%o1) 3*x^5*y^(1/4)
(%i2) radcan((log(2*x+2*x^2)-log(x))/(log(1+1/x)+log(2*x)));
(%o2) 1
(%i3) expr: a^2 + b^2 + c^2$
(%i4) eq1: a^2 + 2*a*b + b^2 = 4$
(%i5) eq2: a * b = 6$
(%i6) string(scsimp(expr, eq1, eq2));
(%o6) c^2-8
(%i7) quit();
Unlike Octave, Maxima by default doesn’t evaluate its expressions, it only simplifies. What it means is that expressions with integers like cos(1), exp(2), sqrt(3), etc. may remain as is in the most simplified form, instead of evaluating to their respective float numerical values. In such cases, we may force the evaluation by passing the option numer. Similar evaluation can be achieved for predicates, using pred.
$ maxima -q
(%i1) cos(1);
(%o1) cos(1)
(%i2) cos(1), numer;
(%o2) .5403023058681398
(%i3) sqrt(7);
(%o3) sqrt(7)
(%i4) sqrt(7), numer;
(%o4) 2.645751311064591
(%i4) 1 + 2 > 9;
(%o4) 3 > 9
(%i5) 1 + 2 > 9, pred;
(%o5) false
(%i6) string(%e^%pi < %pi^%e); /* string to print it on one line */
(%o6) %e^%pi < %pi^%e
(%i7) %e^%pi < %pi^%e, pred;
(%o7) false
(%i8) quit();
Summation Simplifications
Symbolical representation and manipulations of summations can be beautifully achieved using sum() and the option simpsum. Check out the code execution below:
$ maxima -q
(%i1) sum(a * i, i, 1, 5);
(%o1) 15 a
(%i2) sum(a, i, 1, 5);
(%o2) 5 a
(%i3) sum(a * i, i, 1, n);
n
====
\
(%o3) a > i
/
====
i = 1
(%i4) simpsum: true$ /* Enable simplification of summations */
(%i5) string(sum(a * i, i, 1, n)); /* string to print it on one line */
(%o5) a*(n^2+n)/2
(%i6) string(sum(i^2 - i, i, 1, n) + sum(j, j, 1, n));
(%o6) (2*n^3+3*n^2+n)/6
(%i7) string(factor(sum(i^2 - i, i, 1, n) + sum(j, j, 1, n)));
(%o7) n*(n+1)*(2*n+1)/6
(%i8) quit();