# Generated by using Rcpp::compileAttributes() -> do not edit by hand
# Generator token: 10BE3573-1514-4C36-9D1C-5A225CD40393

#' Create New GEDI Model Object (Internal)
#'
#' Constructs the C++ GEDI model object and returns an external pointer.
#' This function is called internally by the R6 GEDI class during model setup
#' and should not be called directly by users.
#'
#' @param params List containing initialized parameter matrices:
#'   \itemize{
#'     \item Bi: List of cell projection matrices (K x Ni) for each sample
#'     \item Qi: List of sample-specific metagene matrices (J x K)
#'     \item si, oi: Cell and sample-specific offset vectors
#'     \item o: Global gene offset vector (length J)
#'     \item Z: Shared metagene matrix (J x K)
#'     \item U, S, D: SVD components and scaling factors
#'     \item sigma2: Initial variance estimate
#'     \item A: Pathway-latent factor connection matrix (if C provided)
#'     \item Rk, Ro: Sample covariate effect matrices (if H provided)
#'   }
#' @param aux List containing auxiliary variables and dimensions:
#'   \itemize{
#'     \item J, N, K, P, L: Dimensions (genes, cells, factors, pathways, covariates)
#'     \item numSamples: Number of samples
#'     \item obs.type: Observation type ("M", "M_paired", "Y", or "X")
#'     \item mode: Normalization mode ("Bl2" or "Bsphere")
#'     \item orthoZ, adjustD, is_si_fixed: Boolean flags
#'     \item C, H: Prior matrices (gene pathways, sample covariates)
#'     \item diag_K, J_vec, Ni_vec, Ni: Dimension vectors
#'     \item ZDBi, QiDBi: Precomputed product matrices
#'   }
#' @param target List containing target data matrices:
#'   \itemize{
#'     \item Yi: Log-transformed expression by sample (computed by C++ if empty)
#'     \item Mi: Raw count matrix by sample (for obs.type = "M")
#'     \item M1i, M2i: Paired count matrices (for obs.type = "M_paired")
#'     \item Xi: Binary indicator matrix (for obs.type = "X")
#'   }
#' @param hyperparams List containing hyperparameters for regularization:
#'   \itemize{
#'     \item S_Qi, S_oi, S_Z, S_A, S_R: Shrinkage parameters
#'     \item S_Qi_mean, S_oi_mean, S_si, S_o: Mean shrinkage parameters
#'     \item o_0, si_0: Prior mean values
#'     \item O: Random matrix for rSVD initialization
#'   }
#' @param verbose Integer verbosity level (0=silent, 1=info, 2=debug, 4=timing)
#' @param num_threads Number of OpenMP threads (0=auto, uses all available)
#'
#' @return External pointer (SEXP) to C++ GEDI object
#'
#' @details
#' This function creates a stateful C++ GEDI object that stores all model parameters
#' and data. The C++ object performs all heavy computation, while the R6 wrapper
#' remains lightweight (~1 KB). Memory-efficient design: if Yi is not provided,
#' C++ computes it from raw counts M, eliminating duplicate storage in R.
#'
#' The returned external pointer is managed by R's garbage collector and will
#' automatically free the C++ object when no longer referenced.
#'
#' @keywords internal
#' @noRd
GEDI_new <- function(params, aux, target, hyperparams, verbose = 1L, num_threads = 0L) {
    .Call(`_gedi2_GEDI_new`, params, aux, target, hyperparams, verbose, num_threads)
}

#' Set Verbose Level on Existing GEDI Object (Internal)
#'
#' Updates the verbosity level of an already-created GEDI C++ object.
#' This allows R to suppress C++ output when using an R-side progress bar.
#'
#' @param model_ptr External pointer to C++ GEDI object (from GEDI_new)
#' @param verbose Integer verbosity level: 0 (silent), 1 (info), 2+ (debug)
#'
#' @keywords internal
#' @noRd
GEDI_set_verbose <- function(model_ptr, verbose) {
    invisible(.Call(`_gedi2_GEDI_set_verbose`, model_ptr, verbose))
}

