Understanding how to effectively use a computer as a tool in doing mathematics is the subject of Computational Mathematics.
The first step is to learn how to program, and for this class we will use today's most powerful "platform" for programming in mathematics.

Sage is a platform that brings together many powerful open source software packages for doing computational mathematics, and we talk to these packages using the Python programming language.
Python is a highlevel scripting language that is particularly well suited for supporting the exploratory nature of Computational Mathematics.

In Part II we introduced functions and used them to do some preliminary explorations of mathematical sequences, in particular, arithmetic sequences, geometric sequences, and the Hailstone sequences. Two fundamental approaches to defining a sequence are (1) to provide a function that directly calculates the value of the $n$th term from the value of $n$, and (2) to provide a recurrence relation that defines the $n$th term in terms of preceding terms and the necessary initial values of the sequence. We saw that we can easily define the arithmetic and geometric sequences using either of these approaches. The sequence of Fibonacci numbers and the sequence of Lucas numbers were defined using the recurrence relation $f_{n+1} = f_n + f_{n1}$ with $f_0$ and $f_1$ given. The Hailstone sequences were defined by the Collatz function and we do not have a simple recurrence relation.
The next four blocks provide a quick review of these ideas.




This completes a quick review of Part II.
As noted in Part I, one of the important data structures provided by Python is the List, which is an ordered, dynamic, inhomogeneous collection of objects. Three other key Python data structures are Tuples, Sets, and Dictionaries.
First, a little more on Lists. We have already explored lists in some detail. As we have seen, a list in Python is entered and displayed with square brackets. When Python indexes into a list it starts at 0, and the index is specified with square brackets. When indexing into a 2dimensional list, Python uses two separate indices. The first index indicates which list in the list of lists, and the second index indicates which element in that list.



Python provides a number of "slicing" operations

Python does not deal directly with matrices, although Sage definitely does. In Python adding two lists is just concatenation.

In the last example A+B is a list consisting of 8 elements. The first element is a number. The second element is a list of 3 numbers. The next 4 elements are strings, and the last two elements are lists.
Lists in Python are very general collections. In Python we can walk through a list in 3 different ways.

The expression range(len(A)) generates a list of integers. The number of integers is the same as the number of items in A, and the list starts with 0. In other words this generates the list of indices for A. This is a somewhat "old fashioned" way to walk through a list.

Using the enumerate function we can retrieve the index and the item at the same time. This can be very handy sometimes.

Python has a very flexible initialization construction, called list comprehension. It mirrors the way we typically define a set in mathematics.

Even trickier constructions are possible by adding a conditional phrase.

A Tuple is an ordered, inhomogeneous collection of objects, but it is not dynamic. In fact, tuples are immutable. Once created they can not be changed. A tuple is a collection of objects separated by commas and enclosed with parentheses. The following blocks provide a few demonstrations about tuples.



Note: If an item in a tuple is mutable, then that item can be changed, but the tuple itself cannot be changed.


Note: Use tab completion on T and notice that tuples have only two methods, while lists have 9 methods.

In many cases a tuple can be constructed implicitly and "unpacked" implicitly. This can be particularly convenient in blocks of assignment statements. The first and last statements in the following block implicitly construct the tuple on the right, assign it to the implicit tuple on the left, and then unpack the implicit tuple. The subsequent block writes this out explicitly. The third block shows that a collection returned by a function is actually packaged as a tuple.



It may be surprising, but in Python numbers and strings are immutable objects as well as tuples. This guarantees that there is only one copy of each of these objects when your program is running, and this allows Python to exploit a powerful technique called hashing. In Python each immutable object has almost unique 64 bit hash code.
While a tuple is an immutable collection of arbitrary objects, in Python a Set is an unordered, dynamic collection of immutable objects. A set is an object that is defined using the statement set, followed by a collection of zero or more immutable objects enclosed in parentheses. The next several blocks illustrate the features of the set data structure.


Use tab completion to check out the many methods available to a set. In particular, the methods include the union and intersection operations that we commonly associate with a set. However, the more important feature of a set is the fact that the immutability requirement enables the "in" operation to be implemented much faster than possible for the ordered collections  list and tuple.




A Dictionary is a collection that consists of ordered pairs of objects. The first object must be an immutable object and is called the key. The second object can be an arbitrary object and is called the value. The key:value pairs are written with a colon separating them. The dictionary can be defined by a collection of key:value pairs separated by commas and enclosed in curly braces.

A value is retrieved from a dictionary by "indexing" with the key. This "indexing" notation can be used to change the values in the dictionary and to add new key:value pairs.





Note that the keys of a dictionary form a set and sets are not ordered.
