K_Gausovo = function(t) {
  exp(-t^2 / 2) / sqrt(2 * pi)
}

K_bikvadratno = function(t) {
  ifelse(abs(t) < 1, 15 / 16 * (1 - t^2)^2, 0)
}

K_trougaono = function(t) {
  ifelse(abs(t) < 1, 1 - abs(t), 0)
}

K_Epanecnikovo = function(t) {
  ifelse(abs(t) < sqrt(5), 3 / 4 / sqrt(5) * (1 - t^2 / 5), 0)
}

K_Epanecnikovo_1 = function(t) {
  ifelse(abs(t) < 1, 3 / 4 * (1 - t^2), 0)
}

K_uniformno = function(t) {
  ifelse(abs(t) < 1, 1 / 2, 0)
}

ocena_gustine_jezgrom = function(x, podaci, h, jezgro = "Gausovo") {
  fn = rep(0, length(x))
  
  if (jezgro == "Gausovo") {
    for (j in 1:length(x)) {
      # racunamo ocenu gustine u svakoj tacki iz x
      fn[j] = sum(K_Gausovo((x[j] - podaci) / h))
    }
  }
  else if (jezgro == "bikvadratno") {
    for (j in 1:length(x)) {
      fn[j] = sum(K_bikvadratno((x[j] - podaci) / h))
    }
  }
  else if (jezgro == "trougaono") {
    for (j in 1:length(x)) {
      fn[j] = sum(K_trougaono((x[j] - podaci) / h))
    }
  }
  else if (jezgro == "Epanehnikovo") {
    for (j in 1:length(x)) {
      fn[j] = sum(K_Epanehnikovo((x[j] - podaci) / h))
    }
  }
  else if (jezgro == "uniformno") {
    for (j in 1:length(x)) {
      fn[j] = sum(K_uniformno((x[j] - podaci) / h))
    }
  }
  return(fn / (n * h))
}

M = function(x, h) {
  M_pom = rep(0, length(h))
  
  for (i in 1:n) {
    for (j in 1:n) {
      M_pom = M_pom + K2((x[i] - x[j]) / h) - 2 * K_Gausovo((x[i] - x[j]) / h)
    }
  }
  
  M_pom = M_pom / (n^2 * h) + 2 * K_Gausovo(0) / (n * h)
  return(M_pom)
}

CV = function(uzorak, h, ocena = ocena_gustine_jezgrom){
  # po redovima: red i -> ocene gustine bez i-tog elementa, i = 1:n
  f_i = matrix(0, n, length(h))
  
  for (i in 1:n) {
    # x - tacke u kojima racunamo ocenu gustine, podaci - uzorak iz koga dobijamo ocenu
    f_i[i, ] = sapply(h, ocena, x = uzorak[i], podaci = uzorak[-i])
  }
  
  cv = rep(0, length(h))
  for (j in 1:length(h)) {  
    cv[j] = sum(log(f_i[, j])) / n
  }
  return(cv)
}