#' Initialize Latent Variables (Internal)
#'
#' Initializes latent variables Z, Qi, and Bi using randomized SVD on residual
#' expression data. This is the first step in GEDI model fitting and must be
#' called before optimization.
#'
#' @param model_ptr External pointer to C++ GEDI object (from GEDI_new)
#' @param multimodal Logical, if TRUE skips normalization steps for multi-modal
#'   integration (used internally when combining multiple data modalities)
#'
#' @return List containing initialized model state:
#'   \itemize{
#'     \item params: Updated parameter matrices (Z, Qi, Bi, etc.)
#'     \item aux: Auxiliary variables and dimensions
#'     \item hyperparams: Hyperparameters
#'   }
#'
#' @details
#' Initialization procedure:
#' \enumerate{
#'   \item Solve for initial oi (sample-specific offsets)
#'   \item Compute residual Yp after removing o, oi, si effects
#'   \item Perform randomized SVD on Yp to obtain initial Z
#'   \item Initialize Qi = Z for all samples
#'   \item Solve for initial Bi given Z and Qi
#'   \item Normalize B matrices and update auxiliary products (ZDBi, QiDBi)
#' }
#'
#' Uses randomized SVD (rSVD) for computational efficiency with large matrices.
#' The multimodal flag is used internally for advanced integration workflows.
#'
#' @keywords internal
#' @noRd
GEDI_initialize <- function(model_ptr, multimodal = FALSE) {
    .Call(`_gedi2_GEDI_initialize`, model_ptr, multimodal)
}

#' Optimize GEDI Model via Block Coordinate Descent (Internal)
#'
#' Performs block coordinate descent optimization to fit the GEDI model.
#' Iteratively updates all model parameters (Bi, Z, Qi, oi, si, o, sigma2)
#' until convergence or maximum iterations reached.
#'
#' @param model_ptr External pointer to initialized C++ GEDI object
#' @param iterations Integer, number of optimization iterations to perform
#' @param track_interval Integer, interval for tracking convergence metrics
#'   (e.g., track_interval=5 tracks every 5th iteration; track_interval=1 tracks all)
#'
#' @return List containing optimized model results:
#'   \itemize{
#'     \item params: Optimized parameter matrices (Z, Bi, Qi, sigma2, etc.)
#'     \item aux: Auxiliary variables and dimensions
#'     \item hyperparams: Updated hyperparameters (o_0, S_o, S_si)
#'     \item tracking: Convergence metrics (dZ, dBi, dQi, sigma2 trajectory)
#'     \item convergence: Summary statistics (iterations, total_time_ms, final_sigma2)
#'   }
#'
#' @details
#' Block coordinate descent iteration:
#' \enumerate{
#'   \item Solve Bi for all samples (parallelized with OpenMP)
#'   \item Normalize B matrices
#'   \item Solve Z (orthogonal or regular, depending on orthoZ flag)
#'   \item Solve Qi for all samples (parallelized)
#'   \item Solve oi, si, o (offset parameters)
#'   \item Update Yi from raw counts M (for count data)
#'   \item Solve sigma2 (variance parameter)
#'   \item Update hyperpriors (o_0, S_o, S_si)
#'   \item Solve A, Rk, Ro (if priors C or H are provided)
#'   \item Track convergence metrics at specified intervals
#' }
#'
#' OpenMP parallelization is automatically enabled if available. Progress and
#' timing information printed based on verbosity level.
#'
#' @keywords internal
#' @noRd
GEDI_optimize <- function(model_ptr, iterations, track_interval = 5L) {
    .Call(`_gedi2_GEDI_optimize`, model_ptr, iterations, track_interval)
}

#' Train GEDI Model (Initialize + Optimize) (Internal)
#'
#' Convenience function that performs both initialization and optimization in a
#' single call. Equivalent to calling GEDI_initialize() followed by GEDI_optimize().
#'
#' @param model_ptr External pointer to C++ GEDI object (from GEDI_new)
#' @param iterations Integer, number of optimization iterations to perform
#' @param track_interval Integer, interval for tracking convergence metrics
#' @param multimodal Logical, if TRUE skips normalization during initialization
#'   (for multi-modal integration workflows)
#'
#' @return List containing trained model results (same format as GEDI_optimize):
#'   \itemize{
#'     \item params: Optimized parameter matrices
#'     \item aux: Auxiliary variables
#'     \item hyperparams: Updated hyperparameters
#'     \item tracking: Convergence metrics
#'     \item convergence: Summary statistics
#'   }
#'
#' @details
#' This is the recommended way to fit a GEDI model in a single step. Internally:
#' \enumerate{
#'   \item Calls initialize() to set up latent variables via rSVD
#'   \item Calls optimize() to perform block coordinate descent
#'   \item Returns the final optimized model state
#' }
#'
#' For more control over the fitting process, use GEDI_initialize() and
#' GEDI_optimize() separately. The multimodal parameter is for advanced use cases.
#'
#' @keywords internal
#' @noRd
GEDI_train <- function(model_ptr, iterations, track_interval = 5L, multimodal = FALSE) {
    .Call(`_gedi2_GEDI_train`, model_ptr, iterations, track_interval, multimodal)
}

