from numpy import *
from scipy import linalg
from scipy.linalg import norm
from matplotlib.pyplot import *
from prettytable import PrettyTable
from timeit import default_timer as timer
import sys
sys.path.append('fncbook/')
import fncbook as FNC
# This (optional) block is for improving the display of plots.
# from IPython.display import set_matplotlib_formats
# set_matplotlib_formats("svg","pdf")
# %config InlineBackend.figure_format = 'svg'
rcParams["figure.figsize"] = [7, 4]
rcParams["lines.linewidth"] = 2
rcParams["lines.markersize"] = 4
rcParams['animation.html'] = "jshtml" # or try "html5"
An idealized mathematical problem f(x) can usually only be approximated using a finite number of steps in finite precision. A complete set of instructions for transforming data into a result is called an algorithm. In most cases it is reasonable to represent an algorithm by another mathematical function, denoted here by f~(x).
Even simple problems can be associated with multiple algorithms.
Descriptions of algorithms may be presented as a mixture of mathematics, words, and computer-style instructions called pseudocode, which varies in syntax and level of formality. In this book we use pseudocode to explain the outline of an algorithm, but the specifics are usually presented as working code.
Of all the desirable traits of code, we emphasize clarity the most after correctness. We do not represent our programs as always being the shortest, fastest, or most elegant. Our primary goal is to illustrate and complement the mathematical underpinnings, while occasionally pointing out key implementation details.
As our first example, Function 1.3.1 implements an algorithm that applies Horner’s algorithm to a general polynomial, using the identity
Any collection of statements organized around solving a type of problem should probably be wrapped in a function. One clue is that if you find yourself copying and pasting code, perhaps with small changes in each instance, you should probably be writing a function instead.
Functions can be defined in text files with the extension .py, at the command line (called the REPL prompt), or in notebooks.
As seen in Function 1.3.1, one way to start a function definition is with the def keyword, followed by the function name and the input arguments in parentheses, ending with a colon. The statements for the body of the function must then all be indented. For example, to represent the mathematical function esinx, we could use
def myfun(x):
s = np.sin(x)
return np.exp(s)
The return statement is used to end execution of the function and return one or more (comma-separated) values to the caller of the function.
For a function with a short definition like the one above, there is a more compact syntax to do the same thing:
myfun = lambda x : np.exp(np.sin(x))
The syntax on the right of the = above defines an anonymous function (called a lambda function in computer science), which can be used in place without giving it a name as we did here. We’ll have examples of doing this later on.
As in most languages, input arguments and variables defined within a function have scope limited to the function itself. However, they can access values defined within an enclosing scope. For instance:
mycfun = lambda x : np.exp(c * np.sin(x))
c = 1; print(mycfun(3)) # exp(1*sin(3))
c = 2; print(mycfun(3)) # exp(2*sin(3))
There’s a lot more to be said about functions in Python, but this is enough to get started.