## ----setup, include=FALSE-----------------------------------------------------
library(BiocStyle)
knitr::opts_chunk$set(eval = TRUE, echo = TRUE, collapse = TRUE)

## ----install-cran, echo=TRUE, eval=FALSE--------------------------------------
# install.packages(c("Rcpp", "RcppArmadillo", "parallel"))

## ----install-bioc, echo=TRUE, eval=FALSE--------------------------------------
# # Install Bioconductor dependencies
# if (!requireNamespace("BiocManager", quietly = TRUE)) {
#   install.packages("BiocManager")
# }
# BiocManager::install(c("rhdf5", "strawr", "rtracklayer", "GenomicRanges", "BSgenome", "Biostrings"))

## ----load-package, echo=TRUE, eval=TRUE---------------------------------------
# Loading the package:
# install.packages(HiCPotts)
library(HiCPotts)

## ----simulate-data, include=FALSE, eval=TRUE----------------------------------
set.seed(4921)

# Lattice size: an N x N grid of genomic bins.
# Each cell of the grid represents an interaction between bin i and bin j.
N <- 10

# Define the start coordinate of each bin (10 bins, 2 kb wide → 20 kb region)
bins <- seq(1, 20000, by = 2000)

# Create every pairwise combination of bin i vs bin j
data <- expand.grid(start = bins, start.j. = bins)

# Bin end coordinates (each bin is 2 kb wide)
data$end.i. <- data$start + 1999

data$end <- data$start.j. + 1999

# Chromosome label (Drosophila chr2L here)
data$chrom <- "chr2L"

# ── Simulate the four bias covariates ────────────────────────────────────────
data$GC <- runif(nrow(data), 0.3, 0.7) # Simulated GC content, GC fraction (biological range 30–70%)

data$ACC <- runif(nrow(data), 0, 1) # Simulated accessibility, DNase-I accessibility score (0–1)

data$TES <- rpois(nrow(data), 2) # Simulated TE counts, Count of overlapping transposable elements

# Poisson(λ = 5) approximates sparse Hi-C counts at this resolution
data$interactions <- rpois(nrow(data), lambda = 5) # Simulated interaction counts

# Coerce to a plain data.frame (expand.grid returns a class with extra attrs)
data <- as.data.frame(data)

# Inspect the first few rows – note the required column names:
#   start, start.j., end.i., end, chrom, GC, ACC, TES, interactions
head(data)

## ----get_data, include=FALSE, eval=FALSE--------------------------------------
# # Example (not run)
# # For actual Hi-C / Micro-C files use get_data() with these arguments:
# #
# #   file_path      – path to a .cool, .mcool, .hic, or .h5 matrix
# #   chr            – chromosome to extract (e.g. "chr2L", "chr4")
# #   start, end     – genomic window (bp, 1-based inclusive)
# #   resolution     – target bin size in bp; native bins are merged/sliced
# #   genome_package – BSgenome package used for GC computation
# #   acc_wig        – optional bedGraph/wig of DNase-I (or ATAC) accessibility
# #   chain_file     – optional liftOver chain if acc_wig is in another assembly
# #   te_granges     – optional BED/GTF (or GRanges) of transposable elements
# 
# data <- prepare_data(
#   file_path = "path/to/hic_file.h5",
#   chr = "chr2L",
#   start = 1,
#   end = 20000,
#   resolution = 2000,
#   genome_package = "BSgenome.Dmelanogaster.UCSC.dm6",
#   acc_wig = "path/to/dnase.wig",
#   chain_file = "path/to/chain.file",
#   te_granges = "path/to/te.gtf"
# )

## ----process_data, include=FALSE, eval=TRUE-----------------------------------
# ── Reshape the tidy interaction table into matrices for MCMC ────────────────
# process_data() returns a list with two elements:
#   $y      – an N x N matrix of observed interaction counts
#   $x_vars – a list of N x N matrices, one per covariate
#             (distance, GC, TES, ACC)
#
# Arguments:
#   data             – data.frame with the 9 required columns (see above)
#   N                – lattice dimension (here 10, matching 10 bins)
#   scale_max        – upper bound used when rescaling counts (prevents
#                      very large values from dominating the likelihood)
#   standardization_y – TRUE rescales counts to [0, scale_max]; FALSE keeps raw