getDiffO_cpp <- function(Ro, H_rotation, contrast, verbose = 0L) {
    .Call(`_gedi2_getDiffO_cpp`, Ro, H_rotation, contrast, verbose)
}

getDiffQ_cpp <- function(Rk_list, H_rotation, contrast, verbose = 0L) {
    .Call(`_gedi2_getDiffQ_cpp`, Rk_list, H_rotation, contrast, verbose)
}

getDiffExp_cpp <- function(Rk_list, H_rotation, contrast, D, Bi_list, verbose = 0L) {
    .Call(`_gedi2_getDiffExp_cpp`, Rk_list, H_rotation, contrast, D, Bi_list, verbose)
}

compute_svd_factorized_cpp <- function(Z, D, Bi_list, verbose = 0L) {
    .Call(`_gedi2_compute_svd_factorized_cpp`, Z, D, Bi_list, verbose)
}

run_factorized_svd_cpp <- function(Z, projDB, verbose = 0L) {
    .Call(`_gedi2_run_factorized_svd_cpp`, Z, projDB, verbose)
}

#' Compute Residual After Removing Sample Effects (Internal)
#'
#' Removes sample-specific effects (QiDBi, si, oi) and global offset (o) from Yi.
#' Used to extract the shared biological signal (ZDBi component).
#'
#' @param Yi Dense matrix (J x Ni) - fitted log-expression for sample i
#' @param QiDBi Dense matrix (J x Ni) - sample-specific metagene projections
#' @param si Vector (Ni) - cell-specific library size offsets for sample i
#' @param o Vector (J) - global gene-specific offsets
#' @param oi Vector (J) - sample-specific gene offsets
#'
#' @return Dense matrix (J x Ni) - residual Yi after removing sample effects
#'
#' @details
#' Computes: Yi - QiDBi - (si (x) 1^T) - (o + oi) (x) 1^T
#' This leaves only the ZDBi component (shared biological signal).
#'
#' @keywords internal
#' @noRd
Yi_resZ <- function(Yi, QiDBi, si, o, oi) {
    .Call(`_gedi2_Yi_resZ`, Yi, QiDBi, si, o, oi)
}

#' Predict Yi from Model Parameters (Internal)
#'
#' Reconstructs the model's prediction of Yi (log-expression) from all components.
#'
#' @param ZDBi Dense matrix (J x Ni) - shared metagene projections
#' @param QiDBi Dense matrix (J x Ni) - sample-specific metagene projections
#' @param si Vector (Ni) - cell-specific library size offsets
#' @param o Vector (J) - global gene-specific offsets
#' @param oi Vector (J) - sample-specific gene offsets
#'
#' @return Dense matrix (J x Ni) - predicted Yi
#'
#' @details
#' Computes: Y_hati = ZDBi + QiDBi + (si (x) 1^T) + (o + oi) (x) 1^T
#' This is the full model prediction for log-expression.
#'
#' @keywords internal
#' @noRd
predict_Yhat <- function(ZDBi, QiDBi, si, o, oi) {
    .Call(`_gedi2_predict_Yhat`, ZDBi, QiDBi, si, o, oi)
}

#' Variance of Yi for Single Count Matrix (Internal)
#'
#' Computes posterior variance of Yi given the fitted values and model variance.
#' For observation type "M" (single count matrix).
#'
#' @param Yi Dense matrix (J x Ni) - fitted log-expression
#' @param sigma2 Scalar - model variance parameter
#'
#' @return Dense matrix (J x Ni) - posterior variance at each position
#'
#' @details
#' Variance formula: Var(Yi | Mi, model) = 1 / (exp(Yi) + 1/sigma2)
#'
#' This comes from the Poisson-lognormal model where:
#' - Mi ~ Poisson(exp(Yi))
#' - Yi ~ N(Y_hati, sigma2)
#'
#' The posterior variance decreases where:
#' - Counts are high (exp(Yi) large)
#' - Model uncertainty is low (sigma2 small)
#'
#' @keywords internal
#' @noRd
Yi_var_M <- function(Yi, sigma2) {
    .Call(`_gedi2_Yi_var_M`, Yi, sigma2)
}

