Python for Quantum Mechanics: Numpy Tools#

from IPython.display import YouTubeVideo
YouTubeVideo('0ezvWFQhdck',width=700, height=400)
import numpy as np

Random Sampling (np.random)#

import numpy.random as rnd

rnd.random((n,m))

This gives us a uniform random distribution between \(0\rightarrow 1\), of shape \((n,m)\)

rarr = rnd.random((3,2))

print(rarr,'\n')
print(100*rarr,'\n')
[[0.30928649 0.32898824]
 [0.69632499 0.59220966]
 [0.3062973  0.27710655]] 

[[30.9286486  32.89882403]
 [69.63249884 59.22096565]
 [30.62972963 27.71065508]] 

rnd.normal(mu,sig,size)

This gives us a normal distribution with mean \(mu\) and standard deviation \(sig\), of length \(size\).

mu, sig, size = 100,10,10

norm_arr = rnd.normal(mu,sig,size)

print(norm_arr,'\n')
[114.25370723 109.77224905  99.63797278 100.61604811  88.96131716
 101.51811239  89.47384259  93.09429215 103.97483761  95.17300973] 

rnd.choice(array,size)

This randomly chooses elements from this \(array\), with length \(size\).

arr = np.arange(10)
print(arr,'\n')

size = 100

choo = rnd.choice(arr,size)
print(choo)
[0 1 2 3 4 5 6 7 8 9] 

[7 8 6 8 3 7 9 5 9 9 0 3 1 4 3 0 6 9 6 9 5 5 7 8 3 2 7 8 5 7 4 5 5 3 3 2 8
 4 7 1 6 8 2 7 4 8 9 4 2 8 5 0 3 2 0 1 5 6 2 7 0 4 8 8 5 1 4 5 7 8 3 6 8 5
 0 8 7 5 5 3 3 4 3 9 0 5 6 0 3 3 4 8 0 4 4 3 6 3 4 5]

Binary Operations#

Similar to the bitwise operations seen in week one, we can perform binary operations on Numpy arrays.

Bitwise Operations#

a = np.array([5,6,7,8]) # [0101, 0110, 0111,1000]
b = np.array([12,13,14,15]) #[1100, 1101, 1110, 1111]

np.bitwise_and(array1,array2) The bitwise-and operation:

print(np.bitwise_and(a,b)) #[0100, 0100, 0110,1000]
[4 4 6 8]

np.bitwise_or(array1,array2) The bitwise-or operation:

print(np.bitwise_or(a,b)) #[1101,1111,1111,1111]
[13 15 15 15]

np.bitwise_xor(array1,array2) The bitwise-xor operation:

print(np.bitwise_xor(a,b)) #[1001,1011,1001,0111]
[ 9 11  9  7]

np.invert(array) The bitwise-inversion operation:

print(np.invert(a)) #[-(0101+0001)=-0110, -0111, -1000, -1001]
[-6 -7 -8 -9]

Shift Operations#

a = np.array([5,6,7,8]) # [0101, 0110, 0111,1000]

np.left_shift(array,step) Shifts the binary representation of the number \(step\) to the left.

print(np.left_shift(a,1)) #[1010 = 10, 1100=12, 1110=14, 10000=16]
print(np.left_shift(a,2)) #[10100 = 20, 11000=24, 11100=28, 100000=32]
[10 12 14 16]
[20 24 28 32]

np.right_shift(array,step) Shifts the binary representation of the number \(step\) to the right.

print(np.right_shift(a,1)) #[0010 = 2, 0011=3, 0011=3, 0100=4]
print(np.right_shift(a,2)) #[0001 = 1, 0001=1, 0001=1, 0010=2]
[2 3 3 4]
[1 1 1 2]

Polynomials#

A polynomial is an expression with different variables and coefficients, they are encapsulated in the form

\[p(x,n) = c[0]x^n + c[2]x^{n-1} +...+ c[n-1]x ^1 + c[n]x^0 \]

where \(c[i]\) is the i-th coefficient.

In Numpy we can perform many operations with polynomials.

np.polyval(c,x)

We can evaluate a polynomial for \(p(x,n)\), given a list of coefficients \(c\) and \(x\).

For example,

\[ 1x^2+4x^1 -2x^0 \]

or $\( x^2+4x-2\)$

\[x=2\]
\[ \implies 2^2 + 4\times 2 -2 = 10\]
c = [1,4,-2]
x = 2

print('p = ',np.polyval(c,x))
p =  10

np.roots(c)

We can also find the roots of a polynomial, given \(c\).

c = [1,4,4]

print('x = ',np.roots(c))
x =  [-2. -2.]

np.polyfit(x,y,n)

We can also fit data points, (x,y), to some polynomial with a highest power of \(x^n\). This serves as a usual approximation for data.