processed <- process_data(data, N = N, scale_max = 500, standardization_y = TRUE)

# Pull the two pieces out of the returned list
x_vars <- processed[["x_vars"]] # Single matrix for this example
y <- processed[["y"]]

# Inspect x_vars: should be a list of distance, GC, TES, ACC matrices
str(x_vars) # Lists of distance, GC, TEs, ACC matrices

## ----setup_MCMC, include=FALSE, eval=TRUE-------------------------------------
# ── Define MCMC hyper-parameters and starting values ─────────────────────────

# Potts spatial-coupling parameter (γ). Values closer to 1 encourage
# neighbouring bins on the lattice to share the same latent state.
gamma_prior <- 0.3

# Total number of MCMC iterations. Burn-in defaults to iterations / 2.
# Use a small value here for vignette speed; 5 000+ is typical for real data.
iterations <- 20

# Initial value for the zero-inflation parameter (θ).
# Required when dist = "ZIP" or "ZINB"; ignored otherwise.
theta_start <- c(0.5)

# size_start (commented out) – only needed for "NB" or "ZINB":
# one initial over-dispersion value per mixture component.
# size_start <- c(1, 1, 1)

# Choice of count distribution for interactions. Options:
#   "Poisson", "NB", "ZIP", "ZINB"
# ZIP is a reasonable default for sparse Hi-C with many structural zeros.
dist <- "ZIP"

## ----run_MCMC, include=FALSE, eval=TRUE---------------------------------------
# ── Run the Metropolis-Hastings MCMC sampler ─────────────────────────────────
# run_chain_betas() samples from the joint posterior of the regression
# coefficients for all three mixture components simultaneously.

results <- run_chain_betas(
  N = N,
  gamma_prior = gamma_prior,
  iterations = iterations,
  x_vars = x_vars,
  y = y,
  theta_start = theta_start,
  use_data_priors = TRUE,
  # user_fixed_priors = FALSE,
  # epsilon = NULL,
  distance_metric = "manhattan",
  dist = dist,
  # size_start = size_start,
  mc_cores = 1
)

## ----MCMC_results, include=FALSE, eval=TRUE-----------------------------------
# ── Extract the individual components of the MCMC output ─────────────────────
# 'results' is a named list. Each element corresponds to a different set
# of posterior samples.

# Regression coefficient chains – one matrix per mixture component
# (rows = iterations, columns = covariates incl. intercept)

chains <- results[["chains"]]

# Posterior samples of the Potts spatial-coupling parameter γ
gamma <- results[["gamma"]]

# Posterior samples of the zero-inflation parameter θ (ZIP / ZINB only)
theta <- results[["theta"]]

# Over-dispersion size parameter – only present for NB / ZINB
# size <- results[["size]]

## ----compute_result, include=FALSE, eval=TRUE---------------------------------
# ── Compute posterior HMRF component-assignment probabilities ────────────────
# For every bin-pair, compute P(component = k) for k = 1, 2, 3 using the
# posterior-mean regression parameters (first iterations/2 are discarded
# as burn-in internally).

probs <- compute_HMRFHiC_probabilities(
  data = data,
  chain_betas = chains,
  iterations = iterations,
  dist = "ZIP"
)

probs$prob1 # This produces matrices of probabilities for the first component, which translate to assigning interactions to biological states (e.g., active vs. inactive chromatin).

## ----hic_paths, echo=TRUE, eval=TRUE------------------------------------------
# Hi-C contact matrix (.cool, 100 kb, BG3 cells, chr4)
hic_file   <- system.file("extdata",
                          "BG3_WT_merged_hic_matrix_chr4_100Kb.cool",
                          package = "HiCPotts")

# DNase-I accessibility bedGraph (dm3 genome coordinates)
dnase_file <- system.file("extdata",
                          "DNaseI_BG3_gr_chr4.bedGraph",
                          package = "HiCPotts")