#' Variance of Yi for Paired Count Matrices (Internal)
#'
#' Computes posterior variance of Yi for paired count data (e.g., CITE-seq, ATAC+RNA).
#' For observation type "M_paired".
#'
#' @param Yi Dense matrix (J x Ni) - fitted log-ratio: log((M1+1)/(M2+1))
#' @param M1i Sparse matrix (J x Ni) - first count matrix (e.g., RNA)
#' @param M2i Sparse matrix (J x Ni) - second count matrix (e.g., protein)
#' @param sigma2 Scalar - model variance parameter
#'
#' @return Dense matrix (J x Ni) - posterior variance at each position
#'
#' @details
#' Variance formula: Var(Yi | M1i, M2i, model) = 1 / (M * exp(-|Yi|) / (1+exp(-|Yi|))^2 + 1/sigma2)
#' where M = M1i + M2i
#'
#' This comes from the binomial-logistic-normal model where:
#' - M1i ~ Binomial(M1i + M2i, p)
#' - logit(p) = Yi ~ N(Y_hati, sigma2)
#'
#' The variance depends on:
#' - Total counts M (more counts = less variance)
#' - Yi magnitude (variance minimized at Yi = 0, i.e., p = 0.5)
#' - Model uncertainty sigma2
#'
#' @keywords internal
#' @noRd
Yi_var_M_paired <- function(Yi, M1i, M2i, sigma2) {
    .Call(`_gedi2_Yi_var_M_paired`, Yi, M1i, M2i, sigma2)
}

#' Compute Dispersion Statistics (Sparse-Optimized) (Internal)
#'
#' Analyzes the relationship between predicted and observed variance for count data.
#' Only samples nonzero positions from the sparse count matrix for memory efficiency.
#'
#' @param Yi_fitted Dense matrix (J x Ni) - model prediction of log-expression
#' @param Mi Sparse matrix (J x Ni) - observed count matrix
#' @param subsample Integer - maximum number of nonzero positions to sample
#'
#' @return List containing:
#'   - predicted: Vector of predicted counts (lambda = exp(Yi_fitted))
#'   - observed: Vector of observed counts from Mi
#'
#' @details
#' For Poisson model: Mi ~ Poisson(lambda), expected variance = lambda.
#' This function samples nonzero positions and returns predicted vs observed values
#' for downstream dispersion analysis (binning and aggregation done in R).
#'
#' Memory optimization: Works only on sparse nonzero positions (typically 5-10% of matrix).
#' For 30K genes x 10K cells with 5% nonzero: samples from ~15M positions instead of 300M.
#'
#' @keywords internal
#' @noRd
compute_dispersion_sparse <- function(Yi_fitted, Mi, subsample) {
    .Call(`_gedi2_compute_dispersion_sparse`, Yi_fitted, Mi, subsample)
}

#' Sum of Squared Errors for Paired Data (Internal)
#'
#' Computes the SSE term used in sigma2 optimization for M_paired observation type.
#' This is included for completeness but is called during optimization, not imputation.
#'
#' @param Yi Dense matrix (J x Ni) - fitted log-ratio
#' @param M1i Sparse matrix (J x Ni) - first count matrix
#' @param M2i Sparse matrix (J x Ni) - second count matrix
#' @param ZDBi Dense matrix (J x Ni) - shared metagene projections
#' @param QiDBi Dense matrix (J x Ni) - sample-specific metagene projections
#' @param si Vector (Ni) - cell-specific offsets
#' @param o Vector (J) - global gene offsets
#' @param oi Vector (J) - sample-specific gene offsets
#' @param sigma2 Scalar - current variance estimate
#'
#' @return Scalar - SSE contribution from sample i
#'
#' @keywords internal
#' @noRd
Yi_SSE_M_paired <- function(Yi, M1i, M2i, ZDBi, QiDBi, si, o, oi, sigma2) {
    .Call(`_gedi2_Yi_SSE_M_paired`, Yi, M1i, M2i, ZDBi, QiDBi, si, o, oi, sigma2)
}

