0% found this document useful (0 votes)
114 views48 pages

CS 51500 Homework 1 Solutions

The document contains solutions to homework problems involving matrix computations. Problem 4.2 asks about matrix multiplication of the matrices P and Q, where P and Q are partitioned matrices with identity matrices I along the main diagonal and matrices A and -A in the off-diagonals. The student applies blockwise matrix multiplication rules and shows that PQ results in the identity matrix I, indicating that P and Q are inverse matrices.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
114 views48 pages

CS 51500 Homework 1 Solutions

The document contains solutions to homework problems involving matrix computations. Problem 4.2 asks about matrix multiplication of the matrices P and Q, where P and Q are partitioned matrices with identity matrices I along the main diagonal and matrices A and -A in the off-diagonals. The student applies blockwise matrix multiplication rules and shows that PQ results in the identity matrix I, indicating that P and Q are inverse matrices.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd

HOMEWORK 1 SOLUTIONS

purdue university · cs 51500


Akshya Gupta
matrix computations
September 13, 2021

Problem 0
I would like to thank my wife Preeti Agarwal whose understanding of matrices
helped me with deriving the solutions for a number of problems in the homework
I would also like to thank Professor Gleich, Nadim and Sai for providing help with
the classes and homeworks. I also took references and directionfrom wikipedia,
particularly for Problem 8. Lastly I took a lot of reference from Julia online
documentation

1
Problem 1.1
    
2 3 5 1 2 −3 25 −51 21
 7 11 13 −4 −5 −6 =  54 −145 30
17 19 23 7 −8 9 102 −245 42

Julia code:
A=[
2 3 5
7 11 13
17 19 23
]

B = [
1 2 -3
-4 -5 -6
7 -8 9
]

A*B

2
Problem 1.2
xT y = 500500.0

Julia code:
x=ones(1000, 1)
y=1:1000

x'y

3
Problem 1.3
 
1.5 2.0 3.0
T
1.5 2.0 3.0
ex = 1.5

2.0 3.0
1.5 2.0 3.0
 
1.5 1.5 1.5 1.5
xeT = 2.0 2.0 2.0 2.0
3.0 3.0 3.0 3.0

Julia code:
x=[1.5 2 3]'
e = ones(4, 1)