x = 10*rnd.random(10)
y = 10*rnd.random(10)

poly = np.polyfit(x,y,2) # poly[0]x^2 + poly[1]x^1 + poly[2]x^0 = y 
print('poly = ',poly, '\n') 

print('c[0] = ', poly[0])
print('c[1] = ', poly[1])
print('c[2] = ', poly[2])
poly =  [-2.25901938e-02 -4.46632785e-03  5.49986853e+00] 

c[0] =  -0.022590193823405644
c[1] =  -0.004466327852596221
c[2] =  5.4998685335336255

Data Analysis#

We can calculate the mean, standard deviation, variation, min, max, sum and product of arrays.

data = 100*rnd.random((1000,2))
print(data)
[[30.49636051  3.29232635]
 [ 5.40517187 71.206984  ]
 [99.99268527  6.96008259]
 ...
 [20.64278275  0.4891114 ]
 [ 8.28252653 63.72162147]
 [22.7924933  44.91821739]]

np.mean(array)

This finds the average/mean of some data.

print(np.mean(data))
49.786737095600536

np.std(array)

The standard deviation.

print(np.std(data))
28.711654139899085

np.var(array)

The variance.

print(np.var(data))
824.3590834491844

np.min(array)

The minimum.

print(data.min())
0.012047158999284324

np.max(array)

The maximum.

print(data.max())
99.9926852658622

sum(array)

The sum.

data = np.arange(1,10)
print(data)
[1 2 3 4 5 6 7 8 9]
print(sum(data))
45

np.prod(array)

The product.

print(np.prod(data[0:4])) #1x2x3x4=24
24

np.cumsum(array)

The cumulative sum.

print(np.cumsum(data))
[ 1  3  6 10 15 21 28 36 45]

np.cumprod(array)

The cumulative product.

print(np.cumprod(data))
[     1      2      6     24    120    720   5040  40320 362880]

np.trace(array)

The trace of the array/matrix.(The sum along the diagonal.)

data1 = [1,5,10]
data2 = [13,4,27]
data3 = [7,18,100]


data = np.array([data1,data2,data3])
print(data)
[[  1   5  10]
 [ 13   4  27]
 [  7  18 100]]
print(np.trace(data))
105

I/O#

We can use \(np.loadtxt()\) and \(np.savetxt()\) to read in and save files. Recall 2.3 Inputs & Files and the related exercises involving the normalisation of quibits.

print(np.loadtxt("quibits.txt"))
[[2.3000e+01 2.5000e+01]
 [6.7000e+01 3.8470e+03]
 [2.3600e+02 8.7420e+03]
 [5.6000e+01 8.4300e+02]
 [4.6720e+03 7.8000e+01]
 [3.6200e+02 9.2490e+03]
 [4.6730e+03 4.3000e+01]
 [4.8210e+03 7.4890e+03]
 [2.3300e+02 2.9348e+04]
 [3.7200e+02 4.8900e+02]]
q_col1 = np.loadtxt("quibits.txt", delimiter = ' ', usecols= 0)
q_col2 = np.loadtxt("quibits.txt", delimiter = ' ', usecols= 1)

print(q_col1, '\n')
print(q_col2, '\n')
[  23.   67.  236.   56. 4672.  362. 4673. 4821.  233.  372.] 

[2.5000e+01 3.8470e+03 8.7420e+03 8.4300e+02 7.8000e+01 9.2490e+03
 4.3000e+01 7.4890e+03 2.9348e+04 4.8900e+02] 
#Normalise
q_col1, q_col2 = q_col1/(np.sqrt(q_col1**2+q_col2**2)), q_col2/(np.sqrt(q_col1**2+q_col2**2))

print(q_col1, '\n')
print(q_col2, '\n')

print(q_col1**2 + q_col2**2)

np.savetxt("normalised_quibits.txt", list(zip(q_col1,q_col2)))
[0.67705653 0.01741353 0.02698628 0.06628333 0.99986066 0.03910942
 0.99995767 0.54128523 0.00793896 0.6054546 ] 

[0.73593101 0.99984837 0.9996358  0.99780084 0.01669288 0.99923493
 0.00920141 0.84083905 0.99996849 0.79587984] 

[1. 1. 1. 1. 1. 1. 1. 1. 1. 1.]
print(np.loadtxt("normalised_quibits.txt", delimiter = ' '))
[[0.67705653 0.73593101]
 [0.01741353 0.99984837]
 [0.02698628 0.9996358 ]
 [0.06628333 0.99780084]
 [0.99986066 0.01669288]
 [0.03910942 0.99923493]
 [0.99995767 0.00920141]
 [0.54128523 0.84083905]
 [0.00793896 0.99996849]
 [0.6054546  0.79587984]]