#' Compute Single Feature Projection (Internal)
#'
#' Projects a single feature (gene) through the GEDI model to get cell-level values.
#' Computes: (feature_weights * D) %*% B, avoiding full ZDB computation.
#'
#' @param feature_weights Vector of length K (factor loadings for this feature)
#' @param D Scaling vector of length K
#' @param Bi_list List of sample-specific cell projection matrices (K x Ni each)
#' @param verbose Integer verbosity level
#'
#' @return Vector of length N (total cells) with projected values
#'
#' @keywords internal
#' @noRd
compute_feature_projection <- function(feature_weights, D, Bi_list, verbose = 0L) {
    .Call(`_gedi2_compute_feature_projection`, feature_weights, D, Bi_list, verbose)
}

#' Compute Multi-Feature Projection (Internal)
#'
#' Projects multiple features through the GEDI model simultaneously.
#' Computes: (feature_weights * D) %*% B for F features.
#'
#' @param feature_weights Matrix K x F (factor loadings for F features)
#' @param D Scaling vector of length K
#' @param Bi_list List of sample-specific cell projection matrices (K x Ni each)
#' @param verbose Integer verbosity level
#'
#' @return Matrix N x F with projected values for each feature
#'
#' @keywords internal
#' @noRd
compute_multi_feature_projection <- function(feature_weights, D, Bi_list, verbose = 0L) {
    .Call(`_gedi2_compute_multi_feature_projection`, feature_weights, D, Bi_list, verbose)
}

#' Aggregate Vector Field into Bins (Internal)
#'
#' Bins vector field data into a grid and computes mean vectors per bin.
#' Used for cleaner arrow plots without overplotting.
#'
#' @param Dim1 Start x-coordinates (length N)
#' @param Dim2 Start y-coordinates (length N)
#' @param To1 End x-coordinates (length N)
#' @param To2 End y-coordinates (length N)
#' @param color Color values (length N), can be numeric or will be converted
#' @param alpha Alpha values (length N)
#' @param n_bins Number of bins per dimension
#' @param min_per_bin Minimum observations required per bin
#'
#' @return Data frame with columns: Dim1, Dim2, To1, To2, deltaDim1, deltaDim2,
#'   Color, Alpha, n (observations per bin)
#'
#' @keywords internal
#' @noRd
aggregate_vectors <- function(Dim1, Dim2, To1, To2, color, alpha, n_bins, min_per_bin) {
    .Call(`_gedi2_aggregate_vectors`, Dim1, Dim2, To1, To2, color, alpha, n_bins, min_per_bin)
}

#' Compute ZDB Projection (Internal)
#'
#' Computes the shared manifold projection ZDB = Z * diag(D) * B, where B is
#' the concatenation of all sample-specific Bi matrices. This is the main
#' integrated representation of cells in the GEDI latent space.
#'
#' @param Z Shared metagene matrix (J x K), where J = genes, K = latent factors
#' @param D Scaling vector (length K) representing the importance of each factor
#' @param Bi_list List of sample-specific cell projection matrices, where each
#'   Bi is a K x Ni matrix (Ni = number of cells in sample i)
#' @param verbose Integer verbosity level:
#'   \itemize{
#'     \item 0: Silent (no output)
#'     \item 1: Progress bar and summary statistics
#'     \item 2: Detailed per-sample information
#'   }
#'
#' @return Dense matrix ZDB of dimensions J x N, where N = sum(Ni) is the total
#'   number of cells across all samples. Each column represents a cell in the
#'   integrated latent space.
#'
#' @details
#' The ZDB projection represents each cell as a linear combination of shared
#' metagenes (Z), weighted by latent factors and scaled by their importance (D).
#' 
#' Computational strategy:
#' \enumerate{
#'   \item Pre-compute ZD = Z * diag(D) once (saves KxJxnumSamples operations)
#'   \item For each sample i: compute ZD * Bi and concatenate
#'   \item Use Eigen block operations for efficient memory access
#' }
#'
#' Memory: Allocates one J x N dense matrix. For large datasets (e.g., 20k genes,
#' 50k cells), this requires ~8 GB RAM. Consider computing projections on demand
#' or working with subsets if memory is limited.
#'
#' Performance: OpenMP parallelization available if enabled during compilation.
#' Typical speed: ~100-200ms for 20k x 5k dataset on modern CPU.
#'
#' @keywords internal
#' @noRd
compute_ZDB_cpp <- function(Z, D, Bi_list, verbose = 0L) {
    .Call(`_gedi2_compute_ZDB_cpp`, Z, D, Bi_list, verbose)
}

