# Stochasticke simulacne metody
# Radoslav Harman, KAMS FMFI UK
# Cvicenie 3 (Generovanie spojitych premennych a vektorov) - strucny zaznam prikazov pre R

# Poznamka: Nasledovne funkcie sluzia na demonstraciu teoretickych principov generovania.
# Na prakticke simulacie v jazyku R je vyhodnejsie pouzit standardne funkcie rnorm, rbeta a rgamma.


rnorm.rej <- function(n, mu=0, sigma=1) {
   # Specialnou zamietacou metodou generuje n iid realizacii z N(mu,sigma^2)
   
   res <- rep(0, n)
   for (i in 1:n) {
      ok <- FALSE
      while (!ok) {
         Y <- rexp(1)
         if (runif(1) < exp(-(Y - 1)^2/2)) ok <- TRUE
      }
      res[i] <- Y
   }
   rsgn <- 2*floor(2*runif(n)) - 1
   
   return(sigma * rsgn * res + mu)
}

res <- rnorm.rej(10000); hist(res); ks.test(res, pnorm)


rnorm.bm <- function(n, mu=0, sigma=1) {
   # Boxovou-Muellerovou metodou generuje n iid realizacii z N(mu,sigma^2)
   
   m <- floor(n/2) + 1; res <- c(0, 2*m)
   for (i in 1:m) {
      U <- runif(1); L <- rexp(1)
      res[2*i - 1] <- sqrt(2*L)*cos(2*pi*U)
      res[2*i] <- sqrt(2*L)*sin(2*pi*U)
   }
   
   return(sigma*res + mu)
}

res <- rnorm.bm(10000); hist(res); ks.test(res, pnorm)


rbeta.rej <- function(n, a=1, b=1) {
   # Von-Johnkovou metodou generuje n iid realizacii z Be(a,b)
   
   res <- rep(0, n)
   for (i in 1:n) {
      ok <- FALSE
      while (!ok) {
         X <- runif(2)
         V <- X[1]^(1/a); W <- X[2]^(1/b)
         if (V + W < 1) ok <- TRUE
      }
      res[i] <- V/(V + W)
   }
   
   return(res)
}

res <- rbeta.rej(10000, a = 2, b = 2); hist(res)
ks.test(res, pbeta, shape1 = 2, shape2 = 2)


rgamma.bex <- function(n, a=1, b=1)
{
   # Generuje n iid realizacii z Gamma(a,b)
   
   m <- floor(b); r <- b - m
   res <- rep(0, n)
   for (i in 1:n) {
      Y <- 0; if (r > 0) Y <- rbeta(1, shape1 = r, shape2 = 1 - r)
      Z <- 0; if (m > 0) Z <- sum(rexp(m))
      res[i] <- (Z + rexp(1)*Y)/a
   }
   
   return(res)
}

res <- rgamma.bex(10000, a = 2, b = 3); hist(res)
ks.test(res, pgamma, rate = 2, shape = 3)


rnorm.2d <- function(n, mu1=0, mu2=0, sd1=1, sd2=1, rho=0) {
   # Genertor realizacii vektora (X1,X2) zo zdruzene normalneho rozdelenia
   # mu1=E(X1), mu2=E(X2), sd1^2=D(X1), sd2^2=D(X2), rho=cor(X1,X2)
   
   X1 <- rnorm(n); X2 <- rnorm(n)
   Y1 <- sd1*X1 + mu1
   Y2 <- sd2*(rho*X1 + sqrt(1 - rho^2)*X2) + mu2
   
   return(rbind(Y1, Y2))
}

res <- rnorm.2d(5000); plot(res[1,], res[2,], pch = 19, cex = 0.1)
res <- rnorm.2d(5000, rho = 0.5); plot(res[1,], res[2,], pch = 19, cex = 0.1)
res <- rnorm.2d(5000, rho = -0.9); plot(res[1,], res[2,], pch = 19, cex = 0.1)


rsimplex <- function(n, m) {
   # Genertor n realizacii z rovnomerneho rozdelenia na m-rozmernom simplexe
   # Poznamka: klasicky, nie pravdepodobnostny simplex
   
   res <- matrix(ncol = n, nrow = m)
   for (i in 1:n) {
      X <- runif(m); Y <- sort(X)
      Z <- c(Y[1], Y[2:m] - Y[1:(m - 1)])
      res[, i] <- Z
   }
   
   return(res)
}

res <- rsimplex(10000, 2); plot(res[1,], res[2,], pch = 19, cex = 0.1, asp = 1) # +m=3,10


rsphere <- function(n, m) {
   # Genertor n realizacii z rovnomernho rozdelenia na povrchu m-rozmernej gule
   
   res <- matrix(ncol = n, nrow = m)
   for (i in 1:n) {
      X <- rnorm(m)
      res[, i] <- X/sqrt(sum(X^2))
   }
   
   return(res)
}

res <- rsphere(10000, 3); plot(res[1,], res[2,], pch = 19, cex = 0.1, asp = 1) # +m=4,10


rball <- function(n, m) {
   # Genertor n realizacii z rovnomernho rozdelenia vo vnutri m-rozmernej gule
   
   res <- matrix(ncol = n, nrow = m)
   for (i in 1:n) {
      X <- rnorm(m)
      res[,i] <- runif(1)^(1/m)*X/sqrt(sum(X^2))
   }
   
   return(res)
}

res <- rball(10000, 2); plot(res[1,], res[2,], pch = 19, cex = 0.1, asp = 1) # +m=3,4,10


rtorus <- function(n, R, r) {
   # Evkin generator n rovnomernych bodov na hranici torusu s polomermi R, r
   
   rphitor <- function(n, R, r) {
      # Generuje n hodnot s rozdelenim uhla phi pre torus s polomermi R, r
      res <- rep(0, n); k <- 0; OK <- FALSE
      while (!OK) {
         U <- 2*pi*runif(1); V <- (R + r)*runif(1)
         if (abs(R + r*cos(U)) > V) {
            k <- k + 1; if (k == n) OK <- TRUE
            res[k] <- U
         }
      }
      return(res)
   }
   
   phi <- rphitor(n, R, r)
   psi <- 2*pi*runif(n)
   x <- cos(psi)*(R + r*cos(phi))
   y <- sin(psi)*(R + r*cos(phi))
   z <- r*sin(phi)
   
   return(rbind(x, y, z))
}

H <- matrix(rnorm(9), ncol = 3); U <- eigen(H %*% t(H))$vectors
plot(t((U %*% rtorus(10000, 5, 1))[1:2,]), pch = 19, cex = 0.2, asp = 1)

