# Math 300: Python Algebra (back to Math 300 notes)

Sympy has a sophisticated ability to solve systems of equations. For small linear and nonlinear systems, this centers around the solve command. This takes at least one argument: the left-hand-side of an equation to be solved. The right-hand-side is assumed to be zero. To emphasize this, solve solves an equation of the form \$\$f(x)=0,\$\$ and you type the expression for \(f(x)\) into the first argument.

>>> from sympy import * >>> var('x') x >>> solve(x**2-1) [1, -1]

In this case, there was only one variable, so it was clear what we wanted to solve for. In a case where it is less clear, we can use a second argument to solve to specify which symbolic object we want to solve for.

>>> import sys >>> sys.displayhook=pprint >>> var('a') a >>> solve(a*x**2-1,x) ___ ___ / 1 / 1 [- / - , / - ] \/ a \/ a

We can solve more than one equation, i.e. we can solve systems. In this case, we must supply the collection of equations to be solved as an array (or a tuple), and list the variables we are solving for also as an array.

>>> solve([x**2-1,2*x+y-a**2],[x,y]) 2 2 [(-1, a + 2), (1, a - 2)] >>> solve((x**2+y**2-1,2*x+y-a**2),(x,y)) __________ __________ __________ 2 / 4 2 / 4 2 / 4 2 2*a \/ - a + 5 a 2*\/ - a + 5 2*a \/ - a + 5 a 2*\ [(---- - -------------, -- + ---------------), (---- + -------------, -- - --- 5 5 5 5 5 5 5 __________ / 4 / - a + 5 ------------)] 5

We are not able to solve most transcendental equations exactly, of course. On the other, hand, sympy can sometimes find numerical solutions. To to this, it requires a third argument containing a starting point for its numerical method.

>>> nsolve((x**2+exp(y)-1,2*x+y),(x,y),(1,1)) [-1.31320559579531e-23] [ 2.62641119159062e-23] >>> nsolve([x**2+exp(y)-1,2*x+y],[x,y],[1,6]) Traceback (most recent call last): File "./solver.py", line 6, in soln=nsolve([x**2+exp(y)-1,2*x+y],[x,y],[1,6]) File "/usr/lib/python2.7/site-packages/sympy/solvers/solvers.py", line 1255, in nsolve x = findroot(f, x0, J=J, **kwargs) File "/usr/lib/python2.7/site-packages/mpmath/calculus/optimization.py", line 972, in findroot % (norm(f(*xl))**2, tol)) ValueError: Could not find root within given tolerance. (2.88602e-18 > 2.1684e-19) Try another starting point or tweak arguments.

The first command started a numerical method to find the solution of the system \(x^2+\exp(y)-1=0, 2x+y=0\), using a starting guess of \(x=1,y=1\). It found a solution, namely (0,0). Alright, it found that solution to within some tolerance less than \(10^{-22}\). That is how numerical schemes go, and having 22 correct digits of the solution is sufficient for most household purposes.

The second command tried to solve the same equations with a different initial guess, one farther from the actual solution. This time sympy failed hard. This is regrettably common when solving nonlinear equations with bad initial guesses for the solution. When we see that message:
Try another starting point or tweak arguments.
it means that we need to guess again on our starting point. It is often a good idea when solving nonlinear systems to plot the functions to get an idea of where they are zero.

>>> newexpr=expr.expand() >>> newexpr u**4 + 4*u**3*v + 6*u**2*v**2 + 4*u*v**3 + v**4 >>> newexpr.factor() (u + v)**4 >>> newexpr.subs(u,2) v**4 + 8*v**3 + 24*v**2 + 32*v + 16 >>> (newexpr.subs(u,2)).factor() (v + 2)**4

Notice in the last expression that we simply put parentheses around a computed quantity, which was symbolic because it was created from symbolic expressions, and then used a method associated with this new symbolic object. Once again for emphasis: any time we perform a computation that uses a symbolic variable, the result is itself symbolic, and hence has access to all the methods associated with symbolic variables.

When we use symbolic expressions, we really don't want to have to look at all that "**" stuff. We want to see something that resembles ordinary mathematical notation. Many symbolic packages call this "pretty printing". Regrettably, the result is not always pretty, but most of the time it produce result that are more legible than the straight python syntax. To do pretty printing using sympy, run three commands in your session:

```>>> import sys
>>> oh=sys.displayhook
>>> sys.displayhook=pprint
```
After that is done, your expressions should be "pretty printed".

>>> u=1/((y+3)*(y-4)**2) >>> u 1/((y - 4)**2*(y + 3)) >>> import sys >>> oh=sys.displayhook >>> sys.displayhook=pprint >>> u 1 ---------------- 2 (y - 4) *(y + 3)

In all further discussion of the sympy package, we will suppose that you have run these commands.