#' Compute DB Projection (Internal)
#'
#' Computes the latent factor embedding DB = diag(D) * B, where B is the
#' concatenation of all sample-specific Bi matrices. This represents cells
#' in the K-dimensional latent factor space.
#'
#' @param D Scaling vector (length K) representing factor importance
#' @param Bi_list List of sample-specific cell projection matrices, where each
#'   Bi is a K x Ni matrix
#' @param verbose Integer verbosity level (0 = silent, 1 = progress, 2 = detailed)
#'
#' @return Dense matrix DB of dimensions K x N, where N = sum(Ni). Each column
#'   represents a cell's coordinates in the latent factor space.
#'
#' @details
#' The DB projection is simpler than ZDB as it operates directly in the K-dimensional
#' latent space without projecting through the gene space. This is useful for:
#' \itemize{
#'   \item Visualization (when K is small, e.g., K=2 or K=3)
#'   \item Downstream clustering or classification
#'   \item Understanding factor contributions per cell
#' }
#'
#' Computational strategy:
#' \enumerate{
#'   \item Concatenate all Bi matrices horizontally
#'   \item Apply diagonal scaling: diag(D) * B
#' }
#'
#' Memory: Much smaller than ZDB (K x N vs. J x N). For K=10 and N=50k cells,
#' requires only ~4 MB vs. ~8 GB for ZDB when J=20k.
#'
#' Performance: Very fast (~10-50ms) since K << J typically.
#'
#' @keywords internal
#' @noRd
compute_DB_cpp <- function(D, Bi_list, verbose = 0L) {
    .Call(`_gedi2_compute_DB_cpp`, D, Bi_list, verbose)
}

#' Compute ADB Projection (Internal)
#'
#' Computes the pathway activity projection ADB = C.rotation * A * diag(D) * B.
#' This represents cells in terms of their pathway/gene set activities rather
#' than individual gene expression.
#'
#' @param C_rotation Rotation matrix (num_pathways x P) that maps from the P-dimensional
#'   reduced SVD space back to the original pathway space
#' @param A Pathway-factor connection matrix (P x K) learned during training, where
#'   P is the number of reduced components and K is the number of latent factors
#' @param D Scaling vector (length K) representing factor importance
#' @param Bi_list List of sample-specific cell projection matrices (K x Ni each)
#' @param verbose Integer verbosity level (0 = silent, 1 = progress, 2 = detailed)
#'
#' @return Dense matrix ADB of dimensions num_pathways x N, where num_pathways is the
#'   number of original pathways and N = total cells. Each column represents a cell's
#'   pathway activities.
#'
#' @details
#' The ADB projection is only available when a gene-level prior matrix C was
#' provided during model setup. It enables:
#' \itemize{
#'   \item Pathway-level interpretation of cell states
#'   \item Identifying enriched pathways per cell type
#'   \item Biological interpretation in original pathway space
#' }
#'
#' Mathematical formulation:
#' \deqn{ADB = C.rotation \times A \times diag(D) \times B}
#'
#' where:
#' \itemize{
#'   \item C.rotation (num_pathways x P) maps from reduced space to original pathways
#'   \item A (P x K) captures pathway-factor associations in reduced space
#'   \item D (K) scales the importance of each latent factor
#'   \item B (K x N) contains cell projections in latent space
#' }
#'
#' Computational strategy:
#' \enumerate{
#'   \item Concatenate B from all Bi matrices
#'   \item Compute (C.rotation x A) x (diag(D) x B) efficiently
#'   \item Return in original pathway space for interpretation
#' }
#'
#' Memory: num_pathways x N matrix. For 100 original pathways and N=50k cells, ~40 MB.
#'
#' Performance: Fast due to small P and K dimensions (~50-100ms typical).
#'
#' @keywords internal
#' @noRd
compute_ADB_cpp <- function(C_rotation, A, D, Bi_list, verbose = 0L) {
    .Call(`_gedi2_compute_ADB_cpp`, C_rotation, A, D, Bi_list, verbose)
}