# LiftOver chain — maps dm3 accessibility up to dm6 assembly
chain_file <- system.file("extdata",
                          "dm3ToDm6_chr4_only.chain",
                          package = "HiCPotts")

# Transposable-element annotations (GTF, dm6 chr4)
te_file    <- system.file("extdata",
                          "dm6_TEs_chr4.gtf",
                          package = "HiCPotts")

stopifnot(file.exists(hic_file),
          file.exists(dnase_file),
          file.exists(chain_file),
          file.exists(te_file))

## ----hic_get_data, echo=TRUE, eval=TRUE---------------------------------------
# get_data() does four things in one call:
#   1. Reads the .cool file and rebins to the requested resolution
#   2. Calculates GC content from the BSgenome package
#   3. Lifts over the DNase-I signal (dm3 -> dm6) and aggregates per bin
#   4. Counts transposable elements overlapping each bin pair
hic_data <- get_data(
  file_path      = hic_file,
  chr            = "chr4",
  start          = 1,
  end            = 400000,
  resolution     = 200000,
  genome_package = "BSgenome.Dmelanogaster.UCSC.dm6",
  acc_wig        = dnase_file,
  chain_file     = chain_file,
  te_granges     = te_file
)

head(hic_data)

## ----hic_process, echo=TRUE, eval=FALSE---------------------------------------
# # (end - start) / resolution, rounded up for the edge bin.
# N_hic <- 14
# 
# processed_hic <- process_data(
#   hic_data,
#   N                 = N_hic,
#   scale_max         = 500,
#   standardization_y = TRUE
# )
# 
# x_vars_hic <- processed_hic[["x_vars"]]
# y_hic      <- processed_hic[["y"]]

## ----hic_mcmc, echo=TRUE, eval=FALSE------------------------------------------
# # ZINB is recommended for Hi-C because of structural zeros and
# # over-dispersion typical of ligation-based count data.
# set.seed(2025)
# 
# hic_results <- run_chain_betas(
#   N                = N_hic,
#   gamma_prior      = 0.3,
#   iterations       = 5000,
#   x_vars           = x_vars_hic,
#   y                = y_hic,
#   theta_start      = 0.5,
#   size_start       = c(1, 1, 1),
#   use_data_priors  = TRUE,
#   distance_metric  = "manhattan",
#   dist             = "ZINB",
#   mc_cores         = min(4L, parallel::detectCores() - 1L)
# )
# 
# # run_chain_betas() returns a list with one element per input dataset.
# # Unpack the first (and here only) chain set:
# hic_chains <- hic_results[[1]][["chains"]]
# hic_gamma  <- hic_results[[1]][["gamma"]]
# hic_theta  <- hic_results[[1]][["theta"]]
# hic_size   <- hic_results[[1]][["size"]]

## ----hic_probs, echo=TRUE, eval=FALSE-----------------------------------------
# # Pass the full results list, not just the chains.
# hic_probs <- compute_HMRFHiC_probabilities(
#   data        = hic_data,
#   chain_betas = hic_results,
#   iterations  = 5000,
#   dist        = "ZINB"
# )
# 
# # hic_probs is a data.frame with prob1, prob2, prob3 columns that sum to 1
# # per row. prob1 is the noise/baseline component; prob2 and prob3 are the
# # elevated-signal regimes.
# head(hic_probs[, c("start", "end", "interactions", "prob1", "prob2", "prob3")])
# 
# # Bin-pairs confidently classified as elevated signal (prob2 > 0.9). This value can be increase or reduce based on user's justification.
# genuine_signal <- hic_probs[hic_probs$prob2 > 0.9,
#                             c("start", "end", "interactions", "prob2")]
# head(genuine_signal)

## ----microc_paths, echo=TRUE, eval=FALSE--------------------------------------
# # Replace these with the actual paths on your machine.
# microc_file <- "path/to/MicroC_BG3_chr4_1kb.cool"
# dnase_file  <- "path/to/DNaseI_BG3_gr_chr4.bedGraph"
# chain_file  <- "path/to/dm3ToDm6_chr4_only.chain"
# te_file     <- "path/to/dm6_TEs_chr4.gtf"

