Sep 28

Lecture Overview

Here are some examples of using functions, passing arguments, and so forth. I have mentioned several times that functions are just data values that are stored on in memory and referenced by namespace entries. This means that functions can be passed as arguments to functions. Here are several examples: keep in mind that a function is an unnamed block of code which is stored as a data value.

Riemann Sum

Here is code to compute the Riemann Sum in python. It takes a function as its first parameter, the start and end x coordinates, and an optional number of iterations.

def riemann(f, xstart, xend, iterations=50):
    # Compute the area under the curve f from xstart to xend

    delta = (float(xend) - float(xstart)) / iterations
    area = 0.0

    for i in range(iterations):
        # compute the x coordinate
        x = xstart + i * delta
        boxarea = delta * f(x)  # Note the call to the function f
        area += boxarea

    return area

We can use this by passing in a function for the first argument.

import math

print(riemann(math.cos, 0, 4))
print(riemann(math.cos, 0, 4, 100))
print(riemann(math.sin, xend=15, xstart=0))
print(riemann(math.sin, iterations=100, xstart=0, xend=2*math.pi)) # Why does this not print zero?

Note that math.cos is a namespace entry for the (unnamed) function located somewhere in memory. During the call to riemann, a namespace entry for f is created which references this location in memory.

We can also call riemann with our own functions.

def squareplustwo(x):
    return x * x + 2

print(riemann(xstart=4, xend=15, f=squareplustwo, iterations=100))

Because creating functions to be passed to other functions is quite common, python provides a way to create functions as an expression and without giving them a name: the lambda (see also here). This creates a function value out in memory and then immediately sets up the namespace entry for f to point to it.

print(riemann(lambda x: x*x+2, 4, 15, 100))
print(riemann(lambda x: x ** 4 - 3*x, 20, 200))

Images

One of the most common ways of storing colors in the computer is the RGB Color Model. To store images, we organize an image to a rectangular grid of pixels. The color of each pixel is stored via the RGB color model. There are no image manipulation facilities in the python standard library. Instead, there are a number of 3rd party libraries that work with images, perhaps the most common is pillow. Instead of using this library, we will create images directly using tkinter.

This library expects colors in web form, meaning a string like this: #2E8B57 which happens to be a sea green. To understand this, we split it into three chunks of two digits: 2E 8B 57. These are hexadecimal numbers, in this case the numbers 46, 139, and 87. The 46 is the red component, the 139 is the green component, and the 87 is the blue component. These numbers are out of 255 and therefore we view the color as \(46/255\) or \(18%\) red, \(139/255\) or \(50%\) green, and \(87/255\) or \(34%\) blue.

List Comprehension

One nice technique to create lists in python is list comprehension. The tutorial has some good examples so I won't repeat it here.

Fractals

The goal is to create Julia Fractals. The Wikipedia page is somewhat complicated, but what we are going to do is the following:

Here is the code

import tkinter
import cmath


def julia(f, max_iter=100, cutoff=2.0, image_width=700, image_height=500, x_min=-2.0, x_max=2.0, y_min=-1.25, y_max=1.25):

    # Given an r, g, b (numbers between 0 and 255), this function creates a web label
    # color string like #2E8B57.
    def make_color(r, g, b):
        return "#%02x%02x%02x" % (r%255, g%255, b%255)

    # Use a list comprehension to create a list of colors. The result will be a
    # list of strings.  The colors I am using here is a collection of colors spanning
    # gradually from teal to aqua since that is a mix of green and blue with zero red.
    colors = [ make_color(0, i*2+40, i*2+40) for i in range(max_iter) ]

    # This function is given a complex point, and computes the color.  It does
    # this by repeatedly applying the function f (note the namespace lookups
    # needed to find f).  Once the value goes above the cutoff, the iteration
    # count is used as an index into the colors list to determine the color.
    def color_for(c):
        for trials in range(max_iter):
            if abs(c) <= cutoff:
                c = f(c)
            else:
                break
        return colors[trials]

    # Given a pixel coordinate, this function returns a complex number for the point of
    # the plane representing this pixel.
    def coord_for_pixel(pixel_x, pixel_y):
        percentX = pixel_x / float(image_width)
        percentY = pixel_y / float(image_height)
        x = x_min + percentX * (x_max - x_min)
        y = y_max - percentY * (y_max - y_min)
        return complex(x, y)

    # Use a list comprehension to create a list of (pixel_x, pixel_y, color) entries
    # The color is found by passing the return value from coord_for_pixel to color_for.
    # The list comprehension then makes px and py range through the entire grid.
    pixels = [ (px, py, color_for(coord_for_pixel(px, py))) for px in range(image_width) for py in range(image_height) ]
    return pixels


# This function uses tkinter to draw the image, you can ignore this.
def draw(pixels):
    image_width =  max([ p[0] for p in pixels])
    image_height = max([ p[1] for p in pixels])
    root = tkinter.Tk()
    im = tkinter.PhotoImage(width=image_width, height=image_height)
    for p in pixels: im.put(p[2], (p[0], p[1]))
    l = tkinter.Label(root, image=im)
    l.pack()
    root.mainloop()

# Some images

pixels = julia(lambda x: complex(1,0.3)*cmath.sin(x), cutoff=50, x_min=-2, x_max=2)
#pixels = julia(lambda x: x * x + complex(-0.70176, -0.3842))
#pixels = julia(lambda x: x * x + complex(-0.70176, -0.3842), x_min=-0.1, x_max=0.1, y_min=-0.1, y_max=0.1)
#pixels = julia(lambda x: x * x + complex(0.285, 0.01))
#pixels = julia(lambda x: complex(1,0.4)*cmath.sin(x), cutoff=50, x_min=-2, x_max=2)


draw(pixels)

Exercises

The Mandelbrot set is one of the most famous fractals. Update the code above to draw the Mandelbrot set. To do so, most of the above code can be left alone. The changes you need are