#' Compute Cell-Specific Scaling Factors (Dense)
#'
#' Calculates column-wise means of a dense expression matrix for hyperparameter initialization.
#' This function computes s_0 = (J_vec^T * Y) / J, where each element represents the mean
#' expression across all genes for each cell. Used internally during GEDI model setup.
#'
#' @param J_vec Vector of ones with length equal to number of genes (J)
#' @param Y Dense log-transformed expression matrix (genes x cells)
#' @param J Number of genes (rows in Y)
#'
#' @return Vector of length N (number of cells) containing cell-specific scaling factors
#'
#' @details
#' This is the dense matrix version used when Y matrix is provided directly.
#' For count matrices (M), use the sparse version \code{compute_s_0()} instead.
#' The function uses BLAS-optimized dense matrix-vector multiplication for efficiency.
#'
#' @keywords internal
#' @noRd
compute_s_0_dense <- function(J_vec, Y, J) {
    .Call(`_gedi2_compute_s_0_dense`, J_vec, Y, J)
}

#' Compute Library-Size Normalized Expression (Sparse)
#'
#' Normalizes sparse expression matrix Y by dividing each element by the outer product
#' of J_vec and s_0. This is equivalent to Y / (J_vec * s_0^T).
#'
#' @param Y Sparse expression matrix (genes x cells)
#' @param J_vec Vector of ones with length J (number of genes)
#' @param s_0 Vector of cell-specific scaling factors (length N)
#'
#' @return Sparse matrix Yp with normalized expression values
#'
#' @details
#' Efficiently iterates through non-zero elements only, preserving sparsity.
#' Each Y(i,j) is divided by (J_vec(i) * s_0(j)).
#'
#' @keywords internal
#' @noRd
compute_Yp <- function(Y, J_vec, s_0) {
    .Call(`_gedi2_compute_Yp`, Y, J_vec, s_0)
}

#' Compute Gene-Specific Offsets (Dense)
#'
#' Calculates row-wise means of normalized expression matrix for hyperparameter initialization.
#' Computes o_0 = (Yp * N_vec) / N, where each element represents the mean expression
#' of a gene across all cells after library size normalization.
#'
#' @param Yp Normalized dense expression matrix (genes x cells)
#' @param N_vec Vector of ones with length N (number of cells)
#' @param N Number of cells (columns in Yp)
#'
#' @return Vector of length J (number of genes) containing gene-specific offsets
#'
#' @details
#' Used in conjunction with \code{compute_s_0_dense()} and \code{compute_Yp_dense()}
#' to initialize hyperparameters o_0 and s_0 for the GEDI model.
#'
#' @keywords internal
#' @noRd
compute_o_0_dense <- function(Yp, N_vec, N) {
    .Call(`_gedi2_compute_o_0_dense`, Yp, N_vec, N)
}

#' Compute Library-Size Normalized Expression (Dense)
#'
#' Computes normalized expression Yp by subtracting the outer product of J_vec and s_0 from Y.
#' This is equivalent to Yp = Y - J_vec * s_0^T.
#'
#' @param Y Dense expression matrix (genes x cells)
#' @param J_vec Vector of ones with length J (number of genes)
#' @param s_0 Vector of cell-specific scaling factors (length N)
#'
#' @return Dense matrix Yp with normalized expression values
#'
#' @details
#' Alternative formulation of library size normalization for dense matrices.
#' Uses \code{noalias()} for efficient in-place subtraction without temporary objects.
#'
#' @keywords internal
#' @noRd
compute_Yp_dense <- function(Y, J_vec, s_0) {
    .Call(`_gedi2_compute_Yp_dense`, Y, J_vec, s_0)
}

#' Vector Outer Product
#'
#' Computes the outer product of two vectors: a * b^T, returning a dense matrix.
#' This is used internally for efficient matrix operations in GEDI model fitting.
#'
#' @param a First vector (length m)
#' @param b Second vector (length n)
#'
#' @return Dense matrix of dimensions (m x n) containing the outer product
#'
#' @details
#' Uses BLAS-optimized operations for efficient computation.
#' Equivalent to R's \code{a \%*\% t(b)}.
#'
#' @keywords internal
#' @noRd
VecVecProduct <- function(a, b) {
    .Call(`_gedi2_VecVecProduct`, a, b)
}