## ----microc_get_data, echo=TRUE, eval=FALSE-----------------------------------
# # Aggregate from the native 1 kb to 5 kb to keep the lattice manageable.
# microc_data <- get_data(
#   file_path      = microc_file,
#   chr            = "chr4",
#   start          = 1,
#   end            = 1350000,
#   resolution     = 5000,
#   genome_package = "BSgenome.Dmelanogaster.UCSC.dm6",
#   acc_wig        = dnase_file,
#   chain_file     = chain_file,
#   te_granges     = te_file
# )
# 
# head(microc_data)

## ----microc_process, echo=TRUE, eval=FALSE------------------------------------
# # 1,350,000 / 5,000 = 270 bins -> a 270 x 270 lattice.
# N_microc <- 270
# 
# processed_microc <- process_data(
#   microc_data,
#   N                 = N_microc,
#   scale_max         = 500,
#   standardization_y = TRUE
# )
# 
# x_vars_microc <- processed_microc[["x_vars"]]
# y_microc      <- processed_microc[["y"]]

## ----microc_mcmc, echo=TRUE, eval=FALSE---------------------------------------
# set.seed(2025)
# 
# microc_results <- run_chain_betas(
#   N                = N_microc,
#   gamma_prior      = 0.3,
#   iterations       = 10000,
#   x_vars           = x_vars_microc,
#   y                = y_microc,
#   theta_start      = 0.5,
#   size_start       = c(1, 1, 1),
#   use_data_priors  = TRUE,
#   distance_metric  = "manhattan",
#   dist             = "ZINB",
#   mc_cores         = min(4L, parallel::detectCores() - 1L)
# )

## ----microc_probs, echo=TRUE, eval=FALSE--------------------------------------
# microc_probs <- compute_HMRFHiC_probabilities(
#   data        = microc_data,
#   chain_betas = microc_results,
#   iterations  = 10000,
#   dist        = "ZINB"
# )
# 
# # Hard component assignment: the column with the highest posterior probability.
# probs_mat    <- as.matrix(microc_probs[, c("prob1", "prob2", "prob3")])
# component    <- max.col(probs_mat, ties.method = "first")
# table(component)

## ----User_prior, include=FALSE, eval=TRUE-------------------------------------
user_priors <- list(
  list(mean = c(0, 0, 0, 0, 0), sd = c(1, 1, 1, 1, 1)),
  list(mean = c(0, 0, 0, 0, 0), sd = c(1, 1, 1, 1, 1)),
  list(mean = c(0, 0, 0, 0, 0), sd = c(1, 1, 1, 1, 1))
)

# Run MCMC
results <- run_chain_betas(
  N = N,
  gamma_prior = gamma_prior,
  iterations = iterations,
  x_vars = x_vars,
  y = y,
  theta_start = theta_start,
  # use_data_priors = TRUE,
  user_fixed_priors = user_priors,
  # epsilon = NULL,
  distance_metric = "manhattan",
  dist = dist,
  # size_start = size_start,
  mc_cores = 1
)

## ----multiple_matrices, include=FALSE, eval=FALSE-----------------------------
# y_list <- list(y, y) # Example with two matrices
# 
# results <- run_chain_betas(
#   N = N,
#   gamma_prior = gamma_prior,
#   iterations = iterations,
#   x_vars = x_vars,
#   y = y_list,
#   theta_start = theta_start,
#   size_start = size_start,
#   use_data_priors = TRUE,
#   user_fixed_priors = NULL,
#   epsilon = NULL,
#   distance_metric = "manhattan",
#   dist = dist,
#   mc_cores = 2
# )

## ----Additional_distributions, include=FALSE, eval=TRUE-----------------------
# Run MCMC
results <- run_chain_betas(
  N = N,
  gamma_prior = gamma_prior,
  iterations = iterations,
  x_vars = x_vars,
  y = y,
  theta_start = theta_start,
  # use_data_priors = TRUE,
  user_fixed_priors = user_priors,
  # epsilon = NULL,
  distance_metric = "manhattan",
  dist = "Poisson",
  # size_start = size_start,
  mc_cores = 1
)

## ----echo = FALSE-------------------------------------------------------------
sessionInfo()

