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.91216062 0.12074881]
 [0.01691399 0.65971895]
 [0.03409919 0.71638617]] 

[[91.21606185 12.07488068]
 [ 1.69139936 65.97189453]
 [ 3.40991851 71.63861657]] 

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')
[109.85258764 110.03299906 110.3406091  108.86650419  98.66439488
  87.88079625 118.4172657  110.05681778  96.58434912  90.13171615] 

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] 

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

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 =  [ 0.15318928 -1.46361298  8.3404622 ] 

c[0] =  0.15318927626765813
c[1] =  -1.4636129814764012
c[2] =  8.340462203834697

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)
[[44.77808706 30.68621983]
 [83.53466436 65.38420451]
 [67.27158589 65.89424838]
 ...
 [75.91462553  8.60942722]
 [81.89209388 88.06786131]
 [43.81097408 89.03144589]]

np.mean(array)

This finds the average/mean of some data.

print(np.mean(data))
50.611578720352085

np.std(array)

The standard deviation.

print(np.std(data))
28.522436534235837

np.var(array)

The variance.

print(np.var(data))
813.5293858495113

np.min(array)

The minimum.

print(data.min())
0.0024326101346616724

np.max(array)

The maximum.

print(data.max())
99.91655216422271

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]]