In [1]:
using Gadfly
using RandomMatrices


WARNING: deprecated syntax "x[i:]" at /home/jiahao/.julia/Compose/src/cairo_backends.jl:380.
Use "x[i:end]" instead.

WARNING: deprecated syntax "x[i:]" at /home/jiahao/.julia/Compose/src/cairo_backends.jl:398.
Use "x[i:end]" instead.

WARNING: deprecated syntax "x[i:]" at /home/jiahao/.julia/Compose/src/cairo_backends.jl:562.
Use "x[i:end]" instead.

WARNING: deprecated syntax "x[i:]" at /home/jiahao/.julia/GZip/src/GZip.jl:460.
Use "x[i:end]" instead.
Warning: ignoring conflicting import of Stats.minmax into DataFrames

WARNING: deprecated syntax "x[i:]" at /home/jiahao/.julia/DataFrames/src/formula.jl:59.
Use "x[i:end]" instead.

WARNING: deprecated syntax "x[i:]" at /home/jiahao/.julia/DataFrames/src/formula.jl:72.
Use "x[i:end]" instead.

WARNING: deprecated syntax "x[i:]" at /home/jiahao/.julia/DataFrames/src/formula.jl:78.
Use "x[i:end]" instead.

WARNING: deprecated syntax "x[i:]" at /home/jiahao/.julia/DataFrames/src/formula.jl:93.
Use "x[i:end]" instead.

WARNING: deprecated syntax "x[i:]" at /home/jiahao/.julia/DataFrames/src/formula.jl:107.
Use "x[i:end]" instead.

WARNING: deprecated syntax "x[i:]" at /home/jiahao/.julia/DataFrames/src/formula.jl:112.
Use "x[i:end]" instead.

WARNING: deprecated syntax "x[i:]" at /home/jiahao/.julia/DataFrames/src/formula.jl:123.
Use "x[i:end]" instead.
Warning: using FS.rename in module DataFrames conflicts with an existing identifier.
Warning: could not import Distributions.kde into Stat
Warning: could not import Distributions.bandwidth into Stat
Warning: New definition 
    |(SynchronousStepCollection,Any) at /home/jiahao/.julia/BinDeps/src/BinDeps.jl:283
is ambiguous with: 
    |(Any,NAtype) at /home/jiahao/.julia/DataArrays/src/operators.jl:502.
To fix, define 
    |(SynchronousStepCollection,NAtype)
before the new definition.
Warning: New definition 
    |(Any,SynchronousStepCollection) at /home/jiahao/.julia/BinDeps/src/BinDeps.jl:286
is ambiguous with: 
    |(NAtype,Any) at /home/jiahao/.julia/DataArrays/src/operators.jl:502.
To fix, define 
    |(NAtype,SynchronousStepCollection)
before the new definition.
Warning: imported binding for Wishart overwritten in module RandomMatrices
Warning: import of Distributions.Wishart into RandomMatrices conflicts with an existing identifier; ignored.
Warning: import of Distributions.Wishart into RandomMatrices conflicts with an existing identifier; ignored.
Warning: using Distributions.Wishart in module RandomMatrices conflicts with an existing identifier.

In [2]:
#Let's generate a lot of Gaussian random variables
t = 1000 #Number of trials
data = randn(t);
_, b = hist(data, -3:0.5:3)
plot(x=-3:0.5:3, y=b, Geom.bar)
#plot(x=data, Geom.histogram)
#The answer is an approximation to the Bell curve


WARNING: radians2degrees is deprecated, use rad2deg instead.
 in radians2degrees at deprecated.jl:8
 in draw at /home/jiahao/.julia/Compose/src/d3.jl:439
 in draw at /home/jiahao/.julia/Compose/src/form.jl:376
 in draw at /home/jiahao/.julia/Compose/src/form.jl:157
 in drawpart at /home/jiahao/.julia/Compose/src/canvas.jl:291
 in draw at /home/jiahao/.julia/Compose/src/canvas.jl:242
 in writemime at /home/jiahao/.julia/Gadfly/src/Gadfly.jl:715
 in sprint at io.jl:467
