-->

## Friday, 25 October 2013

### IPython Notebook Playing With Functions

In [149]:
%pylab inline
from matplotlib import mpl,pyplot,colors
import numpy as np
from sympy import *
from sympy.interactive import printing
import functools

Populating the interactive namespace from numpy and matplotlib


WARNING: pylab import has clobbered these variables: ['prod', 'plotting', 'cosh', 'Circle', 'power', 'diag', 'sinh', 'trunc', 'binomial', 'plot', 'eye', 'det', 'tan', 'product', 'gamma', 'roots', 'vectorize', 'zeros', 'interactive', 'conjugate', 'take', 'solve', 'trace', 'beta', 'colors', 'ones', 'multinomial', 'transpose', 'cos', 'diff', 'invert', 'pi', 'tanh', 'Polygon', 'reshape', 'sqrt', 'source', 'add', 'test', 'poly', 'mod', 'sign', 'log', 'var', 'seterr', 'flatten', 'floor', 'nan', 'exp', 'sin']
%pylab --no-import-all prevents importing * from pylab and numpy


In [150]:
x = Symbol('x')

class Function(object):
def __init__(self, coeff, start=-5, end = 5, points = 20):
# more points = more accurate but take more time
self.points =(end-start)* points

# tuples in the form (coefficient, power of x)
l = len(coeff)
self.coeff = [(value, l - 1 - index) for index, value in enumerate(coeff)]

self.X = np.linspace(start, end, self.points)

# coefficients for the first and second derivatives
self.D1 = [(a*b, b-1) for a,b in self.coeff[:-1]]
self.D2 = [(a*b, b-1) for a,b in self.D1[:-1]]

# set the Y values
self.Y = np.zeros(self.points)
for a,b in self.coeff:
self.Y = self.Y +a*(self.X**b)

def y(self,coeff, change = None):
y = np.zeros(self.points)

for a,b in coeff:
if b == change:
print "changing",change
y = y -a*(self.X**b)
else:

y = y +a*(self.X**b)

return y

def values(self):
pass

def d1(self):
return self.D1

def d2(self):
return self.D2

# plot the function and its first derivative
def plotD1(self):
pyplot.plot(self.X,self.Y)
pyplot.plot(self.X,self.y(self.D1))

# plot the function and its first AND second derivatives
def plotD1D2(self):
pyplot.plot(self.X,self.Y)
pyplot.plot(self.X,self.y(self.D1))
pyplot.plot(self.X,self.y(self.D2))
grid(True)

def plot(self, coeff = None):
pyplot.plot(self.X,self.Y)
pyplot.grid()

pyplot.show()

def change(self,co):
pyplot.plot(self.X,self.Y)
#pyplot.plot(self.X,self.y(self.D1))
#pyplot.plot(self.X,self.y(self.D1,co-1))
pyplot.grid()
pyplot.plot(self.X,self.y(self.coeff, co))

def changeWithDerivative(self,co):
x1 = self.X

#plt.subplot(2, 1, 1)
plt.plot(x1, self.Y, 'b-')
plt.plot(x1, self.y(self.D1), 'b-')

plt.grid(which='major', color='k', linestyle='-')

#plt.subplot(2, 1, 2)
plt.plot(self.X,self.y(self.coeff, co), 'r-')
plt.plot(self.X, self.y(self.D1,co-1), 'r-')

plt.grid(which='major', color='k', linestyle='-')

plt.show()

def functionFromRoots(listOfRoots, start=-5, end = 5, points = 10):
factors = [(x-a) for a in listOfRoots]
print "Here are the factors:", factors

def ffr(a,b):
return expand(a*b)
poly = functools.reduce(lambda a,b: ffr(a,b), factors)

print "Here is the polynomial", latex(poly)

poly = Poly(poly)

return Function(poly.coeffs(), start, end, points)

roots = [1,-1,4]
ffr = functionFromRoots(roots)
ffr.plot()

l = [1,-1,-14,0]
a = Function(l)

#a.plotD1D2()

Here are the factors: [x - 1, x + 1, x - 4]
Here is the polynomial x^{3} - 4 x^{2} - x + 4


In [151]:
ff = functionFromRoots([1,2,3])

z = Poly(expand((x+1)*(x+2)*(x+3)))

print z.coeffs()

Here are the factors: [x - 1, x - 2, x - 3]
Here is the polynomial x^{3} - 6 x^{2} + 11 x - 6
[1, 6, 11, 6]



### Drawing a Polynomial From Roots

When working with larger degree polynomials we could just enter more numbers into the Function constructor. For example:
 f = Function[1,5,-7,12])
The higher the degree the harder it is to intuitively get real roots in a narrow range. For this we can use functionFromRoots(listOfRoots) which takes a list of roots as its argument.
In [152]:
roots = [1,-1,4]
ffr = functionFromRoots(roots)
ffr.plot()

Here are the factors: [x - 1, x + 1, x - 4]
Here is the polynomial x^{3} - 4 x^{2} - x + 4


Using [1,-1,4] makes it hard to look at the key parts so I will also use 'start = -2' to bring the picture into focus
In [153]:
ffr = functionFromRoots(roots, start=-2)
ffr.plotD1D2()

Here are the factors: [x - 1, x + 1, x - 4]
Here is the polynomial x^{3} - 4 x^{2} - x + 4



### Change The Sign Of a Coefficient

What happens if we change the sign for each part. First lets plot a function.
Note that you can change the numbers here and then go 'Cell' > 'Run All Below' to change everything in one go.
In [170]:
m = Function([2,-1,2])
m.plot()

Ok let's change the sign by calling the power of the exponent of the cell we wish to change.
m.change(0) changes the constant, m.change(1) changes the coeff of the x ... where m is the name of our function
In [171]:
m.change(0)

changing 0


All the constant does is move a curve up or down. Note it may look like the curves are getting closer together but if you check where they cross grid lines you will see that they are not.
Next up change the x part.
In [172]:
m.change(1)

changing 1


Changing the x part will move the graph either left or right. Can you figure out which?
Hint: If the coefficient of x is positive then it is pulling the graph down until it reaches 0. After 0 it is pulling the graph up. The converse is true for a negative coefficient.
Perhaps it is easier to see with derivatives.
In [173]:
m.changeWithDerivative(1)

changing 1
changing 0


Changing the sign of the x part will change the constant part of the derivative. We have already learned that this shifts things up and down.
So if changing the constant moves us vertically and changing the x part moves us horizontally then what is left for the x^2 part?
In [175]:
m.change(2)

changing 2