In [3]:

```
%pylab inline
```

J.R. Johansson and P.D. Nation

For more information about QuTiP see http://qutip.org

In [5]:

```
a=[1,2,3]
a=a+1
```

Instead we would have to do

In [6]:

```
for k in range(3):
a[k]=a[k]+1
```

**arrays** as our preferred data structure.

**vectorization** leads to very fast Python code, and can replace many of the for-loops that you would have use if you coded a problem using lists. As a general rule, **minimizing the number of for-loops maximizes the performance of your code**. To start using arrays, we can start with a simple list and use it as an argument to the array function

In [7]:

```
from numpy import *
a=array([1,2,3,4,5,6])
print(a)
```

In [8]:

```
a=array([2.0,4.0,8.0,16.0])
b=array([0,1+0j,1+1j,2-2j])
c=array(['a','b','c','d'])
print(a)
print(b)
print(c)
```

In general there are three different ways of creating arrays in Python:

First create a list and then call the array function using the list as an input argument.

Use NumPy functions that are designed to create arrays:

**zeros, ones, arange, linspace**.Import data into Python from file.

In [9]:

```
output=[n for n in range(10)]
print(output)
```

This code is doing the exact same thing as the longer expression

In [10]:

```
output=[]
for n in range(10):
output.append(n)
print(output)
```

We could turn this into an array quite easy

In [11]:

```
array(output)
```

Out[11]:

Or, we can save even more space and create the list inside of the array function:

In [12]:

```
array([n for n in range(10)])
```

Out[12]:

This can also be used to create more complicated arrays

In [13]:

```
array([2.0*k**0.563 for k in range(0,10,2)])
```

Out[13]:

In [14]:

```
zeros(5)
```

Out[14]:

In [15]:

```
ones(10)
```

Out[15]:

In [16]:

```
arange(5)
```

Out[16]:

In [17]:

```
arange(0,10,2)
```

Out[17]:

In [18]:

```
linspace(0,10,20) #makes an array of 20 points linearly spaced from 0 to 10
```

Out[18]:

In [19]:

```
linspace(-5,5,15) #15 points in range from -5 to 5
```

Out[19]:

**arrays can only hold one type of data** (integers, floats, strings, complex). If we try to combine different types of data, then the array function will **upcast** the data in the array such that it all has the same type

In [20]:

```
array([1,2,3.14]) # [int,int,float] -> [float,float,float]
```

Out[20]:

In [21]:

```
array([1.0,1+1j,'hello']) #array data is upcast to strings
```

Out[21]:

`dtype`

("data type") keyword argument. Frequently used dtypes are: `int, float, complex, bool, str, object`

, etc. For example, to convert a list of integers to floats we can write

In [22]:

```
array([1,2,3,4,5],dtype=float)
```

Out[22]:

In [23]:

```
arange(2,10,2,dtype=complex)
```

Out[23]:

In [24]:

```
array([k for k in range(10)],dtype=str)
```

Out[24]:

**we can not remove or add elements to an array once it has been created**. Therefore, we must know the size of the array before creating it.

**elementwise**, which means that each element gets acted on in the same way. This is an example of **vectorization**. For example:

In [25]:

```
a=array([1,2,3,4])
5.0*a #This gets upcasted because 5.0 is a float
```

Out[25]:

In [26]:

```
5*a**2-4
```

Out[26]:

Recall that none of these operations worked on Python lists.

In [27]:

```
x=linspace(-pi,pi,10)
sin(x)
```

Out[27]:

In [28]:

```
x=array([x**2 for x in range(4)])
sqrt(x)
```

Out[28]:

In [29]:

```
x=array([2*n+1 for n in range(10)])
sum(x) #sums up all elements in the array
```

Out[29]:

In [30]:

```
a=array([0,-1,2,-3,4])
print(a<0)
```

`True/False`

) values indicating whether a given element is less than zero. Or, for example, we can find all of the odd numbers in an array.

In [31]:

```
a=arange(10)
print((mod(a,2)!=0))
```

In [32]:

```
a=arange(20)
a[3::3]
```

Out[32]:

Now lets set each of these elements equal to -1.

In [33]:

```
a[3::3]=-1
print(a)
```

We can also slice the array so that it returns the original array in reverse

In [34]:

```
a=arange(10)
a[::-1]
```

Out[34]:

`True`

.

In [35]:

```
a=linspace(-10,10,20)
print(a[a<=-5])
```

We must be careful though. Checking for multiple conditionals is not allowed

In [36]:

```
print(a[-8<a<=-5])
```

`True/False`

values and return just a single value.

In [42]:

```
N=20
# generate a list from 2->N
numbers = []
for i in range(2,N+1): # This can be replaced by array
numbers.append(i)
# Run Seive of Eratosthenes algorithm marking nodes with -1
for j in range(N-1):
if numbers[j]!=-1:
p=numbers[j]
for k in range(j+p,N-1,p): # This can be replaced by array
numbers[k]=-1
# Collect all elements not -1 (these are the primes)
primes = []
for i in range(N-1): # This can be replaced by array
if numbers[i]!=-1:
primes.append(numbers[i])
print(primes)
```

Using arrays instead of lists simplifies the code:

In [41]:

```
N=20
# generate a list from 2->N
numbers=arange(2,N+1) # replaced for-loop with call to arange
# Run Seive of Eratosthenes algorithm
# by marking nodes with -1
for j in range(N-1):
if numbers[j]!=-1:
p=numbers[j]
numbers[j+p:N-1:p]=-1 # replaced for-loop by slicing array
# Collect all elements not -1 (these are the primes)
primes=numbers[numbers!=-1] # Used conditional statement to get elements !=-1
print(primes)
```

In [1]:

```
from IPython.core.display import HTML
def css_styling():
styles = open("styles/style.css", "r").read()
return HTML(styles)
css_styling()
```

Out[1]:

In [ ]:

```
```