0

I've been given a matrix:

P <- matrix(c(0, 0, 0, 0.5, 0, 0.5, 0.1, 0.1, 0, 0.4, 0, 0.4, 0, 0.2, 0.2, 0.3, 0, 0.3, 0, 0, 0.3, 0.5, 0, 0.2, 0, 0, 0, 0.4, 0.6, 0, 0, 0, 0, 0, 0.4, 0.6), nrow = 6, ncol = 6, byrow = TRUE)

Using the functions, mpow, rows_equal, matrices_equal. I want to find when P^n converges, in other words what n is, when all the rows are equal in the matrix and when P^n = P^(n+1).

By just looking at the functions i have managed to deduce that around n=19-21 the matrix will converge.

Although, I want to find the right n using a loop. Here under are the functions mpow, rows_equal and matrices_equal. I know they can be written differently but please keep them as they are.

mpow <- function(P, n, d=4) {
  if (n == 0) diag(nrow(P)))
  else if (n== 1) P
  else P %*% mpow(P, n - 1))
  }

rows_equal <- function(P, d = 4) {
  P_new <- trunc(P * 10^d)
  for (k in 2:nrow(P_new)) {
    if (!all(P_new[1, ] == P_new[k, ])) {
      return(FALSE)}
      }
    return(TRUE)
    }

matrices_equal <- function(A, B, d = 4) {
  A_new <- trunc(A * 10^d)
  B_new <-trunc(B * 10^d)
  if (all(A_new == B_new)) TRUE else FALSE
  }

Now, to write the loop, we should do it something along the lines of:

First creating a function like so:

when_converged <- function(P) {...}

and

for (n in 1:50)

To try for when t.ex n = 50.

Although i don't know how to write the code correctly to do so, can anyone help me with that?

Thank you for reading my question.

Zheyuan Li
  • 71,365
  • 17
  • 180
  • 248
PeterNiklas
  • 75
  • 1
  • 9
  • Well I want to find when P Converges using the functions mpow, rows_equal and matrices_equal. My teacher gave the advice that we could make a function that takes a matrix P as input and shows us for what n, P^n = P^n+1. We should do that using a loop for instance like "for (n in 1:50)". – PeterNiklas Jul 01 '16 at 11:20
  • Please add linebreaks to your code. It is not readable. I assume that you define "convergence" as equality up to the precision controled by `d`? You probably know that convergence has to be proven and can't really be shown by a numerical exercise. – Roland Jul 01 '16 at 11:20
  • What do you know about the matrix? Is it e.g. quadratic and symmetric? See [here](http://www.statmethods.net/advstats/matrix.html). – Christoph Jul 01 '16 at 11:34

1 Answers1

2

Actually, a much better way is to do this:

## transition probability matrix
P <- matrix(c(0, 0, 0, 0.5, 0, 0.5, 0.1, 0.1, 0, 0.4, 0, 0.4, 0, 0.2, 0.2, 0.3, 0, 0.3, 0, 0, 0.3, 0.5, 0, 0.2, 0, 0, 0, 0.4, 0.6, 0, 0, 0, 0, 0, 0.4, 0.6), nrow = 6, ncol = 6, byrow = TRUE)

## a function to find stationary distribution
stydis <- function(P, tol = 1e-16) {
  n <- 1; e <- 1
  P0 <- P  ## transition matrix P0
  while(e > tol) {
    P <- P %*% P0  ## resulting matrix P
    e <- max(abs(sweep(P, 2, colMeans(P))))
    n <- n + 1
    }
  cat(paste("convergence after",n,"steps\n"))
  P[1, ]
  }

Then when you call the function:

stydis(P)
# convergence after 71 steps
# [1] 0.002590674 0.025906736 0.116580311 0.310880829 0.272020725 0.272020725

The function stydis, essentially continuously does:

P <- P %*% P0

until convergence of P is reached. Convergence is numerically determined by the L1 norm of discrepancy matrix:

sweep(P, 2, colMeans(P))

The L1 norm is the maximum, absolute value of all matrix elements. When the L1 norm drops below 1e-16, convergence occurs.

As you can see, convergence takes 71 steps. Now, we can obtain faster "convergence" by controlling tol (tolerance):

stydis(P, tol = 1e-4)
# convergence after 17 steps
# [1] 0.002589361 0.025898057 0.116564506 0.310881819 0.272068444 0.271997814

But if you check:

mpow(P, 17)
#             [,1]       [,2]      [,3]      [,4]      [,5]      [,6]
# [1,] 0.002589361 0.02589806 0.1165645 0.3108818 0.2720684 0.2719978
# [2,] 0.002589415 0.02589722 0.1165599 0.3108747 0.2720749 0.2720039
# [3,] 0.002589738 0.02589714 0.1165539 0.3108615 0.2720788 0.2720189
# [4,] 0.002590797 0.02590083 0.1165520 0.3108412 0.2720638 0.2720515
# [5,] 0.002592925 0.02592074 0.1166035 0.3108739 0.2719451 0.2720638
# [6,] 0.002588814 0.02590459 0.1166029 0.3109419 0.2720166 0.2719451

Only the first 4 digits are the same, as you put tol = 1e-4.

A floating point number has a maximum of 16 digits, so I would suggest you use tol = 1e-16 for reliable convergence test.

Zheyuan Li
  • 71,365
  • 17
  • 180
  • 248
  • Hey! Thank you for your answer, I see now that I didn't write that we should find when the matrix converges with 4 decimals places. Do i have to change the code in anyway for that? – PeterNiklas Jul 01 '16 at 11:50
  • Okej, well thank you for your answer! It's been to great help. I have a question about "tol = 1e-4" The thing is yes the first 4 decimals are all equal. However, if we for instance look at the 4th kolumn: we find: 0.3108412 and 0.3108615 When rounded up/down to 4 digits the upper one becomes 0.3108 and the lower one 0.3109. Which is not the same. Is there a way to see if they are equal to 4 decimals with the rousing up/down included? – PeterNiklas Jul 01 '16 at 12:26
  • Hello again, Your answer has been very useful. However, I'm wondering is there a way to create a loop with the function that I derived in the beginning, mpow, rows_equal and matrices_equal? I want to create a loop thats spits out the n for when P is converged. Under is what I've tried to do, can u help me add whats missing to get it right? when_converged <- function(P) for (n in 1:50) { A <- mpow(P, n) B <- mpow(P, n+1) } { if rows_equal(mpow(P, n), 4) and matrices_equal(A, B, 4) return(n) } – PeterNiklas Jul 05 '16 at 19:11