#' Dense Matrix-Vector Product
#'
#' Computes the product of a dense matrix A and vector b: A * b.
#' Returns the result as a column vector.
#'
#' @param A Dense matrix (m x n)
#' @param b Vector of length n
#'
#' @return Vector of length m containing the product A * b
#'
#' @details
#' Uses BLAS level-2 optimized matrix-vector multiplication.
#' Equivalent to R's \code{A \%*\% b}.
#'
#' @keywords internal
#' @noRd
MatVecProduct <- function(A, b) {
    .Call(`_gedi2_MatVecProduct`, A, b)
}

#' Sparse Matrix-Vector Product
#'
#' Computes the product of a sparse matrix A and vector b: A * b.
#' Efficiently handles sparse matrices by only operating on non-zero elements.
#'
#' @param A Sparse matrix (m x n)
#' @param b Vector of length n
#'
#' @return Vector of length m containing the product A * b
#'
#' @details
#' Optimized for sparse matrices, avoiding unnecessary multiplications by zero.
#' Useful for large-scale single-cell data where most entries are zero.
#'
#' @keywords internal
#' @noRd
eigenSparseMatVecProduct <- function(A, b) {
    .Call(`_gedi2_eigenSparseMatVecProduct`, A, b)
}

#' Compute Library-Size Normalized Count Matrix (Sparse)
#'
#' Normalizes sparse count matrix M by dividing each element by the outer product
#' of J_vec and s_0. This is equivalent to Mp = M / (J_vec * s_0^T).
#'
#' @param M Sparse raw count matrix (genes x cells)
#' @param J_vec Vector of ones with length J (number of genes)
#' @param s_0 Vector of cell-specific scaling factors (length N)
#'
#' @return Sparse matrix Mp with normalized counts
#'
#' @details
#' Efficiently iterates through non-zero elements only, preserving sparsity structure.
#' Each M(i,j) is divided by (J_vec(i) * s_0(j)).
#' Used for initializing hyperparameters from raw count data.
#'
#' @keywords internal
#' @noRd
compute_Mp <- function(M, J_vec, s_0) {
    .Call(`_gedi2_compute_Mp`, M, J_vec, s_0)
}

#' Compute Cell-Specific Scaling Factors from Counts (Sparse)
#'
#' Calculates column-wise sums of sparse count matrix M for hyperparameter initialization.
#' Computes s_0 = (J_vec^T * M + 0.01) / J, where each element represents the library
#' size (total count) for each cell with a small constant added for numerical stability.
#'
#' @param J_vec Vector of ones with length equal to number of genes (J)
#' @param M Sparse raw count matrix (genes x cells)
#' @param J Number of genes (rows in M)
#'
#' @return Vector of length N (number of cells) containing cell-specific scaling factors
#'
#' @details
#' This is the sparse matrix version used when raw count matrix M is provided.
#' For pre-processed Y matrices, use \code{compute_s_0_dense()} instead.
#' The small constant (0.01) prevents division by zero for cells with very low counts.
#' Uses BLAS-optimized sparse matrix-vector multiplication.
#'
#' @keywords internal
#' @noRd
compute_s_0 <- function(J_vec, M, J) {
    .Call(`_gedi2_compute_s_0`, J_vec, M, J)
}

#' Compute Gene-Specific Offsets from Normalized Counts (Sparse)
#'
#' Calculates row-wise sums of library-size normalized sparse matrix Mp for
#' hyperparameter initialization. Computes o_0 = (Mp * N_vec + 1e-5) / N, where
#' each element represents the mean normalized count of a gene across all cells.
#'
#' @param Mp Sparse library-size normalized count matrix (genes x cells)
#' @param N_vec Vector of ones with length N (number of cells)
#' @param N Number of cells (columns in Mp)
#'
#' @return Vector of length J (number of genes) containing gene-specific offsets
#'
#' @details
#' Used in conjunction with \code{compute_s_0()} and \code{compute_Mp()} to initialize
#' hyperparameters o_0 and s_0 from raw count data. The small constant (1e-5) provides
#' numerical stability for genes with very low expression.
#' Uses BLAS-optimized sparse matrix-vector multiplication.
#'
#' @keywords internal
#' @noRd
compute_o_0 <- function(Mp, N_vec, N) {
    .Call(`_gedi2_compute_o_0`, Mp, N_vec, N)
}