display(e*x')
display(x*e')
Output:
julia>
4×3 Matrix{Float64}:
1.5 2.0 3.0
1.5 2.0 3.0
1.5 2.0 3.0
1.5 2.0 3.0
3×4 Matrix{Float64}:
1.5 1.5 1.5 1.5
2.0 2.0 2.0 2.0
3.0 3.0 3.0 3.0

4
Problem1.4
 
−5 4 2
e2 xT =
−5 4 2
 
−5
xeT1 =  4 
2
Julia code:
x=[-5 4 2]'
e1 = ones(1,1)
e2 = ones(2,1)

display(e2*x')
display(x*e1')
Output:
julia>
2×3 Matrix{Float64}:
-5.0 4.0 2.0
-5.0 4.0 2.0
3×1 Matrix{Float64}:
-5.0
4.0
2.0

5
Problem 1.5
   
2 3 5 10
 7 11 13 e3 = 31
17 19 23 59
 
2 3 5  
eT3  7 11 13 = 26 33 41
17 19 23
Julia code:
x=[
2 3 5
7 11 13
17 19 23
]
e1 = ones(1,1)
e3 = ones(3,1)

display(x*e3)
display(e3'*x)
Output:
julia>
3×1 Matrix{Float64}:
10.0
31.0
59.0
1×3 Matrix{Float64}:
26.0 33.0 41.0 2.0

6
Problem 1.6
    
2 0 0 1 2 3 2 4 6
0 1/2 0   10 8 6  = 5 4 3
0 0 −1 −2 −2 −2 2 2 2
Julia code:
x=[
2 0 0
0 1/2 0
0 0 -1
]

y=[
1 2 3
10 8 6
-2 -2 -2
]

display(x*y)

Output:
julia>
3×3 Matrix{Float64}:
2.0 4.0 6.0
5.0 4.0 3.0
2.0 2.0 2.0

7
Problem 2.1
Consider
 the 2-D array as mentioned in the problem: 
1 2 3 4 5 6 7 8 9 1 0 1 1 1 2 1
1 2 3 4 5 6 7 8 9 1 3 1 4 1 5 1
 
 .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. 
. . . . . . . . . . . . . . . .
9 8 7 6 5 4 3 2 1 0 1 1 1 2 1 3

In my understanding, the credit cards numbers can be decoded as:


1. Digit 1: Determines industry
2. Digit 2-7: Determines issuer
3. Remaining digits: Cardholder account number
The way cards are issued, no credit-card number should be able to be a
combination of any other card (or the hackers could use that to generate fake
credit card numbers) Thus there is no relationships in different rows of this 2D-
Array. No manipulations of this array would give us any more data or information.

Thus, this array is not a matrix.

8
Problem 2.2
 
Given 4096 X 10000 matrix, where each column represents a grayscale
image of 64X64 pixels.

In image processing, it’s a common practice to superimpose images by


simply adding the pixel models. We could very well have such images in our
dataset which were formed through such linear combination of other images in
the set.

Transformations can be applied on the transpose of this matrix to figure


out how many unique images were present in the dataset (and how many others
were a combination of those).

Thus, this array can be considered as a matrix

9
Problem 2.3
Given that A is the matrix from part 1.
Considering the new matrix B = AT A [16x16 matrix]

Typically AT A gives us a way of quantifying correlations between different rows


of A.
But in this case since the different credit-card numbers are supposed to show no
correlation, we do not really get any new information from the Bor any of its
transformations.

Thus, this array is not a matrix.

10
Problem 2.4
Given that A is the matrix from part 2.
Considering the new matrix B = AT A [10000X10000 matrix]

Typically AT A gives us a way of quantifying correlations between different rows


of A.
In this case, each entry in the matrix B can be considered to be denoting some
measure of correlation between different images.

Thus, this array can be considered as a matrix

11
Problem 3.1
Two diagonal matrices can only be multiplied if they have same dimensions,

For two n × n diagonal matrices A and B, C = AB means,

n
X
C i,k = Ai,j B j,k (1)
j=1

Since for a diagonal matrix A,

Ai,j = 0, ∀i 6= j

Ai,j 6= 0, ∀i = j

Thus, applying this to above equation,

C i,j = 0, ∀i 6= j
C i,j = Ai,i B i,i , ∀i = j

Which is again the definition of a diagonal matrix


Thus if A and B are diagonal matrices, then C = AB is also a diagonal matrix

12
Problem 3.2
Two upper triangular matrices can only be multiplied if they have same dimensions,

For two n × n upper triangular matrices A and B, C = AB means,

n
X
C i,k = Ai,j B j,k (2)
j=1

Since for a upper triangular matrix A,

Ai,j = 0, ∀i > j

Ai,j 6= 0, ∀i ≤ j

Thus, applying this to above equation

Ai,j 6= 0 if i ≤ j
and
B j,k 6= 0 if j ≤ k

For C i,j 6= 0, both Ai,j and B j,k must be non-zero for some j
⇒ C i,j 6= 0 only when i ≤ j and j ≤ k

C i,k = 0, ∀i > k
C i,k 6= 0, ∀i ≤ k

Which is again the definition of a diagonal matrix


Thus if A and B are diagonal matrices, then C = AB is also a diagonal matrix

13
Problem 3.3
Let A be a diagonal matrix and B be a general matrix,
C = AB means,
n
X
C i,k = Ai,j B j,k (3)
j=1

Since for a diagonal matrix A,

Ai,j = 0, ∀i 6= j

Ai,j 6= 0, ∀i = j

Applying this to the above equation

C i,k = Ai,i B i,k

Thus each row i of B is scaled by a factor of corresponding diagonal element in A

14
Problem 3.4
Let A be a diagonal matrix and B be a general matrix,
C = BA means,
n
X
C i,k = B i,j Aj,k ∀0 ≤ i, k ≤ n (4)
j=1

Since for a diagonal matrix A,

Ai,j = 0, ∀i 6= j

Ai,j 6= 0, ∀i = j

Applying this to the above equation

C i,k = B i,k Ak,k

Thus, each column k of B is scaled by a factor of corresponding diagonal element


in A

15
Problem 4.1
   
1 a 1 −a
Given matrices A = and B =
0 1 0 1
 
1 + 0 −a + a
AB =
0+0 0+1
 
1 0
⇒ AB = = I2
0 1

Also
 
1+0 a−a
BA =
0+0 0+1
 
1 0
⇒ BA = = I2
0 1

Thus A and B are inverse of each other, or B = A−1

16
Problem 4.2
   
I A I −A
Given matrices P = and Q =
0 I 0 I
Applying blockwise matrix multiplication rules
 
I + 0 −A + A
PQ =
0+0 0+I
 
I 0
⇒ PQ = =I
0 I

Similarly
 
I +0 A−A
QP =
0+0 0+I
 
I 0
⇒ PQ = =I
0 I

Thus P and Q are inverse of each other, or Q = P −1

17
Problem 4.3
 
A B
Given matrices P = where A and C are invertible
0 C
P can be decomposed into a matrix-product as:

A 0 I A−1 B
  
P =
0 C 0 I
−1  −1
A−1 B

I A 0
⇒ P −1 = (using(AB)−1 = A−1 B −1 )
0 I 0 C

A matrix of form D = diag(D 1 , D 2 , D 3 , . . .) has the inverse as D −1 =


diag(D −1 −1 −1
1 , D 2 , D 3 , . . .) [Since here DD
−1
= I and D −1 D = I ]
And, taking solution of Problem 4.2 into account

I −A−1 B A−1
  
−1 0
⇒P =
0 I 0 C −1
 −1
−A−1 BC −1

−1 A
⇒P = (Soln )
0 C −1

18
Problem 5.1
Given F and G are square diagonal matrices. Lets say they are of size n × n
Their product H = F G can be written as:

n
X
H i,k = F i,j Gj,k
j=1

Since for a diagonal matrix F ,

F i,j = 0, ∀i 6= j

F i,j 6= 0, ∀i = j

Thus, applying this to above equation,

H i,j = 0, ∀i 6= j
H i,j = F i,j Gi,j , ∀i = j

Rearraging the elements, we can write

H i,j = 0, ∀i 6= j

H i,j = Gi,j F i,j , ∀i = j

Thus, we can write,


n
X
H i,k = Gi,j F j,k
j=1

Hence, we can write


H = F G = GF

19
Problem 5.2
Given,
q(x) = Diag((I − H)x)(I + H)x (5)

Considering I and H to be n × n matrices, we get in Eq (5),

     
1 − h1,1 −h1,2 ... −h1,n x1 1 + h1,1 h1,2 ... h1,n x1
 −h2,1 1 − h2,2 ... −h2,n   x2   h2,1 1 + h2,2 ... h2,n   x2 
q(x) = Diag 
      
.. .. .. ..   ..   .. .. .. ..   .. 
 . . . .   .   . . . .  . 
−hn,1 −hn,2 ... 1 − hn,n xn hn,1 hn,2 ... 1 + hn,n xn

   
x1 − h1,1 x1 − h1,2 x2 . . . − h1,n xn x1 + h1,1 x1 + h1,2 x2 + . . . + h1,n xn
 x2 − h2,1 x1 − h2,2 x2 . . . − h2,n xn   x2 + h2,1 x1 + h2,2 x2 + . . . + h2,n xn 
= Diag 
   
..   .. 
 .   . 
xn − hn,1 x1 − hn,2 x2 . . . − hn,n xn xn + hn,1 x1 + hn,2 x2 + . . . + hn,n xn

Pn Pn
x1 − j h1,j xj

...

x1 + j h1,j xj

0 0
Pn Pn
 0 x2 − j h2,j xj ... 0  x2 + j h2,j xj 
=
  
..  .. 
 . Pn

P.n

0 0 . . . xn − j hn,j xj xn + j hn,j xj

Pn  Pn
x21 − ( j h1,j xj )2 x21 ( j h1,j xj )2
    
 x22 − ( nj h2,j xj )2   x22   ( nj h2,j xj )2
P P

=  =  .. −
     
.. .. 
.   .
Pn .
   
n
x2n − ( j hn,j xj )2 x2n ( j hn,j xj )2
P

⇒ q(x) = Diag(x)x − Diag(Hx)Hx

20
Problem 5.3
Given,
yT q(x) = xT Cx (6)

In the previous solution section we showed

q(x) = Diag(x)x − Diag(Hx)Hx

Putting this in LHS of Eq (6),

yT q(x) = yT Diag(x)x − yT Diag(Hx)Hx

Rearranging the vectors x, Hx and y (both are of same length), we can write,

yT q(x) = xT Diag(y)x − (Hx)T Diag(y)Hx


Since, (AB)T = B T AT

yT q(x) = xT Diag(y)x − xT H T Diag(y)Hx

Using Distributive properties of matrix multiplication

yT q(x) = xT (Diag(y) − H T Diag(y)H)x

Applying this to Eq (6), we get,

xT (Diag(y) − H T Diag(y)H)x = xT Cx

Thus we can write C in terms of y and H as,

C = Diag(y) − H T Diag(y)H (Soln )

21
Problem 6.1
Sparse Matrix showing adjacencies A:
10×10 SparseMatrixCSC{Int64, Int64} with 48 stored entries:
. . 1 . . . . . . 1
. . 1 . . . . . . 1
1 1 . . 1 1 . . . 1
. . . . 1 1 1 1 1 1
. . 1 1 . . 1 1 1 1
. . 1 1 . . 1 1 . 1
. . . 1 1 1 . 1 . 1
. . . 1 1 1 1 . . 1
. . . 1 1 . . . . 1
1 1 1 1 1 1 1 1 1 .

Coordinates matrix xy:


2×10 Matrix{Float64}:
0.112582 0.344454 0.120781 0.381813 0.242208 0.669931 0.844007 0.72525 0.066098 0.171655
0.368314 0.0566454 0.179574 0.815104 0.819778 0.453058 0.67919 0.923676 0.999172 0.420418

22
Problem 6.2
Plot of neighbor connections for 10 persons:

23
Problem 6.3
We need to fill in the missing code in the evolves teps function so that for the
given initial vector of infected as x0, probability of infecting a neighbor as p and
an adjacency matrix A Given the conditions:
p = 0.2
x0 = zeros(size(A,1))
x0[1] = 1
evolve_steps(x0, p, A, 10)

The final probability matrix X after 10 iterations is:


10×11 Matrix{Float64}:
1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0
0.0 0.0 0.0784 0.090647 0.110359 0.122842 0.134809 0.144292 0.152113 0.158224 0.162959
0.0 0.2 0.232 0.272446 0.294771 0.318103 0.33611 0.351586 0.363733 0.373316 0.380634
0.0 0.0 0.04 0.0980678 0.146417 0.191514 0.228331 0.258509 0.282196 0.300517 0.314412
0.0 0.0 0.0784 0.119399 0.170777 0.210193 0.245303 0.273059 0.295271 0.312349 0.325367
0.0 0.0 0.0784 0.112297 0.159197 0.194145 0.225779 0.250766 0.270849 0.286319 0.298134
0.0 0.0 0.04 0.0907942 0.135779 0.17689 0.210768 0.238573 0.26043 0.277372 0.290232
0.0 0.0 0.04 0.0907942 0.135779 0.17689 0.210768 0.238573 0.26043 0.277372 0.290232
0.0 0.0 0.04 0.0688616 0.0995726 0.12609 0.14877 0.167469 0.182367 0.194005 0.202901
0.0 0.2 0.232 0.29545 0.33945 0.380123 0.413122 0.439911 0.460918 0.477098 0.489353

Code used was:


function evolve(x::Vector, p::Real, A::AbstractMatrix)
log_not_infected = log.(1 .- p.*x)
y = 1 .- exp.(A*log_not_infected)
end
"""
Run k steps of the evolution and return the results as a matrix.
Each column of the matrix has the probabilities that the node
is infected under the `wrong` evolve function.
The first column of X is the initial vector x0.
At each iteration, we make sure the probabilities are at least x0 and these
are fixed.
"""
function evolve_steps(x0::Vector, p::Real, A::AbstractMatrix, k::Int)
X = zeros(length(x0),k+1)
X[:, 1] = x0 ##inserted code here
for i=1:k ##inserted code here
X[:,i+1] = max.(evolve(X[:,i], p, A), X[:,1]) # fix the initial probability x0
end ##inserted code here
return X
end

24
Problem 6.4.i
Plot of Expected number of infections at 20 iterations:

Code for the generation of plot


p = 0.2
x0 = zeros(size(A,1))
x0[1] = 1
X=evolve_steps(x0, p, A, 20)

ExpectedInfected = sum(X[:,2:end],dims=1)
display(ExpectedInfected)
plot(ExpectedInfected', legend = false, markershape = :ltriangle, w = 3)

xlabel!("Iteration")
ylabel!("Expected number of infected")
savefig("/Users/akshyag/Documents/Purdue/CS515_Homeworks/JuliaCodes/ExpectedInfected10_20steps")

25
Problem [Link]
Looking at the plots in the previous problem answer (6.4.i),
I feel that the plot indeed show the expected number of infections resulting from
an initial set of infections.
Running the simulation sufficient number of times, we can observe that the plots
ultimately converges.
In a real world scenario, ultimately all the persons would get infected (unless
isolated clusters are formed - because of vaccinations, lockdowns etc).
In case of this intuitive expected number of infections at any iteration, this is
covered. Because correctly modeled, all of the xi will converge to 1. And the
sum of expected columns would then converge to the number of people in the
simulation.
Thus this model of expected number of infected at an iteration is a sound one.

26
Problem 6.5.i
Code for the new approximated evolution steps. The rationale for taking a max
is because the probability of getting infected does not reduce as the iterations
proceed and can only increase as the infections grow.
"""
Run k steps of the approximate evolution and return the results as a matrix.
Each column of the matrix has the probabilities that the node
is infected under the `wrong` evolve function.
The first column of X is the initial vector x0.
At each iteration, we make sure the probabilities are at least x0 and these
are fixed.
"""
function approx_evolve_steps(x0::Vector, p::Real, A::AbstractMatrix, k::Int)
Y = zeros(length(x0),k+1)
Y[:, 1] = x0
for i=1:k
Y[:,i+1] = max.(p.*(A*Y[:,i]),x0)
end
return Y
end

27
Problem [Link]
Plots of different values of ρ, comparing the exact and approximate models.

28
Problem [Link]
From the plots in Problem [Link] solution, we can see that the plots start diverging
after ρ = 0.5

29
Problem 6.6
Code for 1000 node network with infections starting at node 1000
[Link]!(10) # ensure repeatable results...
A,xy = spatial_network(1000, 2)

p = 0.2
x0 = zeros(size(A,1))
x0[1000] = 1
X=evolve_steps(x0, p, A, 10)
Y=approx_evolve_steps(x0, p, A, 10)
display(sum(X[:,2:end],dims=1)[end])
display(sum(Y[:,2:end],dims=1)[end])
We notice the following results:
ρ Exact Approximate
0.05 1.47931 1.48714
0.1 3.88078 4.44701
0.15 19.69975 43.91785
0.2 62.03265 492.21783

30
Problem 6.7
Code used to generate the expected values:
"""
Function to calculate expected number of infections
for exact and approximate models given a vector of p,
initial infections vector x0, number of steps to run
and the adjacency matrix
"""
function simulate_expected_infections_10iter(A::AbstractMatrix, x0::Vector, pVector::Vector{Float64})
exact = Float64[]
approx = Float64[]
for i=1:size(pVector,1)
X=evolve_steps(x0, pVector[i], A, 10)
Y=approx_evolve_steps(x0, pVector[i], A, 10)
push!(exact, sum(X[:,2:end],dims=1)[end])
push!(approx, sum(Y[:,2:end],dims=1)[end])
end
return exact, approx
end

Evaluations:
Social Distancing 0%
ρ Exact Approximate
0.05 1.47931 1.48714
0.1 3.88078 4.44701
0.15 19.69975 43.91785
0.2 62.03265 492.21783
Social Distancing 10%
ρ Exact Approximate
0.05 1.47268 1.48032
0.1 3.72681 4.24232
0.15 18.1778 39.1121
0.2 57.3423 428.62
Social Distancing 20%
ρ Exact Approximate
0.05 1.44329 1.44925
0.1 3.19047 3.51014
0.15 12.9564 23.9737
0.2 41.6802 232.104
Social Distancing 30%
ρ Exact Approximate
0.05 1.41041 1.41545
0.1 2.66461 2.85352
0.15 7.88834 12.3597
0.2 24.7874 92.109
Social Distancing 40%
ρ Exact Approximate
0.05 1.31856 1.32110
0.1 2.19239 2.27393
0.15 5.43858 7.083111
0.2 16.3768 39.5507

31
Problem 6.7(continued)
Social Distancing 50%
ρ Exact Approximate
0.05 1.19099 1.19186
0.1 1.52555 1.54015
0.15 2.27787 2.41471
0.2 4.573 5.76687
Social Distancing 60%
ρ Exact Approximate
0.05 1.18397 1.1848
0.1 1.47751 1.49016
0.15 2.02066 2.12222
0.2 3.21915 3.92562
Thus we can clearly see that with the increase in the amount of social distancing,
we can drastically bring down the number of infected and the rate of spread of
infection.

32
Problem 6.8
Wearing of masks will directly effect the probability of getting infected in case we
come in close proximity of the infected neighbor.
We need to cover the case when either the person or neighbor or both or neither
wear masks.
Consider probability of infecting others while wearing a mask as αmask_save_others
Consider probability of getting infected while wearing a mask as αmask_self _saf ety
Consider probability of a person wearing a mask as ρwear_mask
So now instead of probability of getting infected, we have some extra qualification:

ρ(inf ection_masks) = ρwear_mask × αmask_self _saf ety × (1 − ρwear_mask )+


(1 − ρwear_mask ) × (1 − ρwear_mask )+
(1 − ρwear_mask ) × ρwear_mask × αmask_save_others +
ρwear_mask × αmask_self _saf ety × ρwear_mask × αmask_save_others

P (getting_inf ected) = P (getting_inf ected_without_masks) × ρ(inf ection_masks)

33
Problem 7.1
Given the transition matrix T as a sparse-matrix in I, J , V (co-ordinates) format.
Here,
T i,j = Probability of transition from state j to state i

Thus if we take the transpose of this matrix, we can say

T 0i,j = Probability of transition from state i to state j

Consider a vector of states x = [x1 , x2 , x3 . . . , x100 , x101 ]0 Where,

x1 = Expected number of steps needed to end game from position 1

x2 = Expected number of steps needed to end game from position 2


..
.
x100 = Expected number of steps needed to end game from position 100, i.e. from the end position
x101 = Expected number of steps needed to end game from position 101, i.e. from outside the board or start position

Now, by the given definition, we can write:

x100 = 0

We can also write, (where P (i → j) is probability of going from position i to j)

x99 = 1 + P (99 → 100)x100 + P (99 → 99)x99

x97 = 1 + P (97 → 100)x100 + P (97 → 99)x99 + P (97 → 97)x99 + P (97 → 78)x78


..
.
x2 = 1+P (2 → 3)x3 +P (2 → 5)x5 +P (2 → 6)x6 +P (2 → 7)x7 +P (2 → 8)x8 +P (2 → 14)x14
x101 = 1+P (101 → 2)x2 +P (101 → 3)x3 +P (101 → 5)x5 +P (101 → 6)x6 +P (101 → 14)x14 +P (101 → 38)x38

These can be re-written as:


x99 = 1 + T 099 x
x97 = 1 + T 097 x
..
.
x2 = 1 + T 02 x
x101 = 1 + T 0101 x

34
Problem 7.1 (continued)
Now, since the bases of ladders and tops of chutes are positions on which we do
not stop (for ladders, we go to their tops and for chutes we go to their bases),

We can assume any number for xi for such positions. For simplicity sake, lets
set this to 1. This is ok because we have all 0’s in the rows of matrix T 0 for such
positions.

Thus we can write the previous set of equations as (combining with all the data
about xi we have so far):
x101 = 1 + T 0101 x
x100 = 0
x99 = 1 + T 099 x
x98 = 1 + T 098 x
x97 = 1 + T 097 x
..
.
x2 = 1 + T 02 x
x1 = 1 + T 01 x

Or, to generalize

x100 = 0
xi = 1 + T 0i x where i = 101, 1, 2, . . . , 98, 99

Or, rewriting this as a matrix

Ix − T 0 x = [1 1 1 . . . 1 1 0]0
⇒ (I − T 0 )x = [1 1 1 . . . 1 1 0]0
⇒ x = (I − T 0 )−1 [1 1 1 . . . 1 1 0]0

On solving the above linear equation, we get

Expected number of steps from start, x101 = 40 (soln)

35
Problem 7.1 (continued)
We can solve this equation in Julia through following code:
using CSV, DataFrames, SparseArrays, Plots

CLMatrixDF = [Link]("[Link]", DataFrame, header=false)


CLMatrixCoords = [Link]("[Link]", DataFrame, header=false)

Ivec = CLMatrixDF[!,1]
Jvec = CLMatrixDF[!,2]
Vvec = CLMatrixDF[!,3]

xc = CLMatrixCoords[!,1]
yc = CLMatrixCoords[!,2]

# the sparse matrix representation of chutes and ladders game transition matrix
T = sparse(Ivec, Jvec, Vvec, 101, 101)
# Starting state = 101
# Ending state = 100
Id101 = zeros(101,101)
Id101[diagind(Id101)] .= 1
b=ones(101)
b[end-1] = 0
x = (Id101 - T')\b
y = hcat(1:length(x), x)
sorted_x = y[sortperm(y[:,2]), :]
display(sorted_x[end-10:end, :]) # To list starting points where the expected no. of steps is max
Output:
julia>
11×2 Matrix{Float64}:
13.0 37.8362
12.0 38.2165
11.0 38.643
8.0 38.9844
10.0 39.1129
7.0 39.2315
6.0 39.464
3.0 39.5749
101.0 39.5984
5.0 39.6719
2.0 40.0714
We can see that starting points 2, 5, 101, 3, 6, 7 and 10 all have the expected
number of steps as 40 (considering we need a whole number of steps, because we
cannot play a fractional turn)

36
Problem 7.2
One way to decide how many iterations to run is to stop when the new value to
be added to the final answer is too small to matter. In the code we supplied an
upper bound to number of iterations because we do not want to get caught with
a non-converging series.
From the output, we got that 999 iterations were needed to get upto this point
The code to iteratively arrive at the expected length of the game:
function expected_length_of_game(k, T)
p_k = zeros(101,1)
p_k[101] = 1 # initial state.

expected_len = 0

for i=1:k-1
p_k=T*p_k
# we can stop early if i*p_k is too small ~ eps(Float64)
if (p_k[100] != 0 && i*p_k[100] < eps(Float64))
println("Further iterations will not make a difference.\nIteration=", i)
break;
end
expected_len += i*p_k[100]
end
return expected_len
end

@show expected_length_of_game(2000, T)
Output is:
Further iterations will not make a difference.
Iteration=999
expected_length_of_game(2000, T) = 39.598369794090615

37
Problem 8.1
To write the linear system of equations for n = 3
Given boundary conditions for this case can be written as:
u(x0 , yj ) = u(x3 , yj ) = u(xi , y0 ) = u(xi , y3 ) = 0.

And we can rewrite the discretized Poisson’s equation as:


f (xi , yj )
u(xi−1 , yj ) + u(xi , yj−1 ) − 4u(xi , yj ) + u(xi+1 , yj ) + u(xi , yj+1 ) =
n2
Thus,
For i = 0, j = 1, 2, 3, We can simply write (similarly for i=3, j=0 and j=3):
u(xi , yj ) = 0
For i = 1, j = 1:
f (x1 , y1 )
u(x0 , y1 ) + u(x1 , y0 ) − 4u(x1 , y1 ) + u(x2 , y1 ) + u(x1 , y2 ) =
n2
f (x1 , y1 )
⇒ −4u(x1 , y1 ) + u(x2 , y1 ) + u(x1 , y2 ) =
n2
For i = 1, j = 2:
f (x1 , y2 )
u(x0 , y2 ) + u(x1 , y1 ) − 4u(x1 , y2 ) + u(x2 , y2 ) + u(x1 , y3 ) =
n2
f (x1 , y2 )
⇒ u(x1 , y1 ) − 4u(x1 , y2 ) + u(x2 , y2 ) =
n2
For i = 2, j = 1:
f (x2 , y1 )
u(x1 , y1 ) + u(x2 , y0 ) − 4u(x2 , y1 ) + u(x3 , y1 ) + u(x2 , y2 ) =
n2
f (x2 , y1 )
⇒ u(x1 , y1 ) − 4u(x2 , y1 ) + u(x2 , y2 ) =
n2
For i = 2, j = 2:
f (x2 , y2 )
u(x1 , y2 ) + u(x2 , y1 ) − 4u(x2 , y2 ) + u(x3 , y2 ) + u(x2 , y3 ) =
n2
f (x2 , y2 )
⇒ u(x1 , y2 ) + u(x2 , y1 ) − 4u(x2 , y2 ) =
n2
Combining these equations with the boundary conditions, we can write (Solution):
 
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
 
 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
 
 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
 
 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
 
 0 0 0 0 0 −4 1 0 0 1 0 0 0 0 0 0 
 
 0 0 0 0 0 1 −4 0 0 0 1 0 0 0 0 0 
 
 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
  u = n2 × f
 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
 
 0 0 0 0 0 1
 0 0 0 −4 1 0 0 0 0 0  
 0 0 0 0 0 0
 1 0 0 1 −4 0 0 0 0 0  
 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
 
 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
 
 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
 
 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0

38
Problem 8.1(continued)
Now since the above matrix does not show a lot of structure, We can notice that
there are following structures:
1. There are -4s along main diagonal
2. There are 1s in sub-diagonal and super-diagonal
3. There are 1s in the diagonal three diagonal below and three diagonals above
the main diagonal
Since the other u(xi , yj ) are 0, any linear combination of those will not effect the
respective f (xi , yj ) values.
Thus we can complete the diagonals that were mentioned above and have a more
structured matrix linear equation as:
 
−4 1 0 0 1 0 0 0 0 0 0 0 0 0 0 0
 1 −4 1 0 0 1 0 0 0 0 0 0 0 0 0 0 
 
 0
 1 −4 1 0 0 1 0 0 0 0 0 0 0 0 0 

 0
 0 1 −4 1 0 0 1 0 0 0 0 0 0 0 0 

 1
 0 0 1 −4 1 0 0 1 0 0 0 0 0 0 0 

 0
 1 0 0 1 −4 1 0 0 1 0 0 0 0 0 0 

 0
 0 1 0 0 1 −4 1 0 0 1 0 0 0 0 0 

 0
 0 0 1 0 0 1 −4 1 0 0 1 0 0 0 0  u = n2 ×f

 0
 0 0 0 1 0 0 1 −4 1 0 0 1 0 0 0 

 0
 0 0 0 0 1 0 0 1 −4 1 0 0 1 0 0 

 0
 0 0 0 0 0 1 0 0 1 −4 1 0 0 1 0 

 0
 0 0 0 0 0 0 1 0 0 1 −4 1 0 0 1 

 0
 0 0 0 0 0 0 0 1 0 0 1 −4 1 0 0 

 0
 0 0 0 0 0 0 0 0 1 0 0 1 −4 1 0 

 0 0 0 0 0 0 0 0 0 0 1 0 0 1 −4 1 
0 0 0 0 0 0 0 0 0 0 0 1 0 0 1 −4

We can add further structure by removing some 1s from the sub and super
diagonals so that the sub matrices can be written as I 4×4
Hence finally we can write the equation as:
 
−4 1 0 0 1 0 0 0 0 0 0 0 0 0 0 0
 1 −4 1 0 0 1 0 0 0 0 0 0 0 0 0 0 
 
 0
 1 −4 1 0 0 1 0 0 0 0 0 0 0 0 0 

 0
 0 1 −4 0 0 0 1 0 0 0 0 0 0 0 0 

 1
 0 0 0 −4 1 0 0 1 0 0 0 0 0 0 0 

 0
 1 0 0 1 −4 1 0 0 1 0 0 0 0 0 0 

 0
 0 1 0 0 1 −4 1 0 0 1 0 0 0 0 0 

 0
 0 0 1 0 0 1 −4 0 0 0 1 0 0 0 0  u = n2 ×f

 0
 0 0 0 1 0 0 0 −4 1 0 0 1 0 0 0 

 0
 0 0 0 0 1 0 0 1 −4 1 0 0 1 0 0 

 0
 0 0 0 0 0 1 0 0 1 −4 1 0 0 1 0 

 0
 0 0 0 0 0 0 1 0 0 1 −4 0 0 0 1 

 0
 0 0 0 0 0 0 0 1 0 0 0 −4 1 0 0 

 0
 0 0 0 0 0 0 0 0 1 0 0 1 −4 1 0 

 0 0 0 0 0 0 0 0 0 0 1 0 0 1 −4 1 
0 0 0 0 0 0 0 0 0 0 0 1 0 0 1 −4

39
Problem 8.2
From above we can see that, the matrix has a structure as:
     
A I 0 0 −4 1 0 0 1 0 0 0
I A I 0   1 −4 1 0  0 1 0 0
 0 I A I  Where A =  0
    and I =   (4×4 identity matrix)
1 −4 1  0 0 1 0
0 0 I A 0 0 1 −4 0 0 0 1
We can see that:
1. Diagonal is all -4
2. Sub-diagonal is repeated ones vector with every nth element set to 0
3. Super-diagonal has similar structure as sub-diagonal
4. There are diagonals of ones which are n+1 away from main diagonal
Code:
using SparseArrays, Random, Plots

function laplacian(n::Integer, f::Function)


N = (n+1)^2 # number of element in u vector
fvec = zeros(N)
# the transpose mirrors the row indexing we had before.
G = reshape(1:N, n+1, n+1)' # index map, like we saw before;
h = 1.0/(n)

# Form the sparse matrix:


# diagonal is all -4
# sub diagonal is repeated ones vector with every (n+1)th element set to 0
# superdiagonal is similar
# Then there are diagonals of ones
diagVec = -4 .* ones(N)
sub_sup_diag = ones(N-1)
for i=n+1:n:N-1
sub_sup_diag[i] = 0
end
# Now there will be identity diagonals
length_identity_diagonal = n * (n+1)
vector_identity_diagonal = ones(length_identity_diagonal)
position_identity_diagonal = n+1 # -(n+1) for sub and n+1 for super
A = spdiagm(-position_identity_diagonal=>vector_identity_diagonal,
-1 => sub_sup_diag,
0 => diagVec,
1 => sub_sup_diag,
position_identity_diagonal=>vector_identity_diagonal)
for i=0:n
for j=0:n
row = G[i+1,j+1]
if i==0 || j == 0 || i == n || j == n
fvec[row] = 0.0
else
fvec[row] = f(i*h, j*h)*h^2
end
end
end
return A, fvec
end

40
Problem 8.2
The sparse matrix and function vector for n = 10 and f (x, y) = 1 was generated
by:
n = 10
f(::Float64, ::Float64) = 1
A1, f1 = laplacian(n, f)

41
Problem 8.3
For solving and plotting for u(x, y), we ran the code:
n = 10
f(::Float64, ::Float64) = 1
A1, f1 = laplacian(n, f)
u1 = A1\f1
u_mat = reshape(u1, n+1, n+1)
surface([0:10], [0:10], u_mat)
savefig("SurfacePlot_n10")

42
Problem 8.4
As in the solution of Problem 8.1, we have the matrix equation as
   
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0   0 
   
 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0    0 
  
 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0   0 
   
 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0   0 
   
 0
 0 0 0 0 −4 1 0 0 1 0 0 0 0 0 0  
f (1, 1)
 
 0
 0 0 0 0 1 −4 0 0 0 1 0 0 0 0 0  
f (1, 2)
 
 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0   u = n 2 × 0 
 

 0 
 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0    

 0
 0 0 0 0 1 0 0 0 −4 1 0 0 0 0 0  
f (2, 1)
 
 0
 0 0 0 0 0 1 0 0 1 −4 0 0 0 0 0  
f (2, 2)
 
 0 
 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0    

 0 
 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0    

 0 
 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0    

 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0   0 
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0

Removing the 0 rows from both sides, we can re-write the equations as
     
−4 1 1 0 u1,1 f (1, 1)
1
 −4 0 1 × u1,2  = n2 × f (1, 2)
   
1 0 −4 1  u2,1   f (2, 1)
0 1 1 −4 u2,2 f (2, 2)

Generalizing the matrix will be of form:


 
A I 0 0
I A I 0
 
0 I A I
0 0 I A
Where,  
−4 1 ... 0 0
1
 −4 1 ... 0

A =  ... .. .. .. ..
 (n + 1 × n + 1 matrix)
 
 . . . .

0 ... 1 −4 1
0 ... 0 1 −4
 
1 0 ... 0 0
0 1
 ... 0 0 
I =  ... ... .. .. ..  (n + 1 × n + 1 identity matrix)

 . . . 
0 0 ... 1 0
0 0 ... 0 1

Which clearly shows a symmetric structure.

43
Problem 9.1
Code:
""" Returns y = A'*x where A is given by the CSC arrays
colptr, rowval, nzval, m, n and x is the vector. """
function csc_transpose_matvec(colptr, rowval, nzval, m, n, x)
y = zeros(n) # allocate output
for j=1:length(colptr)-1 # for each column ...
for nzi=colptr[j]:colptr[j+1]-1 # for each entry in the column
i = rowval[nzi]
v = nzval[nzi]
# For transpose, row and cols are interchanged
# So we go over all elements of the columns from original
# matrix (ie rows for all range of nzi in the give iteration)
# and multiply them with the value and store it in the
# columns location j
y[j] += v*x[i]
end
end
return y
end

println("B'*x1 = ",B'*x1)
println("csc_transpose_matvec([Link], [Link], [Link], 7, 6, x1) = ",
csc_transpose_matvec([Link], [Link], [Link], 7, 6, x1))

Output:
julia>
B'*x1 = [0; 56; 138; 118; 98; 200]
csc_transpose_matvec([Link], [Link], [Link], 7, 6, x1) = [0.0, 56.0, 138.0, 118.0, 98.0, 200.0]

44
Problem 9.2
Code:
""" Returns = A[:,i]'*x where A is given by the CSC arrays
colptr, rowval, nzval, m, n and x is the vector. """
function csc_column_projection(colptr, rowval, nzval, m, n, i, x)
y = 0
for nzi = colptr[i]:colptr[i+1]-1
i = rowval[nzi]
v = nzval[nzi]
# We go over all elements of the column from original
# matrix (ie rows for all range of nzi for given colptr)
# and multiply them with the nz-value and store it
y += v*x[i]
end
return y
end
@show B[:,3]'*x1
@show csc_column_projection([Link], [Link], [Link], 7, 6, 3, x1)

Output:
(B[:, 3])' * x1 = [138]
csc_column_projection([Link], [Link], [Link], 7, 6, 3, x1) = 138

45
Problem 9.3
Code:
""" Returns rho = A[:,i]'*A[:,j] where A is given by the CSC arrays
colptr, rowval, nzval, m, n and i, and j are the column indices. """
function csc_col_col_prod(colptr, rowval, nzval, m, n, i, j)
y = 0
nzi = colptr[i]
nzj = colptr[j]
while nzi <= colptr[i+1]-1 && nzj <= colptr[j+1]-1
rowi = rowval[nzi]
rowj = rowval[nzj]
if rowi == rowj
y += nzval[nzi]*nzval[nzj]
nzi += 1
nzj += 1

elseif rowi > rowj


# there could be a relevant row in A[:,j] vector further down
nzj += 1
else
# there could be a relevant row in A[:,i] vector further down
nzi += 1
end
end
return y
end

@show B[:,2]'*B[:,3]
@show csc_col_col_prod([Link], [Link], [Link], 7, 6, 2, 3 )
@show B[:,3]'*B[:,6]
@show csc_col_col_prod([Link], [Link], [Link], 7, 6, 3, 6 )

Output:
(B[:, 2])' * B[:, 3] = 208
csc_col_col_prod([Link], [Link], [Link], 7, 6, 2, 3) = 208
(B[:, 3])' * B[:, 6] = 180
csc_col_col_prod([Link], [Link], [Link], 7, 6, 3, 6) = 180

46
Problem 9.4
Code:
""" Returns rho = A[i,j] where A is given by the CSC arrays
colptr, rowval, nzval, m, n and i, and j are the column indices. """
function csc_lookup(colptr, rowval, nzval, m, n, i, j)
for nzi = colptr[j]:colptr[j+1]-1
if i == rowval[nzi]
return nzval[nzi]
end
end
return 0
end

@show B[1,2]
@show csc_lookup([Link], [Link], [Link], 7, 6, 1, 2)
@show B[4,3]
@show csc_lookup([Link], [Link], [Link], 7, 6, 4, 3)
@show B[6,5]
@show csc_lookup([Link], [Link], [Link], 7, 6, 6, 5)

Output:
julia>
B[1, 2] = 16
csc_lookup([Link], [Link], [Link], 7, 6, 1, 2) = 16
B[4, 3] = 9
csc_lookup([Link], [Link], [Link], 7, 6, 4, 3) = 9
B[6, 5] = 0
csc_lookup([Link], [Link], [Link], 7, 6, 6, 5) = 0

47
Problem 9.5
Code:
""" Returns x = A[i,:] where A is given by the CSC arrays
colptr, rowval, nzval, m, n and i is the row index . """
function csc_lookup_row(colptr, rowval, nzval, m, n, i)
y = zeros(n) # since row will have n elements
for j=1:length(colptr)-1 # for each column ...
for nzi=colptr[j]:colptr[j+1]-1 # for each entry in the column
if i == rowval[nzi]
y[j] = nzval[nzi]
end
end
end
return y
end
display(A[2,:])
display(csc_lookup_row([Link], [Link], [Link], 7, 6, 2))

Output:
julia>
6-element Vector{Int64}:
0
0
10
12
0
0
6-element Vector{Float64}:
0.0
0.0
10.0
12.0
0.0
0.0

48

You might also like