- Author: Paul Magwene
- Title: Mathematical notation: sums and products
- Date: 20 January 2016

When studying quantitative subjects like statistics, mathematics, or computer science, it's typical to use short hand notation to represent various operations. This is done because some operations are used so frequently that it would be tedious to write out a full explanation each time they're used.

Some of this mathematical notation can be a little intimidating at first. Don't let it scare you off. With a little practice it's easy to break the notation down into easy to understand parts.

Summing (adding things up) is something you do frequently in all sorts of quantitative fields.

When we carry out statistical analyses we're going to be working with sequences of numbers (mathematicians would usually call these vectors). In Python we might represent such a sequence as a `list`

(or an `array`

which we'll meet in a later class). In statistics we usually give the sequence a name like $\mathbf{x}$; when programming we might use a variable assignment like `x = [3,1,4,...]`

.

In mathematics we represent the operation of summing the elements of a sequence with a capital Greek letter sigma ($\Sigma$). Here's an example: $$ \sum_{i=1}^{10} \mathbf{x}_i $$

Notice that there are two numbers -- one above and one below the $\Sigma$. These are the upper and lower bounds of the indices of the elements we want from $\mathbf{x}$. Note that mathematicians index sequences from one, unlike computer scientists who usually index from zero.

In words, the above notation is equivalent to the written statement: "From the sequence we call $\mathbf{x}$, take the first 10 elements, and add them up."

An equivalent statement in Python would be:

```
sum(x[0:10]) # sum the first ten elements of x
```

Remember that when slicing Python sequences, the second part of the slice is non-inclusive (i.e. we take all the elements up to but not including the element indexed by 10).

Often it's convenient to further abstract our notation. Let's assume our sequence $\mathbf{x}$ has a length we'll call $n$. We don't necessarily know the length of $\mathbf{x}$ ahead of time, so using the label $n$ to refer to its length let's us abstract away this detail. If we want to represent the operation of summing up *all* the elements of $\mathbf{x}$ we could write:
$$
\sum_{i=1}^n \mathbf{x}_i
$$

The equivalent Python statement would be:

```
sum(x) # sum all the elements of x
```

Notice that when using sum notation, the lower index doesn't have to start at 1. For example, to represent the operation of summing up the last 10 elements of $\mathbf{x}$ we could write: $$ \sum_{i = n-10}^n \mathbf{x}_i $$ The equivalent Python statement is:

```
sum(x[-10:]) # sum the last 10 elements of x
```

Python has a convenient `sum`

function that makes it easy to quickly sum the elements of a sequence. But what if we didn't have this function, or what if we wanted to sum not the elements in the list, but rather some operation we applied to those elements? This problem is easy to solve with a for loop (Note: there are more efficient ways to do such operations, but we're aiming for conceptual simplicity). Let's illustrate this with an example:

```
In [1]:
```x = [2,4,6,8,10]
s = 0 # initialize the object that will hold our sum
for i in x:
s = s + i
print("The sum of x is:", s)

```
```

`s = s + i`

we could have written `s += i`

(read this as "`s`

is whatever it was before plus the value of `i`

"). So we could rewrite that `for`

loop as:

```
In [5]:
```x = [2,4,6,8,10]
s = 0
for i in x:
s += i
print("The sum of x is:", s)

```
```

`x`

? A simple change to our code give us:

```
In [6]:
```x = [2,4,6,8,10]
s = 0
for i in x:
s += (1/i)
print("The sum of the reciprocals of x is:", s)

```
```

`y`

or `z`

instead of `x`

? We'd have to go through our code example and change each instance of `x`

. That's boring and error prone. Instead let's write a Python function to abstract away the steps:

```
In [11]:
```def sum_of_reciprocals(x):
s = 0
for i in x:
s += (1.0/i)
return s

```
In [12]:
```# test our function with different inputs
x = [2,4,6,8,10]
y = [1,3,5,7,9]
z = [-1,1,-1,1]
print("The sum of the reciprocals of x is:", sum_of_reciprocals(x))
print("The sum of the reciprocals of y is:", sum_of_reciprocals(y))
print("The sum of the reciprocals of z is:", sum_of_reciprocals(z))

```
```

`sum`

function would be to use a list comprehension as shown below:

```
In [2]:
```sum_recip_x = sum([(1.0/i) for i in x])
print("The sum of the reciprocals of x is: ", sum_recip_x)

```
```

`sum_of_reciprocals`

function (or our solution using list comprehensions) doesn't deal with all possible cases we might use as input. If one of the elements of `x`

was zero what would happen (go ahead and try it)? What if we passed a list of strings to the function instead of numbers?

Now that you (hopefully) understand sum notation, it should be easy to understand product notation. We use product notation to represent the products of the elements of a sequence (i.e. the value we get when we multiply the elements of the sequence). As we'll see later in the course, product notation arises frequently in discussions of probability.

The mathematical shorthand for taking the product of a sequence of numbers is the capital Greek Pi ($\Pi$). In parallel to our first example above, the product of the first ten elements of a sequence $\mathbf{x}$ could be written this way: $$ \prod_{i=1}^{10} \mathbf{x}_i $$

Other than the use of $\Pi$ rather than $\Sigma$, this is identical to the sum notation above. As before the notation includes information about the upper and lower bounds of the element indices for which we want to apply the operation.

In a similar manner to what we saw before, we can represent the operation of getting the product of an arbitrary sequence $\mathbf{x}$ of length $n$ as follows: $$ \prod_{i=1}^{n} \mathbf{x}_i $$

```
In [17]:
```def product(x):
p = 1
for i in x:
p *= i # same as p = p * i
return p

```
In [19]:
```x = [2,4,6,8,10]
product(x)

```
Out[19]:
```

```
In [20]:
```product([(1.0/i) for i in x]) # use list comprehension to get reciprocals of x

```
Out[20]:
```