#states: Gizli Markov Modeli'nde (HMM) iki durum olduğunu belirten bir vektör (alpha ve beta).
states <- c("alpha", "beta")

#observations: Gözlemlenen dizi (GGCT).
observations <- strsplit("GGCT", "")[[1]]

#start_prob: Her bir durum için başlangıç olasılıklarını logaritmik formda belirten vektör. Burada alpha ve beta durumlarının başlangıç olasılıkları eşit olarak log(1) (0) 
start_prob <- c(alpha = log(1), beta = log(1))  

#trans_prob: Durumlar arası geçiş olasılıklarını logaritmik formda belirten matris. alpha durumundan diğer durumlara geçiş olasılıkları, beta durumundan diğer durumlara geçiş olasılıklarıdır.
trans_prob <- matrix(c(log(9/10), log(1/10),
                       log(1/10), log(9/10)), nrow=2, byrow=TRUE,
                     dimnames=list(states, states))

#emission_prob: Her bir durum için her bir gözlemin yayılma olasılıklarını logaritmik formda belirten matris
emission_prob <- matrix(c(log(2/5), log(2/5), log(1/10), log(1/10),  # alpha
                          log(1/5), log(1/5), log(3/10), log(3/10)),  # beta
                        nrow=2, byrow=TRUE,
                        dimnames=list(states, c("A", "G", "C", "T")))

# Viterbi algoritmasının uygulanması
viterbi <- function(observations, states, start_prob, trans_prob, emission_prob) {
  n <- length(observations)
  m <- length(states)
  delta <- matrix(NA, nrow=m, ncol=n)
  psi <- matrix(NA, nrow=m, ncol=n)
#n: Gözlem dizisinin uzunluğu.
#m: Durum sayısı.
#delta: Maksimum olasılıkların logaritmalarını tutan matris.
#psi: Backtracking matrisidir ve maksimum olasılıkları sağlayan önceki durumları tutar.
  
  # Başlangıç durumu
  for (i in 1:m) {
    delta[i, 1] <- start_prob[states[i]] + emission_prob[states[i], observations[1]]
    psi[i, 1] <- 0
  }
#İlk gözlem için her bir durumun başlangıç olasılığı ve yayılma olasılığı logaritmalarının toplamı hesaplanır ve delta matrisine atanır.
#psi matrisinin ilk sütunu başlangıç durumu olduğundan 0 olarak atanır.
  
  # Recursion
  for (t in 2:n) {
    for (j in 1:m) {
      max_val <- -Inf
      max_state <- NA
      for (i in 1:m) {
        val <- delta[i, t-1] + trans_prob[states[i], states[j]]
        if (val > max_val) {
          max_val <- val
          max_state <- i
        }
      }
      delta[j, t] <- max_val + emission_prob[states[j], observations[t]]
      psi[j, t] <- max_state
    }
  }
#Her zaman adımı (t=2'den n'e kadar) ve her durumu (j) için:
#Her bir önceki durumdan (i) geçiş olasılıkları ve yayılma olasılıkları hesaplanarak maksimum değer bulunur (max_val) ve ilgili durum (max_state) kaydedilir.
#Bu değerler delta ve psi matrislerine atanır.
  
  # Termination
  p_star <- max(delta[, n])
  q_star <- numeric(n)
  q_star[n] <- which.max(delta[, n])
#delta matrisinin son sütununda en yüksek log-olasılık değeri (p_star) ve bu değeri sağlayan durum (q_star[n]) bulunur.
  
  # Backtracking
  for (t in (n-1):1) {
    q_star[t] <- psi[q_star[t+1], t+1]
  }
#Son durumdan başlayarak (q_star[n]), psi matrisini kullanarak önceki durumlar belirlenir ve en olası durum dizisi (state_sequence) oluşturulur. 
  
  state_sequence <- states[q_star]
  return(list(state_sequence=state_sequence, log_prob=p_star))
}

# HMM ile en olası durum dizisini bulma ve olasılığını hesaplama
result <- viterbi(observations, states, start_prob, trans_prob, emission_prob)

# Sonuçları ekrana yazdırma
cat("En olası durum dizisi:", paste(result$state_sequence, collapse=" "), "\n")
## En olası durum dizisi: beta beta beta beta
cat("En yüksek log-olasılık:", result$log_prob, "\n")
## En yüksek log-olasılık: -5.942903
library(HMM)
## 
## Attaching package: 'HMM'
## The following object is masked _by_ '.GlobalEnv':
## 
##     viterbi
# Initialize the HMM
hmm <- initHMM(
  States = c("alpha", "beta"),
  Symbols = c("A", "T", "G", "C"),
  transProbs = matrix(c(log(9/10), log(1/10), log(1/10), log(9/10)), 2),
  emissionProbs = matrix(c(
    log(0.4), log(0.1), log(0.4), log(0.1),
    log(0.2), log(0.3), log(0.2), log(0.3)
  ), nrow = 2, byrow = TRUE)
)

print(hmm)
## $States
## [1] "alpha" "beta" 
## 
## $Symbols
## [1] "A" "T" "G" "C"
## 
## $startProbs
## alpha  beta 
##   0.5   0.5 
## 
## $transProbs
##        to
## from         alpha       beta
##   alpha -0.1053605 -2.3025851
##   beta  -2.3025851 -0.1053605
## 
## $emissionProbs
##        symbols
## states           A         T          G         C
##   alpha -0.9162907 -2.302585 -0.9162907 -2.302585
##   beta  -1.6094379 -1.203973 -1.6094379 -1.203973
start_prob <- c(log(0.5), log(0.5))

 
viterbi <- function(hmm, observations, start_prob) {
  n_states <- length(hmm$States)
  n_obs <- length(observations)
  
  # Initialization
  V <- matrix(NA, nrow = n_states, ncol = n_obs)
  path <- matrix(NA, nrow = n_states, ncol = n_obs)
  
  for (s in 1:n_states) {
    V[s, 1] <- start_prob[s] + hmm$emissionProbs[s, observations[1]]
    path[s, 1] <- s
  }
  
  # Recursion
  for (t in 2:n_obs) {
    for (s in 1:n_states) {
      max_prob <- -Inf
      best_state <- NA
      for (s_prev in 1:n_states) {
        prob <- V[s_prev, t-1] + hmm$transProbs[s_prev, s] + hmm$emissionProbs[s, observations[t]]
        if (prob > max_prob) {
          max_prob <- prob
          best_state <- s_prev
        }
      }
      V[s, t] <- max_prob
      path[s, t] <- best_state
    }
  }
  
  # Termination
  best_path <- rep(NA, n_obs)
  best_prob <- -Inf
  for (s in 1:n_states) {
    if (V[s, n_obs] > best_prob) {
      best_prob <- V[s, n_obs]
      best_path[n_obs] <- s
    }
  }
  
  for (t in (n_obs-1):1) {
    best_path[t] <- path[best_path[t+1], t+1]
  }
  
  best_path <- hmm$States[best_path]
  return(list(path = best_path, prob = best_prob))
}

observations <- c("G", "G", "C", "T")
viterbi_result <- viterbi(hmm, observations, start_prob)
print(viterbi_result)
## $path
## [1] "beta" "beta" "beta" "beta"
## 
## $prob
## [1] -6.63605