# Lecture 15: Normalizing Expressions¶

Deciding whether two expressions represent the same mathematical object is an important problem in symbolic computation. We distinguish between the canonical and a normal form. Rewriting expressions using collection and sorting is a way of normalization. The quick, numerical, and probabilistic way to check whether two expressions are mathematically equivalent is by evaluation at a random point.

## Normal and Canonical Form¶

Expressions can take many forms. We call two expressions to be equal if they are mathematically the same.

```
var('x,y')
e1 = x*(1+y)
e2 = x + x*y
print('e1 = ', e1)
print('e2 = ', e2)
print('e1 == e1 : ', e1 == e2)
```

From the last `print`

we see that the equality operator `==`

does not evaluate to `True`

or `False`

.
We could compare identities, but this would only result in `True`

if both names would refer to the same object,

```
print(id(e1) == id(e2))
```

which is not the case as we see `False`

printed.
If we are comparing expressions,
then we could compare operands and operators.

```
print(e1.operands(), e1.operator())
print(e2.operands(), e2.operator())
```

But then we see
`[x, y + 1] <built-in function mul>`

for `e1`

and `[x*y, x] <built-in function add>`

for `e2`

.
At the data level, the two expressions are different.

What is we would take the difference of the two expressions?

```
print('e1 - e2 :', e1 - e2)
```

which then shows `e1 - e2 : x*(y + 1) - x*y - x`

so Sage does not simplify.
To check for equality, we can normalize, fully expand the expressions.

```
ee1 = e1.expand()
print('e1 expanded :', ee1)
print('e2 :', e2)
print('e1 expanded - e2 :', ee1 - e2)
```

Then the difference between the expanded `e1`

and the `e2`

leads to `0`

.

Expanding polynomials in several variables, for a given order of the variables
and an order of the monomials, gives *a normal form*.
Normalization is the process of bringing a mathematical expression
in a normal form.
For rational expressions we have seen that we can normalize numerator
and denominator by removing common factors.
A normal form is usually not unique, as we can then still
represent numerator and denominator in expanded or factored form,
which could lead to four different forms for the same expression.

*The canonical form* is *the* unique form of an expression.
For polynomials in one variable, we can fully expand the polynomial,
remove superfluous terms (like x - x) and then sort the monomials by degree
in descending order (highest degree first).

## Rewriting Multivariate Polynomials¶

For a multivariate polynomial, once we fix the order of the variables, we can order the terms lexicographically, first all monomials which contains the first variable, in order of degree in that variable, before all terms that do not contain the first variable.

```
R.<x,y,z> = PolynomialRing(QQ, order='lex')
p = R.random_element(degree=5, terms=20)
p
```

The default order is the degree lexicographic order, which places the terms with the highest degree first. Terms with the same degree are ordered lexicographically, first come the terms where the degree in the first variable is highest.

```
S.<x,y,z> = PolynomialRing(QQ, order='deglex')
q = S(p)
print(q, 'has type', type(q))
```

The statement `S(p)`

converts the polynomial `p`

into
an object of the ring `S`

where the terms are sorted in the degree lexicographical order.

We can rewrite the polynomial as a polynomial in one variable, where the coefficients are polynomials in the other variables. We illustrate this on a random polynomial.

```
P = QQ[x,y,z]
q = P.random_element(degree=5,terms=20)
print(q, 'has type', type(q))
```

We see that multivariate polynomials in Sage
are implemented via `libSINGULAR`

.
SINGULAR is a computer algebra system
for computational algebraic geometry.

We can write a polynomial in several variables recursively as a polynomial in one variable with its coefficients again polynomials in the same form.

To write the polynomial q as a polynomial in z, with coefficients polynomials in y that have coefficients in x, we do

```
QQ[x][y][z](q)
```

This is another normal form for multivariate polynomials.

## A Numerical Test on Equality¶

There is a numerical probability-one test
n the equality of expressions.
First we generate a random point, choosing random complex numbers
for `x`

and `y`

.

```
rx = CC.random_element()
ry = CC.random_element()
print('a random point :', (rx, ry))
```

And then we evaluate the expressions.

```
v1 = e1(x=rx, y=ry)
v2 = e2(x=rx, y=ry)
print(v1 - v2)
```

we see `0.000000000000000`

With probability one (we could have picked a point on
some common factor of `e1 - e2`

),
a number (close to) zero will guarantee equality of expressions.
We can increase our confidence in this test by generating more random points
and increasing the working precision of the computations.

## Assignments¶

Consider the polynomial \(p = (x^2 + x y + x + y) (x+y)\).

Order the monomials in \(p\) in total degree order, using \(x > y\).

Order the monomials in \(p\) in pure lexicographic order, using \(x > y\).

Consider the polynomial \(p = (x^2 + x y + x + y) (x+y)\). Rewrite \(p\) as a polynomial in \(x\) with coefficients in \(y\).

Consider the expressions \(x+1\) and \((x^2 - 1)/(x - 1)\).

Are these expressions symbolically the same? Give the Sage commands to illustrate your answer.

Verify the equality numerically. Show how a numerical equality test can go wrong.