Skip to content

Commit

Permalink
speed up model matrix, finish ame_obs for fanhmm
Browse files Browse the repository at this point in the history
  • Loading branch information
helske committed Jan 14, 2025
1 parent 51d5f1f commit ea1be76
Show file tree
Hide file tree
Showing 9 changed files with 237 additions and 141 deletions.
8 changes: 6 additions & 2 deletions R/RcppExports.R
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ ame_obs_nhmm_multichannel <- function(eta_pi, eta_A, eta_B, obs, Ti, icpt_only_p
.Call(`_seqHMM_ame_obs_nhmm_multichannel`, eta_pi, eta_A, eta_B, obs, Ti, icpt_only_pi1, icpt_only_A1, icpt_only_B1, iv_A1, iv_B1, tv_A1, tv_B1, X1_pi, X1_A, X1_B, icpt_only_pi2, icpt_only_A2, icpt_only_B2, iv_A2, iv_B2, tv_A2, tv_B2, X2_pi, X2_A, X2_B, boot_gamma_pi, boot_gamma_A, boot_gamma_B, start, probs, idx)
}

ame_obs_fanhmm_singlechannel <- function(eta_pi, eta_A, eta_B, obs, Ti, icpt_only_pi1, icpt_only_A1, icpt_only_B1, iv_A1, iv_B1, tv_A1, tv_B1, X1_pi, X1_A, X1_B, icpt_only_pi2, icpt_only_A2, icpt_only_B2, iv_A2, iv_B2, tv_A2, tv_B2, X2_pi, X2_A, X2_B, boot_gamma_pi, boot_gamma_A, boot_gamma_B, start, probs, idx) {
.Call(`_seqHMM_ame_obs_fanhmm_singlechannel`, eta_pi, eta_A, eta_B, obs, Ti, icpt_only_pi1, icpt_only_A1, icpt_only_B1, iv_A1, iv_B1, tv_A1, tv_B1, X1_pi, X1_A, X1_B, icpt_only_pi2, icpt_only_A2, icpt_only_B2, iv_A2, iv_B2, tv_A2, tv_B2, X2_pi, X2_A, X2_B, boot_gamma_pi, boot_gamma_A, boot_gamma_B, start, probs, idx)
ame_obs_fanhmm_singlechannel <- function(eta_pi, eta_A, eta_B, obs, Ti, icpt_only_pi1, icpt_only_A1, icpt_only_B1, iv_A1, iv_B1, tv_A1, tv_B1, X1_pi, X1_A, X1_B, icpt_only_pi2, icpt_only_A2, icpt_only_B2, iv_A2, iv_B2, tv_A2, tv_B2, X2_pi, X2_A, X2_B, boot_gamma_pi, boot_gamma_A, boot_gamma_B, start, probs, idx, W1_A, W1_B, W2_A, W2_B) {
.Call(`_seqHMM_ame_obs_fanhmm_singlechannel`, eta_pi, eta_A, eta_B, obs, Ti, icpt_only_pi1, icpt_only_A1, icpt_only_B1, iv_A1, iv_B1, tv_A1, tv_B1, X1_pi, X1_A, X1_B, icpt_only_pi2, icpt_only_A2, icpt_only_B2, iv_A2, iv_B2, tv_A2, tv_B2, X2_pi, X2_A, X2_B, boot_gamma_pi, boot_gamma_A, boot_gamma_B, start, probs, idx, W1_A, W1_B, W2_A, W2_B)
}

cost_matrix_singlechannel <- function(gamma_pi_est, gamma_pi_ref, gamma_A_est, gamma_A_ref, gamma_B_est, gamma_B_ref) {
Expand Down Expand Up @@ -333,3 +333,7 @@ state_obs_probs_mnhmm_multichannel <- function(eta_omega, X_omega, eta_pi, X_pi,
.Call(`_seqHMM_state_obs_probs_mnhmm_multichannel`, eta_omega, X_omega, eta_pi, X_pi, eta_A, X_A, eta_B, X_B, obs, Ti, icpt_only_omega, icpt_only_pi, icpt_only_A, icpt_only_B, iv_A, iv_B, tv_A, tv_B, start)
}

state_obs_probs_fanhmm_singlechannel <- function(eta_pi, X_pi, eta_A, X_A, eta_B, X_B, obs, Ti, icpt_only_pi, icpt_only_A, icpt_only_B, iv_A, iv_B, tv_A, tv_B, start, W_A, W_B) {
.Call(`_seqHMM_state_obs_probs_fanhmm_singlechannel`, eta_pi, X_pi, eta_A, X_A, eta_B, X_B, obs, Ti, icpt_only_pi, icpt_only_A, icpt_only_B, iv_A, iv_B, tv_A, tv_B, start, W_A, W_B)
}

27 changes: 21 additions & 6 deletions R/ame_obs.R
Original file line number Diff line number Diff line change
Expand Up @@ -248,28 +248,43 @@ ame_obs.fanhmm <- function(
newdata <- model$data
}
newdata[[variable]][newdata[[time]] >= start_time] <- values[1]
X1 <- update(model, newdata)[c("X_pi", "X_A", "X_B", "W_A", "W_B")]
X1 <- update(model, newdata)[c("X_pi", "X_A", "X_B")]
W1_A <- W1_B <- vector("list", model$n_symbols)
# Memory usage could be improved by not computing and storing the full matrices
for (i in seq_len(model$n_symbols)) {
newdata[[model$channel_names]] <- model$symbol_names[[i]]
mod <- update(model, newdata)
W1_A[[i]] <- mod$X_A[, start_time:ncol(mod$X_A), , drop = FALSE]
W1_B[[i]] <- mod$X_B[, start_time:ncol(mod$X_B), , drop = FALSE]
}
newdata[[variable]][newdata[[time]] >= start_time] <- values[2]
X2 <- update(model, newdata)[c("X_pi", "X_A", "X_B", "W_A", "W_B")]
W2_A <- W2_B <- vector("list", model$n_symbols)
X2 <- update(model, newdata)[c("X_pi", "X_A", "X_B")]
for (i in seq_len(model$n_symbols)) {
newdata[[model$channel_names]] <- model$symbol_names[[i]]
mod <- update(model, newdata)
W2_A[[i]] <- mod$X_A[, start_time:ncol(mod$X_A), , drop = FALSE]
W2_B[[i]] <- mod$X_B[, start_time:ncol(mod$X_B), , drop = FALSE]
}
C <- model$n_channels
start <- which(sort(unique(newdata[[time]])) == start_time)
times <- as.numeric(colnames(model$observations))
symbol_names <- list(model$symbol_names)
obs <- create_obsArray(model)[1L, , ]
out <- ame_obs_fanhmm_singlechannel(
model$etas$pi, model$etas$A, model$etas$B, model$rho_A, model$rho_B,
model$etas$pi, model$etas$A, model$etas$B,
obs, model$sequence_lengths,
attr(X1$X_pi, "icpt_only"), attr(X1$X_A, "icpt_only"),
attr(X1$X_B, "icpt_only"), attr(X1$X_A, "iv"),
attr(X1$X_B, "iv"), attr(X1$X_A, "tv"), attr(X1$X_B, "tv"),
X1$X_pi, X1$X_A, X1$X_B, X1$W_A, X1$W_B,
X1$X_pi, X1$X_A, X1$X_B,
attr(X2$X_pi, "icpt_only"), attr(X2$X_A, "icpt_only"),
attr(X2$X_B, "icpt_only"), attr(X2$X_A, "iv"),
attr(X2$X_B, "iv"), attr(X2$X_A, "tv"), attr(X2$X_B, "tv"),
X2$X_pi, X2$X_A, X2$X_B, X2$W_A, X2$W_B,
X2$X_pi, X2$X_A, X2$X_B,
model$boot$gamma_pi, model$boot$gamma_A, model$boot$gamma_B,
model$boot$rho_A, model$boot_rho_B,
start, probs, model$boot$idx - 1L
start, probs, model$boot$idx - 1L, W1_A, W1_B, W2_A, W2_B
)
d <- data.frame(
observation = model$symbol_names,
Expand Down
26 changes: 18 additions & 8 deletions R/model_matrix.R
Original file line number Diff line number Diff line change
@@ -1,12 +1,22 @@
#' Does covariate values vary per ID?
#' @noRd
iv_X <- function(X) {
dim(unique(X, MARGIN = 3))[3] > 1L
all_same <- TRUE
for (i in seq_len(dim(X)[3])) {
all_same <- all_same && all(X[, , i] == X[, , 1])
if (!all_same) break
}
!all_same #dim(unique(X, MARGIN = 3))[3] > 1L
}
#' Does covariate values vary in time?
#' @noRd
tv_X <- function(X) {
dim(unique(X, MARGIN = 2))[2] > 1L
all_same <- TRUE
for (i in seq_len(dim(X)[2])) {
all_same <- all_same && all(X[, i, ] == X[, 1, ])
if (!all_same) break
}
!all_same #dim(unique(X, MARGIN = 2))[2] > 1L
}

# Function to check uniqueness along the N dimension
Expand Down Expand Up @@ -190,9 +200,9 @@ model_matrix_transition_formula <- function(formula, data, n_sequences,
}

if (check) .check_identifiability(X[complete, ], "transition")
dim(X) <- c(length_of_sequences, n_sequences, ncol(X))
n_pars <- n_states * (n_states - 1L) * dim(X)[3]
X <- aperm(X, c(3, 1, 2))
X <- t(X)
dim(X) <- c(nrow(X), length_of_sequences, n_sequences)
n_pars <- n_states * (n_states - 1L) * nrow(X)
iv <- iv_X(X)
tv <- tv_X(X)
missing_values <- which(is.na(X))
Expand Down Expand Up @@ -270,9 +280,9 @@ model_matrix_emission_formula <- function(formula, data, n_sequences,
)
}
if (check) .check_identifiability(X[complete, ], "emission")
dim(X) <- c(length_of_sequences, n_sequences, ncol(X))
n_pars <- sum(n_states * (n_symbols - 1L) * dim(X)[3])
X <- aperm(X, c(3, 1, 2))
X <- t(X)
dim(X) <- c(nrow(X), length_of_sequences, n_sequences)
n_pars <- sum(n_states * (n_symbols - 1L) * nrow(X))
iv <- iv_X(X)
tv <- tv_X(X)
missing_values <- which(is.na(X))
Expand Down
49 changes: 41 additions & 8 deletions src/RcppExports.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -94,8 +94,8 @@ BEGIN_RCPP
END_RCPP
}
// ame_obs_fanhmm_singlechannel
Rcpp::List ame_obs_fanhmm_singlechannel(arma::mat& eta_pi, arma::cube& eta_A, arma::cube& eta_B, const arma::umat& obs, const arma::uvec Ti, const bool icpt_only_pi1, const bool icpt_only_A1, const bool icpt_only_B1, const bool iv_A1, const bool iv_B1, const bool tv_A1, const bool tv_B1, const arma::mat& X1_pi, const arma::field<arma::cube>& X1_A, const arma::field<arma::cube>& X1_B, const bool icpt_only_pi2, const bool icpt_only_A2, const bool icpt_only_B2, const bool iv_A2, const bool iv_B2, const bool tv_A2, const bool tv_B2, const arma::mat& X2_pi, const arma::field<arma::cube>& X2_A, const arma::field<arma::cube>& X2_B, const arma::field<arma::mat>& boot_gamma_pi, const arma::field<arma::cube>& boot_gamma_A, const arma::field<arma::cube>& boot_gamma_B, const arma::uword start, const arma::vec& probs, const arma::umat& idx);
RcppExport SEXP _seqHMM_ame_obs_fanhmm_singlechannel(SEXP eta_piSEXP, SEXP eta_ASEXP, SEXP eta_BSEXP, SEXP obsSEXP, SEXP TiSEXP, SEXP icpt_only_pi1SEXP, SEXP icpt_only_A1SEXP, SEXP icpt_only_B1SEXP, SEXP iv_A1SEXP, SEXP iv_B1SEXP, SEXP tv_A1SEXP, SEXP tv_B1SEXP, SEXP X1_piSEXP, SEXP X1_ASEXP, SEXP X1_BSEXP, SEXP icpt_only_pi2SEXP, SEXP icpt_only_A2SEXP, SEXP icpt_only_B2SEXP, SEXP iv_A2SEXP, SEXP iv_B2SEXP, SEXP tv_A2SEXP, SEXP tv_B2SEXP, SEXP X2_piSEXP, SEXP X2_ASEXP, SEXP X2_BSEXP, SEXP boot_gamma_piSEXP, SEXP boot_gamma_ASEXP, SEXP boot_gamma_BSEXP, SEXP startSEXP, SEXP probsSEXP, SEXP idxSEXP) {
Rcpp::List ame_obs_fanhmm_singlechannel(arma::mat& eta_pi, arma::cube& eta_A, arma::cube& eta_B, const arma::umat& obs, const arma::uvec Ti, const bool icpt_only_pi1, const bool icpt_only_A1, const bool icpt_only_B1, const bool iv_A1, const bool iv_B1, const bool tv_A1, const bool tv_B1, const arma::mat& X1_pi, const arma::cube& X1_A, const arma::cube& X1_B, const bool icpt_only_pi2, const bool icpt_only_A2, const bool icpt_only_B2, const bool iv_A2, const bool iv_B2, const bool tv_A2, const bool tv_B2, const arma::mat& X2_pi, const arma::cube& X2_A, const arma::cube& X2_B, const arma::field<arma::mat>& boot_gamma_pi, const arma::field<arma::cube>& boot_gamma_A, const arma::field<arma::cube>& boot_gamma_B, const arma::uword start, const arma::vec& probs, const arma::umat& idx, const arma::field<arma::cube>& W1_A, const arma::field<arma::cube>& W1_B, const arma::field<arma::cube>& W2_A, const arma::field<arma::cube>& W2_B);
RcppExport SEXP _seqHMM_ame_obs_fanhmm_singlechannel(SEXP eta_piSEXP, SEXP eta_ASEXP, SEXP eta_BSEXP, SEXP obsSEXP, SEXP TiSEXP, SEXP icpt_only_pi1SEXP, SEXP icpt_only_A1SEXP, SEXP icpt_only_B1SEXP, SEXP iv_A1SEXP, SEXP iv_B1SEXP, SEXP tv_A1SEXP, SEXP tv_B1SEXP, SEXP X1_piSEXP, SEXP X1_ASEXP, SEXP X1_BSEXP, SEXP icpt_only_pi2SEXP, SEXP icpt_only_A2SEXP, SEXP icpt_only_B2SEXP, SEXP iv_A2SEXP, SEXP iv_B2SEXP, SEXP tv_A2SEXP, SEXP tv_B2SEXP, SEXP X2_piSEXP, SEXP X2_ASEXP, SEXP X2_BSEXP, SEXP boot_gamma_piSEXP, SEXP boot_gamma_ASEXP, SEXP boot_gamma_BSEXP, SEXP startSEXP, SEXP probsSEXP, SEXP idxSEXP, SEXP W1_ASEXP, SEXP W1_BSEXP, SEXP W2_ASEXP, SEXP W2_BSEXP) {
BEGIN_RCPP
Rcpp::RObject rcpp_result_gen;
Rcpp::RNGScope rcpp_rngScope_gen;
Expand All @@ -112,8 +112,8 @@ BEGIN_RCPP
Rcpp::traits::input_parameter< const bool >::type tv_A1(tv_A1SEXP);
Rcpp::traits::input_parameter< const bool >::type tv_B1(tv_B1SEXP);
Rcpp::traits::input_parameter< const arma::mat& >::type X1_pi(X1_piSEXP);
Rcpp::traits::input_parameter< const arma::field<arma::cube>& >::type X1_A(X1_ASEXP);
Rcpp::traits::input_parameter< const arma::field<arma::cube>& >::type X1_B(X1_BSEXP);
Rcpp::traits::input_parameter< const arma::cube& >::type X1_A(X1_ASEXP);
Rcpp::traits::input_parameter< const arma::cube& >::type X1_B(X1_BSEXP);
Rcpp::traits::input_parameter< const bool >::type icpt_only_pi2(icpt_only_pi2SEXP);
Rcpp::traits::input_parameter< const bool >::type icpt_only_A2(icpt_only_A2SEXP);
Rcpp::traits::input_parameter< const bool >::type icpt_only_B2(icpt_only_B2SEXP);
Expand All @@ -122,15 +122,19 @@ BEGIN_RCPP
Rcpp::traits::input_parameter< const bool >::type tv_A2(tv_A2SEXP);
Rcpp::traits::input_parameter< const bool >::type tv_B2(tv_B2SEXP);
Rcpp::traits::input_parameter< const arma::mat& >::type X2_pi(X2_piSEXP);
Rcpp::traits::input_parameter< const arma::field<arma::cube>& >::type X2_A(X2_ASEXP);
Rcpp::traits::input_parameter< const arma::field<arma::cube>& >::type X2_B(X2_BSEXP);
Rcpp::traits::input_parameter< const arma::cube& >::type X2_A(X2_ASEXP);
Rcpp::traits::input_parameter< const arma::cube& >::type X2_B(X2_BSEXP);
Rcpp::traits::input_parameter< const arma::field<arma::mat>& >::type boot_gamma_pi(boot_gamma_piSEXP);
Rcpp::traits::input_parameter< const arma::field<arma::cube>& >::type boot_gamma_A(boot_gamma_ASEXP);
Rcpp::traits::input_parameter< const arma::field<arma::cube>& >::type boot_gamma_B(boot_gamma_BSEXP);
Rcpp::traits::input_parameter< const arma::uword >::type start(startSEXP);
Rcpp::traits::input_parameter< const arma::vec& >::type probs(probsSEXP);
Rcpp::traits::input_parameter< const arma::umat& >::type idx(idxSEXP);
rcpp_result_gen = Rcpp::wrap(ame_obs_fanhmm_singlechannel(eta_pi, eta_A, eta_B, obs, Ti, icpt_only_pi1, icpt_only_A1, icpt_only_B1, iv_A1, iv_B1, tv_A1, tv_B1, X1_pi, X1_A, X1_B, icpt_only_pi2, icpt_only_A2, icpt_only_B2, iv_A2, iv_B2, tv_A2, tv_B2, X2_pi, X2_A, X2_B, boot_gamma_pi, boot_gamma_A, boot_gamma_B, start, probs, idx));
Rcpp::traits::input_parameter< const arma::field<arma::cube>& >::type W1_A(W1_ASEXP);
Rcpp::traits::input_parameter< const arma::field<arma::cube>& >::type W1_B(W1_BSEXP);
Rcpp::traits::input_parameter< const arma::field<arma::cube>& >::type W2_A(W2_ASEXP);
Rcpp::traits::input_parameter< const arma::field<arma::cube>& >::type W2_B(W2_BSEXP);
rcpp_result_gen = Rcpp::wrap(ame_obs_fanhmm_singlechannel(eta_pi, eta_A, eta_B, obs, Ti, icpt_only_pi1, icpt_only_A1, icpt_only_B1, iv_A1, iv_B1, tv_A1, tv_B1, X1_pi, X1_A, X1_B, icpt_only_pi2, icpt_only_A2, icpt_only_B2, iv_A2, iv_B2, tv_A2, tv_B2, X2_pi, X2_A, X2_B, boot_gamma_pi, boot_gamma_A, boot_gamma_B, start, probs, idx, W1_A, W1_B, W2_A, W2_B));
return rcpp_result_gen;
END_RCPP
}
Expand Down Expand Up @@ -1672,11 +1676,39 @@ BEGIN_RCPP
return rcpp_result_gen;
END_RCPP
}
// state_obs_probs_fanhmm_singlechannel
Rcpp::List state_obs_probs_fanhmm_singlechannel(arma::mat& eta_pi, const arma::mat& X_pi, arma::cube& eta_A, const arma::cube& X_A, arma::cube& eta_B, const arma::cube& X_B, const arma::umat& obs, const arma::uvec Ti, const bool icpt_only_pi, const bool icpt_only_A, const bool icpt_only_B, const bool iv_A, const bool iv_B, const bool tv_A, const bool tv_B, const arma::uword start, const arma::field<arma::cube>& W_A, const arma::field<arma::cube>& W_B);
RcppExport SEXP _seqHMM_state_obs_probs_fanhmm_singlechannel(SEXP eta_piSEXP, SEXP X_piSEXP, SEXP eta_ASEXP, SEXP X_ASEXP, SEXP eta_BSEXP, SEXP X_BSEXP, SEXP obsSEXP, SEXP TiSEXP, SEXP icpt_only_piSEXP, SEXP icpt_only_ASEXP, SEXP icpt_only_BSEXP, SEXP iv_ASEXP, SEXP iv_BSEXP, SEXP tv_ASEXP, SEXP tv_BSEXP, SEXP startSEXP, SEXP W_ASEXP, SEXP W_BSEXP) {
BEGIN_RCPP
Rcpp::RObject rcpp_result_gen;
Rcpp::RNGScope rcpp_rngScope_gen;
Rcpp::traits::input_parameter< arma::mat& >::type eta_pi(eta_piSEXP);
Rcpp::traits::input_parameter< const arma::mat& >::type X_pi(X_piSEXP);
Rcpp::traits::input_parameter< arma::cube& >::type eta_A(eta_ASEXP);
Rcpp::traits::input_parameter< const arma::cube& >::type X_A(X_ASEXP);
Rcpp::traits::input_parameter< arma::cube& >::type eta_B(eta_BSEXP);
Rcpp::traits::input_parameter< const arma::cube& >::type X_B(X_BSEXP);
Rcpp::traits::input_parameter< const arma::umat& >::type obs(obsSEXP);
Rcpp::traits::input_parameter< const arma::uvec >::type Ti(TiSEXP);
Rcpp::traits::input_parameter< const bool >::type icpt_only_pi(icpt_only_piSEXP);
Rcpp::traits::input_parameter< const bool >::type icpt_only_A(icpt_only_ASEXP);
Rcpp::traits::input_parameter< const bool >::type icpt_only_B(icpt_only_BSEXP);
Rcpp::traits::input_parameter< const bool >::type iv_A(iv_ASEXP);
Rcpp::traits::input_parameter< const bool >::type iv_B(iv_BSEXP);
Rcpp::traits::input_parameter< const bool >::type tv_A(tv_ASEXP);
Rcpp::traits::input_parameter< const bool >::type tv_B(tv_BSEXP);
Rcpp::traits::input_parameter< const arma::uword >::type start(startSEXP);
Rcpp::traits::input_parameter< const arma::field<arma::cube>& >::type W_A(W_ASEXP);
Rcpp::traits::input_parameter< const arma::field<arma::cube>& >::type W_B(W_BSEXP);
rcpp_result_gen = Rcpp::wrap(state_obs_probs_fanhmm_singlechannel(eta_pi, X_pi, eta_A, X_A, eta_B, X_B, obs, Ti, icpt_only_pi, icpt_only_A, icpt_only_B, iv_A, iv_B, tv_A, tv_B, start, W_A, W_B));
return rcpp_result_gen;
END_RCPP
}

static const R_CallMethodDef CallEntries[] = {
{"_seqHMM_ame_obs_nhmm_singlechannel", (DL_FUNC) &_seqHMM_ame_obs_nhmm_singlechannel, 31},
{"_seqHMM_ame_obs_nhmm_multichannel", (DL_FUNC) &_seqHMM_ame_obs_nhmm_multichannel, 31},
{"_seqHMM_ame_obs_fanhmm_singlechannel", (DL_FUNC) &_seqHMM_ame_obs_fanhmm_singlechannel, 31},
{"_seqHMM_ame_obs_fanhmm_singlechannel", (DL_FUNC) &_seqHMM_ame_obs_fanhmm_singlechannel, 35},
{"_seqHMM_cost_matrix_singlechannel", (DL_FUNC) &_seqHMM_cost_matrix_singlechannel, 6},
{"_seqHMM_cost_matrix_multichannel", (DL_FUNC) &_seqHMM_cost_matrix_multichannel, 6},
{"_seqHMM_cost_matrix_clusters", (DL_FUNC) &_seqHMM_cost_matrix_clusters, 2},
Expand Down Expand Up @@ -1757,6 +1789,7 @@ static const R_CallMethodDef CallEntries[] = {
{"_seqHMM_state_obs_probs_nhmm_multichannel", (DL_FUNC) &_seqHMM_state_obs_probs_nhmm_multichannel, 16},
{"_seqHMM_state_obs_probs_mnhmm_singlechannel", (DL_FUNC) &_seqHMM_state_obs_probs_mnhmm_singlechannel, 19},
{"_seqHMM_state_obs_probs_mnhmm_multichannel", (DL_FUNC) &_seqHMM_state_obs_probs_mnhmm_multichannel, 19},
{"_seqHMM_state_obs_probs_fanhmm_singlechannel", (DL_FUNC) &_seqHMM_state_obs_probs_fanhmm_singlechannel, 18},
{NULL, NULL, 0}
};

Expand Down
Loading

0 comments on commit ea1be76

Please sign in to comment.