Out[2]:
 in display_dict at /home/jiahao/.julia/IJulia/src/execute_request.jl:35
 in execute_request_0x535c5df2 at /home/jiahao/.julia/IJulia/src/execute_request.jl:178
 in eventloop at /home/jiahao/.julia/IJulia/src/IJulia.jl:68
 in anonymous at multi.jl:1308

In [5]:
#How about matrices of Gaussians, rather than just vectors of Gaussians?
#Let's look at the elements of a matrix using a spy plot.
A=randn(5,5)
A=A+A'
eigvals(A)
spy(A)


WARNING: findn_nzs is deprecated, use findnz instead.
 in findn_nzs at deprecated.jl:8
 in spy at /home/jiahao/.julia/Gadfly/src/poetry.jl:120
 in include_string at loading.jl:89
Out[5]:

In [6]:
#What happens when I look at the statistics of eigenvalues?
n = 100 #Dimension of matrix to generate
t = 1000 #Number of trials

rawdata={}
for i=1:t
    A = randn(n,n)
    A = (A+A')/sqrt(2n)
    push!(rawdata, A)
end

@time data = [eigvals(A) for A in rawdata]

data = [data...]; #Flattens the data
size(data)


elapsed time: 8.419130948 seconds (119497248 bytes allocated)
Out[6]:
(100000,)

In [7]:
#This is not a Bell curve, but instead is a semicircle!
plot(x=data, Geom.histogram)


Out[7]:

In [8]:
#Let's look at another statistic we could generate, which is
#the distribution of the largest eigenvalue

n = 100 #Dimension of matrix to generate
t = 1000 #Number of trials

@time data=[eigmax(A) for A in rawdata]
size(data)


elapsed time: 7.802901254 seconds (119561512 bytes allocated)
Out[8]:
(1000,)

In [9]:
#The resulting plot shows what is called the Tracy-Widom distribution
plot(x=data, Geom.histogram)


Out[9]:

In [10]:
#The RandomMatrices package provides a way to generate tridiagonal random matrices
methods(tridrand)


Out[10]:
3 methods for generic function tridrand:

In [66]:
#So let's generate a bunch of these matrices and look at them!
n = 100 #Dimension of matrix to generate
t = 1000 #Number of trials
rawdata_trid = [tridrand(GaussianHermite(2), n) for i=1:t];
rawdata_trid[1] #Look at one of these matrices


Out[66]:
100x100 SymTridiagonal{Float64}:
diag:  0.0609088  -0.0594983  -0.0642401  …  0.118317  0.0776712  -0.0787849
 sub:  0.998982  0.949272  0.973953  0.917701  …  0.219563  0.122287  0.155795

In [67]:
#Collect eigenvalue statistics. Note that is MUCH faster than before!
@time data=[eigvals(A) for A in rawdata_trid]
data=[data...]
plot(x=data, Geom.histogram)


elapsed time: 0.746425536 seconds (4071744 bytes allocated)
Out[67]:

In [68]:
#Collect maximal eigenvalue statistics. Note that is also MUCH faster than before!
@time data=[eigmax(A) for A in rawdata_trid]
@show data[1]
plot(x=data, Geom.histogram)


elapsed time: 0.274112176 seconds (25183744 bytes allocated)
data[1] => 1.926273279378988
Out[68]:

In [14]:
#Let's look at why eigvals and eigmax are so much faster than before.

#Earlier we were working with dense full matrices
spy(rawdata[1])


Out[14]:

In [15]:
#But the second time round we were generating special matrices!
spy(full(rawdata_trid[1])) #This has the vertical axis flipped


Out[15]:

In [18]:
#Let's look at the individual matrix elements
data_topleft = [A[51,10] for A in rawdata] #Each dense matrix element is a Gaussian.
plot(x=data_topleft, Geom.histogram)


Out[18]:

In [69]:
#But the off-diagonal elements of the random tridiagonal are different
data_topleft = [A.ev for A in rawdata_trid]
data_topleft = [data_topleft...]
plot(x=data_topleft, Geom.histogram) #Very clearly NOT Gaussian - a clue at what's going on...


Out[69]:

In [23]:
#The answer is multiple dispatch. Given a particular function:
help(eigvals)


Loading help data...
Base.eigvals(A)

   Returns the eigenvalues of "A".

In [24]:
#Julia knows multiple ways to calculate eigenvalues
methods(eigvals)


Out[24]:
12 methods for generic function eigvals:
  • eigvals(A::Triangular{T<:Number}) at linalg/triangular.jl:137
  • eigvals{T<:Union(Float64,Float32,Complex{Float32},Complex{Float64})}(m::SymTridiagonal{T<:Union(Float64,Float32,Complex{Float32},Complex{Float64})}) at linalg/tridiag.jl:78
  • eigvals{T<:Number}(D::Diagonal{T<:Number}) at linalg/diagonal.jl:102
  • eigvals(D::Diagonal{T}) at linalg/diagonal.jl:103
  • eigvals(M::Bidiagonal{T}) at linalg/bidiag.jl:179
  • eigvals{T<:Union(Float64,Float32,Complex{Float32},Complex{Float64})}(A::AbstractArray{T<:Union(Float64,Float32,Complex{Float32},Complex{Float64}),2}) at linalg/factorization.jl:494
  • eigvals{T<:Union(Float64,Float32,Complex{Float32},Complex{Float64})}(A::AbstractArray{T<:Union(Float64,Float32,Complex{Float32},Complex{Float64}),2},B::AbstractArray{T<:Union(Float64,Float32,Complex{Float32},Complex{Float64}),2}) at linalg/factorization.jl:559
  • eigvals(A::AbstractArray{T,2},B::AbstractArray{T,2}) at linalg/factorization.jl:560
  • eigvals{T<:Union(Float64,Float32,Complex{Float32},Complex{Float64})}(m::SymTridiagonal{T<:Union(Float64,Float32,Complex{Float32},Complex{Float64})},il::Int64,iu::Int64) at linalg/tridiag.jl:76
  • eigvals{T<:Union(Float64,Float32,Complex{Float32},Complex{Float64})}(m::SymTridiagonal{T<:Union(Float64,Float32,Complex{Float32},Complex{Float64})},vl::Real,vu::Real) at linalg/tridiag.jl:77
  • eigvals(A::AbstractArray{T,2},args...) at linalg/factorization.jl:495
  • eigvals(x::Number) at linalg/factorization.jl:497

In [70]:
#The first time we used this method for dense matrices:
@show typeof(rawdata[1])
@which eigvals(rawdata[1])
#which calls this LAPACK routine: http://www.netlib.no/netlib/lapack/double/dgeev.f


typeof(rawdata[1]) => Array{Float64,2}
eigvals{T<:Union(Float64,Float32,Complex{Float32},Complex{Float64})}(A::AbstractArray{T<:Union(Float64,Float32,Complex{Float32},Complex{Float64}),2}) at linalg/factorization.jl:494


In [71]:
#and the second time we used this method for symmetric tridiagonal matrices:
@show typeof(rawdata_trid[1])
@which eigvals(rawdata_trid[1])
#which calls this LAPACK routine: http://www.netlib.no/netlib/lapack/double/dstev.f


typeof(rawdata_trid[1]) => SymTridiagonal{Float64}
eigvals{T<:Union(Float64,Float32,Complex{Float32},Complex{Float64})}(m::SymTridiagonal{T<:Union(Float64,Float32,Complex{Float32},Complex{Float64})}) at linalg/tridiag.jl:78

Sneak preview of linear algebra with rational numbers


In [34]:
HilbertMatrix = [1//(i+j) for i=1:5, j=1:5]


Out[34]:
5x5 Array{Rational{Int64},2}:
 1//2  1//3  1//4  1//5  1//6 
 1//3  1//4  1//5  1//6  1//7 
 1//4  1//5  1//6  1//7  1//8 
 1//5  1//6  1//7  1//8  1//9 
 1//6  1//7  1//8  1//9  1//10

In [38]:
#With rationals, addition is exact
1//10 + 2//10


Out[38]:
3//10

In [39]:
#which is not always the case with floating-point
0.1 + 0.2


Out[39]:
0.30000000000000004

In [73]:
#Julia supports matrix problems using Rationals, so you can get numerically exact solutions
b = [1//i for i=1:5]
HilbertMatrix \ b


Out[73]:
5-element Array{Rational{Int64},1}:
   30//1
 -210//1
  560//1
 -630//1
  252//1

In [50]:
#We also have some support for matrix factorizations also
lufact(HilbertMatrix)


Out[50]:
LU{Rational{Int64}}(5x5 Array{Rational{Int64},2}:
 1//2   1//3    1//4     1//5      1//6     
 1//2   1//30   1//24    3//70     1//24    
 1//3  20//21   1//504   8//2205   1//210   
 2//3   5//6   -7//10    1//6300   1//2800  
 2//5   1//1    3//5    -3//14    -1//352800,[1,3,5,5,5],0)

eigmax


In [51]:
#We have a special function to compute the largest eigenvalue
methods(eigmax)


Out[51]:
4 methods for generic function eigmax:

In [55]:
@time rawdata_trid = [tridrand(GaussianHermite(2), 300) for i=1:1000];


elapsed time: 0.082317117 seconds (17880064 bytes allocated)

In [55]:
@time data = [maximum(eigvals(A)) for A in rawdata_trid];


elapsed time: 4.731329399 seconds (10039744 bytes allocated)

In [55]:
@time data = [eigmax(A) for A in rawdata_trid]; #significantly faster!


elapsed time: 0.673098931 seconds (67807744 bytes allocated)

QR factorizations


In [57]:
Q, R = qr(randn(3,3))


Out[57]:
(
3x3 Array{Float64,2}:
 -0.272009   0.551741  -0.788411
 -0.544343  -0.763844  -0.346746
 -0.793537   0.334849   0.508109,

3x3 Array{Float64,2}:
 -1.96941  0.380869  -0.233048 
  0.0      1.27859   -0.0188546
  0.0      0.0       -1.69737  )

In [58]:
Q'*Q


Out[58]:
3x3 Array{Float64,2}:
  1.0          1.11022e-16  -1.11022e-16
  1.11022e-16  1.0           1.11022e-16
 -1.11022e-16  1.11022e-16   1.0        

In [60]:
A=qrfact(randn(3,3))


Out[60]:
QR{Float64}(3x3 Array{Float64,2}:
 -0.492184   1.64617    0.725491
  0.520747  -0.904564   1.21284 
 -0.287648   0.630494  -0.473564,3x3 Array{Float64,2}:
 1.47719       -0.717468  0.0
 6.91388e-317   1.4311    0.0
 8.67207e-316   0.0       0.0)

In [61]:
names(A) #A convenient way to find out the fields of a given type


Out[61]:
2-element Array{Symbol,1}:
 :factors
 :T      

In [62]:
A.factors


Out[62]:
3x3 Array{Float64,2}:
 -0.492184   1.64617    0.725491
  0.520747  -0.904564   1.21284 
 -0.287648   0.630494  -0.473564

In [63]:
A.T


Out[63]:
3x3 Array{Float64,2}:
 1.47719       -0.717468  0.0
 6.91388e-317   1.4311    0.0
 8.67207e-316   0.0       0.0

In [ ]: