#' Create Function-based Historical Matrix Projection Model
#' 
#' Function \code{flefko3()} returns function-based historical MPMs
#' corresponding to the patches and occasions given, including the associated
#' component transition and fecundity matrices, data frames detailing the
#' characteristics of the ahistorical stages used and historical stage pairs
#' created, and a data frame characterizing the patch and occasion combinations
#' corresponding to these matrices.
#' 
#' @name flefko3
#' 
#' @param year A variable corresponding to the observation occasion, or a set
#' of such values, given in values associated with the year term used in linear 
#' model development. Defaults to \code{"all"}, in which case matrices will be
#' estimated for all occasions.
#' @param patch A variable designating which patches or subpopulations will have
#' matrices estimated. Defaults to \code{"all"}, but can also be set to specific
#' patch names or a vector thereof.
#' @param stageframe An object of class \code{stageframe}. These objects are
#' generated by function \code{\link{sf_create}()}, and include information on
#' the size, observation status, propagule status, reproduction status,
#' immaturity status, maturity status, stage group, size bin widths, and other
#' key characteristics of each ahistorical stage.
#' @param supplement An optional data frame of class \code{lefkoSD} that
#' provides supplemental data that should be incorporated into the MPM. Three
#' kinds of data may be integrated this way: transitions to be estimated via the
#' use of proxy transitions, transition overwrites from the literature or
#' supplemental studies, and transition multipliers for survival and fecundity.
#' This data frame should be produced using the \code{\link{supplemental}()}
#' function. Can be used in place of or in addition to an overwrite table (see 
#' \code{overwrite} below) and a reproduction matrix (see \code{repmatrix}
#' below).
#' @param repmatrix An optional reproduction matrix. This matrix is composed
#' mostly of \code{0}s, with non-zero entries acting as element identifiers and
#' multipliers for fecundity (with \code{1} equaling full fecundity). If left
#' blank, and no \code{supplement} is provided, then \code{flefko3()} will
#' assume that all stages marked as reproductive produce offspring at 1x that of
#' estimated fecundity, and that offspring production will yield the first stage
#' noted as propagule or immature. May be the dimensions of either a historical
#' or an ahistorical matrix. If the latter, then all stages will be used in
#' occasion \emph{t}-1 for each suggested ahistorical transition.
#' @param overwrite An optional data frame developed with the
#' \code{\link{overwrite}()} function describing transitions to be overwritten
#' either with given values or with other estimated transitions. Note that this
#' function supplements overwrite data provided in \code{supplement}.
#' @param data The historical vertical demographic data frame used to estimate
#' vital rates (class \code{hfvdata}), which is required to initialize times and
#' patches properly. Variable names should correspond to the naming conventions
#' in \code{\link{verticalize3}()} and \code{\link{historicalize3}()}. Not
#' required if option \code{modelsuite} is set to a \code{vrm_input} object.
#' @param modelsuite One of three kinds of lists. The first is a \code{lefkoMod}
#' object holding the vital rate models and associated metadata. The second is
#' a \code{lefkoModList} object, which is a list of \code{lefkoMod} objects
#' generally created to conduct a bootstrapped MPM analysis. Alternatively,
#' an object of class \code{vrm_input} may be provided. If given, then
#' \code{surv_model}, \code{obs_model}, \code{size_model}, \code{sizeb_model},
#' \code{sizec_model}, \code{repst_model}, \code{fec_model}, \code{jsurv_model},
#' \code{jobs_model}, \code{jsize_model}, \code{jsizeb_model},
#' \code{jsizec_model}, \code{jrepst_model}, \code{jmatst_model}, and
#' \code{paramnames} are not required. One or more of these models should
#' include size or reproductive status in occasion \emph{t}-1. Although this is
#' optional input, it is recommended, and without it all vital rate model inputs
#' (named \code{XX_model}) are required.
#' @param surv_model A linear model predicting survival probability. This can 
#' be a model of class \code{glm} or \code{glmer}, and requires a predicted
#' binomial variable under a logit link. Ignored if \code{modelsuite} is
#' provided. This model must have been developed in a modeling exercise testing
#' the impacts of occasions \emph{t} and \emph{t}-1.
#' @param obs_model A linear model predicting sprouting or observation
#' probability. This can be a model of class \code{glm} or \code{glmer}, and
#' requires a predicted binomial variable under a logit link. Ignored if
#' \code{modelsuite} is provided. This model must have been developed in a
#' modeling exercise testing the impacts of occasions \emph{t} and \emph{t}-1.
#' @param size_model A linear model predicting primary size. This can be a model
#' of class \code{glm}, \code{glmer}, \code{glmmTMB}, \code{zeroinfl},
#' \code{vglm}, \code{lm}, or \code{lmer}. Ignored if \code{modelsuite} is
#' provided. This model must have been developed in a modeling exercise testing
#' the impacts of occasions \emph{t} and \emph{t}-1.
#' @param sizeb_model A linear model predicting secondary size. This can be a
#' model of class \code{glm}, \code{glmer}, \code{glmmTMB}, \code{zeroinfl},
#' \code{vglm}, \code{lm}, or \code{lmer}. Ignored if \code{modelsuite} is
#' provided. This model must have been developed in a modeling exercise testing
#' the impacts of occasions \emph{t} and \emph{t}-1.
#' @param sizec_model A linear model predicting tertiary size. This can be a
#' model of class \code{glm}, \code{glmer}, \code{glmmTMB}, \code{zeroinfl},
#' \code{vglm}, \code{lm}, or \code{lmer}. Ignored if \code{modelsuite} is
#' provided. This model must have been developed in a modeling exercise testing
#' the impacts of occasions \emph{t} and \emph{t}-1.
#' @param repst_model A linear model predicting reproduction probability. This 
#' can be a model of class \code{glm} or \code{glmer}, and requires a predicted
#' binomial variable under a logit link. Ignored if \code{modelsuite} is
#' provided. This model must have been developed in a modeling exercise testing
#' the impacts of occasions \emph{t} and \emph{t}-1.
#' @param fec_model A linear model predicting fecundity. This can be a model of
#' class \code{glm}, \code{glmer}, \code{glmmTMB}, \code{zeroinfl}, \code{vglm},
#' \code{lm}, or \code{lmer}. Ignored if \code{modelsuite} is provided. This
#' model must have been developed in a modeling exercise testing the impacts of
#' occasions \emph{t} and \emph{t}-1.
#' @param jsurv_model A linear model predicting juvenile survival probability.
#' This can be a model of class \code{glm} or \code{glmer}, and requires a
#' predicted binomial variable under a logit link. Ignored if \code{modelsuite}
#' is provided. This model must have been developed in a modeling exercise
#' testing the impacts of occasions \emph{t} and \emph{t}-1.
#' @param jobs_model A linear model predicting juvenile sprouting or observation
#' probability. This can be a model of class \code{glm} or \code{glmer}, and
#' requires a predicted binomial variable under a logit link. Ignored if
#' \code{modelsuite} is provided. This model must have been developed in a
#' modeling exercise testing the impacts of occasions \emph{t} and \emph{t}-1.
#' @param jsize_model A linear model predicting juvenile primary size. This
#' can be a model of class \code{glm}, \code{glmer}, \code{glmmTMB},
#' \code{zeroinfl}, \code{vglm}, \code{lm}, or \code{lmer}. Ignored if
#' \code{modelsuite} is provided. This model must have been developed in a
#' modeling exercise testing the impacts of occasions \emph{t} and \emph{t}-1.
#' @param jsizeb_model A linear model predicting juvenile secondary size. This
#' can be a model of class \code{glm}, \code{glmer}, \code{glmmTMB},
#' \code{zeroinfl}, \code{vglm}, \code{lm}, or \code{lmer}. Ignored if
#' \code{modelsuite} is provided. This model must have been developed in a
#' modeling exercise testing the impacts of occasions \emph{t} and \emph{t}-1.
#' @param jsizec_model A linear model predicting juvenile tertiary size. This
#' can be a model of class \code{glm}, \code{glmer}, \code{glmmTMB},
#' \code{zeroinfl}, \code{vglm}, \code{lm}, or \code{lmer}. Ignored if
#' \code{modelsuite} is provided. This model must have been developed in a
#' modeling exercise testing the impacts of occasions \emph{t} and \emph{t}-1.
#' @param jrepst_model A linear model predicting reproduction probability of a 
#' mature individual that was immature in time \emph{t}. This can be a model
#' of class \code{glm} or \code{glmer}, and requires a predicted binomial
#' variable under a logit link. Ignored if \code{modelsuite} is provided. This
#' model must have been developed in a modeling exercise testing the impacts of
#' occasions \emph{t} and \emph{t}-1.
#' @param jmatst_model A linear model predicting maturity probability of an 
#' individual that was immature in time \emph{t}. This can be a model of class
#' \code{glm} or \code{glmer}, and requires a predicted binomial variable under
#' a logit link. Ignored if \code{modelsuite} is provided. This model must have
#' been developed in a modeling exercise testing the impacts of occasions
#' \emph{t} and \emph{t}-1.
#' @param paramnames A data frame with three columns, the first describing all
#' terms used in linear modeling, the second (must be called \code{mainparams})
#' giving the general model terms that will be used in matrix creation, and the
#' third showing the equivalent terms used in modeling (must be named
#' \code{modelparams}). Function \code{\link{create_pm}()} can be used to
#' create a skeleton \code{paramnames} object, which can then be edited. Only
#' required if \code{modelsuite} is not supplied.
#' @param inda Can be a single value to use for individual covariate \code{a}
#' in all matrices, a pair of values to use for times \emph{t} and \emph{t}-1 in
#' historical matrices, or a vector of such values corresponding to each
#' occasion in the dataset. Defaults to \code{NULL}.
#' @param indb Can be a single value to use for individual covariate \code{b}
#' in all matrices, a pair of values to use for times \emph{t} and \emph{t}-1 in
#' historical matrices, or a vector of such values corresponding to each
#' occasion in the dataset. Defaults to \code{NULL}.
#' @param indc Can be a single value to use for individual covariate \code{c}
#' in all matrices, a pair of values to use for times \emph{t} and \emph{t}-1 in
#' historical matrices, or a vector of such values corresponding to each
#' occasion in the dataset. Defaults to \code{NULL}.
#' @param annua Can be a single value to use for annual covariate \code{a}
#' in all matrices, a pair of values to use for times \emph{t} and \emph{t}-1 in
#' historical matrices, or a vector of such values corresponding to each
#' occasion in the dataset. Defaults to \code{NULL}.
#' @param annub Can be a single value to use for annual covariate \code{b}
#' in all matrices, a pair of values to use for times \emph{t} and \emph{t}-1 in
#' historical matrices, or a vector of such values corresponding to each
#' occasion in the dataset. Defaults to \code{NULL}.
#' @param annuc Can be a single value to use for annual covariate \code{c}
#' in all matrices, a pair of values to use for times \emph{t} and \emph{t}-1 in
#' historical matrices, or a vector of such values corresponding to each
#' occasion in the dataset. Defaults to \code{NULL}.
#' @param surv_dev A numeric value to be added to the y-intercept in the linear
#' model for survival probability. Defaults to \code{0}.
#' @param obs_dev A numeric value to be added to the y-intercept in the linear
#' model for observation probability. Defaults to \code{0}.
#' @param size_dev A numeric value to be added to the y-intercept in the linear
#' model for primary size. Defaults to \code{0}.
#' @param sizeb_dev A numeric value to be added to the y-intercept in the linear
#' model for secondary size. Defaults to \code{0}.
#' @param sizec_dev A numeric value to be added to the y-intercept in the linear
#' model for tertiary size. Defaults to \code{0}.
#' @param repst_dev A numeric value to be added to the y-intercept in the linear
#' model for probability of reproduction. Defaults to \code{0}.
#' @param fec_dev A numeric value to be added to the y-intercept in the linear
#' model for fecundity. Defaults to \code{0}.
#' @param jsurv_dev A numeric value to be added to the y-intercept in the linear
#' model for juvenile survival probability. Defaults to \code{0}.
#' @param jobs_dev A numeric value to be added to the y-intercept in the linear
#' model for juvenile observation probability. Defaults to \code{0}.
#' @param jsize_dev A numeric value to be added to the y-intercept in the linear
#' model for juvenile primary size. Defaults to \code{0}.
#' @param jsizeb_dev A numeric value to be added to the y-intercept in the
#' linear model for juvenile secondary size. Defaults to \code{0}.
#' @param jsizec_dev A numeric value to be added to the y-intercept in the
#' linear model for juvenile tertiary size. Defaults to \code{0}.
#' @param jrepst_dev A numeric value to be added to the y-intercept in the
#' linear model for juvenile reproduction probability. Defaults to \code{0}.
#' @param jmatst_dev A numeric value to be added to the y-intercept in the
#' linear model for juvenile maturity probability. Defaults to \code{0}.
#' @param density A numeric value indicating density value to use to propagate
#' matrices. Only needed if density is an explanatory term used in one or more
#' vital rate models. Defaults to \code{NA}.
#' @param fecmod A scalar multiplier of fecundity. Defaults to \code{1.0}.
#' @param random.inda A logical value denoting whether to treat individual
#' covariate \code{a} as a random, categorical variable. Otherwise is treated as
#' a fixed, numeric variable. Defaults to \code{FALSE}.
#' @param random.indb A logical value denoting whether to treat individual
#' covariate \code{b} as a random, categorical variable. Otherwise is treated as
#' a fixed, numeric variable. Defaults to \code{FALSE}.
#' @param random.indc A logical value denoting whether to treat individual
#' covariate \code{c} as a random, categorical variable. Otherwise is treated as
#' a fixed, numeric variable. Defaults to \code{FALSE}.
#' @param negfec A logical value denoting whether fecundity values estimated to
#' be negative should be reset to \code{0}. Defaults to \code{FALSE}.
#' @param format A string indicating whether to estimate matrices in
#' \code{ehrlen} format or \code{deVries} format. The latter adds one extra
#' prior stage to account for the prior state of newborns. Defaults to
#' \code{ehrlen} format.
#' @param ipm_method A string indicating what method to use to estimate size
#' transition probabilities, if size is treated as continuous. Options include:
#' \code{"midpoint"}, which utilizes the midpoint method; and \code{"CDF"},
#' which uses the cumulative distribution function. Defaults to \code{"CDF"}.
#' @param reduce A logical value denoting whether to remove historical stages
#' associated solely with \code{0} transitions. These are only removed in cases
#' where the associated row and column sums in ALL matrices estimated equal 0. 
#' Defaults to \code{FALSE}.
#' @param simple A logical value indicating whether to produce \code{A},
#' \code{U}, and \code{F} matrices, or only the latter two. Defaults to
#' \code{FALSE}, in which case all three are output.
#' @param err_check A logical value indicating whether to append extra
#' information used in matrix calculation within the output list. Defaults to
#' \code{FALSE}.
#' @param exp_tol A numeric value used to indicate a maximum value to set
#' exponents to in the core kernel to prevent numerical overflow. Defaults to
#' \code{700}.
#' @param theta_tol A numeric value used to indicate a maximum value to theta as
#' used in the negative binomial probability density kernel. Defaults to
#' \code{100000000}, but can be reset to other values during error checking.
#' @param sparse_output A logical value indicating whether to output matrices
#' in sparse format. Defaults to \code{FALSE}, in which case all matrices are
#' output in standard matrix format.
#'
#' @return If the user inputs a standard \code{lefkoMod} or \code{vrm_input}
#' object in argument \code{modelsuite}, or individual vital rate models are
#' input separately,then this function will return an object of class
#' \code{lefkoMat}. If the user inputs an object of class \code{lefkoModList}
#' in argument \code{modelsuite}, then the output will be an object of class
#' \code{lefkoMatList}, in which each element is an object of class
#' \code{lefkoMat}.
#' 
#' A \code{lefkoMat} object is a list that holds one full  matrix projection
#' model and all of its metadata. The structure has the following elements:
#' 
#' \item{A}{A list of full projection matrices in order of sorted patches and
#' occasion times. All matrices output in R's \code{matrix} class, or in
#' the \code{dgCMatrix} class from the \code{Matrix} package if sparse.}
#' \item{U}{A list of survival transition matrices sorted as in \code{A}. All 
#' matrices output in R's \code{matrix} class, or in the \code{dgCMatrix} class
#' from the \code{Matrix} package if sparse.}
#' \item{F}{A list of fecundity matrices sorted as in \code{A}. All matrices 
#' output in R's \code{matrix} class, or in the \code{dgCMatrix} class from the
#' \code{Matrix} package if sparse.}
#' \item{hstages}{A data frame matrix showing the pairing of ahistorical stages
#' used to create historical stage pairs.}
#' \item{agestages}{A data frame showing age-stage pairs. In this function, it
#' is set to \code{NA}. Only used in output to function \code{aflefko2}().}
#' \item{ahstages}{A data frame detailing the characteristics of associated
#' ahistorical stages, in the form of a modified stageframe that includes
#' status as an entry stage through reproduction.}
#' \item{labels}{A data frame giving the population, patch, and year of each
#' matrix in order. In \code{flefko3()}, only one population may be analyzed at
#' once.}
#' \item{dataqc}{A vector showing the numbers of individuals and rows in the
#' vertical dataset used as input.}
#' \item{matrixqc}{A short vector describing the number of non-zero elements in
#' \code{U} and \code{F} matrices, and the number of annual matrices.}
#' \item{modelqc}{This is the \code{qc} portion of the \code{modelsuite} input.}
#' \item{prob_out}{An optional element only added if \code{err_check = TRUE}.
#' This is a list of vital rate probability matrices, with 7 columns in the
#' order of survival, observation probability, reproduction probability, primary
#' size transition probability, secondary size transition probability, tertiary
#' size transition probability, and probability of juvenile transition to
#' maturity.}
#' \item{allstages}{An optional element only added if \code{err_check = TRUE}.
#' This is a data frame giving the values used to determine each matrix element
#' capable of being estimated.}
#' 
#' @section Notes:
#' Unlike \code{\link{rlefko2}()}, \code{\link{rlefko3}()},
#' \code{\link{arlefko2}()}, and \code{\link{rleslie}()}, this function does not
#' currently distinguish populations. Users wishing to use the same vital rate
#' models across populations should label them as patches (though we do not
#' advise this approach, as populations should typically be treated as
#' statistically independent).
#' 
#' The default behavior of this function is to estimate fecundity with regards
#' to transitions specified via associated fecundity multipliers in the
#' \code{supplement}. If this field is left empty, then fecundity will be
#' estimated at full for all transitions leading from reproductive stages to
#' immature and propagule stages.
#' 
#' Users may at times wish to estimate MPMs using a dataset incorporating
#' multiple patches or subpopulations, but without discriminating between those
#' patches or subpopulations. Should the aim of analysis be a general MPM that
#' does not distinguish these patches or subpopulations, the
#' \code{modelsearch()} run should not include patch terms.
#'
#' Input options including multiple variable names must be entered in the order
#' of variables in occasion \emph{t}+1, \emph{t}, and \emph{t}-1. Rearranging
#' the order will lead to erroneous calculations, and will may lead to fatal
#' errors.
#' 
#' The \code{ipm_method} function gives the option of using two different means
#' of estimating the probability of size transition. The midpoint method
#' (\code{"midpoint"}) refers to the method in which the probability is
#' estimated by first estimating the probability associated with transition from
#' the exact size at the midpoint of the size class using the corresponding
#' probability density function, and then multiplying that value by the bin
#' width of the size class. Doak et al. 2021 (Ecological Monographs) noted that
#' this method can produce biased results, with total size transitions
#' associated with a specific size not totaling to 1.0 and even specific size
#' transition probabilities capable of being estimated at values greater than
#' 1.0. The alternative and default method, \code{"CDF"}, uses the corresponding
#' cumulative density function to estimate the probability of size transition as
#' the cumulative probability of size transition at the greater limit of the
#' size class minus the cumulative probability of size transition at the lower
#' limit of the size class. This latter method avoids this bias. Note, however,
#' that both methods are exact and unbiased for negative binomial and Poisson
#' distributions.
#' 
#' Under the Gaussian and gamma size distributions, the number of estimated
#' parameters may differ between the two \code{ipm_method} settings. Because
#' the midpoint method has a tendency to incorporate upward bias in the
#' estimation of size transition probabilities, it is more likely to yield non-
#' zero values when the true probability is extremely close to 0. This will
#' result in the \code{summary.lefkoMat} function yielding higher numbers of
#' estimated parameters than the \code{ipm_method = "CDF"} yields in some cases.
#' 
#' Using the \code{err_check} option will produce a matrix of 7 columns, each
#' characterizing a different vital rate. The product of each row yields an
#' element in the associated \code{U} matrix. The number and order of elements
#' in each column of this matrix matches the associated matrix in column vector
#' format. Use of this option is generally for the purposes of debugging code.
#'`
#' Individual covariates are treated as categorical only if they are set as
#' random terms. Fixed categorical individual covariates are currently not
#' allowed. However, such terms may be supplied if the \code{modelsuite} option
#' is set to a \code{vrm_input} object. In that case, the user should also set
#' the logical random switch for the individual covariate to be used to 
#' \code{TRUE} (e.g., \code{random.inda = TRUE}).
#' 
#' @seealso \code{\link{mpm_create}()}
#' @seealso \code{\link{flefko2}()}
#' @seealso \code{\link{aflefko2}()}
#' @seealso \code{\link{arlefko2}()}
#' @seealso \code{\link{fleslie}()}
#' @seealso \code{\link{rlefko3}()}
#' @seealso \code{\link{rlefko2}()}
#' @seealso \code{\link{rleslie}()}
#' 
#' @examples
#' \donttest{
#' # Lathyrus example
#' data(lathyrus)
#' 
#' sizevector <- c(0, 4.6, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 1, 2, 3, 4, 5, 6, 7, 8,
#'   9)
#' stagevector <- c("Sd", "Sdl", "Dorm", "Sz1nr", "Sz2nr", "Sz3nr", "Sz4nr",
#'   "Sz5nr", "Sz6nr", "Sz7nr", "Sz8nr", "Sz9nr", "Sz1r", "Sz2r", "Sz3r", 
#'   "Sz4r", "Sz5r", "Sz6r", "Sz7r", "Sz8r", "Sz9r")
#' repvector <- c(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1)
#' obsvector <- c(0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1)
#' matvector <- c(0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1)
#' immvector <- c(1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
#' propvector <- c(1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
#'   0)
#' indataset <- c(0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1)
#' binvec <- c(0, 4.6, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 
#'   0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5)
#' 
#' lathframeln <- sf_create(sizes = sizevector, stagenames = stagevector, 
#'   repstatus = repvector, obsstatus = obsvector, matstatus = matvector, 
#'   immstatus = immvector, indataset = indataset, binhalfwidth = binvec, 
#'   propstatus = propvector)
#' 
#' lathvertln <- verticalize3(lathyrus, noyears = 4, firstyear = 1988,
#'   patchidcol = "SUBPLOT", individcol = "GENET", blocksize = 9, 
#'   juvcol = "Seedling1988", sizeacol = "lnVol88", repstracol = "Intactseed88",
#'   fecacol = "Intactseed88", deadacol = "Dead1988", 
#'   nonobsacol = "Dormant1988", stageassign = lathframeln, stagesize = "sizea",
#'   censorcol = "Missing1988", censorkeep = NA, NAas0 = TRUE, censor = TRUE)
#' 
#' lathvertln$feca2 <- round(lathvertln$feca2)
#' lathvertln$feca1 <- round(lathvertln$feca1)
#' lathvertln$feca3 <- round(lathvertln$feca3)
#' 
#' lathsupp3 <- supplemental(stage3 = c("Sd", "Sd", "Sdl", "Sdl", "mat", "Sd", "Sdl"), 
#'   stage2 = c("Sd", "Sd", "Sd", "Sd", "Sdl", "rep", "rep"),
#'   stage1 = c("Sd", "rep", "Sd", "rep", "Sd", "mat", "mat"),
#'   eststage3 = c(NA, NA, NA, NA, "mat", NA, NA),
#'   eststage2 = c(NA, NA, NA, NA, "Sdl", NA, NA),
#'   eststage1 = c(NA, NA, NA, NA, "Sdl", NA, NA),
#'   givenrate = c(0.345, 0.345, 0.054, 0.054, NA, NA, NA),
#'   multiplier = c(NA, NA, NA, NA, NA, 0.345, 0.054),
#'   type = c(1, 1, 1, 1, 1, 3, 3), type_t12 = c(1, 2, 1, 2, 1, 1, 1),
#'   stageframe = lathframeln, historical = TRUE)
#' 
#' lathvertln_adults <- subset(lathvertln, stage2index > 2)
#' surv_model <- glm(alive3 ~ sizea2 + sizea1 + as.factor(patchid) +
#'   as.factor(year2), data = lathvertln_adults, family = "binomial")
#' 
#' obs_data <- subset(lathvertln_adults, alive3 == 1)
#' obs_model <- glm(obsstatus3 ~ as.factor(patchid), data = obs_data,
#'   family = "binomial")
#' 
#' size_data <- subset(obs_data, obsstatus3 == 1)
#' siz_model <- lm(sizea3 ~ sizea2 + sizea1 + repstatus1 + as.factor(patchid) +
#'   as.factor(year2), data = size_data)
#' 
#' reps_model <- glm(repstatus3 ~ sizea2 + sizea1 + as.factor(patchid) +
#'   as.factor(year2), data = size_data, family = "binomial")
#' 
#' fec_data <- subset(lathvertln_adults, repstatus2 == 1)
#' fec_model <- glm(feca2 ~ sizea2 + sizea1 + repstatus1 + as.factor(patchid),
#'   data = fec_data, family = "poisson")
#' 
#' lathvertln_juvs <- subset(lathvertln, stage2index < 3)
#' jsurv_model <- glm(alive3 ~ as.factor(patchid), data = lathvertln_juvs,
#'   family = "binomial")
#' 
#' jobs_data <- subset(lathvertln_juvs, alive3 == 1)
#' jobs_model <- glm(obsstatus3 ~ 1, family = "binomial", data = jobs_data)
#' 
#' jsize_data <- subset(jobs_data, obsstatus3 == 1)
#' jsiz_model <- lm(sizea3 ~ as.factor(year2), data = jsize_data)
#' 
#' jrepst_model <- 0
#' jmatst_model <- 1
#' 
#' mod_params <- create_pm(name_terms = TRUE)
#' mod_params$modelparams[3] <- "patchid"
#' mod_params$modelparams[4] <- "alive3"
#' mod_params$modelparams[5] <- "obsstatus3"
#' mod_params$modelparams[6] <- "sizea3"
#' mod_params$modelparams[9] <- "repstatus3"
#' mod_params$modelparams[11] <- "feca2"
#' mod_params$modelparams[12] <- "sizea2"
#' mod_params$modelparams[13] <- "sizea1"
#' mod_params$modelparams[18] <- "repstatus2"
#' mod_params$modelparams[19] <- "repstatus1"
#' 
#' lathmat3ln <- flefko3(year = "all", patch = "all", data = lathvertln,
#'   stageframe = lathframeln, supplement = lathsupp3, paramnames = mod_params,
#'   surv_model = surv_model, obs_model = obs_model, size_model = siz_model,
#'   repst_model = reps_model, fec_model = fec_model, jsurv_model = jsurv_model,
#'   jobs_model = jobs_model, jsize_model = jsiz_model,
#'   jrepst_model = jrepst_model, jmatst_model = jmatst_model, reduce = FALSE)
#' 
#' 
#' # Cypripedium example using three size metrics for classification
#' data(cypdata)
#' 
#' sizevector_f <- c(0, 0, 0, 0, 0, 0, seq(1, 12, by = 1), seq(0, 9, by = 1),
#'   seq(0, 8, by = 1), seq(0, 7, by = 1), seq(0, 6, by = 1), seq(0, 5, by = 1),
#'   seq(0, 4, by = 1), seq(0, 3, by = 1), 0, 1, 2, 0, 1, 0, 
#'   0, 0, 1, 0)
#' sizebvector_f <- c(0, 0, 0, 0, 0, 0, rep(0, 12), rep(1, 10), rep(2, 9),
#'   rep(3, 8), rep(4, 7), rep(5, 6), rep(6, 5), rep(7, 4), rep(8, 3), 9, 9, 10, 
#'   0, 1, 1, 2)
#' sizecvector_f <- c(0, 0, 0, 0, 0, 0, rep(0, 12), rep(0, 10), rep(0, 9),
#'   rep(0, 8), rep(0, 7), rep(0, 6), rep(0, 5), rep(0, 4), 0, 0, 0, 0, 0, 0, 
#'   1, 1, 1, 1)
#' stagevector_f <- c("DS", "P1", "P2", "P3", "Sdl", "Dorm", "V1 I0 D0",
#'   "V2 I0 D0", "V3 I0 D0", "V4 I0 D0", "V5 I0 D0", "V6 I0 D0", "V7 I0 D0",
#'   "V8 I0 D0", "V9 I0 D0", "V10 I0 D0", "V11 I0 D0", "V12 I0 D0", "V0 I1 D0",
#'   "V1 I1 D0", "V2 I1 D0", "V3 I1 D0", "V4 I1 D0", "V5 I1 D0", "V6 I1 D0",
#'   "V7 I1 D0", "V8 I1 D0", "V9 I1 D0", "V0 I2 D0", "V1 I2 D0", "V2 I2 D0",
#'   "V3 I2 D0", "V4 I2 D0", "V5 I2 D0", "V6 I2 D0", "V7 I2 D0", "V8 I2 D0",
#'   "V0 I3 D0", "V1 I3 D0", "V2 I3 D0", "V3 I3 D0", "V4 I3 D0", "V5 I3 D0",
#'   "V6 I3 D0", "V7 I3 D0", "V0 I4 D0", "V1 I4 D0", "V2 I4 D0", "V3 I4 D0",
#'   "V4 I4 D0", "V5 I4 D0", "V6 I4 D0", "V0 I5 D0", "V1 I5 D0", "V2 I5 D0",
#'   "V3 I5 D0", "V4 I5 D0", "V5 I5 D0", "V0 I6 D0", "V1 I6 D0", "V2 I6 D0",
#'   "V3 I6 D0", "V4 I6 D0", "V0 I7 D0", "V1 I7 D0", "V2 I7 D0", "V3 I7 D0",
#'   "V0 I8 D0", "V1 I8 D0", "V2 I8 D0", "V0 I9 D0", "V1 I9 D0", "V0 I10 D0",
#'   "V0 I0 D1", "V0 I1 D1", "V1 I1 D1", "V0 I2 D1")
#' repvector_f <- c(0, 0, 0, 0, 0, rep(0, 13), rep(1, 59))
#' obsvector_f <- c(0, 0, 0, 0, 0, 0, rep(1, 71))
#' matvector_f <- c(0, 0, 0, 0, 0, rep(1, 72))
#' immvector_f <- c(0, 1, 1, 1, 1, rep(0, 72))
#' propvector_f <- c(1, rep(0, 76))
#' indataset_f <- c(0, 0, 0, 0, 0, rep(1, 72))
#' binvec_f <- c(0, 0, 0, 0, 0, rep(0.5, 72))
#' binbvec_f <- c(0, 0, 0, 0, 0, rep(0.5, 72))
#' bincvec_f <- c(0, 0, 0, 0, 0, rep(0.5, 72))
#' 
#' vertframe_f <- sf_create(sizes = sizevector_f, sizesb = sizebvector_f,
#'   sizesc = sizecvector_f, stagenames = stagevector_f, repstatus = repvector_f,
#'   obsstatus = obsvector_f, propstatus = propvector_f, immstatus = immvector_f,
#'   matstatus = matvector_f, indataset = indataset_f, binhalfwidth = binvec_f,
#'   binhalfwidthb = binbvec_f, binhalfwidthc = bincvec_f)
#' 
#' vert_data_f <- verticalize3(cypdata, noyears = 6, firstyear = 2004,
#'   individcol = "plantid", blocksize = 4, sizeacol = "Veg.04",
#'   sizebcol = "Inf.04", sizeccol = "Inf2.04", repstracol = "Inf.04",
#'   repstrbcol = "Inf2.04", fecacol = "Pod.04", censorcol = "censor",
#'   censorkeep = 1, censorRepeat = FALSE, stageassign = vertframe_f,
#'   stagesize = "sizeabc", NAas0 = TRUE, censor = FALSE)
#' 
#' vertsupp3f <- supplemental(stage3 = c("DS", "P1", "DS", "P1", "P2", "P2", "P3",
#'     "Sdl", "Sdl", "Sdl", "Dorm", "V1 I0 D0", "V2 I0 D0", "V3 I0 D0", "Dorm",
#'     "V1 I0 D0", "V2 I0 D0", "V3 I0 D0", "mat", "mat", "mat", "mat", "DS", "P1"),
#'   stage2 = c("DS", "DS", "DS", "DS", "P1", "P1", "P2", "P3", "Sdl", "Sdl", "Sdl",
#'     "Sdl", "Sdl", "Sdl", "Sdl", "Sdl", "Sdl", "Sdl", "Dorm", "V1 I0 D0",
#'     "V2 I0 D0", "V3 I0 D0", "rep", "rep"),
#'   stage1 = c("DS", "DS", "rep", "rep", "DS", "rep", "P1", "P2", "P3", "Sdl",
#'     "Sdl", "Sdl", "Sdl", "Sdl", "P3", "P3", "P3", "P3", "Sdl", "Sdl", "Sdl",
#'     "Sdl", "mat", "mat"),
#'   eststage3 = c(NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, "Dorm", "V1 I0 D0",
#'     "V2 I0 D0", "V3 I0 D0", "Dorm", "V1 I0 D0", "V2 I0 D0", "V3 I0 D0", "mat",
#'     "mat", "mat", "mat", NA, NA), 
#'   eststage2 = c(NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, "V1 I0 D0", "V1 I0 D0",
#'     "V1 I0 D0", "V1 I0 D0", "V1 I0 D0", "V1 I0 D0", "V1 I0 D0", "V1 I0 D0",
#'     "Dorm", "V1 I0 D0", "V2 I0 D0", "V3 I0 D0", NA, NA),
#'   eststage1 = c(NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, "V1 I0 D0", "V1 I0 D0",
#'     "V1 I0 D0", "V1 I0 D0", "V1 I0 D0", "V1 I0 D0", "V1 I0 D0", "V1 I0 D0",
#'     "V1 I0 D0", "V1 I0 D0", "V1 I0 D0", "V1 I0 D0", NA, NA),
#'   givenrate = c(0.10, 0.20, 0.10, 0.20, 0.20, 0.20, 0.20, 0.25, 0.40, 0.40, NA,
#'     NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
#'   multiplier = c(NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA,
#'     NA, NA, NA, NA, NA, NA, NA, 0.5 * 5000, 0.5 * 5000),
#'   type =c(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
#'     3, 3),
#'   type_t12 = c(1, 1, 2, 2, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
#'     1, 1, 1),
#'   stageframe = vertframe_f, historical = TRUE)
#' 
#' surv_model <- glm(alive3 ~ sizea2 + sizeb2, data = vert_data_f,
#'   family = "binomial")
#' 
#' obs_data <- subset(vert_data_f, alive3 == 1)
#' obs_model <- glm(obsstatus3 ~ sizeb2 + sizec1 + as.factor(year2),
#'   data = obs_data, family = "binomial")
#' 
#' size_data <- subset(obs_data, obsstatus3 == 1)
#' siz_model <- MASS::glm.nb(sizea3 ~ sizea2 + sizea1 + sizeb1, data = size_data)
#' sizb_model <- glm(sizeb3 ~ sizea2 + sizeb2 + sizec1 + repstatus2 + repstatus1 +
#'   as.factor(year2), data = size_data, family = "poisson")
#' sizc_model <- glm(sizec3 ~ sizea1 + repstatus2, data = size_data,
#'   family = "poisson")
#' 
#' reps_model <- glm(repstatus3 ~ sizea2 + sizeb2 + repstatus2 + as.factor(year2),
#'   data = size_data, family = "binomial")
#' 
#' fec_data <- subset(vert_data_f, repstatus2 == 1)
#' fec_model <- glm(feca2 ~ sizeb2 + as.factor(year2), data = fec_data,
#'   family = "poisson")
#' 
#' mod_params <- create_pm(name_terms = TRUE)
#' mod_params$modelparams[3] <- "patchid"
#' mod_params$modelparams[4] <- "alive3"
#' mod_params$modelparams[5] <- "obsstatus3"
#' mod_params$modelparams[6] <- "sizea3"
#' mod_params$modelparams[9] <- "repstatus3"
#' mod_params$modelparams[11] <- "feca2"
#' mod_params$modelparams[12] <- "sizea2"
#' mod_params$modelparams[13] <- "sizea1"
#' mod_params$modelparams[18] <- "repstatus2"
#' mod_params$modelparams[19] <- "repstatus1"
#' 
#' vert_mats_f3 <- flefko3(stageframe = vertframe_f, supplement = vertsupp3f,
#'   data = vert_data_f, surv_model = surv_model, obs_model = obs_model,
#'   size_model = siz_model, sizeb_model = sizb_model, sizec_model = sizc_model,
#'   repst_model = reps_model, fec_model = fec_model, paramnames = mod_params,
#'   sparse_output = TRUE)
#' }
#' 
#' @export
flefko3 <- function(year = "all", patch = "all", stageframe, supplement = NULL,
  repmatrix = NULL, overwrite = NULL, data = NULL, modelsuite = NULL,
  surv_model = NULL, obs_model = NULL, size_model = NULL, sizeb_model = NULL,
  sizec_model = NULL, repst_model = NULL, fec_model = NULL, jsurv_model = NULL,
  jobs_model = NULL, jsize_model = NULL, jsizeb_model = NULL,
  jsizec_model = NULL, jrepst_model = NULL, jmatst_model = NULL,
  paramnames = NULL, inda = NULL, indb = NULL, indc = NULL, annua = NULL,
  annub = NULL, annuc = NULL, surv_dev = 0, obs_dev = 0, size_dev = 0,
  sizeb_dev = 0, sizec_dev = 0, repst_dev = 0, fec_dev = 0, jsurv_dev = 0,
  jobs_dev = 0, jsize_dev = 0, jsizeb_dev = 0, jsizec_dev = 0, jrepst_dev = 0,
  jmatst_dev = 0, density = NA, fecmod = 1.0, random.inda = FALSE,
  random.indb = FALSE, random.indc = FALSE, negfec = FALSE, format = "ehrlen",
  ipm_method = "CDF", reduce = FALSE, simple = FALSE, err_check = FALSE,
  exp_tol = 700, theta_tol = 100000000, sparse_output = FALSE) {
  
  format_dev <- FALSE
  cdf <- TRUE
  
  if (grepl("dev", tolower(format))) {
    format_dev <- TRUE
  }
  
  ipm_method <- tolower(ipm_method)
  if (grepl("mi", ipm_method)) {
    cdf <- FALSE
  }
  
  devterms <- c(surv_dev, obs_dev, size_dev, sizeb_dev, sizec_dev, repst_dev,
    fec_dev, jsurv_dev, jobs_dev, jsize_dev, jsizeb_dev, jsizec_dev, jrepst_dev,
    jmatst_dev)
  
  if (is.null(modelsuite)) {
    if (!is.null(surv_model)) {
      modelsuite <- list(surv_model = surv_model, obs_model = obs_model,
        size_model = size_model, sizeb_model = sizeb_model,
        sizec_model = sizec_model, repst_model = repst_model,
        fec_model = fec_model, jsurv_model = jsurv_model,
        jobs_model = jobs_model, jsize_model = jsize_model,
        jsizeb_model = jsizeb_model, jsizec_model = jsizec_model,
        jrepst_model = jrepst_model, jmatst_model = jmatst_model)
      if (!is.null(paramnames)) modelsuite$paramnames <- paramnames
    }
  }
  
  output <- mpm_create(historical = TRUE, stage = TRUE, age = FALSE,
    devries = format_dev, reduce = reduce, data = data, year = year,
    patch = patch, stageframe = stageframe, supplement = supplement,
    overwrite = overwrite, repmatrix = repmatrix, modelsuite = modelsuite,
    paramnames = paramnames, inda = inda, indb = indb, indc = indc,
    annua = annua, annub = annub, annuc = annuc, dev_terms = devterms,
    density = density, fecmod = fecmod, CDF = cdf, random_inda = random.inda,
    random_indb = random.indb, random_indc = random.indc, negfec = negfec,
    exp_tol = exp_tol, theta_tol = theta_tol, simple = simple,
    err_check = err_check, sparse_output = sparse_output)  
  
  return(output)
}

#' Create Function-based Ahistorical Matrix Projection Model
#'
#' Function \code{flefko2()} returns ahistorical MPMs corresponding to the
#' patches and occasions given, including the associated component transition
#' and fecundity matrices, a data frame detailing the characteristics of the
#' ahistorical stages used, and a data frame characterizing the patch and
#' occasion combinations corresponding to these matrices.
#' 
#' @name flefko2
#' 
#' @param year A variable corresponding to the observation occasion, or a set
#' of such values, given in values associated with the year term used in linear 
#' model development. Defaults to \code{"all"}, in which case matrices will be
#' estimated for all occasions.
#' @param patch A variable designating which patches or subpopulations will have
#' matrices estimated. Defaults to \code{"all"}, but can also be set to specific
#' patch names or a vector thereof.
#' @param stageframe An object of class \code{stageframe}. These objects are
#' generated by function \code{\link{sf_create}()}, and include information on
#' the size, observation status, propagule status, reproduction status,
#' immaturity status, maturity status, stage group, size bin widths, and other
#' key characteristics of each ahistorical stage.
#' @param supplement An optional data frame of class \code{lefkoSD} that
#' provides supplemental data that should be incorporated into the MPM. Three
#' kinds of data may be integrated this way: transitions to be estimated via the
#' use of proxy transitions, transition overwrites from the literature or
#' supplemental studies, and transition multipliers for survival and fecundity.
#' This data frame should be produced using the \code{\link{supplemental}()}
#' function. Can be used in place of or in addition to an overwrite table (see 
#' \code{overwrite} below) and a reproduction matrix (see \code{repmatrix}
#' below).
#' @param repmatrix An optional reproduction matrix. This matrix is composed
#' mostly of \code{0}s, with non-zero entries acting as element identifiers and
#' multipliers for fecundity (with \code{1} equaling full fecundity). If left
#' blank, and no \code{supplement} is provided, then \code{flefko2()} will
#' assume that all stages marked as reproductive produce offspring at 1x that of
#' estimated fecundity, and that offspring production will yield the first stage
#' noted as propagule or immature. Must be the dimensions of an ahistorical
#' matrix.
#' @param overwrite An optional data frame developed with the
#' \code{\link{overwrite}()} function describing transitions to be overwritten
#' either with given values or with other estimated transitions. Note that this
#' function supplements overwrite data provided in \code{supplement}.
#' @param data  The historical vertical demographic data frame used to estimate
#' vital rates (class \code{hfvdata}), which is required to initialize times and
#' patches properly. Variable names should correspond to the naming conventions
#' in \code{\link{verticalize3}()} and \code{\link{historicalize3}()}. Not
#' required if option \code{modelsuite} is set to a \code{vrm_input} object.
#' @param modelsuite One of three kinds of lists. The first is a \code{lefkoMod}
#' object holding the vital rate models and associated metadata. The second is
#' a \code{lefkoModList} object, which is a list of \code{lefkoMod} objects
#' generally created to conduct a bootstrapped MPM analysis. Alternatively,
#' an object of class \code{vrm_input} may be provided. If given, then
#' \code{surv_model}, \code{obs_model}, \code{size_model}, \code{sizeb_model},
#' \code{sizec_model}, \code{repst_model}, \code{fec_model}, \code{jsurv_model},
#' \code{jobs_model}, \code{jsize_model}, \code{jsizeb_model},
#' \code{jsizec_model}, \code{jrepst_model}, \code{jmatst_model}, and
#' \code{paramnames} are not required. One or more of these models should
#' include size or reproductive status in occasion \emph{t}-1. Although this is
#' optional input, it is recommended, and without it all vital rate model inputs
#' (named \code{XX_model}) are required.
#' @param surv_model A linear model predicting survival probability. This can 
#' be a model of class \code{glm} or \code{glmer}, and requires a predicted
#' binomial variable under a logit link. Ignored if \code{modelsuite} is
#' provided. This model must have been developed in a modeling exercise testing
#' only the impacts of occasion \emph{t}.
#' @param obs_model A linear model predicting sprouting or observation
#' probability. This can be a model of class \code{glm} or \code{glmer}, and
#' requires a predicted binomial variable under a logit link. Ignored if
#' \code{modelsuite} is provided. This model must have been developed in a
#' modeling exercise testing only the impacts of occasion \emph{t}.
#' @param size_model A linear model predicting primary size. This can be a model
#' of class \code{glm}, \code{glmer}, \code{glmmTMB}, \code{zeroinfl},
#' \code{vglm}, \code{lm}, or \code{lmer}. Ignored if \code{modelsuite} is
#' provided. This model must have been developed in a modeling exercise testing
#' only the impacts of occasion \emph{t}.
#' @param sizeb_model A linear model predicting secondary size. This can be a
#' model of class \code{glm}, \code{glmer}, \code{glmmTMB}, \code{zeroinfl},
#' \code{vglm}, \code{lm}, or \code{lmer}. Ignored if \code{modelsuite} is
#' provided. This model must have been developed in a modeling exercise testing
#' only the impacts of occasion \emph{t}.
#' @param sizec_model A linear model predicting tertiary size. This can be a
#' model of class \code{glm}, \code{glmer}, \code{glmmTMB}, \code{zeroinfl},
#' \code{vglm}, \code{lm}, or \code{lmer}. Ignored if \code{modelsuite} is
#' provided. This model must have been developed in a modeling exercise testing
#' only the impacts of occasion \emph{t}.
#' @param repst_model A linear model predicting reproduction probability. This 
#' can be a model of class \code{glm} or \code{glmer}, and requires a predicted
#' binomial variable under a logit link. Ignored if \code{modelsuite} is
#' provided. This model must have been developed in a modeling exercise testing
#' only the impacts of occasion \emph{t}.
#' @param fec_model A linear model predicting fecundity. This can be a model of
#' class \code{glm}, \code{glmer}, \code{glmmTMB}, \code{zeroinfl}, \code{vglm},
#' \code{lm}, or \code{lmer}. Ignored if \code{modelsuite} is provided. This
#' model must have been developed in a modeling exercise testing only the
#' impacts of occasion \emph{t}.
#' @param jsurv_model A linear model predicting juvenile survival probability.
#' This can be a model of class \code{glm} or \code{glmer}, and requires a
#' predicted binomial variable under a logit link. Ignored if \code{modelsuite}
#' is provided. This model must have been developed in a modeling exercise
#' testing only the impacts of occasion \emph{t}.
#' @param jobs_model A linear model predicting juvenile sprouting or observation
#' probability. This can be a model of class \code{glm} or \code{glmer}, and
#' requires a predicted binomial variable under a logit link. Ignored if
#' \code{modelsuite} is provided. This model must have been developed in a
#' modeling exercise testing only the impacts of occasion \emph{t}.
#' @param jsize_model A linear model predicting juvenile primary size. This
#' can be a model of class \code{glm}, \code{glmer}, \code{glmmTMB},
#' \code{zeroinfl}, \code{vglm}, \code{lm}, or \code{lmer}. Ignored if
#' \code{modelsuite} is provided. This model must have been developed in a
#' modeling exercise testing only the impacts of occasion \emph{t}.
#' @param jsizeb_model A linear model predicting juvenile secondary size. This
#' can be a model of class \code{glm}, \code{glmer}, \code{glmmTMB},
#' \code{zeroinfl}, \code{vglm}, \code{lm}, or \code{lmer}. Ignored if
#' \code{modelsuite} is provided. This model must have been developed in a
#' modeling exercise testing only the impacts of occasion \emph{t}.
#' @param jsizec_model A linear model predicting juvenile tertiary size. This
#' can be a model of class \code{glm}, \code{glmer}, \code{glmmTMB},
#' \code{zeroinfl}, \code{vglm}, \code{lm}, or \code{lmer}. Ignored if
#' \code{modelsuite} is provided. This model must have been developed in a
#' modeling exercise testing only the impacts of occasion \emph{t}.
#' @param jrepst_model A linear model predicting reproduction probability of a 
#' mature individual that was immature in time \emph{t}. This can be a model
#' of class \code{glm} or \code{glmer}, and requires a predicted binomial
#' variable under a logit link. Ignored if \code{modelsuite} is provided. This
#' model must have been developed in a modeling exercise testing only the
#' impacts of occasion \emph{t}.
#' @param jmatst_model A linear model predicting maturity probability of an 
#' individual that was immature in time \emph{t}. This can be a model of class
#' \code{glm} or \code{glmer}, and requires a predicted binomial variable under
#' a logit link. Ignored if \code{modelsuite} is provided. This model must have
#' been developed in a modeling exercise testing only the impacts of occasion
#' \emph{t}.
#' @param paramnames A data frame with three columns, the first describing all
#' terms used in linear modeling, the second (must be called \code{mainparams})
#' giving the general model terms that will be used in matrix creation, and the
#' third showing the equivalent terms used in modeling (must be named
#' \code{modelparams}). Function \code{\link{create_pm}()} can be used to
#' create a skeleton \code{paramnames} object, which can then be edited. Only
#' required if \code{modelsuite} is not supplied.
#' @param inda Can be a single value to use for individual covariate \code{a}
#' in all matrices, a pair of values to use for times \emph{t} and \emph{t}-1 in
#' historical matrices, or a vector of such values corresponding to each
#' occasion in the dataset. Defaults to \code{NULL}.
#' @param indb Can be a single value to use for individual covariate \code{b}
#' in all matrices, a pair of values to use for times \emph{t} and \emph{t}-1 in
#' historical matrices, or a vector of such values corresponding to each
#' occasion in the dataset. Defaults to \code{NULL}.
#' @param indc Can be a single value to use for individual covariate \code{c}
#' in all matrices, a pair of values to use for times \emph{t} and \emph{t}-1 in
#' historical matrices, or a vector of such values corresponding to each
#' occasion in the dataset. Defaults to \code{NULL}.
#' @param annua Can be a single value to use for annual covariate \code{a}
#' in all matrices, a pair of values to use for times \emph{t} and \emph{t}-1 in
#' historical matrices, or a vector of such values corresponding to each
#' occasion in the dataset. Defaults to \code{NULL}.
#' @param annub Can be a single value to use for annual covariate \code{b}
#' in all matrices, a pair of values to use for times \emph{t} and \emph{t}-1 in
#' historical matrices, or a vector of such values corresponding to each
#' occasion in the dataset. Defaults to \code{NULL}.
#' @param annuc Can be a single value to use for annual covariate \code{c}
#' in all matrices, a pair of values to use for times \emph{t} and \emph{t}-1 in
#' historical matrices, or a vector of such values corresponding to each
#' occasion in the dataset. Defaults to \code{NULL}.
#' @param surv_dev A numeric value to be added to the y-intercept in the linear
#' model for survival probability. Defaults to \code{0}.
#' @param obs_dev A numeric value to be added to the y-intercept in the linear
#' model for observation probability. Defaults to \code{0}.
#' @param size_dev A numeric value to be added to the y-intercept in the linear
#' model for primary size. Defaults to \code{0}.
#' @param sizeb_dev A numeric value to be added to the y-intercept in the linear
#' model for secondary size. Defaults to \code{0}.
#' @param sizec_dev A numeric value to be added to the y-intercept in the linear
#' model for tertiary size. Defaults to \code{0}.
#' @param repst_dev A numeric value to be added to the y-intercept in the linear
#' model for probability of reproduction. Defaults to \code{0}.
#' @param fec_dev A numeric value to be added to the y-intercept in the linear
#' model for fecundity. Defaults to \code{0}.
#' @param jsurv_dev A numeric value to be added to the y-intercept in the linear
#' model for juvenile survival probability. Defaults to \code{0}.
#' @param jobs_dev A numeric value to be added to the y-intercept in the linear
#' model for juvenile observation probability. Defaults to \code{0}.
#' @param jsize_dev A numeric value to be added to the y-intercept in the linear
#' model for juvenile primary size. Defaults to \code{0}.
#' @param jsizeb_dev A numeric value to be added to the y-intercept in the
#' linear model for juvenile secondary size. Defaults to \code{0}.
#' @param jsizec_dev A numeric value to be added to the y-intercept in the
#' linear model for juvenile tertiary size. Defaults to \code{0}.
#' @param jrepst_dev A numeric value to be added to the y-intercept in the
#' linear model for juvenile reproduction probability. Defaults to \code{0}.
#' @param jmatst_dev A numeric value to be added to the y-intercept in the
#' linear model for juvenile maturity probability. Defaults to \code{0}.
#' @param density A numeric value indicating density value to use to propagate
#' matrices. Only needed if density is an explanatory term used in one or more
#' vital rate models. Defaults to \code{NA}.
#' @param fecmod A scalar multiplier of fecundity. Defaults to \code{1.0}.
#' @param random.inda A logical value denoting whether to treat individual
#' covariate \code{a} as a random, categorical variable. Otherwise is treated as
#' a fixed, numeric variable. Defaults to \code{FALSE}.
#' @param random.indb A logical value denoting whether to treat individual
#' covariate \code{b} as a random, categorical variable. Otherwise is treated as
#' a fixed, numeric variable. Defaults to \code{FALSE}.
#' @param random.indc A logical value denoting whether to treat individual
#' covariate \code{c} as a random, categorical variable. Otherwise is treated as
#' a fixed, numeric variable. Defaults to \code{FALSE}.
#' @param negfec A logical value denoting whether fecundity values estimated to
#' be negative should be reset to \code{0}. Defaults to \code{FALSE}.
#' @param ipm_method A string indicating what method to use to estimate size
#' transition probabilities, if size is treated as continuous. Options include:
#' \code{"midpoint"}, which utilizes the midpoint method; and \code{"CDF"},
#' which uses the cumulative distribution function. Defaults to \code{"CDF"}.
#' @param reduce A logical value denoting whether to remove ahistorical stages
#' associated solely with \code{0} transitions. These are only removed in cases
#' where the associated row and column sums in ALL matrices estimated equal 0. 
#' Defaults to \code{FALSE}.
#' @param simple A logical value indicating whether to produce \code{A},
#' \code{U}, and \code{F} matrices, or only the latter two. Defaults to
#' \code{FALSE}, in which case all three are output.
#' @param err_check A logical value indicating whether to append extra
#' information used in matrix calculation within the output list. Defaults to
#' \code{FALSE}.
#' @param exp_tol A numeric value used to indicate a maximum value to set
#' exponents to in the core kernel to prevent numerical overflow. Defaults to
#' \code{700}.
#' @param theta_tol A numeric value used to indicate a maximum value to theta as
#' used in the negative binomial probability density kernel. Defaults to
#' \code{100000000}, but can be reset to other values during error checking.
#' @param sparse_output A logical value indicating whether to output matrices
#' in sparse format. Defaults to \code{FALSE}, in which case all matrices are
#' output in standard matrix format.
#'
#' @return If the user inputs a standard \code{lefkoMod} or \code{vrm_input}
#' object in argument \code{modelsuite}, or individual vital rate models are
#' input separately,then this function will return an object of class
#' \code{lefkoMat}. If the user inputs an object of class \code{lefkoModList}
#' in argument \code{modelsuite}, then the output will be an object of class
#' \code{lefkoMatList}, in which each element is an object of class
#' \code{lefkoMat}.
#' 
#' A \code{lefkoMat} object is a list that holds one full  matrix projection
#' model and all of its metadata. The structure has the following elements:
#' 
#' \item{A}{A list of full projection matrices in order of sorted patches and
#' occasion times. All matrices output in R's \code{matrix} class, or in
#' the \code{dgCMatrix} class from the \code{Matrix} package if sparse.}
#' \item{U}{A list of survival transition matrices sorted as in \code{A}. All 
#' matrices output in R's \code{matrix} class, or in the \code{dgCMatrix} class
#' from the \code{Matrix} package if sparse.}
#' \item{F}{A list of fecundity matrices sorted as in \code{A}. All matrices 
#' output in R's \code{matrix} class, or in the \code{dgCMatrix} class from the
#' \code{Matrix} package if sparse.}
#' \item{hstages}{A data frame matrix showing the pairing of ahistorical stages
#' used to create historical stage pairs. Set to \code{NA} for ahistorical
#' matrices.}
#' \item{agestages}{A data frame showing age-stage pairs. In this function, it
#' is set to \code{NA}. Only used in output to function \code{aflefko2}().}
#' \item{ahstages}{A data frame detailing the characteristics of associated
#' ahistorical stages, in the form of a modified stageframe that includes
#' status as an entry stage through reproduction.}
#' \item{labels}{A data frame giving the population, patch, and year of each
#' matrix in order. In \code{flefko2()}, only one population may be analyzed at
#' once.}
#' \item{dataqc}{A vector showing the numbers of individuals and rows in the
#' vertical dataset used as input.}
#' \item{matrixqc}{A short vector describing the number of non-zero elements in
#' \code{U} and \code{F} matrices, and the number of annual matrices.}
#' \item{modelqc}{This is the \code{qc} portion of the \code{modelsuite} input.}
#' \item{prob_out}{An optional element only added if \code{err_check = TRUE}.
#' This is a list of vital rate probability matrices, with 7 columns in the
#' order of survival, observation probability, reproduction probability, primary
#' size transition probability, secondary size transition probability, tertiary
#' size transition probability, and probability of juvenile transition to
#' maturity.}
#' \item{allstages}{An optional element only added if \code{err_check = TRUE}.
#' This is a data frame giving the values used to determine each matrix element
#' capable of being estimated.}
#' 
#' @section Notes:
#' Unlike \code{\link{rlefko2}()}, \code{\link{rlefko3}()},
#' \code{\link{arlefko2}()}, and \code{\link{rleslie}()}, this function does not
#' currently distinguish populations. Users wishing to use the same vital rate
#' models across populations should label them as patches (though we do not
#' advise this approach, as populations should typically be treated as
#' statistically independent).
#' 
#' This function will yield incorrect estimates if the models utilized
#' incorporate state in occasion \emph{t}-1. Only use models developed testing
#' for ahistorical effects.
#' 
#' The default behavior of this function is to estimate fecundity with regards
#' to transitions specified via associated fecundity multipliers in the
#' \code{supplement}. If this field is left empty, then fecundity will be
#' estimated at full for all transitions leading from reproductive stages to
#' immature and propagule stages.
#' 
#' Users may at times wish to estimate MPMs using a dataset incorporating
#' multiple patches or subpopulations, but without discriminating between those
#' patches or subpopulations. Should the aim of analysis be a general MPM that
#' does not distinguish these patches or subpopulations, the
#' \code{modelsearch()} run should not include patch terms.
#'
#' Input options including multiple variable names must be entered in the order
#' of variables in occasion \emph{t}+1 and \emph{t}. Rearranging the order will
#' lead to erroneous calculations, and may lead to fatal errors.
#'
#' Care should be taken to match the random status of year and patch to the
#' states of those variables within the \code{modelsuite}. If they do not match,
#' then they will be treated as zeroes in vital rate estimation.
#' 
#' The \code{ipm_method} function gives the option of using two different means
#' of estimating the probability of size transition. The midpoint method
#' (\code{"midpoint"}) refers to the method in which the probability is
#' estimated by first estimating the probability associated with transition from
#' the exact size at the midpoint of the size class using the corresponding
#' probability density function, and then multiplying that value by the bin
#' width of the size class. Doak et al. 2021 (Ecological Monographs) noted that
#' this method can produce biased results, with total size transitions
#' associated with a specific size not totaling to 1.0 and even specific size
#' transition probabilities capable of being estimated at values greater than
#' 1.0. The alternative and default method, \code{"CDF"}, uses the corresponding
#' cumulative density function to estimate the probability of size transition as
#' the cumulative probability of size transition at the greater limit of the
#' size class minus the cumulative probability of size transition at the lower
#' limit of the size class. The latter method avoids this bias. Note, however,
#' that both methods are exact and unbiased for negative binomial and Poisson
#' distributions.
#' 
#' Under the Gaussian and gamma size distributions, the number of estimated
#' parameters may differ between the two \code{ipm_method} settings. Because
#' the midpoint method has a tendency to incorporate upward bias in the
#' estimation of size transition probabilities, it is more likely to yield non-
#' zero values when the true probability is extremely close to 0. This will
#' result in the \code{summary.lefkoMat} function yielding higher numbers of
#' estimated parameters than the \code{ipm_method = "CDF"} yields in some cases.
#' 
#' Using the \code{err_check} option will produce a matrix of 7 columns, each
#' characterizing a different vital rate. The product of each row yields an
#' element in the associated \code{U} matrix. The number and order of elements
#' in each column of this matrix matches the associated matrix in column vector
#' format. Use of this option is generally for the purposes of debugging code.
#' 
#' Individual covariates are treated as categorical only if they are set as
#' random terms. Fixed categorical individual covariates are currently not
#' allowed. However, such terms may be supplied if the \code{modelsuite} option
#' is set to a \code{vrm_input} object. In that case, the user should also set
#' the logical random switch for the individual covariate to be used to 
#' \code{TRUE} (e.g., \code{random.inda = TRUE}).
#'
#' @seealso \code{\link{mpm_create}()}
#' @seealso \code{\link{flefko3}()}
#' @seealso \code{\link{aflefko2}()}
#' @seealso \code{\link{arlefko2}()}
#' @seealso \code{\link{fleslie}()}
#' @seealso \code{\link{rlefko3}()}
#' @seealso \code{\link{rlefko2}()}
#' @seealso \code{\link{rleslie}()}
#' 
#' @examples
#' # Lathyrus example
#' data(lathyrus)
#' 
#' sizevector <- c(0, 4.6, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 1, 2, 3, 4, 5, 6, 7, 8,
#'   9)
#' stagevector <- c("Sd", "Sdl", "Dorm", "Sz1nr", "Sz2nr", "Sz3nr", "Sz4nr", 
#'   "Sz5nr", "Sz6nr", "Sz7nr", "Sz8nr", "Sz9nr", "Sz1r", "Sz2r", "Sz3r", 
#'   "Sz4r", "Sz5r", "Sz6r", "Sz7r", "Sz8r", "Sz9r")
#' repvector <- c(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1)
#' obsvector <- c(0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1)
#' matvector <- c(0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1)
#' immvector <- c(1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
#' propvector <- c(1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
#'   0)
#' indataset <- c(0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1)
#' binvec <- c(0, 4.6, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5,
#'   0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5)
#' 
#' lathframeln <- sf_create(sizes = sizevector, stagenames = stagevector, 
#'   repstatus = repvector, obsstatus = obsvector, matstatus = matvector,
#'   immstatus = immvector, indataset = indataset, binhalfwidth = binvec,
#'   propstatus = propvector)
#' 
#' lathvertln <- verticalize3(lathyrus, noyears = 4, firstyear = 1988, 
#'   patchidcol = "SUBPLOT", individcol = "GENET", blocksize = 9,
#'   juvcol = "Seedling1988", sizeacol = "lnVol88", repstracol = "Intactseed88",
#'   fecacol = "Intactseed88", deadacol = "Dead1988", 
#'   nonobsacol = "Dormant1988", stageassign = lathframeln,
#'   stagesize = "sizea", censorcol = "Missing1988", censorkeep = NA,
#'   NAas0 = TRUE, censor = TRUE)
#' 
#' lathvertln$feca2 <- round(lathvertln$feca2)
#' lathvertln$feca1 <- round(lathvertln$feca1)
#' lathvertln$feca3 <- round(lathvertln$feca3)
#' 
#' lathvertln_adults <- subset(lathvertln, stage2index > 2)
#' surv_model <- glm(alive3 ~ sizea2 + as.factor(patchid),
#'   data = lathvertln_adults, family = "binomial")
#' 
#' obs_data <- subset(lathvertln_adults, alive3 == 1)
#' obs_model <- glm(obsstatus3 ~ as.factor(patchid), data = obs_data,
#'   family = "binomial")
#' 
#' size_data <- subset(obs_data, obsstatus3 == 1)
#' siz_model <- lm(sizea3 ~ sizea2 + repstatus2 + as.factor(patchid) + 
#'   as.factor(year2), data = size_data)
#' 
#' reps_model <- glm(repstatus3 ~ sizea2 + as.factor(patchid) + as.factor(year2),
#'   data = size_data, family = "binomial")
#' 
#' fec_data <- subset(lathvertln_adults, repstatus2 == 1)
#' fec_model <- glm(feca2 ~ sizea2 + as.factor(patchid) + as.factor(year2),
#'   data = fec_data, family = "poisson")
#' 
#' lathvertln_juvs <- subset(lathvertln, stage2index < 3)
#' jsurv_model <- glm(alive3 ~ as.factor(patchid), data = lathvertln_juvs,
#'   family = "binomial")
#' 
#' jobs_data <- subset(lathvertln_juvs, alive3 == 1)
#' jobs_model <- glm(obsstatus3 ~ 1, family = "binomial", data = jobs_data)
#' 
#' jsize_data <- subset(jobs_data, obsstatus3 == 1)
#' jsiz_model <- lm(sizea3 ~ as.factor(year2), data = jsize_data)
#' 
#' jrepst_model <- 0
#' jmatst_model <- 1
#' 
#' mod_params <- create_pm(name_terms = TRUE)
#' mod_params$modelparams[3] <- "patchid"
#' mod_params$modelparams[5] <- "obsstatus3"
#' mod_params$modelparams[6] <- "sizea3"
#' mod_params$modelparams[9] <- "repstatus3"
#' mod_params$modelparams[11] <- "feca2"
#' mod_params$modelparams[12] <- "sizea2"
#' mod_params$modelparams[18] <- "repstatus2"
#' 
#' lathsupp2 <- supplemental(stage3 = c("Sd", "Sdl", "Sd", "Sdl"), 
#'   stage2 = c("Sd", "Sd", "rep", "rep"),
#'   givenrate = c(0.345, 0.054, NA, NA),
#'   multiplier = c(NA, NA, 0.345, 0.054),
#'   type = c(1, 1, 3, 3), stageframe = lathframeln, historical = FALSE)
#' 
#' lathmat2ln <- flefko2(year = "all", patch = "all", data = lathvertln,
#'   stageframe = lathframeln, supplement = lathsupp2, paramnames = mod_params,
#'   surv_model = surv_model, obs_model = obs_model, size_model = siz_model,
#'   repst_model = reps_model, fec_model = fec_model, jsurv_model = jsurv_model,
#'   jobs_model = jobs_model, jsize_model = jsiz_model,
#'   jrepst_model = jrepst_model, jmatst_model = jmatst_model, reduce = FALSE)
#' 
#' 
#' # Cypripedium example using three size metrics for classification
#' data(cypdata)
#' 
#' sizevector_f <- c(0, 0, 0, 0, 0, 0, seq(1, 12, by = 1), seq(0, 9, by = 1),
#'   seq(0, 8, by = 1), seq(0, 7, by = 1), seq(0, 6, by = 1), seq(0, 5, by = 1),
#'   seq(0, 4, by = 1), seq(0, 3, by = 1), 0, 1, 2, 0, 1, 0, 
#'   0, 0, 1, 0)
#' sizebvector_f <- c(0, 0, 0, 0, 0, 0, rep(0, 12), rep(1, 10), rep(2, 9),
#'   rep(3, 8), rep(4, 7), rep(5, 6), rep(6, 5), rep(7, 4), rep(8, 3), 9, 9, 10, 
#'   0, 1, 1, 2)
#' sizecvector_f <- c(0, 0, 0, 0, 0, 0, rep(0, 12), rep(0, 10), rep(0, 9),
#'   rep(0, 8), rep(0, 7), rep(0, 6), rep(0, 5), rep(0, 4), 0, 0, 0, 0, 0, 0, 
#'   1, 1, 1, 1)
#' stagevector_f <- c("DS", "P1", "P2", "P3", "Sdl", "Dorm", "V1 I0 D0",
#'   "V2 I0 D0", "V3 I0 D0", "V4 I0 D0", "V5 I0 D0", "V6 I0 D0", "V7 I0 D0",
#'   "V8 I0 D0", "V9 I0 D0", "V10 I0 D0", "V11 I0 D0", "V12 I0 D0", "V0 I1 D0",
#'   "V1 I1 D0", "V2 I1 D0", "V3 I1 D0", "V4 I1 D0", "V5 I1 D0", "V6 I1 D0",
#'   "V7 I1 D0", "V8 I1 D0", "V9 I1 D0", "V0 I2 D0", "V1 I2 D0", "V2 I2 D0",
#'   "V3 I2 D0", "V4 I2 D0", "V5 I2 D0", "V6 I2 D0", "V7 I2 D0", "V8 I2 D0",
#'   "V0 I3 D0", "V1 I3 D0", "V2 I3 D0", "V3 I3 D0", "V4 I3 D0", "V5 I3 D0",
#'   "V6 I3 D0", "V7 I3 D0", "V0 I4 D0", "V1 I4 D0", "V2 I4 D0", "V3 I4 D0",
#'   "V4 I4 D0", "V5 I4 D0", "V6 I4 D0", "V0 I5 D0", "V1 I5 D0", "V2 I5 D0",
#'   "V3 I5 D0", "V4 I5 D0", "V5 I5 D0", "V0 I6 D0", "V1 I6 D0", "V2 I6 D0",
#'   "V3 I6 D0", "V4 I6 D0", "V0 I7 D0", "V1 I7 D0", "V2 I7 D0", "V3 I7 D0",
#'   "V0 I8 D0", "V1 I8 D0", "V2 I8 D0", "V0 I9 D0", "V1 I9 D0", "V0 I10 D0",
#'   "V0 I0 D1", "V0 I1 D1", "V1 I1 D1", "V0 I2 D1")
#' repvector_f <- c(0, 0, 0, 0, 0, rep(0, 13), rep(1, 59))
#' obsvector_f <- c(0, 0, 0, 0, 0, 0, rep(1, 71))
#' matvector_f <- c(0, 0, 0, 0, 0, rep(1, 72))
#' immvector_f <- c(0, 1, 1, 1, 1, rep(0, 72))
#' propvector_f <- c(1, rep(0, 76))
#' indataset_f <- c(0, 0, 0, 0, 0, rep(1, 72))
#' binvec_f <- c(0, 0, 0, 0, 0, rep(0.5, 72))
#' binbvec_f <- c(0, 0, 0, 0, 0, rep(0.5, 72))
#' bincvec_f <- c(0, 0, 0, 0, 0, rep(0.5, 72))
#' 
#' vertframe_f <- sf_create(sizes = sizevector_f, sizesb = sizebvector_f,
#'   sizesc = sizecvector_f, stagenames = stagevector_f, repstatus = repvector_f,
#'   obsstatus = obsvector_f, propstatus = propvector_f, immstatus = immvector_f,
#'   matstatus = matvector_f, indataset = indataset_f, binhalfwidth = binvec_f,
#'   binhalfwidthb = binbvec_f, binhalfwidthc = bincvec_f)
#' 
#' vert_data_f <- verticalize3(cypdata, noyears = 6, firstyear = 2004,
#'   individcol = "plantid", blocksize = 4, sizeacol = "Veg.04",
#'   sizebcol = "Inf.04", sizeccol = "Inf2.04", repstracol = "Inf.04",
#'   repstrbcol = "Inf2.04", fecacol = "Pod.04", censorcol = "censor",
#'   censorkeep = 1, censorRepeat = FALSE, stageassign = vertframe_f,
#'   stagesize = "sizeabc", NAas0 = TRUE, censor = FALSE)
#' 
#' surv_model <- glm(alive3 ~ sizea2 + sizeb2, data = vert_data_f,
#'   family = "binomial")
#' 
#' obs_data <- subset(vert_data_f, alive3 == 1)
#' obs_model <- glm(obsstatus3 ~ sizeb2 + as.factor(year2), data = obs_data,
#'   family = "binomial")
#' 
#' size_data <- subset(obs_data, obsstatus3 == 1)
#' siz_model <- MASS::glm.nb(sizea3 ~ sizea2 + sizeb2 + as.factor(year2),
#'   data = size_data)
#' sizb_model <- glm(sizeb3 ~ sizea2 + sizeb2 + repstatus2 + as.factor(year2),
#'   data = size_data, family = "poisson")
#' sizc_model <- glm(sizec3 ~ repstatus2, data = size_data, family = "poisson")
#' 
#' reps_model <- glm(repstatus3 ~ sizea2 + sizeb2 + repstatus2 + as.factor(year2),
#'   data = size_data, family = "binomial")
#' 
#' fec_data <- subset(vert_data_f, repstatus2 == 1)
#' fec_model <- glm(feca2 ~ sizeb2 + as.factor(year2), data = fec_data,
#'   family = "poisson")
#' 
#' mod_params <- create_pm(name_terms = TRUE)
#' mod_params$modelparams[3] <- "patchid"
#' mod_params$modelparams[4] <- "alive3"
#' mod_params$modelparams[5] <- "obsstatus3"
#' mod_params$modelparams[6] <- "sizea3"
#' mod_params$modelparams[9] <- "repstatus3"
#' mod_params$modelparams[11] <- "feca2"
#' mod_params$modelparams[12] <- "sizea2"
#' mod_params$modelparams[18] <- "repstatus2"
#' 
#' vertsupp2f <- supplemental(stage3 = c("DS", "P1", "P2", "P3", "Sdl", "Sdl",
#'     "Dorm", "V1 I0 D0", "V2 I0 D0", "V3 I0 D0", "DS", "P1"),
#'   stage2 = c("DS", "DS", "P1", "P2", "P3", "Sdl", "Sdl", "Sdl", "Sdl", "Sdl",
#'     "rep", "rep"), 
#'   eststage3 = c(NA, NA, NA, NA, NA, NA, "Dorm", "V1 I0 D0", "V2 I0 D0",
#'     "V3 I0 D0", NA, NA), 
#'   eststage2 = c(NA, NA, NA, NA, NA, NA, "V1 I0 D0", "V1 I0 D0", "V1 I0 D0",
#'     "V1 I0 D0", NA, NA), 
#'   givenrate = c(0.10, 0.20, 0.20, 0.20, 0.25, 0.40, NA, NA, NA, NA, NA, NA),
#'   multiplier = c(NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, 0.5 * 5000,
#'     0.5 * 5000),
#'   type =c(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 3), stageframe = vertframe_f,
#'   historical = FALSE)
#' 
#' vert_mats_f2 <- flefko2(stageframe = vertframe_f, supplement = vertsupp2f,
#'   data = vert_data_f, surv_model = surv_model, obs_model = obs_model,
#'   size_model = siz_model, sizeb_model = sizb_model, sizec_model = sizc_model,
#'   repst_model = reps_model, fec_model = fec_model, paramnames = mod_params)
#' 
#' @export
flefko2 <- function(year = "all", patch = "all", stageframe, supplement = NULL,
  repmatrix = NULL, overwrite = NULL, data = NULL, modelsuite = NULL,
  surv_model = NULL, obs_model = NULL, size_model = NULL, sizeb_model = NULL,
  sizec_model = NULL, repst_model = NULL, fec_model = NULL, jsurv_model = NULL,
  jobs_model = NULL, jsize_model = NULL, jsizeb_model = NULL,
  jsizec_model = NULL, jrepst_model = NULL, jmatst_model = NULL,
  paramnames = NULL, inda = NULL, indb = NULL, indc = NULL, annua = NULL,
  annub = NULL, annuc = NULL, surv_dev = 0, obs_dev = 0, size_dev = 0,
  sizeb_dev = 0, sizec_dev = 0, repst_dev = 0, fec_dev = 0, jsurv_dev = 0,
  jobs_dev = 0, jsize_dev = 0, jsizeb_dev = 0, jsizec_dev = 0, jrepst_dev = 0,
  jmatst_dev = 0, density = NA, fecmod = 1.0, random.inda = FALSE,
  random.indb = FALSE, random.indc = FALSE, negfec = FALSE, ipm_method = "CDF",
  reduce = FALSE, simple = FALSE, err_check = FALSE, exp_tol = 700,
  theta_tol = 100000000, sparse_output = FALSE) {
  
  cdf <- TRUE
  
  ipm_method <- tolower(ipm_method)
  if (grepl("mi", ipm_method)) {
    cdf <- FALSE
  }
  
  devterms <- c(surv_dev, obs_dev, size_dev, sizeb_dev, sizec_dev, repst_dev,
    fec_dev, jsurv_dev, jobs_dev, jsize_dev, jsizeb_dev, jsizec_dev, jrepst_dev,
    jmatst_dev)
  
  if (is.null(modelsuite)) {
    if (!is.null(surv_model)) {
      modelsuite <- list(surv_model = surv_model, obs_model = obs_model,
        size_model = size_model, sizeb_model = sizeb_model,
        sizec_model = sizec_model, repst_model = repst_model,
        fec_model = fec_model, jsurv_model = jsurv_model,
        jobs_model = jobs_model, jsize_model = jsize_model,
        jsizeb_model = jsizeb_model, jsizec_model = jsizec_model,
        jrepst_model = jrepst_model, jmatst_model = jmatst_model)
      if (!is.null(paramnames)) modelsuite$paramnames <- paramnames
    }
  }
  
  output <- mpm_create(historical = FALSE, stage = TRUE, age = FALSE,
    devries = FALSE, reduce = reduce, data = data, year = year, patch = patch,
    stageframe = stageframe, supplement = supplement, overwrite = overwrite,
    repmatrix = repmatrix, modelsuite = modelsuite, paramnames = paramnames,
    inda = inda, indb = indb, indc = indc, annua = annua, annub = annub,
    annuc = annuc,dev_terms = devterms, density = density, fecmod = fecmod,
    CDF = cdf, random_inda = random.inda, random_indb = random.indb,
    random_indc = random.indc, negfec = negfec, exp_tol = exp_tol,
    theta_tol = theta_tol, simple = simple, err_check = err_check,
    sparse_output = sparse_output)
  
  return(output)
}

#' Create Function-based Ahistorical Age x Stage Matrix Projection Model
#'
#' Function \code{aflefko2()} returns ahistorical age x stage MPMs corresponding
#' to the patches and occasions given, including the associated component
#' transition and fecundity matrices, data frames detailing the characteristics
#' of ahistorical stages and the exact age-stage combinations corresponding to
#' rows and columns in estimated matrices, and a data frame characterizing the
#' patch and occasion combinations corresponding to these matrices.
#' 
#' @name aflefko2
#' 
#' @param year A variable corresponding to the observation occasion, or a set
#' of such values, given in values associated with the year term used in linear 
#' model development. Defaults to \code{"all"}, in which case matrices will be
#' estimated for all occasions.
#' @param patch A variable designating which patches or subpopulations will have
#' matrices estimated. Defaults to \code{"all"}, but can also be set to specific
#' patch names or a vector thereof.
#' @param stageframe An object of class \code{stageframe}. These objects are
#' generated by function \code{\link{sf_create}()}, and include information on
#' the size, observation status, propagule status, reproduction status,
#' immaturity status, maturity status, stage group, size bin widths, and other
#' key characteristics of each ahistorical stage.
#' @param supplement An optional data frame of class \code{lefkoSD} that
#' provides supplemental data that should be incorporated into the MPM. Three
#' kinds of data may be integrated this way: transitions to be estimated via the
#' use of proxy transitions, transition overwrites from the literature or
#' supplemental studies, and transition multipliers for survival and fecundity.
#' This data frame should be produced using the \code{\link{supplemental}()}
#' function. Can be used in place of or in addition to an overwrite table (see 
#' \code{overwrite} below) and a reproduction matrix (see \code{repmatrix}
#' below).
#' @param repmatrix An optional reproduction matrix. This matrix is composed
#' mostly of \code{0}s, with non-zero entries acting as element identifiers and
#' multipliers for fecundity (with \code{1} equaling full fecundity). If left
#' blank, and no \code{supplement} is provided, then \code{aflefko2()} will
#' assume that all stages marked as reproductive produce offspring at 1x that of
#' estimated fecundity, and that offspring production will yield the first stage
#' noted as propagule or immature. Must be the dimensions of an ahistorical
#' stage-based matrix.
#' @param overwrite An optional data frame developed with the
#' \code{\link{overwrite}()} function describing transitions to be overwritten
#' either with given values or with other estimated transitions. Note that this
#' function supplements overwrite data provided in \code{supplement}.
#' @param data  The historical vertical demographic data frame used to estimate
#' vital rates (class \code{hfvdata}), which is required to initialize times and
#' patches properly. Variable names should correspond to the naming conventions
#' in \code{\link{verticalize3}()} and \code{\link{historicalize3}()}. Not
#' required if option \code{modelsuite} is set to a \code{vrm_input} object.
#' @param modelsuite One of three kinds of lists. The first is a \code{lefkoMod}
#' object holding the vital rate models and associated metadata. The second is
#' a \code{lefkoModList} object, which is a list of \code{lefkoMod} objects
#' generally created to conduct a bootstrapped MPM analysis. Alternatively,
#' an object of class \code{vrm_input} may be provided. If given, then
#' \code{surv_model}, \code{obs_model}, \code{size_model}, \code{sizeb_model},
#' \code{sizec_model}, \code{repst_model}, \code{fec_model}, \code{jsurv_model},
#' \code{jobs_model}, \code{jsize_model}, \code{jsizeb_model},
#' \code{jsizec_model}, \code{jrepst_model}, \code{jmatst_model}, and
#' \code{paramnames} are not required. One or more of these models should
#' include size or reproductive status in occasion \emph{t}-1. Although this is
#' optional input, it is recommended, and without it all vital rate model inputs
#' (named \code{XX_model}) are required.
#' @param surv_model A linear model predicting survival probability. This can 
#' be a model of class \code{glm} or \code{glmer}, and requires a predicted
#' binomial variable under a logit link. Ignored if \code{modelsuite} is
#' provided. This model must have been developed in a modeling exercise testing
#' only the impacts of occasion \emph{t}.
#' @param obs_model A linear model predicting sprouting or observation
#' probability. This can be a model of class \code{glm} or \code{glmer}, and
#' requires a predicted binomial variable under a logit link. Ignored if
#' \code{modelsuite} is provided. This model must have been developed in a
#' modeling exercise testing only the impacts of occasion \emph{t}.
#' @param size_model A linear model predicting primary size. This can be a model
#' of class \code{glm}, \code{glmer}, \code{glmmTMB}, \code{zeroinfl},
#' \code{vglm}, \code{lm}, or \code{lmer}. Ignored if \code{modelsuite} is
#' provided. This model must have been developed in a modeling exercise testing
#' only the impacts of occasion \emph{t}.
#' @param sizeb_model A linear model predicting secondary size. This can be a
#' model of class \code{glm}, \code{glmer}, \code{glmmTMB}, \code{zeroinfl},
#' \code{vglm}, \code{lm}, or \code{lmer}. Ignored if \code{modelsuite} is
#' provided. This model must have been developed in a modeling exercise testing
#' only the impacts of occasion \emph{t}.
#' @param sizec_model A linear model predicting tertiary size. This can be a
#' model of class \code{glm}, \code{glmer}, \code{glmmTMB}, \code{zeroinfl},
#' \code{vglm}, \code{lm}, or \code{lmer}. Ignored if \code{modelsuite} is
#' provided. This model must have been developed in a modeling exercise testing
#' only the impacts of occasion \emph{t}.
#' @param repst_model A linear model predicting reproduction probability. This 
#' can be a model of class \code{glm} or \code{glmer}, and requires a predicted
#' binomial variable under a logit link. Ignored if \code{modelsuite} is
#' provided. This model must have been developed in a modeling exercise testing
#' only the impacts of occasion \emph{t}.
#' @param fec_model A linear model predicting fecundity. This can be a model of
#' class \code{glm}, \code{glmer}, \code{glmmTMB}, \code{zeroinfl}, \code{vglm},
#' \code{lm}, or \code{lmer}. Ignored if \code{modelsuite} is provided. This
#' model must have been developed in a modeling exercise testing only the
#' impacts of occasion \emph{t}.
#' @param jsurv_model A linear model predicting juvenile survival probability.
#' This can be a model of class \code{glm} or \code{glmer}, and requires a
#' predicted binomial variable under a logit link. Ignored if \code{modelsuite}
#' is provided. This model must have been developed in a modeling exercise
#' testing only the impacts of occasion \emph{t}.
#' @param jobs_model A linear model predicting juvenile sprouting or observation
#' probability. This can be a model of class \code{glm} or \code{glmer}, and
#' requires a predicted binomial variable under a logit link. Ignored if
#' \code{modelsuite} is provided. This model must have been developed in a
#' modeling exercise testing only the impacts of occasion \emph{t}.
#' @param jsize_model A linear model predicting juvenile primary size. This
#' can be a model of class \code{glm}, \code{glmer}, \code{glmmTMB},
#' \code{zeroinfl}, \code{vglm}, \code{lm}, or \code{lmer}. Ignored if
#' \code{modelsuite} is provided. This model must have been developed in a
#' modeling exercise testing only the impacts of occasion \emph{t}.
#' @param jsizeb_model A linear model predicting juvenile secondary size. This
#' can be a model of class \code{glm}, \code{glmer}, \code{glmmTMB},
#' \code{zeroinfl}, \code{vglm}, \code{lm}, or \code{lmer}. Ignored if
#' \code{modelsuite} is provided. This model must have been developed in a
#' modeling exercise testing only the impacts of occasion \emph{t}.
#' @param jsizec_model A linear model predicting juvenile tertiary size. This
#' can be a model of class \code{glm}, \code{glmer}, \code{glmmTMB},
#' \code{zeroinfl}, \code{vglm}, \code{lm}, or \code{lmer}. Ignored if
#' \code{modelsuite} is provided. This model must have been developed in a
#' modeling exercise testing only the impacts of occasion \emph{t}.
#' @param jrepst_model A linear model predicting reproduction probability of a 
#' mature individual that was immature in time \emph{t}. This can be a model
#' of class \code{glm} or \code{glmer}, and requires a predicted binomial
#' variable under a logit link. Ignored if \code{modelsuite} is provided. This
#' model must have been developed in a modeling exercise testing only the
#' impacts of occasion \emph{t}.
#' @param jmatst_model A linear model predicting maturity probability of an 
#' individual that was immature in time \emph{t}. This can be a model of class
#' \code{glm} or \code{glmer}, and requires a predicted binomial variable under
#' a logit link. Ignored if \code{modelsuite} is provided. This model must have
#' been developed in a modeling exercise testing only the impacts of occasion
#' \emph{t}.
#' @param paramnames A data frame with three columns, the first describing all
#' terms used in linear modeling, the second (must be called \code{mainparams})
#' giving the general model terms that will be used in matrix creation, and the
#' third showing the equivalent terms used in modeling (must be named
#' \code{modelparams}). Function \code{\link{create_pm}()} can be used to
#' create a skeleton \code{paramnames} object, which can then be edited. Only
#' required if \code{modelsuite} is not supplied.
#' @param inda Can be a single value to use for individual covariate \code{a}
#' in all matrices, a pair of values to use for times \emph{t} and \emph{t}-1 in
#' historical matrices, or a vector of such values corresponding to each
#' occasion in the dataset. Defaults to \code{NULL}.
#' @param indb Can be a single value to use for individual covariate \code{b}
#' in all matrices, a pair of values to use for times \emph{t} and \emph{t}-1 in
#' historical matrices, or a vector of such values corresponding to each
#' occasion in the dataset. Defaults to \code{NULL}.
#' @param indc Can be a single value to use for individual covariate \code{c}
#' in all matrices, a pair of values to use for times \emph{t} and \emph{t}-1 in
#' historical matrices, or a vector of such values corresponding to each
#' occasion in the dataset. Defaults to \code{NULL}.
#' @param annua Can be a single value to use for annual covariate \code{a}
#' in all matrices, a pair of values to use for times \emph{t} and \emph{t}-1 in
#' historical matrices, or a vector of such values corresponding to each
#' occasion in the dataset. Defaults to \code{NULL}.
#' @param annub Can be a single value to use for annual covariate \code{b}
#' in all matrices, a pair of values to use for times \emph{t} and \emph{t}-1 in
#' historical matrices, or a vector of such values corresponding to each
#' occasion in the dataset. Defaults to \code{NULL}.
#' @param annuc Can be a single value to use for annual covariate \code{c}
#' in all matrices, a pair of values to use for times \emph{t} and \emph{t}-1 in
#' historical matrices, or a vector of such values corresponding to each
#' occasion in the dataset. Defaults to \code{NULL}.
#' @param surv_dev A numeric value to be added to the y-intercept in the linear
#' model for survival probability. Defaults to \code{0}.
#' @param obs_dev A numeric value to be added to the y-intercept in the linear
#' model for observation probability. Defaults to \code{0}.
#' @param size_dev A numeric value to be added to the y-intercept in the linear
#' model for primary size. Defaults to \code{0}.
#' @param sizeb_dev A numeric value to be added to the y-intercept in the linear
#' model for secondary size. Defaults to \code{0}.
#' @param sizec_dev A numeric value to be added to the y-intercept in the linear
#' model for tertiary size. Defaults to \code{0}.
#' @param repst_dev A numeric value to be added to the y-intercept in the linear
#' model for probability of reproduction. Defaults to \code{0}.
#' @param fec_dev A numeric value to be added to the y-intercept in the linear
#' model for fecundity. Defaults to \code{0}.
#' @param jsurv_dev A numeric value to be added to the y-intercept in the linear
#' model for juvenile survival probability. Defaults to \code{0}.
#' @param jobs_dev A numeric value to be added to the y-intercept in the linear
#' model for juvenile observation probability. Defaults to \code{0}.
#' @param jsize_dev A numeric value to be added to the y-intercept in the linear
#' model for juvenile primary size. Defaults to \code{0}.
#' @param jsizeb_dev A numeric value to be added to the y-intercept in the
#' linear model for juvenile secondary size. Defaults to \code{0}.
#' @param jsizec_dev A numeric value to be added to the y-intercept in the
#' linear model for juvenile tertiary size. Defaults to \code{0}.
#' @param jrepst_dev A numeric value to be added to the y-intercept in the
#' linear model for juvenile reproduction probability. Defaults to \code{0}.
#' @param jmatst_dev A numeric value to be added to the y-intercept in the
#' linear model for juvenile maturity probability. Defaults to \code{0}.
#' @param density A numeric value indicating density value to use to propagate
#' matrices. Only needed if density is an explanatory term used in one or more
#' vital rate models. Defaults to \code{NA}.
#' @param fecmod A scalar multiplier of fecundity. Defaults to \code{1.0}.
#' @param random.inda A logical value denoting whether to treat individual
#' covariate \code{a} as a random, categorical variable. Otherwise is treated as
#' a fixed, numeric variable. Defaults to \code{FALSE}.
#' @param random.indb A logical value denoting whether to treat individual
#' covariate \code{b} as a random, categorical variable. Otherwise is treated as
#' a fixed, numeric variable. Defaults to \code{FALSE}.
#' @param random.indc A logical value denoting whether to treat individual
#' covariate \code{c} as a random, categorical variable. Otherwise is treated as
#' a fixed, numeric variable. Defaults to \code{FALSE}.
#' @param final_age The final age to model in the matrix, where the first age
#' will be age \code{0} if post-breeding, and \code{1} if pre-breeding. Defaults
#' to the maximum age in the dataset.
#' @param continue A logical value designating whether to allow continued
#' survival of individuals past the final age noted in the stageframe, using the 
#' demographic characteristics of the final age. Defaults to \code{TRUE}.
#' @param prebreeding A logical value indicating whether the life history model
#' is a pre-breeding model. Defaults to \code{TRUE}.
#' @param negfec A logical value denoting whether fecundity values estimated to
#' be negative should be reset to \code{0}. Defaults to \code{FALSE}.
#' @param ipm_method A string indicating what method to use to estimate size
#' transition probabilities, if size is treated as continuous. Options include:
#' \code{"midpoint"}, which utilizes the midpoint method; and \code{"CDF"},
#' which uses the cumulative distribution function. Defaults to \code{"CDF"}.
#' @param reduce A logical value denoting whether to remove age-stages
#' associated solely with \code{0} transitions. These are only removed in cases
#' where the associated row and column sums in ALL matrices estimated equal 0. 
#' Defaults to \code{FALSE}.
#' @param simple A logical value indicating whether to produce \code{A},
#' \code{U}, and \code{F} matrices, or only the latter two. Defaults to
#' \code{FALSE}, in which case all three are output.
#' @param err_check A logical value indicating whether to append extra
#' information used in matrix calculation within the output list. Defaults to
#' \code{FALSE}.
#' @param exp_tol A numeric value used to indicate a maximum value to set
#' exponents to in the core kernel to prevent numerical overflow. Defaults to
#' \code{700}.
#' @param theta_tol A numeric value used to indicate a maximum value to theta as
#' used in the negative binomial probability density kernel. Defaults to
#' \code{100000000}, but can be reset to other values during error checking.
#' @param sparse_output A logical value indicating whether to output matrices
#' in sparse format. Defaults to \code{FALSE}, in which case all matrices are
#' output in standard matrix format.
#'
#' @return If the user inputs a standard \code{lefkoMod} or \code{vrm_input}
#' object in argument \code{modelsuite}, or individual vital rate models are
#' input separately,then this function will return an object of class
#' \code{lefkoMat}. If the user inputs an object of class \code{lefkoModList}
#' in argument \code{modelsuite}, then the output will be an object of class
#' \code{lefkoMatList}, in which each element is an object of class
#' \code{lefkoMat}.
#' 
#' A \code{lefkoMat} object is a list that holds one full  matrix projection
#' model and all of its metadata. The structure has the following elements:
#' 
#' \item{A}{A list of full projection matrices in order of sorted patches and
#' occasions. All matrices output in R's \code{matrix} class, or in
#' the \code{dgCMatrix} class from the \code{Matrix} package if sparse.}
#' \item{U}{A list of survival transition matrices sorted as in \code{A}. All 
#' matrices output in R's \code{matrix} class, or in the \code{dgCMatrix} class
#' from the \code{Matrix} package if sparse.}
#' \item{F}{A list of fecundity matrices sorted as in \code{A}. All matrices 
#' output in R's \code{matrix} class, or in the \code{dgCMatrix} class from the
#' \code{Matrix} package if sparse.}
#' \item{hstages}{A data frame matrix showing the pairing of ahistorical stages
#' used to create historical stage pairs. Set to \code{NA} for age-by-stage
#' MPMs.}
#' \item{agestages}{A data frame showing the stage number and stage name
#' corresponding to \code{ahstages}, as well as the associated age, of each
#' row in each age-by-stage matrix.}
#' \item{ahstages}{A data frame detailing the characteristics of associated
#' ahistorical stages, in the form of a modified stageframe that includes
#' status as an entry stage through reproduction.}
#' \item{labels}{A data frame giving the patch and year of each matrix in order.
#' In \code{aflefko2()}, only one population may be analyzed at once.}
#' \item{dataqc}{A vector showing the numbers of individuals and rows in the
#' vertical dataset used as input.}
#' \item{matrixqc}{A short vector describing the number of non-zero elements in
#' \code{U} and \code{F} matrices, and the number of annual matrices.}
#' \item{modelqc}{This is the \code{qc} portion of the \code{modelsuite} input.}
#' \item{prob_out}{An optional element only added if \code{err_check = TRUE}.
#' This is a list of vital rate probability matrices, with 7 columns in the
#' order of survival, observation probability, reproduction probability, primary
#' size transition probability, secondary size transition probability, tertiary
#' size transition probability, and probability of juvenile transition to
#' maturity.}
#' \item{allstages}{An optional element only added if \code{err_check = TRUE}.
#' This is a data frame giving the values used to determine each matrix element
#' capable of being estimated.}
#' 
#' @section Notes:
#' Unlike \code{\link{rlefko2}()}, \code{\link{rlefko3}()},
#' \code{\link{arlefko2}()}, and \code{\link{rleslie}()}, this function does not
#' currently distinguish populations. Users wishing to use the same vital rate
#' models across populations should label them as patches (though we do not
#' advise this approach, as populations should typically be treated as
#' statistically independent).
#' 
#' This function will yield incorrect estimates if the models utilized
#' incorporate state in occasion \emph{t}-1. Only use models developed testing
#' for ahistorical effects.
#' 
#' The default behavior of this function is to estimate fecundity with regards
#' to transitions specified via associated fecundity multipliers in the
#' \code{supplement}. If this field is left empty, then fecundity will be
#' estimated at full for all transitions leading from reproductive stages to
#' immature and propagule stages.
#' 
#' Stageframes used in this function should include ages for minimum and maximum
#' age for each stage. \code{NA}s are treated as \code{0}s in minimum age, and
#' as \code{final_age} for maximum age.
#' 
#' Users may at times wish to estimate MPMs using a dataset incorporating
#' multiple patches or subpopulations, but without discriminating between those
#' patches or subpopulations. Should the aim of analysis be a general MPM that
#' does not distinguish these patches or subpopulations, the
#' \code{modelsearch()} run should not include patch terms.
#'
#' Input options including multiple variable names must be entered in the order
#' of variables in occasion \emph{t}+1 and \emph{t}. Rearranging the order will
#' lead to erroneous calculations, and may lead to fatal errors.
#'
#' Care should be taken to match the random status of year and patch to the
#' states of those variables within the \code{modelsuite}. If they do not match,
#' then they will be treated as zeroes in vital rate estimation.
#' 
#' The \code{ipm_method} function gives the option of using two different means
#' of estimating the probability of size transition. The midpoint method
#' (\code{"midpoint"}) refers to the method in which the probability is
#' estimated by first estimating the probability associated with transition from
#' the exact size at the midpoint of the size class using the corresponding
#' probability density function, and then multiplying that value by the bin
#' width of the size class. Doak et al. 2021 (Ecological Monographs) noted that
#' this method can produce biased results, with total size transitions
#' associated with a specific size not totaling to 1.0 and even specific size
#' transition probabilities capable of being estimated at values greater than
#' 1.0. The alternative and default method, \code{"CDF"}, uses the corresponding
#' cumulative density function to estimate the probability of size transition as
#' the cumulative probability of size transition at the greater limit of the
#' size class minus the cumulative probability of size transition at the lower
#' limit of the size class. The latter method avoids this bias. Note, however,
#' that both methods are exact and unbiased for the Poisson and negative
#' binomial distributions.
#' 
#' Under the Gaussian and gamma size distributions, the number of estimated
#' parameters may differ between the two \code{ipm_method} settings. Because
#' the midpoint method has a tendency to incorporate upward bias in the
#' estimation of size transition probabilities, it is more likely to yield non-
#' zero values when the true probability is extremely close to 0. This will
#' result in the \code{summary.lefkoMat} function yielding higher numbers of
#' estimated parameters than the \code{ipm_method = "CDF"} yields in some cases.
#' 
#' Using the \code{err_check} option will produce a matrix of 7 columns, each
#' characterizing a different vital rate. The product of each row yields an
#' element in the associated \code{U} matrix. The number and order of elements
#' in each column of this matrix matches the associated matrix in column vector
#' format. Use of this option is generally for the purposes of debugging code.
#' 
#' Individual covariates are treated as categorical only if they are set as
#' random terms. Fixed categorical individual covariates are currently not
#' allowed. However, such terms may be supplied if the \code{modelsuite} option
#' is set to a \code{vrm_input} object. In that case, the user should also set
#' the logical random switch for the individual covariate to be used to 
#' \code{TRUE} (e.g., \code{random.inda = TRUE}).
#'
#' @seealso \code{\link{mpm_create}()}
#' @seealso \code{\link{flefko3}()}
#' @seealso \code{\link{flefko2}()}
#' @seealso \code{\link{fleslie}()}
#' @seealso \code{\link{arlefko2}()}
#' @seealso \code{\link{rlefko3}()}
#' @seealso \code{\link{rlefko2}()}
#' @seealso \code{\link{rleslie}()}
#' 
#' @examples
#' data(lathyrus)
#' 
#' sizevector <- c(0, 4.6, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 1, 2, 3, 4, 5, 6, 7, 8,
#'   9)
#' stagevector <- c("Sd", "Sdl", "Dorm", "Sz1nr", "Sz2nr", "Sz3nr", "Sz4nr",
#'   "Sz5nr", "Sz6nr", "Sz7nr", "Sz8nr", "Sz9nr", "Sz1r", "Sz2r", "Sz3r",
#'   "Sz4r", "Sz5r", "Sz6r", "Sz7r", "Sz8r", "Sz9r")
#' repvector <- c(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1)
#' obsvector <- c(0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1)
#' matvector <- c(0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1)
#' immvector <- c(1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
#' propvector <- c(1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
#'   0)
#' indataset <- c(0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1)
#' minima <- c(1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2)
#' binvec <- c(0, 4.6, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5,
#'   0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5)
#' 
#' lathframeln <- sf_create(sizes = sizevector, stagenames = stagevector,
#'   repstatus = repvector, obsstatus = obsvector, matstatus = matvector,
#'   immstatus = immvector, indataset = indataset, binhalfwidth = binvec,
#'   propstatus = propvector, minage = minima)
#' 
#' lathvertln <- verticalize3(lathyrus, noyears = 4, firstyear = 1988,
#'   patchidcol = "SUBPLOT", individcol = "GENET", blocksize = 9,
#'   juvcol = "Seedling1988", sizeacol = "lnVol88", repstracol = "Intactseed88",
#'   fecacol = "Intactseed88", deadacol = "Dead1988",
#'   nonobsacol = "Dormant1988", stageassign = lathframeln,
#'   stagesize = "sizea", censorcol = "Missing1988", censorkeep = NA,
#'   NAas0 = TRUE, censor = TRUE)
#' 
#' lathvertln$feca2 <- round(lathvertln$feca2)
#' lathvertln$feca1 <- round(lathvertln$feca1)
#' lathvertln$feca3 <- round(lathvertln$feca3)
#' 
#' lathvertln_adults <- subset(lathvertln, stage2index > 2)
#' surv_model <- glm(alive3 ~ obsage + sizea2 + as.factor(patchid) +
#'   as.factor(year2), data = lathvertln_adults, family = "binomial")
#' 
#' obs_data <- subset(lathvertln_adults, alive3 == 1)
#' obs_model <- glm(obsstatus3 ~ obsage + as.factor(patchid) +
#'   as.factor(year2), data = obs_data, family = "binomial")
#' 
#' size_data <- subset(obs_data, obsstatus3 == 1)
#' siz_model <- lm(sizea3 ~ sizea2 + repstatus2 + obsage + as.factor(patchid) +
#'   as.factor(year2), data = size_data)
#' 
#' reps_model <- glm(repstatus3 ~ sizea2 + as.factor(patchid) + as.factor(year2),
#'   data = size_data, family = "binomial")
#' 
#' fec_data <- subset(lathvertln_adults, repstatus2 == 1)
#' fec_model <- glm(feca2 ~ sizea2 + obsage + as.factor(patchid) +
#'   as.factor(year2), data = fec_data, family = "poisson")
#' 
#' lathvertln_juvs <- subset(lathvertln, stage2index < 3)
#' jsurv_model <- glm(alive3 ~ as.factor(patchid), data = lathvertln_juvs,
#'   family = "binomial")
#' 
#' jobs_data <- subset(lathvertln_juvs, alive3 == 1)
#' jobs_model <- glm(obsstatus3 ~ 1, family = "binomial", data = jobs_data)
#' 
#' jsize_data <- subset(jobs_data, obsstatus3 == 1)
#' jsiz_model <- lm(sizea3 ~ as.factor(year2), data = jsize_data)
#' 
#' jrepst_model <- 0
#' jmatst_model <- 1
#' 
#' lathsupp2 <- supplemental(stage3 = c("Sd", "Sdl", "mat", "Sd", "Sdl"), 
#'   stage2 = c("Sd", "Sd", "Sdl", "rep", "rep"),
#'   eststage3 = c(NA, NA, "mat", NA, NA),
#'   eststage2 = c(NA, NA, "Dorm", NA, NA),
#'   givenrate = c(0.345, 0.054, NA, NA, NA),
#'   multiplier = c(NA, NA, 0.8, 0.345, 0.054), type = c(1, 1, 1, 3, 3),
#'   stageframe = lathframeln, historical = FALSE, agebased = TRUE)
#' 
#' mod_params <- create_pm(name_terms = TRUE)
#' mod_params$modelparams[3] <- "patchid"
#' mod_params$modelparams[5] <- "obsstatus3"
#' mod_params$modelparams[6] <- "sizea3"
#' mod_params$modelparams[9] <- "repstatus3"
#' mod_params$modelparams[11] <- "feca2"
#' mod_params$modelparams[12] <- "sizea2"
#' mod_params$modelparams[18] <- "repstatus2"
#' mod_params$modelparams[22] <- "obsage"
#' 
#' lathmat2age2 <- aflefko2(year = "all", patch = "all", data = lathvertln,
#'   stageframe = lathframeln, supplement = lathsupp2, final_age = 3,
#'   surv_model = surv_model, obs_model = obs_model, size_model = siz_model,
#'   repst_model = reps_model, fec_model = fec_model, jsurv_model = jsurv_model,
#'   jobs_model = jobs_model, jsize_model = jsiz_model,
#'   jrepst_model = jrepst_model, jmatst_model = jmatst_model,
#'   paramnames = mod_params, continue = TRUE, reduce = FALSE)
#' 
#' @export
aflefko2 <- function(year = "all", patch = "all", stageframe, supplement = NULL,
  repmatrix = NULL, overwrite = NULL, data = NULL, modelsuite = NULL,
  surv_model = NULL, obs_model = NULL, size_model = NULL, sizeb_model = NULL,
  sizec_model = NULL, repst_model = NULL, fec_model = NULL, jsurv_model = NULL,
  jobs_model = NULL, jsize_model = NULL, jsizeb_model = NULL,
  jsizec_model = NULL, jrepst_model = NULL, jmatst_model = NULL,
  paramnames = NULL, inda = NULL, indb = NULL, indc = NULL, annua = NULL,
  annub = NULL, annuc = NULL, surv_dev = 0, obs_dev = 0, size_dev = 0,
  sizeb_dev = 0, sizec_dev = 0, repst_dev = 0, fec_dev = 0, jsurv_dev = 0,
  jobs_dev = 0, jsize_dev = 0, jsizeb_dev = 0, jsizec_dev = 0, jrepst_dev = 0,
  jmatst_dev = 0, density = NA, fecmod = 1.0, random.inda = FALSE,
  random.indb = FALSE, random.indc = FALSE, final_age = NA, continue = TRUE,
  prebreeding = TRUE, negfec = FALSE, ipm_method = "CDF", reduce = FALSE,
  simple = FALSE, err_check = FALSE, exp_tol = 700, theta_tol = 100000000,
  sparse_output = FALSE) {
  
  cdf <- TRUE
  
  ipm_method <- tolower(ipm_method)
  if (grepl("mi", ipm_method)) {
    cdf <- FALSE
  }
  
  devterms <- c(surv_dev, obs_dev, size_dev, sizeb_dev, sizec_dev, repst_dev,
    fec_dev, jsurv_dev, jobs_dev, jsize_dev, jsizeb_dev, jsizec_dev, jrepst_dev,
    jmatst_dev)
  
  if (is.null(modelsuite)) {
    if (!is.null(surv_model)) {
      modelsuite <- list(surv_model = surv_model, obs_model = obs_model,
        size_model = size_model, sizeb_model = sizeb_model,
        sizec_model = sizec_model, repst_model = repst_model,
        fec_model = fec_model, jsurv_model = jsurv_model,
        jobs_model = jobs_model, jsize_model = jsize_model,
        jsizeb_model = jsizeb_model, jsizec_model = jsizec_model,
        jrepst_model = jrepst_model, jmatst_model = jmatst_model)
      if (!is.null(paramnames)) modelsuite$paramnames <- paramnames
    }
  }
  
  output <- mpm_create(historical = FALSE, stage = TRUE, age = TRUE,
    devries = FALSE, reduce = reduce, data = data, year = year, patch = patch,
    stageframe = stageframe, supplement = supplement, overwrite = overwrite,
    repmatrix = repmatrix, modelsuite = modelsuite, paramnames = paramnames,
    inda = inda, indb = indb, indc = indc, annua = annua, annub = annub,
    annuc = annuc, dev_terms = devterms, density = density, fecmod = fecmod,
    CDF = cdf, random_inda = random.inda, random_indb = random.indb,
    random_indc = random.indc, negfec = negfec, exp_tol = exp_tol,
    theta_tol = theta_tol, last_age = final_age, cont = continue,
    prebreeding = prebreeding, simple = simple, err_check = err_check,
    sparse_output = sparse_output)
  
  return(output)
}

#' Create Function-based Age-based (Leslie) Matrix Projection Model
#'
#' Function \code{fleslie()} returns age-based (Leslie) MPMs corresponding to
#' the patches and occasions given, including the associated component
#' transition and fecundity matrices, data frames detailing the characteristics
#' of the exact ages corresponding to rows and columns in estimated matrices,
#' and a data frame characterizing the patch and occasion combinations
#' corresponding to these matrices.
#' 
#' @name fleslie
#' 
#' @param year A variable corresponding to observation occasion, or a set
#' of such values, given in values associated with the year term used in linear 
#' model development. Defaults to \code{"all"}, in which case matrices will be
#' estimated for all occasions.
#' @param patch A variable designating which patches or subpopulations will have
#' matrices estimated. Defaults to \code{"all"}, but can also be set to specific
#' patch names or a vector thereof.
#' @param prebreeding A logical value indicating whether the life history model
#' is a pre-breeding model. Defaults to \code{TRUE}.
#' @param data The historical vertical demographic data frame used to estimate
#' vital rates (class \code{hfvdata}). The original data frame is generally
#' required in order to initialize occasions and patches properly, and to assess
#' the range of ages observed in the population. Not required if option
#' \code{modelsuite} is set to a \code{vrm_input} object.
#' @param modelsuite One of three kinds of lists. The first is a \code{lefkoMod}
#' object holding the vital rate models and associated metadata. The second is
#' a \code{lefkoModList} object, which is a list of \code{lefkoMod} objects
#' generally created to conduct a bootstrapped MPM analysis. Alternatively,
#' an object of class \code{vrm_input} may be provided. If given, then
#' \code{surv_model}, \code{obs_model}, \code{size_model}, \code{sizeb_model},
#' \code{sizec_model}, \code{repst_model}, \code{fec_model}, \code{jsurv_model},
#' \code{jobs_model}, \code{jsize_model}, \code{jsizeb_model},
#' \code{jsizec_model}, \code{jrepst_model}, \code{jmatst_model}, and
#' \code{paramnames} are not required. One or more of these models should
#' include size or reproductive status in occasion \emph{t}-1. Although this is
#' optional input, it is recommended, and without it all vital rate model inputs
#' (named \code{XX_model}) are required.
#' @param surv_model A linear model predicting survival probability. This can be
#' a model of class \code{glm} or \code{glmer}, and requires a predicted
#' binomial variable under a logit link. Ignored if \code{modelsuite} is
#' provided. This model must have been developed in a modeling exercise testing
#' only the impacts of occasion \emph{t}.
#' @param fec_model A linear model predicting fecundity. This can be a model of
#' class \code{glm}, \code{glmer}, \code{glmmTMB}, \code{zeroinfl},
#' \code{vglm}, \code{lm}, or \code{lmer}. Ignored if \code{modelsuite} is
#' provided. This model must have been developed in a modeling exercise testing
#' only the impacts of occasion \emph{t}.
#' @param paramnames  A data frame with three columns, the first describing all
#' terms used in linear modeling, the second (must be called \code{mainparams})
#' giving the general model terms that will be used in matrix creation, and the
#' third showing the equivalent terms used in modeling (must be named
#' \code{modelparams}). Function \code{\link{create_pm}()} can be used to
#' create a skeleton \code{paramnames} object, which can then be edited. Only
#' required if \code{modelsuite} is not supplied.
#' @param supplement An optional data frame of class \code{lefkoSD} that
#' provides supplemental data that should be incorporated into the MPM. Three
#' kinds of data may be integrated this way: transitions to be estimated via the
#' use of proxy transitions, transition overwrites from the literature or
#' supplemental studies, and transition multipliers for survival and fecundity.
#' This data frame should be produced using the \code{\link{supplemental}()}
#' function.
#' @param start_age The age from which to start the matrix. Defaults to
#' \code{NA}, in which case age \code{1} is used if \code{prebreeding = TRUE},
#' and age \code{0} is used if \code{prebreeding = FALSE}.
#' @param last_age The final age to use in the matrix. Defaults to \code{NA}, in
#' which case the highest age in the dataset is used.
#' @param fecage_min The minimum age at which reproduction is possible. Defaults
#' to \code{NA}, which is interpreted to mean that fecundity should be assessed
#' starting in the minimum age observed in the dataset.
#' @param fecage_max The maximum age at which reproduction is possible. Defaults
#' to \code{NA}, which is interpreted to mean that fecundity should be assessed
#' until the final observed age.
#' @param continue A logical value designating whether to allow continued
#' survival of individuals past the final age noted in the stageframe, using the 
#' demographic characteristics of the final age. Defaults to \code{TRUE}.
#' @param inda Can be a single value to use for individual covariate \code{a}
#' in all matrices, or a vector of such values corresponding to each occasion in
#' the dataset. Defaults to \code{NULL}.
#' @param indb Can be a single value to use for individual covariate \code{b}
#' in all matrices, or a vector of such values corresponding to each occasion in
#' the dataset. Defaults to \code{NULL}.
#' @param indc Can be a single value to use for individual covariate \code{c}
#' in all matrices, or a vector of such values corresponding to each occasion in
#' the dataset. Defaults to \code{NULL}.
#' @param annua Can be a single value to use for annual covariate \code{a}
#' in all matrices, a pair of values to use for times \emph{t} and \emph{t}-1 in
#' historical matrices, or a vector of such values corresponding to each
#' occasion in the dataset. Defaults to \code{NULL}.
#' @param annub Can be a single value to use for annual covariate \code{b}
#' in all matrices, a pair of values to use for times \emph{t} and \emph{t}-1 in
#' historical matrices, or a vector of such values corresponding to each
#' occasion in the dataset. Defaults to \code{NULL}.
#' @param annuc Can be a single value to use for annual covariate \code{c}
#' in all matrices, a pair of values to use for times \emph{t} and \emph{t}-1 in
#' historical matrices, or a vector of such values corresponding to each
#' occasion in the dataset. Defaults to \code{NULL}.
#' @param surv_dev A numeric value to be added to the y-intercept in the linear
#' model for survival probability. Defaults to \code{0}.
#' @param fec_dev A numeric value to be added to the y-intercept in the linear
#' model for fecundity. Defaults to \code{0}.
#' @param density A numeric value indicating density value to use to propagate
#' matrices. Only needed if density is an explanatory term used in linear
#' models. Defaults to \code{NA}.
#' @param fecmod A scalar multiplier of fecundity. Defaults to \code{1.0}.
#' @param random.inda A logical value denoting whether to treat individual
#' covariate \code{a} as a random, categorical variable. Otherwise is treated as
#' a fixed, numeric variable. Defaults to \code{FALSE}.
#' @param random.indb A logical value denoting whether to treat individual
#' covariate \code{b} as a random, categorical variable. Otherwise is treated as
#' a fixed, numeric variable. Defaults to \code{FALSE}.
#' @param random.indc A logical value denoting whether to treat individual
#' covariate \code{c} as a random, categorical variable. Otherwise is treated as
#' a fixed, numeric variable. Defaults to \code{FALSE}.
#' @param negfec A logical value denoting whether fecundity values estimated to
#' be negative should be reset to \code{0}. Defaults to \code{FALSE}.
#' @param reduce A logical value denoting whether to remove ages associated
#' solely with \code{0} transitions. These are only removed in cases where the
#' associated row and column sums in ALL matrices estimated equal 0. Defaults to
#' \code{FALSE}, and should generally not be used in age-based MPMs.
#' @param simple A logical value indicating whether to produce \code{A},
#' \code{U}, and \code{F} matrices, or only the latter two. Defaults to
#' \code{FALSE}, in which case all three are output.
#' @param err_check A logical value indicating whether to append extra
#' information used in matrix calculation within the output list. Defaults to
#' \code{FALSE}.
#' @param exp_tol A numeric value used to indicate a maximum value to set
#' exponents to in the core kernel to prevent numerical overflow. Defaults to
#' \code{700}.
#' @param theta_tol A numeric value used to indicate a maximum value to theta as
#' used in the negative binomial probability density kernel. Defaults to
#' \code{100000000}, but can be reset to other values during error checking.
#' @param sparse_output A logical value indicating whether to output matrices
#' in sparse format. Defaults to \code{FALSE}, in which case all matrices are
#' output in standard matrix format.
#'
#' @return If the user inputs a standard \code{lefkoMod} or \code{vrm_input}
#' object in argument \code{modelsuite}, or individual vital rate models are
#' input separately,then this function will return an object of class
#' \code{lefkoMat}. If the user inputs an object of class \code{lefkoModList}
#' in argument \code{modelsuite}, then the output will be an object of class
#' \code{lefkoMatList}, in which each element is an object of class
#' \code{lefkoMat}.
#' 
#' A \code{lefkoMat} object is a list that holds one full  matrix projection
#' model and all of its metadata. The structure has the following elements:
#' 
#' \item{A}{A list of full projection matrices in order of sorted patches and
#' occasions. All matrices output in R's \code{matrix} class, or in
#' the \code{dgCMatrix} class from the \code{Matrix} package if sparse.}
#' \item{U}{A list of survival transition matrices sorted as in \code{A}. All 
#' matrices output in R's \code{matrix} class, or in the \code{dgCMatrix} class
#' from the \code{Matrix} package if sparse.}
#' \item{F}{A list of fecundity matrices sorted as in \code{A}. All matrices 
#' output in R's \code{matrix} class, or in the \code{dgCMatrix} class from the
#' \code{Matrix} package if sparse.}
#' \item{hstages}{Set to \code{NA} for Leslie MPMs.}
#' \item{agestages}{Set to \code{NA} for Leslie MPMs.}
#' \item{ahstages}{A data frame detailing the characteristics of associated
#' ages, in the form of a modified stageframe including reproduction status.}
#' \item{labels}{A data frame giving the patch and year of each matrix in order.
#' In \code{fleslie()}, only one population may be analyzed at once.}
#' \item{dataqc}{A vector showing the numbers of individuals and rows in the
#' vertical dataset used as input.}
#' \item{matrixqc}{A short vector describing the number of non-zero elements in
#' \code{U} and \code{F} matrices, and the number of annual matrices.}
#' \item{modelqc}{This is the \code{qc} portion of the \code{modelsuite} input.}
#' \item{prob_out}{An optional element only added if \code{err_check = TRUE}.
#' This is a list of vital rate probability matrices, with 7 columns in the
#' order of survival, observation probability, reproduction probability, primary
#' size transition probability, secondary size transition probability, tertiary
#' size transition probability, and probability of juvenile transition to
#' maturity.}
#' 
#' @section Notes:
#' Unlike \code{\link{rlefko2}()}, \code{\link{rlefko3}()},
#' \code{\link{arlefko2}()}, and \code{\link{rleslie}()}, this function does not
#' currently distinguish populations.
#' 
#' This function will yield incorrect estimates if the models utilized
#' incorporate state in occasion \emph{t}-1, or any size or reproductive status
#' terms.
#' 
#' Users may at times wish to estimate MPMs using a dataset incorporating
#' multiple patches or subpopulations, but without discriminating between those
#' patches or subpopulations. Should the aim of analysis be a general MPM that
#' does not distinguish these patches or subpopulations, the
#' \code{modelsearch()} run should not include patch terms.
#'
#' Input options including multiple variable names must be entered in the order
#' of variables in occasion \emph{t}+1 and \emph{t}. Rearranging the order will
#' lead to erroneous calculations, and may lead to fatal errors.
#'
#' Care should be taken to match the random status of year and patch to the
#' states of those variables within the modelsuite. If they do not match, then
#' they will be treated as zeroes in vital rate estimation.
#' 
#' Individual covariates are treated as categorical only if they are set as
#' random terms. Fixed categorical individual covariates are currently not
#' allowed. However, such terms may be supplied if the \code{modelsuite} option
#' is set to a \code{vrm_input} object. In that case, the user should also set
#' the logical random switch for the individual covariate to be used to 
#' \code{TRUE} (e.g., \code{random.inda = TRUE}).
#'
#' @seealso \code{\link{mpm_create}()}
#' @seealso \code{\link{flefko3}()}
#' @seealso \code{\link{flefko2}()}
#' @seealso \code{\link{aflefko2}()}
#' @seealso \code{\link{arlefko2}()}
#' @seealso \code{\link{rlefko3}()}
#' @seealso \code{\link{rlefko2}()}
#' @seealso \code{\link{rleslie}()}
#' 
#' @examples
#' data(lathyrus)
#' 
#' lathvert_base <- verticalize3(lathyrus, noyears = 4, firstyear = 1988,
#'   patchidcol = "SUBPLOT", individcol = "GENET", blocksize = 9,
#'   sizeacol = "Volume88", repstracol = "FCODE88", fecacol = "Intactseed88",
#'   deadacol = "Dead1988", censorcol = "Missing1988", censorkeep = NA,
#'   censor = TRUE, NAas0 = TRUE, NRasRep = TRUE, NOasObs = TRUE)
#' 
#' lathvert_base$feca3 <- round(lathvert_base$feca3)
#' lathvert_base$feca2 <- round(lathvert_base$feca2)
#' lathvert_base$feca1 <- round(lathvert_base$feca1)
#' 
#' lathvert_age <- subset(lathvert_base, firstseen > 1988)
#' 
#' lath_survival <- glm(alive3 ~ obsage + as.factor(year2), data = lathvert_age,
#'   family = "binomial")
#' lath_fecundity <- glm(feca2 ~ obsage + as.factor(year2), data = lathvert_age,
#'   family = "poisson")
#' 
#' mod_params <- create_pm(name_terms = TRUE)
#' mod_params$modelparams[22] <- "obsage"
#' 
#' lathmat2fleslie <- fleslie(year = "all", data = lathvert_age,
#'   surv_model = lath_survival, fec_model = lath_fecundity,
#'   paramnames = mod_params, fecage_min = 1)
#'   
#' @export
fleslie <- function(year = "all", patch = NULL, prebreeding = TRUE,
  data = NULL, modelsuite = NULL, surv_model = NULL, fec_model = NULL,
  paramnames = NULL, supplement = NULL, start_age = NA, last_age = NA,
  fecage_min = NA, fecage_max = NA, continue = TRUE, inda = NULL, indb = NULL,
  indc = NULL, annua = NULL, annub = NULL, annuc = NULL, surv_dev = 0,
  fec_dev = 0, density = NA, fecmod = 1.0, random.inda = FALSE,
  random.indb = FALSE, random.indc = FALSE, negfec = FALSE, reduce = FALSE,
  simple = FALSE, err_check = FALSE, exp_tol = 700, theta_tol = 100000000,
  sparse_output = FALSE) {
  
  devterms <- c(surv_dev, fec_dev)
  
  if (is.null(modelsuite)) {
    if (!is.null(surv_model)) {
      modelsuite <- list(surv_model = surv_model, obs_model = NULL,
        size_model = NULL, sizeb_model = NULL, sizec_model = NULL,
        repst_model = NULL, fec_model = fec_model, jsurv_model = NULL,
        jobs_model = NULL, jsize_model = NULL, jsizeb_model = NULL,
        jsizec_model = NULL, jrepst_model = NULL, jmatst_model = NULL)
      if (!is.null(paramnames)) modelsuite$paramnames <- paramnames
    }
  }
  
  output <- mpm_create(historical = FALSE, stage = FALSE, age = TRUE,
    devries = FALSE, reduce = reduce, data = data, year = year, patch = patch,
    modelsuite = modelsuite, paramnames = paramnames, supplement = supplement,
    inda = inda, indb = indb, indc = indc, annua = annua, annub = annub,
    annuc = annuc, dev_terms = devterms, density = density, fecmod = fecmod,
    random_inda = random.inda, random_indb = random.indb,
    random_indc = random.indc, negfec = negfec, exp_tol = exp_tol,
    theta_tol = theta_tol, start_age = start_age, last_age = last_age,
    fecage_min = fecage_min, fecage_max = fecage_max, cont = continue,
    prebreeding = prebreeding, simple = simple, err_check = err_check,
    sparse_output = sparse_output)
  
  return(output)
}

#' Create Raw Historical Matrix Projection Model
#' 
#' Function \code{rlefko3()} returns raw historical MPMs, including the
#' associated component transition and fecundity matrices, data frames
#' describing the ahistorical stages used and the historical paired stages, and
#' a data frame describing the population, patch, and occasion time associated
#' with each matrix.
#' 
#' @name rlefko3
#' 
#' @param data A vertical demographic data frame, with variables corresponding 
#' to the naming conventions in functions \code{\link{verticalize3}()} and
#' \code{\link{historicalize3}()}. Alternatively, a list of bootstrapped data of
#' class \code{hfv_list}.
#' @param stageframe A stageframe object that includes information on the size,
#' observation status, propagule status, reproduction status, immaturity status,
#' and maturity status of each ahistorical stage.
#' @param year A variable corresponding to observation occasion, or a set of
#' such values, given in values associated with the \code{year} term used in
#' vital rate model development. Can also equal \code{"all"}, in which case
#' matrices will be estimated for all occasions. Defaults to \code{"all"}.
#' @param pop A variable designating which populations will have matrices
#' estimated. Should be set to specific population names, or to \code{"all"} if
#' all populations should have matrices estimated.
#' @param patch A variable designating which patches or subpopulations will have
#' matrices estimated. Should be set to specific patch names, or to \code{"all"}
#' if matrices should be estimated for all patches. Defaults to \code{NA}, in
#' which case patch designations are ignored..
#' @param censor If \code{TRUE}, then data will be removed according to the
#' variable set in \code{censorcol}, such that only data with censor values
#' equal to \code{censorkeep} will remain. Defaults to \code{FALSE}.
#' @param stages An optional vector denoting the names of the variables within
#' the main vertical dataset coding for the stages of each individual in
#' occasions \emph{t}+1, \emph{t}, and \emph{t}-1. The names of stages in these
#' variables should match those used in the \code{stageframe} exactly. If left
#' blank, then \code{rlefko3()} will attempt to infer stages by matching values
#' of \code{alive}, \code{size}, \code{repst}, and \code{matst} to
#' characteristics noted in the associated \code{stageframe}.
#' @param alive A vector of names of binomial variables corresponding to status
#' as alive (\code{1}) or dead (\code{0}) in occasions \emph{t}+1, \emph{t}, and
#' \emph{t}-1, respectively.
#' @param obsst A vector of names of binomial variables corresponding to
#' observation status in occasions \emph{t}+1, \emph{t}, and \emph{t}-1,
#' respectively. Defaults to \code{NULL}, in which case observation status is
#' not used.
#' @param size A vector of names of variables coding the primary size variable
#' in occasions \emph{t}+1, \emph{t}, and \emph{t}-1, respectively. Defaults to 
#' \code{c("sizea3", "sizea2", "sizea1")}.
#' @param sizeb A vector of names of variables coding the secondary size
#' variable in occasions \emph{t}+1, \emph{t}, and \emph{t}-1, respectively.
#' Defaults to \code{NULL}, in which case this variable is not used.
#' @param sizec A vector of names of variables coding the tertiary size
#' variable in occasions \emph{t}+1, \emph{t}, and \emph{t}-1, respectively.
#' Defaults to \code{NULL}, in which case this variable is not used.
#' @param repst A vector of names of variables coding reproductive status in
#' occasions \emph{t}+1, \emph{t}, and \emph{t}-1, respectively. Defaults to 
#' \code{c("repstatus3", "repstatus2", "repstatus1")}. Must be supplied if
#' \code{stages} is not provided.
#' @param matst A vector of names of variables coding maturity status in
#' occasions \emph{t}+1, \emph{t}, and \emph{t}-1, respectively. Defaults to
#' \code{c("matstatus3", "matstatus2", "matstatus1")}. Must be supplied if
#' \code{stages} is not provided.
#' @param fec A vector of names of variables coding fecundity in occasions
#' \emph{t}+1, \emph{t}, and \emph{t}-1, respectively. Defaults to
#' \code{c("feca3", "feca2", "feca1")}.
#' @param supplement An optional data frame of class \code{lefkoSD} that
#' provides supplemental data that should be incorporated into the MPM. Three
#' kinds of data may be integrated this way: transitions to be estimated via the
#' use of proxy transitions, transition overwrites from the literature or
#' supplemental studies, and transition multipliers for fecundity. This data
#' frame should be produced using the \code{\link{supplemental}()} function.
#' Should be used in place of or in addition to an overwrite table (see 
#' \code{overwrite} below) and a reproduction matrix (see \code{repmatrix}
#' below).
#' @param repmatrix An optional reproduction matrix. This matrix is composed
#' mostly of 0s, with non-zero entries acting as element identifiers and
#' multipliers for fecundity (with 1 equaling full fecundity). If left blank,
#' and no \code{supplement} is provided, then \code{rlefko3()} will assume that
#' all stages marked as reproductive produce offspring at 1x that of estimated
#' fecundity, and that offspring production will yield the first stage noted as
#' propagule or immature. To prevent this behavior, input just \code{0}, which
#' will result in fecundity being estimated only for transitions noted in
#' \code{supplement} above. May be the dimensions of either a historical or an
#' ahistorical matrix. If the former, then the fecundity estimation of this
#' function may be unpredictable. If the latter, then all stages will be used in
#' occasion \emph{t}-1 for each suggested ahistorical transition.
#' @param overwrite An optional data frame developed with the
#' \code{\link{overwrite}()} function describing transitions to be overwritten
#' either with given values or with other estimated transitions. Note that this
#' function supplements overwrite data provided in \code{supplement}.
#' @param yearcol The variable name or column number corresponding to occasion
#' \emph{t} in the dataset.
#' @param popcol The variable name or column number corresponding to the
#' identity of the population.
#' @param patchcol The variable name or column number corresponding to patch in 
#' the dataset.
#' @param indivcol The variable name or column number coding individual
#' identity.
#' @param censorcol The variable name or column number denoting the censor
#' status. Only needed if \code{censor = TRUE}.
#' @param censorkeep The value of the censor variable denoting data elements to
#' keep. Defaults to \code{0}.
#' @param NRasRep If \code{data} does not include stage assignments, then this
#' option determines whether non-reproductive and reproductive individuals
#' should be lumped into the same stages. Defaults to \code{FALSE}.
#' @param format A string indicating whether to estimate matrices in
#' \code{ehrlen} format or \code{deVries} format. The latter adds one unborn
#' prior stage to account for the prior state of newborns. Defaults to
#' \code{ehrlen} format.
#' @param reduce A logical value denoting whether to remove historical stages
#' associated exclusively with zero transitions. These are removed only if the
#' respective row and column sums in ALL matrices estimated equal 0. Defaults to
#' \code{FALSE}.
#' @param simple A logical value indicating whether to produce \code{A},
#' \code{U}, and \code{F} matrices, or only the latter two. Defaults to
#' \code{FALSE}, in which case all three are output.
#' @param err_check A logical value indicating whether to append extra
#' information used in matrix calculation within the output list. Defaults to
#' \code{FALSE}.
#' @param initial_nan A single logical value indicating whether to initialize
#' matrices was all elements set to \code{NaN}. Defaults to \code{FALSE}. Cannot
#' be used with sparse matrices.
#' @param sparse_output A logical value indicating whether to output matrices
#' in sparse format. Defaults to \code{FALSE}, in which case all matrices are
#' output in standard matrix format.
#'
#' @return If the user inputs a standard \code{hfv_data} object in argument
#' \code{data}, then this function will return an object of class
#' \code{lefkoMat}. If the user inputs an object of class \code{hfv_list} in
#' argument \code{data}, then the output will be an object of class
#' \code{lefkoMatList}, in which each element is an object of class
#' \code{lefkoMat}.
#' 
#' A \code{lefkoMat} object is a list that holds one full  matrix projection
#' model and all of its metadata. The structure has the following elements:
#' 
#' \item{A}{A list of full projection matrices in order of sorted populations,
#' patches, and occasions. All matrices output in the \code{matrix} class, or in
#' the \code{dgCMatrix} class from the \code{Matrix} package if sparse.}
#' \item{U}{A list of survival transition matrices sorted as in \code{A}. All 
#' matrices output in the \code{matrix} class, or in the \code{dgCMatrix} class
#' from the \code{Matrix} package if sparse.}
#' \item{F}{A list of fecundity matrices sorted as in \code{A}. All matrices 
#' output in the \code{matrix} class, or in the \code{dgCMatrix} class from the
#' \code{Matrix} package if sparse.}
#' \item{hstages}{A data frame matrix showing the pairing of ahistorical stages
#' used to create historical stage pairs.}
#' \item{agestages}{A data frame showing age-stage pairs. In this function, it
#' is set to NA. Only used in output to function \code{aflefko2}().}
#' \item{ahstages}{A data frame detailing the characteristics of associated
#' ahistorical stages, in the form of a modified stageframe that includes
#' status as an entry stage through reproduction.}
#' \item{labels}{A data frame giving the population, patch, and year of each 
#' matrix in order.}
#' \item{dataqc}{A vector showing the numbers of individuals and rows in the
#' vertical dataset used as input.}
#' \item{matrixqc}{A short vector describing the number of non-zero elements in
#' \code{U} and \code{F} matrices, and the number of annual matrices.}
#' \item{modelqc}{This is the \code{qc} portion of the \code{modelsuite} input
#' in function-based MPMs. Empty in this function.}
#'
#' @section Notes:
#' The default behavior of this function is to estimate fecundity with regards
#' to transitions specified via associated fecundity multipliers in the
#' \code{supplement}. If this field is left empty, then fecundity will be
#' estimated at full for all transitions leading from reproductive stages to
#' immature and propagule stages.
#' 
#' Users may at times wish to estimate MPMs using a dataset incorporating
#' multiple patches or subpopulations. Should the aim of analysis be a general
#' MPM that does not distinguish these patches or subpopulations, the
#' \code{patchcol} variable should be left to \code{NA}, which is the default.
#' Otherwise the variable identifying patch needs to be named.
#'
#' Input options including multiple variable names must be entered in the order
#' of variables in occasion \emph{t}+1, \emph{t}, and \emph{t}-1. Rearranging
#' the order WILL lead to erroneous calculations, and may lead to
#' fatal errors.
#'
#' Although this function is capable of assigning stages given an input
#' stageframe, it lacks the power of \code{\link{verticalize3}()} and
#' \code{\link{historicalize3}()} in this regard. Users are strongly
#' encouraged to use the latter two functions for stage assignment.
#' 
#' @seealso \code{\link{mpm_create}()}
#' @seealso \code{\link{flefko3}()}
#' @seealso \code{\link{flefko2}()}
#' @seealso \code{\link{aflefko2}()}
#' @seealso \code{\link{arlefko2}()}
#' @seealso \code{\link{fleslie}()}
#' @seealso \code{\link{rlefko2}()}
#' @seealso \code{\link{rleslie}()}
#' 
#' @examples
#' # Lathyrus example
#' data(lathyrus)
#' 
#' sizevector <- c(0, 100, 13, 127, 3730, 3800, 0)
#' stagevector <- c("Sd", "Sdl", "VSm", "Sm", "VLa", "Flo", "Dorm")
#' repvector <- c(0, 0, 0, 0, 0, 1, 0)
#' obsvector <- c(0, 1, 1, 1, 1, 1, 0)
#' matvector <- c(0, 0, 1, 1, 1, 1, 1)
#' immvector <- c(1, 1, 0, 0, 0, 0, 0)
#' propvector <- c(1, 0, 0, 0, 0, 0, 0)
#' indataset <- c(0, 1, 1, 1, 1, 1, 1)
#' binvec <- c(0, 100, 11, 103, 3500, 3800, 0.5)
#' 
#' lathframe <- sf_create(sizes = sizevector, stagenames = stagevector, 
#'   repstatus = repvector, obsstatus = obsvector, matstatus = matvector, 
#'   immstatus = immvector, indataset = indataset, binhalfwidth = binvec, 
#'   propstatus = propvector)
#' 
#' lathvert <- verticalize3(lathyrus, noyears = 4, firstyear = 1988, 
#'   patchidcol = "SUBPLOT", individcol = "GENET", blocksize = 9, 
#'   juvcol = "Seedling1988", sizeacol = "Volume88", repstracol = "FCODE88", 
#'   fecacol = "Intactseed88", deadacol = "Dead1988", nonobsacol = "Dormant1988", 
#'   stageassign = lathframe, stagesize = "sizea", censorcol = "Missing1988", 
#'   censorkeep = NA, censor = TRUE)
#' 
#' lathsupp3 <- supplemental(stage3 = c("Sd", "Sd", "Sdl", "Sdl", "Sd", "Sdl", "mat"),
#'   stage2 = c("Sd", "Sd", "Sd", "Sd", "rep", "rep", "Sdl"),
#'   stage1 = c("Sd", "rep", "Sd", "rep", "npr", "npr", "Sd"),
#'   eststage3 = c(NA, NA, NA, NA, NA, NA, "mat"),
#'   eststage2 = c(NA, NA, NA, NA, NA, NA, "Sdl"),
#'   eststage1 = c(NA, NA, NA, NA, NA, NA, "NotAlive"),
#'   givenrate = c(0.345, 0.345, 0.054, 0.054, NA, NA, NA),
#'   multiplier = c(NA, NA, NA, NA, 0.345, 0.054, NA),
#'   type = c(1, 1, 1, 1, 3, 3, 1), type_t12 = c(1, 2, 1, 2, 1, 1, 1),
#'   stageframe = lathframe, historical = TRUE)
#' 
#' ehrlen3 <- rlefko3(data = lathvert, stageframe = lathframe, year = "all", 
#'   stages = c("stage3", "stage2", "stage1"), supplement = lathsupp3,
#'   yearcol = "year2", indivcol = "individ")
#' 
#' # Cypripedium example
#' data(cypdata)
#' 
#' sizevector <- c(0, 0, 0, 0, 0, 0, 1, 2.5, 4.5, 8, 17.5)
#' stagevector <- c("SD", "P1", "P2", "P3", "SL", "D", "XSm", "Sm", "Md", "Lg",
#'   "XLg")
#' repvector <- c(0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1)
#' obsvector <- c(0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1)
#' matvector <- c(0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1)
#' immvector <- c(0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0)
#' propvector <- c(1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
#' indataset <- c(0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1)
#' binvec <- c(0, 0, 0, 0, 0, 0.5, 0.5, 1, 1, 2.5, 7)
#' 
#' cypframe_raw <- sf_create(sizes = sizevector, stagenames = stagevector,
#'   repstatus = repvector, obsstatus = obsvector, matstatus = matvector,
#'   propstatus = propvector, immstatus = immvector, indataset = indataset,
#'   binhalfwidth = binvec)
#' 
#' cypraw_v1 <- verticalize3(data = cypdata, noyears = 6, firstyear = 2004,
#'   patchidcol = "patch", individcol = "plantid", blocksize = 4,
#'   sizeacol = "Inf2.04", sizebcol = "Inf.04", sizeccol = "Veg.04",
#'   repstracol = "Inf.04", repstrbcol = "Inf2.04", fecacol = "Pod.04",
#'   stageassign = cypframe_raw, stagesize = "sizeadded", NAas0 = TRUE,
#'   NRasRep = TRUE)
#' 
#' cypsupp3r <- supplemental(stage3 = c("SD", "SD", "P1", "P1", "P2", "P3", "SL",
#'     "D", "XSm", "Sm", "D", "XSm", "Sm", "mat", "mat", "mat", "SD", "P1"),
#'   stage2 = c("SD", "SD", "SD", "SD", "P1", "P2", "P3", "SL", "SL", "SL", "SL",
#'     "SL", "SL", "D", "XSm", "Sm", "rep", "rep"),
#'   stage1 = c("SD", "rep", "SD", "rep", "SD", "P1", "P2", "P3", "P3", "P3",
#'     "SL", "SL", "SL", "SL", "SL", "SL", "mat", "mat"),
#'   eststage3 = c(NA, NA, NA, NA, NA, NA, NA, "D", "XSm", "Sm", "D", "XSm", "Sm",
#'     "mat", "mat", "mat", NA, NA),
#'   eststage2 = c(NA, NA, NA, NA, NA, NA, NA, "XSm", "XSm", "XSm", "XSm", "XSm",
#'     "XSm", "D", "XSm", "Sm", NA, NA),
#'   eststage1 = c(NA, NA, NA, NA, NA, NA, NA, "XSm", "XSm", "XSm", "XSm", "XSm",
#'     "XSm", "XSm", "XSm", "XSm", NA, NA),
#'   givenrate = c(0.1, 0.1, 0.2, 0.2, 0.2, 0.2, 0.25, NA, NA, NA, NA, NA, NA,
#'     NA, NA, NA, NA, NA),
#'   multiplier = c(NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA,
#'     NA, 0.5, 0.5),
#'   type = c(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 3),
#'   type_t12 = c(1, 2, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1),
#'   stageframe = cypframe_raw, historical = TRUE)
#' 
#' cypmatrix3r <- rlefko3(data = cypraw_v1, stageframe = cypframe_raw,
#'   year = "all", patch = "all", stages = c("stage3", "stage2", "stage1"),
#'   size = c("size3added", "size2added", "size1added"),
#'   supplement = cypsupp3r, yearcol = "year2", patchcol = "patchid",
#'   indivcol = "individ")
#' 
#' @export
rlefko3 <- function(data, stageframe, year = "all", pop = NULL, patch = NULL,
  censor = FALSE, stages = NULL, alive = c("alive3", "alive2", "alive1"),
  obsst = NULL, size = c("sizea3", "sizea2", "sizea1"), sizeb = NULL,
  sizec = NULL, repst = c("repstatus3", "repstatus2", "repstatus1"),
  matst = c("matstatus3", "matstatus2", "matstatus1"),
  fec = c("feca3", "feca2", "feca1"), supplement = NULL, repmatrix = NULL,
  overwrite = NULL, yearcol = NULL, popcol = NULL, patchcol = NULL, indivcol = NULL,
  censorcol = NULL, censorkeep = 0, NRasRep = FALSE, format = "ehrlen",
  reduce = FALSE, simple = FALSE, err_check = FALSE, initial_nan = FALSE,
  sparse_output = FALSE) {
  
  format_dev <- FALSE
  
  if (grepl("dev", tolower(format))) {
    format_dev <- TRUE
  }
  
  output <- mpm_create(historical = TRUE, stage = TRUE, age = FALSE,
    devries = format_dev, reduce = reduce, data = data, year = year, pop = pop,
    patch = patch, stageframe = stageframe, supplement = supplement, 
    overwrite = overwrite, repmatrix = repmatrix, alive = alive,
    obsst = obsst, size = size, sizeb = sizeb, sizec = sizec, repst = repst,
    matst = matst, fec = fec, stages = stages, yearcol = yearcol,
    popcol = popcol, patchcol = patchcol, indivcol = indivcol,
    censorcol = censorcol, censor = censor, censorkeep = censorkeep,
    stage_NRasRep = NRasRep, simple = simple, err_check = err_check,
    initial_nan = initial_nan, sparse_output = sparse_output)
  
  return(output)
}

#' Create Raw Ahistorical Matrix Projection Model
#'
#' Function \code{rlefko2()} returns raw ahistorical MPMs, including the
#' associated component transition and fecundity matrices, a data frame
#' describing the ahistorical stages used, and a data frame describing the
#' population, patch, and occasion time associated with each matrix.
#' 
#' @name rlefko2
#' 
#' @param data A vertical demographic data frame, with variables corresponding 
#' to the naming conventions in functions \code{\link{verticalize3}()} and
#' \code{\link{historicalize3}()}. Alternatively, a list of bootstrapped data of
#' class \code{hfv_list}.
#' @param stageframe A stageframe object that includes information on the size,
#' observation status, propagule status, reproduction status, immaturity status,
#' and maturity status of each ahistorical stage.
#' @param year A variable corresponding to observation occasion, or a set
#' of such values, given in values associated with the \code{year} term used in
#' vital rate model development. Can also equal \code{"all"}, in which case
#' matrices will be estimated for all occasion times. Defaults to \code{"all"}.
#' @param pop A variable designating which populations will have matrices
#' estimated. Should be set to specific population names, or to \code{"all"} if
#' all populations should have matrices estimated.
#' @param patch A variable designating which patches or subpopulations will have
#' matrices estimated. Should be set to specific patch names, or to \code{"all"}
#' if matrices should be estimated for all patches. Defaults to \code{NA}, in
#' which case patch designations are ignored..
#' @param censor If \code{TRUE}, then data will be removed according to the
#' variable set in \code{censorcol}, such that only data with censor values
#' equal to \code{censorkeep} will remain. Defaults to \code{FALSE}.
#' @param stages An optional vector denoting the names of the variables within
#' the main vertical dataset coding for the stages of each individual in
#' occasions \emph{t}+1 and \emph{t}. The names of stages in these variables
#' should match those used in the \code{stageframe} exactly. If left blank, then
#' \code{rlefko2()} will attempt to infer stages by matching values of
#' \code{alive}, \code{size}, \code{repst}, and \code{matst} to characteristics
#' noted in the associated \code{stageframe}.
#' @param alive A vector of names of binomial variables corresponding to status
#' as alive (\code{1}) or dead (\code{0}) in occasions \emph{t}+1 and \emph{t},
#' respectively.
#' @param obsst A vector of names of binomial variables corresponding to
#' observation status in occasions \emph{t}+1, \emph{t}, and \emph{t}-1,
#' respectively. Defaults to \code{NULL}, in which case observation status is
#' not used.
#' @param size A vector of names of variables coding the primary size variable
#' in occasions \emph{t}+1 and \emph{t}, respectively. Defaults to
#' \code{c("sizea3", "sizea2")}.
#' @param sizeb A vector of names of variables coding the secondary size
#' variable in occasions \emph{t}+1 and \emph{t}, respectively. Defaults to
#' \code{NULL}, in which case this variable is not used.
#' @param sizec A vector of names of variables coding the tertiary size
#' variable in occasions \emph{t}+1 and \emph{t}, respectively. Defaults to
#' \code{NULL}, in which case this variable is not used.
#' @param repst A vector of names of variables coding reproductive status in
#' occasions \emph{t}+1 and \emph{t}, respectively. Defaults to 
#' \code{c("repstatus3", "repstatus2")}. Must be supplied if \code{stages} is
#' not provided.
#' @param matst A vector of names of variables coding maturity status in
#' occasions \emph{t}+1 and \emph{t}, respectively. Defaults to
#' \code{c("matstatus3", "matstatus2")}. Must be supplied if \code{stages} is
#' not provided.
#' @param fec A vector of names of variables coding fecundity in occasions
#' \emph{t}+1 and \emph{t}, respectively. Defaults to \code{c("feca3", "feca2")}.
#' @param supplement An optional data frame of class \code{lefkoSD} that
#' provides supplemental data that should be incorporated into the MPM. Three
#' kinds of data may be integrated this way: transitions to be estimated via the
#' use of proxy transitions, transition overwrites from the literature or
#' supplemental studies, and transition multipliers for fecundity. This data
#' frame should be produced using the \code{\link{supplemental}()} function.
#' Should be used in place of or in addition to an overwrite table (see 
#' \code{overwrite} below) and a reproduction matrix (see \code{repmatrix}
#' below).
#' @param repmatrix An optional reproduction matrix. This matrix is composed
#' mostly of 0s, with non-zero entries acting as element identifiers and
#' multipliers for fecundity (with 1 equaling full fecundity). If left blank,
#' and no \code{supplement} is provided, then \code{rlefko2()} will assume that
#' all stages marked as reproductive produce offspring at 1x that of estimated
#' fecundity, and that offspring production will yield the first stage noted as
#' propagule or immature. To prevent this behavior, input just \code{0}, which
#' will result in fecundity being estimated only for transitions noted in
#' \code{supplement} above. Must be the dimensions of an ahistorical matrix.
#' @param overwrite An optional data frame developed with the
#' \code{\link{overwrite}()} function describing transitions to be overwritten
#' either with given values or with other estimated transitions. Note that this
#' function supplements overwrite data provided in \code{supplement}.
#' @param yearcol The variable name or column number corresponding to occasion 
#' \emph{t} in the dataset.
#' @param popcol The variable name or column number corresponding to the
#' identity of the population.
#' @param patchcol The variable name or column number corresponding to patch in
#' the dataset.
#' @param indivcol The variable name or column number coding individual
#' identity.
#' @param censorcol The variable name or column number denoting the censor
#' status. Only needed if \code{censor = TRUE}.
#' @param censorkeep The value of the censor variable denoting data elements to
#' keep. Defaults to \code{0}.
#' @param NRasRep If \code{data} does not include stage assignments, then this
#' option determines whether non-reproductive and reproductive individuals
#' should be lumped into the same stages. Defaults to \code{FALSE}.
#' @param reduce A logical value denoting whether to remove ahistorical stages
#' associated with only zero transitions. These are removed only if the
#' respective row and column sums in ALL matrices estimated equal 0. Defaults to
#' \code{FALSE}.
#' @param simple A logical value indicating whether to produce \code{A},
#' \code{U}, and \code{F} matrices, or only the latter two. Defaults to
#' \code{FALSE}, in which case all three are output.
#' @param err_check A logical value indicating whether to append extra
#' information used in matrix calculation within the output list. Defaults to
#' \code{FALSE}.
#' @param initial_nan A single logical value indicating whether to initialize
#' matrices was all elements set to \code{NaN}. Defaults to \code{FALSE}. Cannot
#' be used with sparse matrices.
#' @param sparse_output A logical value indicating whether to output matrices
#' in sparse format. Defaults to \code{FALSE}, in which case all matrices are
#' output in standard matrix format.
#' 
#' @return If the user inputs a standard \code{hfv_data} object in argument
#' \code{data}, then this function will return an object of class
#' \code{lefkoMat}. If the user inputs an object of class \code{hfv_list} in
#' argument \code{data}, then the output will be an object of class
#' \code{lefkoMatList}, in which each element is an object of class
#' \code{lefkoMat}.
#' 
#' A \code{lefkoMat} object is a list that holds one full  matrix projection
#' model and all of its metadata. The structure has the following elements:
#' 
#' \item{A}{A list of full projection matrices in order of sorted populations,
#' patches, and occasions. All matrices output in the \code{matrix} class, or in
#' the \code{dgCMatrix} class from the \code{Matrix} package if sparse.}
#' \item{U}{A list of survival transition matrices sorted as in \code{A}. All 
#' matrices output in the \code{matrix} class, or in the \code{dgCMatrix} class
#' from the \code{Matrix} package if sparse.}
#' \item{F}{A list of fecundity matrices sorted as in \code{A}. All matrices 
#' output in the \code{matrix} class, or in the \code{dgCMatrix} class from the
#' \code{Matrix} package if sparse.}
#' \item{hstages}{A data frame matrix showing the pairing of ahistorical stages
#' used to create historical stage pairs. Set to NA for ahistorical matrices.}
#' \item{agestages}{A data frame showing age-stage pairs. In this function, it
#' is set to NA. Only used in output to function \code{aflefko2}().}
#' \item{ahstages}{A data frame detailing the characteristics of associated
#' ahistorical stages, in the form of a modified stageframe that includes
#' status as an entry stage through reproduction.}
#' \item{labels}{A data frame giving the population, patch, and year of each 
#' matrix in order.}
#' \item{dataqc}{A vector showing the numbers of individuals and rows in the
#' vertical dataset used as input.}
#' \item{matrixqc}{A short vector describing the number of non-zero elements in
#' \code{U} and \code{F} matrices, and the number of annual matrices.}
#' \item{modelqc}{This is the \code{qc} portion of the \code{modelsuite} input
#' in function-based MPMs. Empty in this function.}
#'
#' @section Notes:
#' The default behavior of this function is to estimate fecundity with regards
#' to transitions specified via associated fecundity multipliers in the
#' \code{supplement}. If this field is left empty, then fecundity will be
#' estimated at full for all transitions leading from reproductive stages to
#' immature and propagule stages.
#' 
#' Users may at times wish to estimate MPMs using a dataset incorporating
#' multiple patches or subpopulations. Should the aim of analysis be a general
#' MPM that does not distinguish these patches or subpopulations, the
#' \code{patchcol} variable should be left to \code{NA}, which is the default.
#' Otherwise the variable identifying patch needs to be named.
#'
#' Input options including multiple variable names must be entered in the order
#' of variables in occasion \emph{t}+1 and \emph{t}. Rearranging the order WILL
#' lead to erroneous calculations, and may lead to fatal errors.
#' 
#' Although this function is capable of assigning stages given an input
#' stageframe, it lacks the power of \code{\link{verticalize3}()} and
#' \code{\link{historicalize3}()} in this regard. Users are strongly
#' encouraged to use the latter two functions for stage assignment.
#' 
#' @seealso \code{\link{mpm_create}()}
#' @seealso \code{\link{flefko3}()}
#' @seealso \code{\link{flefko2}()}
#' @seealso \code{\link{aflefko2}()}
#' @seealso \code{\link{arlefko2}()}
#' @seealso \code{\link{fleslie}()}
#' @seealso \code{\link{rlefko3}()}
#' @seealso \code{\link{rleslie}()}
#' 
#' @examples
#' # Lathyrus example
#' data(lathyrus)
#' 
#' sizevector <- c(0, 100, 13, 127, 3730, 3800, 0)
#' stagevector <- c("Sd", "Sdl", "VSm", "Sm", "VLa", "Flo", "Dorm")
#' repvector <- c(0, 0, 0, 0, 0, 1, 0)
#' obsvector <- c(0, 1, 1, 1, 1, 1, 0)
#' matvector <- c(0, 0, 1, 1, 1, 1, 1)
#' immvector <- c(1, 1, 0, 0, 0, 0, 0)
#' propvector <- c(1, 0, 0, 0, 0, 0, 0)
#' indataset <- c(0, 1, 1, 1, 1, 1, 1)
#' binvec <- c(0, 100, 11, 103, 3500, 3800, 0.5)
#' 
#' lathframe <- sf_create(sizes = sizevector, stagenames = stagevector, 
#'   repstatus = repvector, obsstatus = obsvector, matstatus = matvector, 
#'   immstatus = immvector, indataset = indataset, binhalfwidth = binvec, 
#'   propstatus = propvector)
#' 
#' lathvert <- verticalize3(lathyrus, noyears = 4, firstyear = 1988, 
#'   patchidcol = "SUBPLOT", individcol = "GENET", blocksize = 9, 
#'   juvcol = "Seedling1988", sizeacol = "Volume88", repstracol = "FCODE88", 
#'   fecacol = "Intactseed88", deadacol = "Dead1988", nonobsacol = "Dormant1988", 
#'   stageassign = lathframe, stagesize = "sizea", censorcol = "Missing1988", 
#'   censorkeep = NA, censor = TRUE)
#' 
#' lathsupp2 <- supplemental(stage3 = c("Sd", "Sdl", "Sd", "Sdl"), 
#'   stage2 = c("Sd", "Sd", "rep", "rep"),
#'   givenrate = c(0.345, 0.054, NA, NA),
#'   multiplier = c(NA, NA, 0.345, 0.054),
#'   type = c(1, 1, 3, 3), stageframe = lathframe, historical = FALSE)
#' 
#' ehrlen2 <- rlefko2(data = lathvert, stageframe = lathframe, year = "all", 
#'   stages = c("stage3", "stage2"), supplement = lathsupp2, yearcol = "year2",
#'   indivcol = "individ")
#' 
#' # Cypripedium example
#' data(cypdata)
#' 
#' sizevector <- c(0, 0, 0, 0, 0, 0, 1, 2.5, 4.5, 8, 17.5)
#' stagevector <- c("SD", "P1", "P2", "P3", "SL", "D", "XSm", "Sm", "Md", "Lg",
#'   "XLg")
#' repvector <- c(0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1)
#' obsvector <- c(0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1)
#' matvector <- c(0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1)
#' immvector <- c(0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0)
#' propvector <- c(1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
#' indataset <- c(0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1)
#' binvec <- c(0, 0, 0, 0, 0, 0.5, 0.5, 1, 1, 2.5, 7)
#' 
#' cypframe_raw <- sf_create(sizes = sizevector, stagenames = stagevector,
#'   repstatus = repvector, obsstatus = obsvector, matstatus = matvector,
#'   propstatus = propvector, immstatus = immvector, indataset = indataset,
#'   binhalfwidth = binvec)
#' 
#' cypraw_v1 <- verticalize3(data = cypdata, noyears = 6, firstyear = 2004,
#'   patchidcol = "patch", individcol = "plantid", blocksize = 4,
#'   sizeacol = "Inf2.04", sizebcol = "Inf.04", sizeccol = "Veg.04",
#'   repstracol = "Inf.04", repstrbcol = "Inf2.04", fecacol = "Pod.04",
#'   stageassign = cypframe_raw, stagesize = "sizeadded", NAas0 = TRUE,
#'   NRasRep = TRUE)
#' 
#' # Here we use supplemental() to provide overwrite and reproductive info
#' cypsupp2r <- supplemental(stage3 = c("SD", "P1", "P2", "P3", "SL", "D", 
#'     "XSm", "Sm", "SD", "P1"),
#'   stage2 = c("SD", "SD", "P1", "P2", "P3", "SL", "SL", "SL", "rep",
#'     "rep"),
#'   eststage3 = c(NA, NA, NA, NA, NA, "D", "XSm", "Sm", NA, NA),
#'   eststage2 = c(NA, NA, NA, NA, NA, "XSm", "XSm", "XSm", NA, NA),
#'   givenrate = c(0.10, 0.20, 0.20, 0.20, 0.25, NA, NA, NA, NA, NA),
#'   multiplier = c(NA, NA, NA, NA, NA, NA, NA, NA, 0.5, 0.5),
#'   type =c(1, 1, 1, 1, 1, 1, 1, 1, 3, 3),
#'   stageframe = cypframe_raw, historical = FALSE)
#' 
#' cypmatrix2r <- rlefko2(data = cypraw_v1, stageframe = cypframe_raw, 
#'   year = "all", patch = "all", stages = c("stage3", "stage2", "stage1"),
#'   size = c("size3added", "size2added"), supplement = cypsupp2r,
#'   yearcol = "year2", patchcol = "patchid", indivcol = "individ")
#' 
#' @export
rlefko2 <- function(data, stageframe, year = "all", pop = NULL, patch = NULL,
  censor = FALSE, stages = NULL, alive = c("alive3", "alive2"),
  obsst = NULL, size = c("sizea3", "sizea2"), sizeb = NULL, sizec = NULL,
  repst = c("repstatus3", "repstatus2"), matst = c("matstatus3", "matstatus2"),
  fec = c("feca3", "feca2"), supplement = NULL, repmatrix = NULL,
  overwrite = NULL, yearcol = NULL, popcol = NULL, patchcol = NULL, indivcol = NULL,
  censorcol = NULL, censorkeep = 0, NRasRep = FALSE, reduce = FALSE, simple = FALSE,
  err_check = FALSE, initial_nan = FALSE, sparse_output = FALSE) {

  output <- mpm_create(historical = FALSE, stage = TRUE, age = FALSE,
    devries = FALSE, reduce = reduce, data = data, year = year, pop = pop,
    patch = patch, stageframe = stageframe, supplement = supplement, 
    overwrite = overwrite, repmatrix = repmatrix, alive = alive,
    obsst = obsst, size = size, sizeb = sizeb, sizec = sizec, repst = repst,
    matst = matst, fec = fec, stages = stages, yearcol = yearcol,
    popcol = popcol, patchcol = patchcol, indivcol = indivcol,
    censorcol = censorcol, censor = censor, censorkeep = censorkeep,
    stage_NRasRep = NRasRep, simple = simple, err_check = err_check,
    initial_nan = initial_nan, sparse_output = sparse_output)
  
  return(output)
}

#' Create Raw Ahistorical Age x Stage Matrix Projection Model
#'
#' Function \code{arlefko2()} returns raw ahistorical age x stage MPMs
#' corresponding to the patches and occasion times given, including the
#' associated component transition and fecundity matrices, data frames detailing
#' the characteristics of ahistorical stages and the exact age-stage
#' combinations corresponding to rows and columns in estimated matrices, and a
#' data frame characterizing the patch and occasion time combinations
#' corresponding to these matrices.
#' 
#' @name arlefko2
#' 
#' @param data A vertical demographic data frame, with variables corresponding 
#' to the naming conventions in functions \code{\link{verticalize3}()} and
#' \code{\link{historicalize3}()}. Alternatively, a list of bootstrapped data of
#' class \code{hfv_list}.
#' @param stageframe A stageframe object that includes information on the size,
#' observation status, propagule status, reproduction status, immaturity status,
#' and maturity status of each ahistorical stage. Should also incorporate bin
#' widths if size is continuous.
#' @param year A variable corresponding to observation occasion, or a set
#' of such values, given in values associated with the year term used in linear 
#' model development. Defaults to \code{"all"}, in which case matrices will be
#' estimated for all occasions.
#' @param pop A variable designating which populations will have matrices
#' estimated. Should be set to specific population names, or to \code{"all"} if
#' all populations should have matrices estimated.
#' @param patch A variable designating which patches or subpopulations will have
#' matrices estimated. Should be set to specific patch names, or to \code{"all"}
#' if matrices should be estimated for all patches. Defaults to \code{NA}, in
#' which case patch designations are ignored.
#' @param censor If \code{TRUE}, then data will be removed according to the
#' variable set in \code{censorcol}, such that only data with censor values
#' equal to \code{censorkeep} will remain. Defaults to \code{FALSE}.
#' @param stages An optional vector denoting the names of the variables within
#' the main vertical dataset coding for the stages of each individual in
#' occasions \emph{t}+1 and \emph{t}. The names of stages in these variables
#' should match those used in the \code{stageframe} exactly. If left blank, then
#' \code{arlefko2()} will attempt to infer stages by matching values of
#' \code{alive}, \code{size}, \code{repst}, and \code{matst} to characteristics
#' noted in the associated \code{stageframe}.
#' @param alive A vector of names of binomial variables corresponding to status
#' as alive (\code{1}) or dead (\code{0}) in occasions \emph{t}+1 ans \emph{t},
#' respectively.
#' @param obsst A vector of names of binomial variables corresponding to
#' observation status in occasions \emph{t}+1, \emph{t}, and \emph{t}-1,
#' respectively. Defaults to \code{NULL}, in which case observation status is
#' not used.
#' @param size A vector of names of variables coding the primary size variable
#' in occasions \emph{t}+1 and \emph{t}, respectively. Defaults to
#' \code{c("sizea3", "sizea2")}.
#' @param sizeb A vector of names of variables coding the secondary size
#' variable in occasions \emph{t}+1 and \emph{t}, respectively. Defaults to
#' \code{NULL}, in which case this variable is not used.
#' @param sizec A vector of names of variables coding the tertiary size
#' variable in occasions \emph{t}+1 and \emph{t}, respectively. Defaults to
#' \code{NULL}, in which case this variable is not used.
#' @param repst A vector of names of variables coding reproductive status in
#' occasions \emph{t}+1 and \emph{t}, respectively. Defaults to 
#' \code{c("repstatus3", "repstatus2")}. Must be supplied if \code{stages} is
#' not provided.
#' @param matst A vector of names of variables coding maturity status in
#' occasions \emph{t}+1 and \emph{t}, respectively. Defaults to
#' \code{c("matstatus3", "matstatus2")}. Must be supplied if \code{stages} is
#' not provided.
#' @param fec A vector of names of variables coding fecundity in occasions
#' \emph{t}+1 and \emph{t}, respectively. Defaults to \code{c("feca3", "feca2")}.
#' @param supplement An optional data frame of class \code{lefkoSD} that
#' provides supplemental data that should be incorporated into the MPM. Three
#' kinds of data may be integrated this way: transitions to be estimated via the
#' use of proxy transitions, transition overwrites from the literature or
#' supplemental studies, and transition multipliers for survival and fecundity.
#' This data frame should be produced using the \code{\link{supplemental}()}
#' function. Can be used in place of or in addition to an overwrite table (see 
#' \code{overwrite} below) and a reproduction matrix (see \code{repmatrix}
#' below).
#' @param repmatrix An optional reproduction matrix. This matrix is composed
#' mostly of 0s, with non-zero entries acting as element identifiers and
#' multipliers for fecundity (with 1 equaling full fecundity). If left blank,
#' and no \code{supplement} is provided, then \code{aflefko2()} will assume that
#' all stages marked as reproductive produce offspring at 1x that of estimated
#' fecundity, and that offspring production will yield the first stage noted as
#' propagule or immature.  To prevent this behavior, input just \code{0}, which
#' will result in fecundity being estimated only for transitions noted in
#' \code{supplement} above. Must be the dimensions of an ahistorical stage-based
#' matrix.
#' @param overwrite An optional data frame developed with the
#' \code{\link{overwrite}()} function describing transitions to be overwritten
#' either with given values or with other estimated transitions. Note that this
#' function supplements overwrite data provided in \code{supplement}.
#' @param agecol The variable name or column corresponding to age in time
#' \emph{t}. Defaults to \code{"obsage"}.
#' @param yearcol The variable name or column number corresponding to occasion 
#' \emph{t} in the dataset.
#' @param popcol The variable name or column number corresponding to the
#' identity of the population.
#' @param patchcol The variable name or column number corresponding to patch in
#' the dataset.
#' @param indivcol The variable name or column number coding individual
#' identity.
#' @param agecol The variable name or column number coding for age in time
#' \emph{t}.
#' @param censorcol The variable name or column number denoting the censor
#' status. Only needed if \code{censor = TRUE}.
#' @param censorkeep The value of the censor variable denoting data elements to
#' keep. Defaults to \code{0}.
#' @param final_age The final age to model in the matrix, where the first age
#' will be age \code{0} if post-breeding, and \code{1} if pre-breeding. Defaults
#' to the maximum age in the dataset.
#' @param continue A logical value designating whether to allow continued
#' survival of individuals past the final age noted in the stageframe, using the 
#' demographic characteristics of the final age. Defaults to \code{TRUE}.
#' @param prebreeding A logical value indicating whether the life history model
#' is a pre-breeding model. Defaults to \code{TRUE}.
#' @param NRasRep If \code{data} does not include stage assignments, then this
#' option determines whether non-reproductive and reproductive individuals
#' should be lumped into the same stages. Defaults to \code{FALSE}.
#' @param reduce A logical value denoting whether to remove age-stages
#' associated with only zero transitions. These are removed only if the
#' respective row and column sums in ALL matrices estimated equal 0. Defaults to
#' \code{FALSE}.
#' @param simple A logical value indicating whether to produce \code{A},
#' \code{U}, and \code{F} matrices, or only the latter two. Defaults to
#' \code{FALSE}, in which case all three are output.
#' @param err_check A logical value indicating whether to append extra
#' information used in matrix calculation within the output list. Defaults to
#' \code{FALSE}.
#' @param initial_nan A single logical value indicating whether to initialize
#' matrices was all elements set to \code{NaN}. Defaults to \code{FALSE}. Cannot
#' be used with sparse matrices.
#' @param sparse_output A logical value indicating whether to output matrices
#' in sparse format. Defaults to \code{FALSE}, in which case all matrices are
#' output in standard matrix format.
#' 
#' @return If the user inputs a standard \code{hfv_data} object in argument
#' \code{data}, then this function will return an object of class
#' \code{lefkoMat}. If the user inputs an object of class \code{hfv_list} in
#' argument \code{data}, then the output will be an object of class
#' \code{lefkoMatList}, in which each element is an object of class
#' \code{lefkoMat}.
#' 
#' A \code{lefkoMat} object is a list that holds one full  matrix projection
#' model and all of its metadata. The structure has the following elements:
#' 
#' \item{A}{A list of full projection matrices in order of sorted patches and
#' occasions. All matrices output in R's \code{matrix} class, or in the
#' \code{dgCMatrix} class from the \code{Matrix} package if sparse.}
#' \item{U}{A list of survival transition matrices sorted as in \code{A}. All 
#' matrices output in R's \code{matrix} class, or in the \code{dgCMatrix} class
#' from the \code{Matrix} package if sparse.}
#' \item{F}{A list of fecundity matrices sorted as in \code{A}. All matrices 
#' output in R's \code{matrix} class, or in the \code{dgCMatrix} class from the
#' \code{Matrix} package if sparse.}
#' \item{hstages}{A data frame matrix showing the pairing of ahistorical stages
#' used to create historical stage pairs. Set to \code{NA} for age-by-stage
#' MPMs.}
#' \item{agestages}{A data frame showing the stage number and stage name
#' corresponding to \code{ahstages}, as well as the associated age, of each
#' row in each age-by-stage matrix.}
#' \item{ahstages}{A data frame detailing the characteristics of associated
#' ahistorical stages, in the form of a modified stageframe that includes
#' status as an entry stage through reproduction.}
#' \item{labels}{A data frame giving the patch and year of each matrix in order.
#' In \code{aflefko2()}, only one population may be analyzed at once, and so
#' \code{pop = NA}}
#' \item{dataqc}{A vector showing the numbers of individuals and rows in the
#' vertical dataset used as input.}
#' \item{matrixqc}{A short vector describing the number of non-zero elements in
#' \code{U} and \code{F} matrices, and the number of annual matrices.}
#' \item{modelqc}{This is the \code{qc} portion of the \code{modelsuite} input
#' in function-based MPMs. Empty in this function.}
#' 
#' @section Notes:
#' The default behavior of this function is to estimate fecundity with regards
#' to transitions specified via associated fecundity multipliers in the
#' \code{supplement}. If this field is left empty, then fecundity will be
#' estimated at full for all transitions leading from reproductive stages to
#' immature and propagule stages.
#' 
#' Users may at times wish to estimate MPMs using a dataset incorporating
#' multiple patches or subpopulations. Should the aim of analysis be a general
#' MPM that does not distinguish these patches or subpopulations, the
#' \code{patchcol} variable should be left to \code{NA}, which is the default.
#' Otherwise the variable identifying patch needs to be named.
#'
#' Input options including multiple variable names must be entered in the order
#' of variables in occasion \emph{t}+1 and \emph{t}. Rearranging the order WILL
#' lead to erroneous calculations, and may lead to fatal errors.
#' 
#' Although this function is capable of assigning stages given an input
#' stageframe, it lacks the power of \code{\link{verticalize3}()} and
#' \code{\link{historicalize3}()} in this regard. Users are strongly
#' encouraged to use the latter two functions for stage assignment.
#' 
#' @seealso \code{\link{mpm_create}()}
#' @seealso \code{\link{flefko3}()}
#' @seealso \code{\link{flefko2}()}
#' @seealso \code{\link{aflefko2}()}
#' @seealso \code{\link{fleslie}()}
#' @seealso \code{\link{rlefko3}()}
#' @seealso \code{\link{rlefko2}()}
#' @seealso \code{\link{rleslie}()}
#' 
#' @examples
#' \donttest{
#' # Cypripedium example
#' data(cypdata)
#' 
#' sizevector <- c(0, 0, 0, 0, 0, 0, 1, 2.5, 4.5, 8, 17.5)
#' stagevector <- c("SD", "P1", "P2", "P3", "SL", "D", "XSm", "Sm", "Md", "Lg",
#'   "XLg")
#' repvector <- c(0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1)
#' obsvector <- c(0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1)
#' matvector <- c(0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1)
#' immvector <- c(0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0)
#' propvector <- c(1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
#' indataset <- c(0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1)
#' binvec <- c(0, 0, 0, 0, 0, 0.5, 0.5, 1, 1, 2.5, 7)
#' minagevec <- c(1, 1, 2, 3, 4, 5, 5, 5, 5, 5, 5)
#' maxagevec <- c(rep(NA, 11))
#' 
#' cypframe_raw <- sf_create(sizes = sizevector, stagenames = stagevector,
#'   repstatus = repvector, obsstatus = obsvector, matstatus = matvector,
#'   propstatus = propvector, immstatus = immvector, indataset = indataset,
#'   binhalfwidth = binvec, minage = minagevec, maxage = maxagevec)
#' 
#' cypraw_v1 <- verticalize3(data = cypdata, noyears = 6, firstyear = 2004,
#'   patchidcol = "patch", individcol = "plantid", blocksize = 4,
#'   sizeacol = "Inf2.04", sizebcol = "Inf.04", sizeccol = "Veg.04",
#'   repstracol = "Inf.04", repstrbcol = "Inf2.04", fecacol = "Pod.04",
#'   stageassign = cypframe_raw, stagesize = "sizeadded", NAas0 = TRUE,
#'   NRasRep = TRUE, age_offset = 4)
#' 
#' # Here we use supplemental() to provide overwrite and reproductive info
#' cypsupp2r <- supplemental(stage3 = c("SD", "P1", "P2", "P3", "SL", "D", 
#'     "XSm", "Sm", "SD", "P1"),
#'   stage2 = c("SD", "SD", "P1", "P2", "P3", "SL", "SL", "SL", "rep",
#'     "rep"),
#'   eststage3 = c(NA, NA, NA, NA, NA, "D", "XSm", "Sm", NA, NA),
#'   eststage2 = c(NA, NA, NA, NA, NA, "XSm", "XSm", "XSm", NA, NA),
#'   givenrate = c(0.10, 0.20, 0.20, 0.20, 0.25, NA, NA, NA, NA, NA),
#'   multiplier = c(NA, NA, NA, NA, NA, NA, NA, NA, 0.5, 0.5),
#'   type =c(1, 1, 1, 1, 1, 1, 1, 1, 3, 3),
#'   stageframe = cypframe_raw, historical = FALSE, agebased = TRUE)
#' 
#' cyp_mats <- arlefko2(data = cypraw_v1, stageframe = cypframe_raw, year = "all", 
#'   patch = NA, censor = FALSE, stages = c("stage3", "stage2", "stage1"),
#'   size = c("size3added", "size2added"), fec = c("feca3", "feca2"),
#'   supplement = cypsupp2r, agecol = "obsage", yearcol = "year2", 
#'   patchcol = "patchid", indivcol = "individ", prebreeding = TRUE, final_age = NA,
#'   continue = TRUE, reduce = FALSE)
#' }
#' @export
arlefko2 <- function(data, stageframe, year = "all", pop = NULL, patch = NULL,
  censor = FALSE, stages = NULL, alive = c("alive3", "alive2"), obsst = NULL,
  size = c("sizea3", "sizea2"), sizeb = NULL, sizec = NULL,
  repst = c("repstatus3", "repstatus2"), matst = c("matstatus3", "matstatus2"),
  fec = c("feca3", "feca2"), supplement = NULL, repmatrix = NULL,
  overwrite = NULL, agecol = "obsage", yearcol = NULL, popcol = NULL, patchcol = NULL,
  indivcol = NULL, censorcol = NULL, censorkeep = 0, final_age = NA,
  continue = TRUE, prebreeding = TRUE, NRasRep = FALSE, reduce = FALSE, simple = FALSE,
  err_check = FALSE, initial_nan = FALSE, sparse_output = FALSE) {

  output <- mpm_create(historical = FALSE, stage = TRUE, age = TRUE,
    reduce = reduce, data = data, year = year, pop = pop,
    patch = patch, stageframe = stageframe, supplement = supplement, 
    overwrite = overwrite, repmatrix = repmatrix, alive = alive,
    obsst = obsst, size = size, sizeb = sizeb, sizec = sizec, repst = repst,
    matst = matst, fec = fec, stages = stages, yearcol = yearcol,
    popcol = popcol, patchcol = patchcol, indivcol = indivcol, agecol = agecol,
    censorcol = censorcol, censor = censor, censorkeep = censorkeep,
    last_age = final_age, cont = continue, prebreeding = prebreeding,
    stage_NRasRep = NRasRep, simple = simple, err_check = err_check,
    initial_nan = initial_nan, sparse_output = sparse_output)
  
  return(output)
}

#' Create Raw Leslie (Age-based) Matrix Projection Model
#'
#' Function \code{rleslie()} returns raw Leslie MPMs, including the
#' associated component transition and fecundity matrices, a data frame
#' describing the ages used, and a data frame describing the population, patch,
#' and occasion time associated with each matrix.
#' 
#' @name rleslie
#' 
#' @param data A vertical demographic data frame, with variables corresponding 
#' to the naming conventions in functions \code{\link{verticalize3}()} and
#' \code{\link{historicalize3}()}. Alternatively, a list of bootstrapped data of
#' class \code{hfv_list}.
#' @param start_age The age from which to start the matrix. Defaults to
#' \code{NA}, age \code{1} is used if \code{prebreeding = TRUE}, and age
#' \code{0} is used if \code{prebreeding = FALSE}.
#' @param last_age The final age to use in the matrix. Defaults to \code{NA}, in
#' which case the highest age in the dataset is used.
#' @param continue A logical value designating whether to allow continued
#' survival of individuals past the final age noted in the stageframe, using the 
#' demographic characteristics of the final age. Defaults to \code{TRUE}.
#' @param fecage_min The minimum age at which reproduction is possible. Defaults
#' to \code{NA}, which is interpreted to mean that fecundity should be assessed
#' starting in the minimum age observed in the dataset.
#' @param fecage_max The maximum age at which reproduction is possible. Defaults
#' to \code{NA}, which is interpreted to mean that fecundity should be assessed
#' until the final observed age.
#' @param alive A vector of names of binomial variables corresponding to status
#' as alive (\code{1}) or dead (\code{0}) in occasions \emph{t}+1 ans \emph{t},
#' respectively.
#' @param repst A vector of names of variables coding reproductive status in
#' occasions \emph{t}+1 and \emph{t}, respectively. Defaults to 
#' \code{c("repstatus3", "repstatus2")}.
#' @param fec A vector of names of variables coding fecundity in occasions
#' \emph{t}+1 and \emph{t}, respectively. Defaults to \code{c("feca3", "feca2")}.
#' @param agecol The name or column number of the variable coding for age in
#' \code{data}. Defaults to \code{"obsage"}.
#' @param year A variable corresponding to observation occasion, or a set
#' of such values, given in values associated with the \code{year} term used in
#' vital rate model development. Can also equal \code{"all"}, in which case
#' matrices will be estimated for all occasion times. Defaults to \code{"all"}.
#' @param supplement An optional data frame of class \code{lefkoSD} that
#' provides supplemental data that should be incorporated into the MPM. Three
#' kinds of data may be integrated this way: transitions to be estimated via the
#' use of proxy transitions, transition overwrites from the literature or
#' supplemental studies, and transition multipliers for survival and fecundity.
#' This data frame should be produced using the \code{\link{supplemental}()}
#' function.
#' @param pop A variable designating which populations will have matrices
#' estimated. Should be set to specific population names, or to \code{"all"} if
#' all populations should have matrices estimated.
#' @param patch A variable designating which patches or subpopulations will have
#' matrices estimated. Should be set to specific patch names, or to \code{"all"}
#' if matrices should be estimated for all patches. Defaults to \code{"all"}.
#' @param yearcol The variable name or column number corresponding to occasion 
#' \emph{t} in the dataset.
#' @param popcol The variable name or column number corresponding to the
#' identity of the population.
#' @param patchcol The variable name or column number corresponding to patch in
#' the dataset.
#' @param indivcol The variable name or column number coding individual
#' identity.
#' @param censor If \code{TRUE}, then data will be removed according to the
#' variable set in \code{censorcol}, such that only data with censor values
#' equal to \code{censorkeep} will remain. Defaults to \code{FALSE}.
#' @param censorcol The variable name or column number denoting the censor
#' status. Only needed if \code{censor = TRUE}.
#' @param censorkeep The value of the censor variable denoting data elements to
#' keep. Defaults to \code{0}.
#' @param fectime An integer indicating whether to estimate fecundity using
#' the variable given for \code{fec} in time \emph{t} (\code{2}) or time
#' \emph{t}+1 (\code{3}).
#' @param fecmod A scalar multiplier for fecundity. Defaults to \code{1.0}.
#' @param prebreeding A logical value indicating whether the life history model
#' is a pre-breeding model. Defaults to \code{TRUE}.
#' @param reduce A logical value denoting whether to remove ages associated with
#' only zero transitions. These are removed only if the respective row and
#' column sums in ALL matrices estimated equal 0. Defaults to \code{FALSE}, and
#' should generally not be used in age-based MPMs.
#' @param simple A logical value indicating whether to produce \code{A},
#' \code{U}, and \code{F} matrices, or only the latter two. Defaults to
#' \code{FALSE}, in which case all three are output.
#' @param err_check A logical value indicating whether to append extra
#' information used in matrix calculation within the output list. Defaults to
#' \code{FALSE}.
#' @param initial_nan A single logical value indicating whether to initialize
#' matrices was all elements set to \code{NaN}. Defaults to \code{FALSE}. Cannot
#' be used with sparse matrices.
#' @param sparse_output A logical value indicating whether to output matrices
#' in sparse format. Defaults to \code{FALSE}, in which case all matrices are
#' output in standard matrix format.
#' 
#' @return If the user inputs a standard \code{hfv_data} object in argument
#' \code{data}, then this function will return an object of class
#' \code{lefkoMat}. If the user inputs an object of class \code{hfv_list} in
#' argument \code{data}, then the output will be an object of class
#' \code{lefkoMatList}, in which each element is an object of class
#' \code{lefkoMat}.
#' 
#' A \code{lefkoMat} object is a list that holds one full  matrix projection
#' model and all of its metadata. The structure has the following elements:
#' 
#' \item{A}{A list of full projection matrices in order of sorted populations,
#' patches, and occasions. All matrices output in the \code{matrix} class, or in
#' the \code{dgCMatrix} class from the \code{Matrix} package if sparse.}
#' \item{U}{A list of survival transition matrices sorted as in \code{A}. All 
#' matrices output in the \code{matrix} class, or in the \code{dgCMatrix} class
#' from the \code{Matrix} package if sparse.}
#' \item{F}{A list of fecundity matrices sorted as in \code{A}. All matrices 
#' output in the \code{matrix} class, or in the \code{dgCMatrix} class from the
#' \code{Matrix} package if sparse.}
#' \item{hstages}{A data frame matrix showing the pairing of ahistorical stages
#' used to create historical stage pairs. Set to NA for ahistorical matrices.}
#' \item{agestages}{A data frame showing age-stage pairs. In this function, it
#' is set to NA. Only used in output to function \code{aflefko2}().}
#' \item{ahstages}{A data frame detailing the characteristics of associated
#' ahistorical stages, in the form of a modified stageframe that includes
#' status as an entry stage through reproduction.}
#' \item{labels}{A data frame giving the population, patch, and year of each 
#' matrix in order.}
#' \item{dataqc}{A vector showing the numbers of individuals and rows in the
#' vertical dataset used as input.}
#' \item{matrixqc}{A short vector describing the number of non-zero elements in
#' \code{U} and \code{F} matrices, and the number of annual matrices.}
#' \item{modelqc}{This is the \code{qc} portion of the \code{modelsuite} input
#' in function-based MPMs. Empty in this function.}
#'
#' @section Notes:
#' In order to accomodate survival to time \emph{t}+1 in the final year of a
#' study, the maximum age assessed if no input \code{last_age} is provided is
#' one time step past the final described age.
#' 
#' Users may at times wish to estimate MPMs using a dataset incorporating
#' multiple patches or subpopulations. Should the aim of analysis be a general
#' MPM that does not distinguish these patches or subpopulations, the
#' \code{patchcol} variable should be left to \code{NA}, which is the default.
#' Otherwise the variable identifying patch needs to be named.
#'
#' Input options including multiple variable names must be entered in the order
#' of variables in occasion \emph{t}+1 and \emph{t}. Rearranging the order WILL
#' lead to erroneous calculations, and may lead to fatal errors.
#' 
#' @seealso \code{\link{mpm_create}()}
#' @seealso \code{\link{flefko3}()}
#' @seealso \code{\link{flefko2}()}
#' @seealso \code{\link{aflefko2}()}
#' @seealso \code{\link{arlefko2}()}
#' @seealso \code{\link{fleslie}()}
#' @seealso \code{\link{rlefko3}()}
#' @seealso \code{\link{rlefko2}()}
#' 
#' @examples
#' data(cypdata)
#' 
#' cypraw_v1 <- verticalize3(data = cypdata, noyears = 6, firstyear = 2004,
#'   patchidcol = "patch", individcol = "plantid", blocksize = 4,
#'   sizeacol = "Inf2.04", sizebcol = "Inf.04", sizeccol = "Veg.04",
#'   repstracol = "Inf.04", repstrbcol = "Inf2.04", fecacol = "Pod.04",
#'   age_offset = 3, NAas0 = TRUE, NRasRep = TRUE)
#' 
#' cyp_rl <- rleslie(data = cypraw_v1, start_age = 0, last_age = 4,
#'   continue = TRUE, fecage_min = 3, year = "all", pop = NA, patch = "all",
#'   yearcol = "year2", patchcol = "patchid", indivcol = "individ")
#' 
#' @export
rleslie <- function(data, start_age = NA, last_age = NA, continue = TRUE,
  fecage_min = NA, fecage_max = NA, alive = c("alive3", "alive2", "alive1"),
  repst = c("repstatus3", "repstatus2", "repstatus1"),
  fec = c("feca3", "feca2", "feca1"), agecol = "obsage", year = "all",
  supplement = NULL, pop = NULL, patch = NULL, yearcol = NULL, popcol = NULL,
  patchcol = NULL, indivcol = NULL, censor = FALSE, censorcol = NULL,
  censorkeep = 0, fectime = 2, fecmod = 1.0, prebreeding = TRUE, reduce = FALSE,
  simple = FALSE, err_check = FALSE, initial_nan = FALSE, sparse_output = FALSE) {

  output <- mpm_create(historical = FALSE, stage = FALSE, age = TRUE,
    devries = FALSE, reduce = reduce, data = data, supplement = supplement,
    year = year, pop = pop, patch = patch, alive = alive, repst = repst,
    fec = fec, yearcol = yearcol, popcol = popcol, patchcol = patchcol,
    indivcol = indivcol, agecol = agecol, censorcol = censorcol,
    censor = censor, censorkeep = censorkeep, start_age = start_age,
    last_age = last_age, fecage_min = fecage_min, fecage_max = fecage_max,
    fectime = fectime, fecmod = fecmod, cont = continue, prebreeding = prebreeding,
    simple = simple, err_check = err_check, initial_nan = initial_nan,
    sparse_output = sparse_output)
  
  return(output)
}

#' Summary of Class "lefkoMat"
#'
#' A function to simplify the viewing of basic information describing the
#' matrices produced through functions \code{\link{flefko3}()},
#' \code{\link{flefko2}()}, \code{\link{rlefko3}()}, \code{\link{rlefko2}()},
#' \code{\link{aflefko2}()}, \code{\link{rleslie}()}, and
#' \code{\link{fleslie}()}.
#' 
#' @name summary.lefkoMat
#' 
#' @param object An object of class \code{lefkoMat}.
#' @param colsums A logical value indicating whether column sums should be shown
#' for U matrices, allowing users to check stage survival probabilities.
#' Defaults to \code{TRUE}.
#' @param check_cycle A logical value indicating whether to test matrices for
#' stage discontinuities in the life cycle. Defaults to \code{TRUE}.
#' @param ... Other parameters.
#' 
#' @return A summary of the object, showing the number of each type of matrix,
#' the number of annual matrices, the number of estimated (non-zero) elements
#' across all matrices and per matrix, the number of unique transitions in the
#' dataset, the number of individuals, and summaries of the column sums of the
#' survival-transition matrices. Stage discontinuities are also checked with
#' function \code{cycle_check}. This function will also yield warnings if any
#' survival-transition matrices include elements outside of the interval [0,1],
#' if any fecundity matrices contain negative elements, and if any matrices
#' include NA values.
#' 
#' @section Notes:
#' Under the Gaussian and gamma size distributions, the number of estimated
#' parameters may differ between the two \code{ipm_method} settings. Because
#' the midpoint method has a tendency to incorporate upward bias in the
#' estimation of size transition probabilities, it is more likely to yield non-
#' zero values when the true probability is extremely close to 0. This will
#' result in the \code{summary.lefkoMat} function yielding higher numbers of
#' estimated parameters than the \code{ipm_method = "CDF"} yields in some cases.
#' 
#' @examples
#' data(cypdata)
#' 
#' sizevector <- c(0, 0, 0, 0, 0, 0, 1, 2.5, 4.5, 8, 17.5)
#' stagevector <- c("SD", "P1", "P2", "P3", "SL", "D", "XSm", "Sm", "Md", "Lg",
#'   "XLg")
#' repvector <- c(0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1)
#' obsvector <- c(0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1)
#' matvector <- c(0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1)
#' immvector <- c(0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0)
#' propvector <- c(1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
#' indataset <- c(0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1)
#' binvec <- c(0, 0, 0, 0, 0, 0.5, 0.5, 1, 1, 2.5, 7)
#' 
#' cypframe_raw <- sf_create(sizes = sizevector, stagenames = stagevector,
#'   repstatus = repvector, obsstatus = obsvector, matstatus = matvector,
#'   propstatus = propvector, immstatus = immvector, indataset = indataset,
#'   binhalfwidth = binvec)
#' 
#' cypraw_v1 <- verticalize3(data = cypdata, noyears = 6, firstyear = 2004,
#'   patchidcol = "patch", individcol = "plantid", blocksize = 4,
#'   sizeacol = "Inf2.04", sizebcol = "Inf.04", sizeccol = "Veg.04",
#'   repstracol = "Inf.04", repstrbcol = "Inf2.04", fecacol = "Pod.04",
#'   stageassign = cypframe_raw, stagesize = "sizeadded", NAas0 = TRUE,
#'   NRasRep = TRUE)
#' 
#' # Here we use supplemental() to provide overwrite and reproductive info
#' cypsupp2r <- supplemental(stage3 = c("SD", "P1", "P2", "P3", "SL", "D", 
#'     "XSm", "Sm", "SD", "P1"),
#'   stage2 = c("SD", "SD", "P1", "P2", "P3", "SL", "SL", "SL", "rep",
#'     "rep"),
#'   eststage3 = c(NA, NA, NA, NA, NA, "D", "XSm", "Sm", NA, NA),
#'   eststage2 = c(NA, NA, NA, NA, NA, "XSm", "XSm", "XSm", NA, NA),
#'   givenrate = c(0.10, 0.20, 0.20, 0.20, 0.25, NA, NA, NA, NA, NA),
#'   multiplier = c(NA, NA, NA, NA, NA, NA, NA, NA, 0.5, 0.5),
#'   type =c(1, 1, 1, 1, 1, 1, 1, 1, 3, 3),
#'   stageframe = cypframe_raw, historical = FALSE)
#' 
#' cypmatrix2r <- rlefko2(data = cypraw_v1, stageframe = cypframe_raw, 
#'   year = "all", patch = "all", stages = c("stage3", "stage2", "stage1"),
#'   size = c("size3added", "size2added"), supplement = cypsupp2r,
#'   yearcol = "year2", patchcol = "patchid", indivcol = "individ")
#' 
#' summary(cypmatrix2r)
#' 
#' @export
summary.lefkoMat <- function(object, colsums = TRUE, check_cycle = TRUE, ...) {
  
  histmark <- "ahistorical"
  
  matrices <- object
  
  matdim <- dim(matrices$A[[1]])[1]
  
  mqca <- matrices$matrixqc[1]
  mqcb <- matrices$matrixqc[2]
  mqcc <- matrices$matrixqc[3]
  
  totalpops <- length(unique(matrices$labels$pop))
  totalpatches <- length(unique(matrices$labels$patch))
  totalyears <- length(unique(matrices$labels$year2))
  
  if (!all(is.na(matrices$hstages))) {
    histmark <- "historical"
  }
  
  if (mqcc == 1) {
    writeLines(paste0("\nThis ", histmark, " lefkoMat object contains ", mqcc,
        " matrix."))
  } else {
    writeLines(paste0("\nThis ", histmark, " lefkoMat object contains ", mqcc,
        " matrices."))
  }
  writeLines(paste0("\nEach matrix is square with ", matdim,
    " rows and columns, and a total of ", matdim*matdim, " elements."))
  
  mqac <- mqca / mqcc
  if (mqac != floor(mqac)) mqac <- round(mqac, digits = 3)
  
  if (!all(is.na(mqac))) {
    mqbc <- mqcb / mqcc
    if (mqbc != floor(mqbc)) mqbc <- round(mqbc, digits = 3)
    
    writeLines(paste0("A total of ", mqca, " survival transitions were estimated, with ", 
        mqac, " per matrix."))
    writeLines(paste0("A total of ", mqcb, " fecundity transitions were estimated, with ", 
        mqbc, " per matrix."))
  } else {
    writeLines(paste0("A total of ", mqca, " transitions were estimated, with ", 
        mqac, " per matrix. Positions of survival vs fecundity transitions are not known."))
  }
  
  grammar_pops <- " populations, "
  grammar_patches <- " patches, and "
  grammar_years <- " time steps."
  if (totalpops == 1) grammar_pops <- " population, "
  if (totalpatches == 1) grammar_patches <- " patch, and "
  if (totalyears == 1) grammar_years <- " time step."
  
  writeLines(paste0("This lefkoMat object covers ", totalpops, grammar_pops,
      totalpatches, grammar_patches, totalyears, grammar_years))
  
  if (is.element("dataqc", names(matrices))) {
    dqca <- matrices$dataqc[1]
    dqcb <- matrices$dataqc[2]
    
    if (!is.na(dqca) & !is.na(dqcb)) {
      writeLines(paste0("\nThe dataset contains a total of ", dqca, " unique individuals and ", dqcb, " unique transitions."))
    } else if (!is.na(dqca)) {
      writeLines(paste0("\nThe dataset contains a total of ", dqca, " unique individuals. Number of unique transitions not known."))
    } else if (!is.na(dqcb)) {
      writeLines(paste0("\nThe dataset contains a total of ", dqcb, " unique transitions. Number of unique individuals not known."))
    } else {
      writeLines("\nThis lefkoMat object appears to have been imported. Number of unique individuals and transitions not known.")
    }
  }
  
  if (is.element("modelqc", names(matrices))) {
    if (is.data.frame(matrices$modelqc) & dim(matrices$modelqc)[1] > 0) {
      moqc12 <- matrices$modelqc[1,2]
      moqc22 <- matrices$modelqc[2,2]
      moqc32 <- matrices$modelqc[3,2]
      moqc42 <- matrices$modelqc[4,2]
      moqc52 <- matrices$modelqc[5,2]
      moqc62 <- matrices$modelqc[6,2]
      moqc72 <- matrices$modelqc[7,2]
      moqc82 <- matrices$modelqc[8,2]
      moqc92 <- matrices$modelqc[9,2]
      moqc102 <- matrices$modelqc[10,2]
      moqc112 <- matrices$modelqc[11,2]
      moqc122 <- matrices$modelqc[12,2]
      moqc132 <- matrices$modelqc[13,2]
      moqc142 <- matrices$modelqc[14,2]
      
      moqc13 <- matrices$modelqc[1,3]
      moqc23 <- matrices$modelqc[2,3]
      moqc33 <- matrices$modelqc[3,3]
      moqc43 <- matrices$modelqc[4,3]
      moqc53 <- matrices$modelqc[5,3]
      moqc63 <- matrices$modelqc[6,3]
      moqc73 <- matrices$modelqc[7,3]
      moqc83 <- matrices$modelqc[8,3]
      moqc93 <- matrices$modelqc[9,3]
      moqc103 <- matrices$modelqc[10,3]
      moqc113 <- matrices$modelqc[11,3]
      moqc123 <- matrices$modelqc[12,3]
      moqc133 <- matrices$modelqc[13,3]
      moqc143 <- matrices$modelqc[14,3]
      
      writeLines("\nVital rate modeling quality control:\n")
      
      if (moqc12 > 0) {
        writeLines(paste0("Survival estimated with ", moqc12, " individuals and ", moqc13, " individual transitions."))
      } else {
        writeLines("Survival not estimated.")
      }
      
      if (moqc22 > 0) {
        writeLines(paste0("Observation estimated with ", moqc22, " individuals and ", moqc23, " individual transitions."))
      } else {
        writeLines("Observation probability not estimated.")
      }
      
      if (moqc32 > 0) {
        writeLines(paste0("Primary size estimated with ", moqc32, " individuals and ", moqc33, " individual transitions."))
      } else {
        writeLines("Primary size transition not estimated.")
      }
      
      if (moqc42 > 0) {
        writeLines(paste0("Secondary size estimated with ", moqc42, " individuals and ", moqc43, " individual transitions."))
      } else {
        writeLines("Secondary size transition not estimated.")
      }
      
      if (moqc52 > 0) {
        writeLines(paste0("Tertiary size estimated with ", moqc52, " individuals and ", moqc53, " individual transitions."))
      } else {
        writeLines("Tertiary size transition not estimated.")
      }
      
      if (moqc62 > 0) {
        writeLines(paste0("Reproductive status estimated with ", moqc62, " individuals and ", moqc63, " individual transitions."))
      } else {
        writeLines("Reproduction probability not estimated.")
      }
      
      if (moqc72 > 0) {
        writeLines(paste0("Fecundity estimated with ", moqc72, " individuals and ", moqc73, " individual transitions."))
      } else {
        writeLines("Fecundity not estimated.")
      }
      
      if (moqc82 > 0) {
        writeLines(paste0("Juvenile survival estimated with ", moqc82, " individuals and ", moqc83, " individual transitions."))
      } else {
        writeLines("Juvenile survival not estimated.")
      }
      
      if (moqc92 > 0) {
        writeLines(paste0("Juvenile observation estimated with ", moqc92, " individuals and ", moqc93, " individual transitions."))
      } else {
        writeLines("Juvenile observation probability not estimated.")
      }
      
      if (moqc102 > 0) {
        writeLines(paste0("Juvenile primary size estimated with ", moqc102, " individuals and ", moqc103, " individual transitions."))
      } else {
        writeLines("Juvenile primary size transition not estimated.")
      }
      
      if (moqc112 > 0) {
        writeLines(paste0("Juvenile secondary size estimated with ", moqc112, " individuals and ", moqc113, " individual transitions."))
      } else {
        writeLines("Juvenile secondary size transition not estimated.")
      }
      
      if (moqc122 > 0) {
        writeLines(paste0("Juvenile tertiary size estimated with ", moqc122, " individuals and ", moqc123, " individual transitions."))
      } else {
        writeLines("Juvenile tertiary size transition not estimated.")
      }
      
      if (moqc132 > 0) {
        writeLines(paste0("Juvenile reproduction estimated with ", moqc132, " individuals and ", moqc133, " individual transitions."))
      } else {
        writeLines("Juvenile reproduction probability not estimated.")
      }
      
      if (moqc142 > 0) {
        writeLines(paste0("Juvenile maturity transition estimated with ", moqc142, " individuals and ", moqc143, " individual transitions."))
      } else {
        writeLines("Juvenile maturity transition probability not estimated.")
      }
    }
  }
  
  dethonthetoilet <- apply(as.matrix(c(1:length(matrices$U))), 1, function(X) {
      if (is(matrices$U[[1]], "dgCMatrix")) {  
        summary(Matrix::colSums(matrices$U[[X]]))
      } else {
        summary(colSums(matrices$U[[X]]))
      }
    }
  )
  
  sexinthelavatory <- apply(as.matrix(c(1:length(matrices$U))), 1, function(X) {
      summary(colSums(matrices$F[[X]]))
    }
  )
  
  dethintheurinal <- apply(as.matrix(c(1:length(matrices$U))), 1, function(X) {
      any(is.na(matrices$A[[X]]))
    }
  )
  
  if (colsums) {
    writeLines("\nSurvival probability sum check (each matrix represented by column in order):")
    print(dethonthetoilet, digits = 3)
  }
  
  if (max(dethonthetoilet) > 1) {
    warning("Some matrices include stages with survival probability greater than 1.0.", call. = FALSE)
  }
  
  if (min(dethonthetoilet) < 0) {
    warning("Some matrices include stages with survival probability less than 0.0.", call. = FALSE)
  }
  
  if (min(sexinthelavatory) < 0) {
    warning("Some matrices include stages with fecundity less than 0.0.", call. = FALSE)
  }
  
  if (any(dethintheurinal)) {
    warning("Some matrices include NA values.", call. = FALSE)
  }
  
  writeLines("\n")
  
  if (check_cycle) invisible(cycle_check(matrices))
}

#' Summary of Class "lefkoMatList"
#'
#' A function to simplify the viewing of basic information describing the
#' bootstrapped matrices produced through functions \code{\link{flefko3}()},
#' \code{\link{flefko2}()}, \code{\link{rlefko3}()}, \code{\link{rlefko2}()},
#' \code{\link{aflefko2}()}, \code{\link{rleslie}()}, and
#' \code{\link{fleslie}()} when using bootstrapped data input in format
#' \code{hfvlist}.
#' 
#' @name summary.lefkoMatList
#' 
#' @param object An object of class \code{lefkoMatList}.
#' @param elem_summaries A logical value indicating whether to include
#' summaries of all \code{lefkoMat} elements within the input
#' \code{lefkoMatList} object. Defaults to \code{FALSE}.
#' @param colsums If \code{elem_summaries = TRUE}, then this is a logical value
#' indicating whether column sums should be shown for U matrices, allowing users
#' to check stage survival probabilities. Defaults to \code{TRUE}.
#' @param check_cycle If \code{elem_summaries = TRUE}, then this is a logical
#' value indicating whether to test matrices for stage discontinuities in the
#' life cycle. Defaults to \code{TRUE}.
#' @param ... Other parameters.
#' 
#' @return A general summary of the \code{lefkoMatList} object, showing the
#' number and type of \code{lefkoMat} objects included, the mean number of
#' annual matrices per \code{lefkoMat} element, the mean size of each matrix,
#' the mean number of estimated (non-zero) elements across all matrices and per
#' matrix, the mean number of unique transitions in the bootstrapped datasets,
#' the mean number of individuals, and summaries of the column sums of the survival-transition
#' matrices across all \code{lefkoMat} objects.
#' 
#' if \code{elem_summaries = TRUE}, then \code{\link{summary.lefkoMat}{}} output
#' is also shown for each \code{lefkoMat} object per entered \code{lefkoMatList}
#' object.
#' 
#' Stage discontinuities may also be also checked across all \code{lefkoMat}
#' objects with function \code{cycle_check}. This function will also yield
#' warnings if any survival-transition matrices include elements outside of the
#' interval [0,1], if any fecundity matrices contain negative elements, and if
#' any matrices include NA values.
#' 
#' @section Notes:
#' Under the Gaussian and gamma size distributions, the number of estimated
#' parameters may differ between the two \code{ipm_method} settings. Because
#' the midpoint method has a tendency to incorporate upward bias in the
#' estimation of size transition probabilities, it is more likely to yield non-
#' zero values when the true probability is extremely close to 0. This will
#' result in the \code{summary.lefkoMat} function yielding higher numbers of
#' estimated parameters than the \code{ipm_method = "CDF"} yields in some cases.
#' 
#' @examples
#' data(cypdata)
#' 
#' sizevector <- c(0, 0, 0, 0, 0, 0, 1, 2.5, 4.5, 8, 17.5)
#' stagevector <- c("SD", "P1", "P2", "P3", "SL", "D", "XSm", "Sm", "Md", "Lg",
#'   "XLg")
#' repvector <- c(0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1)
#' obsvector <- c(0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1)
#' matvector <- c(0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1)
#' immvector <- c(0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0)
#' propvector <- c(1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
#' indataset <- c(0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1)
#' binvec <- c(0, 0, 0, 0, 0, 0.5, 0.5, 1, 1, 2.5, 7)
#' 
#' cypframe_raw <- sf_create(sizes = sizevector, stagenames = stagevector,
#'   repstatus = repvector, obsstatus = obsvector, matstatus = matvector,
#'   propstatus = propvector, immstatus = immvector, indataset = indataset,
#'   binhalfwidth = binvec)
#' 
#' cypraw_v1 <- verticalize3(data = cypdata, noyears = 6, firstyear = 2004,
#'   patchidcol = "patch", individcol = "plantid", blocksize = 4,
#'   sizeacol = "Inf2.04", sizebcol = "Inf.04", sizeccol = "Veg.04",
#'   repstracol = "Inf.04", repstrbcol = "Inf2.04", fecacol = "Pod.04",
#'   stageassign = cypframe_raw, stagesize = "sizeadded", NAas0 = TRUE,
#'   NRasRep = TRUE)
#' 
#' cypraw_v1_boot <- bootstrap3(cypraw_v1, reps = 3)
#' 
#' # Here we use supplemental() to provide overwrite and reproductive info
#' cypsupp2r <- supplemental(stage3 = c("SD", "P1", "P2", "P3", "SL", "D", 
#'     "XSm", "Sm", "SD", "P1"),
#'   stage2 = c("SD", "SD", "P1", "P2", "P3", "SL", "SL", "SL", "rep",
#'     "rep"),
#'   eststage3 = c(NA, NA, NA, NA, NA, "D", "XSm", "Sm", NA, NA),
#'   eststage2 = c(NA, NA, NA, NA, NA, "XSm", "XSm", "XSm", NA, NA),
#'   givenrate = c(0.10, 0.20, 0.20, 0.20, 0.25, NA, NA, NA, NA, NA),
#'   multiplier = c(NA, NA, NA, NA, NA, NA, NA, NA, 0.5, 0.5),
#'   type =c(1, 1, 1, 1, 1, 1, 1, 1, 3, 3),
#'   stageframe = cypframe_raw, historical = FALSE)
#' 
#' cypmatrix2r_boot <- rlefko2(data = cypraw_v1_boot, stageframe = cypframe_raw, 
#'   year = "all", patch = "all", stages = c("stage3", "stage2", "stage1"),
#'   size = c("size3added", "size2added"), supplement = cypsupp2r,
#'   yearcol = "year2", patchcol = "patchid", indivcol = "individ")
#' 
#' summary(cypmatrix2r_boot)
#' 
#' @export
summary.lefkoMatList <- function(object, elem_summaries = FALSE, colsums = TRUE,
  check_cycle = TRUE, ...) {
  
  histmark <- "ahistorical"
  dataqc_bool <- FALSE
  modelqc_bool <- FALSE
  
  lmatlist <- object
  lmatlist_length <- length(lmatlist)
  
  if (!all(is.na(lmatlist[[1]]$hstages))) {
    histmark <- "historical"
  }
  if (is.element("dataqc", names(lmatlist[[1]]))) dataqc_bool <- TRUE
  
  if (is.element("modelqc", names(lmatlist[[1]]))) {
    if (is.data.frame(lmatlist[[1]]$modelqc) & dim(lmatlist[[1]]$modelqc)[1] > 0) {
      modelqc_bool <- TRUE
    }
  }
  
  writeLines(paste0("\nThis lefkoMatList object contains ", lmatlist_length, " ",
    histmark, " lefkoMat objects."))
  
  nummats <- rep(1.0, lmatlist_length)
  numpops <- rep(1.0, lmatlist_length)
  numpatches <- rep(1.0, lmatlist_length)
  numyears <- rep(1.0, lmatlist_length)
  
  mqac_vec <- rep(1.0, lmatlist_length)
  mqbc_vec <- rep(1.0, lmatlist_length)
  mqca_vec <- rep(1.0, lmatlist_length)
  mqcb_vec <- rep(1.0, lmatlist_length)
  dqca_vec <- rep(NA, lmatlist_length)
  dqcb_vec <- rep(NA, lmatlist_length)
  
  moqc12_vec <- rep(NA, lmatlist_length)
  moqc22_vec <- rep(NA, lmatlist_length)
  moqc32_vec <- rep(NA, lmatlist_length)
  moqc42_vec <- rep(NA, lmatlist_length)
  moqc52_vec <- rep(NA, lmatlist_length)
  moqc62_vec <- rep(NA, lmatlist_length)
  moqc72_vec <- rep(NA, lmatlist_length)
  moqc82_vec <- rep(NA, lmatlist_length)
  moqc92_vec <- rep(NA, lmatlist_length)
  moqc102_vec <- rep(NA, lmatlist_length)
  moqc112_vec <- rep(NA, lmatlist_length)
  moqc122_vec <- rep(NA, lmatlist_length)
  moqc132_vec <- rep(NA, lmatlist_length)
  moqc142_vec <- rep(NA, lmatlist_length)
  
  moqc13_vec <- rep(NA, lmatlist_length)
  moqc23_vec <- rep(NA, lmatlist_length)
  moqc33_vec <- rep(NA, lmatlist_length)
  moqc43_vec <- rep(NA, lmatlist_length)
  moqc53_vec <- rep(NA, lmatlist_length)
  moqc63_vec <- rep(NA, lmatlist_length)
  moqc73_vec <- rep(NA, lmatlist_length)
  moqc83_vec <- rep(NA, lmatlist_length)
  moqc93_vec <- rep(NA, lmatlist_length)
  moqc103_vec <- rep(NA, lmatlist_length)
  moqc113_vec <- rep(NA, lmatlist_length)
  moqc123_vec <- rep(NA, lmatlist_length)
  moqc133_vec <- rep(NA, lmatlist_length)
  moqc143_vec <- rep(NA, lmatlist_length)
  
  for (i in c(1:lmatlist_length)) {
    matrices <- object[[i]]
    matdim <- dim(matrices$A[[1]])[1]
  
    mqca <- matrices$matrixqc[1]
    mqcb <- matrices$matrixqc[2]
    mqcc <- matrices$matrixqc[3]
    
    mqac <- mqca / mqcc
    if (mqac != floor(mqac)) mqac <- round(mqac, digits = 3)
    
    mqbc <- mqcb / mqcc
    if (mqbc != floor(mqbc)) mqbc <- round(mqbc, digits = 3)
    
    totalpops <- length(unique(matrices$labels$pop))
    totalpatches <- length(unique(matrices$labels$patch))
    totalyears <- length(unique(matrices$labels$year2))
    
    nummats[i] <- mqcc
    numpops[i] <- totalpops
    numpatches[i] <- totalpatches
    numyears[i] <- totalyears
    
    mqac_vec[i] <- mqac
    mqbc_vec[i] <- mqbc
    mqca_vec[i] <- mqca
    mqcb_vec[i] <- mqcb
    
    if (dataqc_bool) {
      dqca <- matrices$dataqc[1]
      dqcb <- matrices$dataqc[2]
      
      dqca_vec[i] <- dqca
      dqcb_vec[i] <- dqcb
    }
    
    if (modelqc_bool) {
      moqc12 <- matrices$modelqc[1,2]
      moqc22 <- matrices$modelqc[2,2]
      moqc32 <- matrices$modelqc[3,2]
      moqc42 <- matrices$modelqc[4,2]
      moqc52 <- matrices$modelqc[5,2]
      moqc62 <- matrices$modelqc[6,2]
      moqc72 <- matrices$modelqc[7,2]
      moqc82 <- matrices$modelqc[8,2]
      moqc92 <- matrices$modelqc[9,2]
      moqc102 <- matrices$modelqc[10,2]
      moqc112 <- matrices$modelqc[11,2]
      moqc122 <- matrices$modelqc[12,2]
      moqc132 <- matrices$modelqc[13,2]
      moqc142 <- matrices$modelqc[14,2]
      
      moqc13 <- matrices$modelqc[1,3]
      moqc23 <- matrices$modelqc[2,3]
      moqc33 <- matrices$modelqc[3,3]
      moqc43 <- matrices$modelqc[4,3]
      moqc53 <- matrices$modelqc[5,3]
      moqc63 <- matrices$modelqc[6,3]
      moqc73 <- matrices$modelqc[7,3]
      moqc83 <- matrices$modelqc[8,3]
      moqc93 <- matrices$modelqc[9,3]
      moqc103 <- matrices$modelqc[10,3]
      moqc113 <- matrices$modelqc[11,3]
      moqc123 <- matrices$modelqc[12,3]
      moqc133 <- matrices$modelqc[13,3]
      moqc143 <- matrices$modelqc[14,3]
      
      moqc12_vec[i] <- moqc12
      moqc22_vec[i] <- moqc22
      moqc32_vec[i] <- moqc32
      moqc42_vec[i] <- moqc42
      moqc52_vec[i] <- moqc52
      moqc62_vec[i] <- moqc62
      moqc72_vec[i] <- moqc72
      moqc82_vec[i] <- moqc82
      moqc92_vec[i] <- moqc92
      moqc102_vec[i] <- moqc102
      moqc112_vec[i] <- moqc112
      moqc122_vec[i] <- moqc122
      moqc132_vec[i] <- moqc132
      moqc142_vec[i] <- moqc142
      
      moqc13_vec[i] <- moqc13
      moqc23_vec[i] <- moqc23
      moqc33_vec[i] <- moqc33
      moqc43_vec[i] <- moqc43
      moqc53_vec[i] <- moqc53
      moqc63_vec[i] <- moqc63
      moqc73_vec[i] <- moqc73
      moqc83_vec[i] <- moqc83
      moqc93_vec[i] <- moqc93
      moqc103_vec[i] <- moqc103
      moqc113_vec[i] <- moqc113
      moqc123_vec[i] <- moqc123
      moqc133_vec[i] <- moqc133
      moqc143_vec[i] <- moqc143
    }
  }
  
  ave_num_mats <- mean(nummats)
  ave_pops <- mean(numpops)
  ave_patches <- mean(numpatches)
  ave_years <- mean(numyears)
  
  if (ave_num_mats != floor(ave_num_mats)) ave_num_mats <- round(ave_num_mats, digits = 3)
  if (ave_pops != floor(ave_pops)) ave_pops <- round(ave_pops, digits = 3)
  if (ave_patches != floor(ave_patches)) ave_patches <- round(ave_patches, digits = 3)
  if (ave_years != floor(ave_years)) ave_years <- round(ave_years, digits = 3)
  
  if (ave_num_mats == 1) {
    writeLines(paste0("The average lefkoMat object contains ", mqcc, " matrix."))
  } else {
    writeLines(paste0("The average lefkoMat object contains ", mqcc, " matrices."))
  }
  
  grammar_pops <- " populations, "
  grammar_patches <- " patches, and "
  grammar_years <- " time steps."
  if (ave_pops == 1) grammar_pops <- " population, "
  if (ave_patches == 1) grammar_patches <- " patch, and "
  if (ave_years == 1) grammar_years <- " time step."
  
  writeLines(paste0("\nThis lefkoMatList object covers an average of ", ave_pops,
    grammar_pops, ave_patches, grammar_patches, ave_years, grammar_years))
  
  writeLines(paste0("Each matrix is square with ", matdim,
    " rows and columns, and a total of ", matdim*matdim, " elements."))
  
  if (!all(is.na(mqca_vec)) & !all(is.na(mqac_vec))) {
    mqac_mean <- mean(mqac_vec, na.rm = TRUE)
    mqbc_mean <- mean(mqbc_vec, na.rm = TRUE)
    mqca_mean <- mean(mqca_vec, na.rm = TRUE)
    mqcb_mean <- mean(mqcb_vec, na.rm = TRUE)
    
    
    if (mqac_mean != floor(mqac_mean)) mqac_mean <- round(mqac_mean, digits = 3)
    if (mqbc_mean != floor(mqac_mean)) mqbc_mean <- round(mqbc_mean, digits = 3)
    if (mqca_mean != floor(mqca_mean)) mqca_mean <- round(mqca_mean, digits = 3)
    if (mqcb_mean != floor(mqcb_mean)) mqcb_mean <- round(mqcb_mean, digits = 3)
    
    writeLines(paste0("An average of ", mqca_mean, " survival transitions were ",
      "estimated in each lefkoMat object,"))
    writeLines(paste0("with an average of ", mqac_mean, " per matrix."))
    writeLines(paste0("An average of ", mqcb_mean, " fecundity transitions were ",
      "estimated in each lefkoMat object,"))
    writeLines(paste0("with an average of ", mqbc_mean, " per matrix."))
  } else {
    mqac_mean <- mean(mqac_vec, na.rm = TRUE)
    mqca_mean <- mean(mqca_vec, na.rm = TRUE)
    
    writeLines(paste0("An average of ", mqca_mean, " transitions were estimated",
      "in each lefkoMat object,"))
    writeLines(paste0("with an average of ", mqac_mean, " per matrix. Positions of ",
      "survival vs fecundity transitions are not known."))
  }
  
  if (dataqc_bool) {
    dqca_mean <- mean(dqca_vec, na.rm = TRUE)
    dqcb_mean <- mean(dqcb_vec, na.rm = TRUE)
    
    if (dqca_mean != floor(dqca_mean)) dqca_mean <- round(dqca_mean, digits = 3)
    if (dqcb_mean != floor(dqcb_mean)) dqcb_mean <- round(dqcb_mean, digits = 3)
    
    if (!is.na(dqca_vec[1]) & !is.na(dqcb_vec[1])) {
      writeLines(paste0("\nThe datasets contain an average total of ", dqca_mean,
        " unique individuals and ", dqcb_mean, " unique transitions."))
    } else if (!is.na(dqca_vec[1])) {
      writeLines(paste0("\nThe datasets contain an average of ", dqca_mean, " unique individuals."))
      writeLines("Average number of unique transitions not known.")
    } else if (!is.na(dqcb_vec[1])) {
      writeLines(paste0("\nThe datasets contain an average of ", dqcb_mean, " unique transitions."))
      writeLines("Average number of unique individuals not known.")
    } else {
      writeLines("\nThese lefkoMatList objects appear to have been imported.")
      writeLines("Average number of unique individuals and transitions not known.")
    }
  }
  
  if (modelqc_bool) {
    writeLines("\nVital rate modeling quality control:\n")
    
    moqc12_mean <- mean(moqc12_vec, na.rm = TRUE)
    moqc22_mean <- mean(moqc22_vec, na.rm = TRUE)
    moqc32_mean <- mean(moqc32_vec, na.rm = TRUE)
    moqc42_mean <- mean(moqc42_vec, na.rm = TRUE)
    moqc52_mean <- mean(moqc52_vec, na.rm = TRUE)
    moqc62_mean <- mean(moqc62_vec, na.rm = TRUE)
    moqc72_mean <- mean(moqc72_vec, na.rm = TRUE)
    moqc82_mean <- mean(moqc82_vec, na.rm = TRUE)
    moqc92_mean <- mean(moqc92_vec, na.rm = TRUE)
    moqc102_mean <- mean(moqc102_vec, na.rm = TRUE)
    moqc112_mean <- mean(moqc112_vec, na.rm = TRUE)
    moqc122_mean <- mean(moqc122_vec, na.rm = TRUE)
    moqc132_mean <- mean(moqc132_vec, na.rm = TRUE)
    moqc142_mean <- mean(moqc142_vec, na.rm = TRUE)
    
    moqc13_mean <- mean(moqc13_vec, na.rm = TRUE)
    moqc23_mean <- mean(moqc23_vec, na.rm = TRUE)
    moqc33_mean <- mean(moqc33_vec, na.rm = TRUE)
    moqc43_mean <- mean(moqc43_vec, na.rm = TRUE)
    moqc53_mean <- mean(moqc53_vec, na.rm = TRUE)
    moqc63_mean <- mean(moqc63_vec, na.rm = TRUE)
    moqc73_mean <- mean(moqc73_vec, na.rm = TRUE)
    moqc83_mean <- mean(moqc83_vec, na.rm = TRUE)
    moqc93_mean <- mean(moqc93_vec, na.rm = TRUE)
    moqc103_mean <- mean(moqc103_vec, na.rm = TRUE)
    moqc113_mean <- mean(moqc113_vec, na.rm = TRUE)
    moqc123_mean <- mean(moqc123_vec, na.rm = TRUE)
    moqc133_mean <- mean(moqc133_vec, na.rm = TRUE)
    moqc143_mean <- mean(moqc143_vec, na.rm = TRUE)
    
    if (moqc12_mean != floor(moqc12_mean)) moqc12_mean <- round(moqc12_mean, digits = 3)
    if (moqc22_mean != floor(moqc22_mean)) moqc22_mean <- round(moqc22_mean, digits = 3)
    if (moqc32_mean != floor(moqc32_mean)) moqc32_mean <- round(moqc32_mean, digits = 3)
    if (moqc42_mean != floor(moqc42_mean)) moqc42_mean <- round(moqc42_mean, digits = 3)
    if (moqc52_mean != floor(moqc52_mean)) moqc52_mean <- round(moqc52_mean, digits = 3)
    if (moqc62_mean != floor(moqc62_mean)) moqc62_mean <- round(moqc62_mean, digits = 3)
    if (moqc72_mean != floor(moqc72_mean)) moqc72_mean <- round(moqc72_mean, digits = 3)
    if (moqc82_mean != floor(moqc82_mean)) moqc82_mean <- round(moqc82_mean, digits = 3)
    if (moqc92_mean != floor(moqc92_mean)) moqc92_mean <- round(moqc92_mean, digits = 3)
    if (moqc102_mean != floor(moqc102_mean)) moqc102_mean <- round(moqc102_mean, digits = 3)
    if (moqc112_mean != floor(moqc112_mean)) moqc112_mean <- round(moqc112_mean, digits = 3)
    if (moqc122_mean != floor(moqc122_mean)) moqc122_mean <- round(moqc122_mean, digits = 3)
    if (moqc132_mean != floor(moqc132_mean)) moqc132_mean <- round(moqc132_mean, digits = 3)
    if (moqc142_mean != floor(moqc142_mean)) moqc142_mean <- round(moqc142_mean, digits = 3)
    
    if (moqc13_mean != floor(moqc13_mean)) moqc13_mean <- round(moqc13_mean, digits = 3)
    if (moqc23_mean != floor(moqc23_mean)) moqc23_mean <- round(moqc23_mean, digits = 3)
    if (moqc33_mean != floor(moqc33_mean)) moqc33_mean <- round(moqc33_mean, digits = 3)
    if (moqc43_mean != floor(moqc43_mean)) moqc43_mean <- round(moqc43_mean, digits = 3)
    if (moqc53_mean != floor(moqc53_mean)) moqc53_mean <- round(moqc53_mean, digits = 3)
    if (moqc63_mean != floor(moqc63_mean)) moqc63_mean <- round(moqc63_mean, digits = 3)
    if (moqc73_mean != floor(moqc73_mean)) moqc73_mean <- round(moqc73_mean, digits = 3)
    if (moqc83_mean != floor(moqc83_mean)) moqc83_mean <- round(moqc83_mean, digits = 3)
    if (moqc93_mean != floor(moqc93_mean)) moqc93_mean <- round(moqc93_mean, digits = 3)
    if (moqc103_mean != floor(moqc103_mean)) moqc103_mean <- round(moqc103_mean, digits = 3)
    if (moqc113_mean != floor(moqc113_mean)) moqc113_mean <- round(moqc113_mean, digits = 3)
    if (moqc123_mean != floor(moqc123_mean)) moqc123_mean <- round(moqc123_mean, digits = 3)
    if (moqc133_mean != floor(moqc133_mean)) moqc133_mean <- round(moqc133_mean, digits = 3)
    if (moqc143_mean != floor(moqc143_mean)) moqc143_mean <- round(moqc143_mean, digits = 3)
    
    if (!is.na(moqc12_vec[1])) {
      if (moqc12_mean > 0) {
        writeLines(paste0("Survival estimated with an average of ", moqc12_mean,
          " individuals and ", moqc13_mean, " individual transitions."))
      } else {
        writeLines("Survival not estimated.")
      }
    }
    if (!is.na(moqc22_vec[1])) {
      if (moqc22_mean > 0) {
        writeLines(paste0("Observation estimated with an average of ", moqc22_mean,
          " individuals and ", moqc23_mean, " individual transitions."))
      } else {
        writeLines("Observation probability not estimated.")
      }
    }
    if (!is.na(moqc32_vec[1])) {
      if (moqc32_mean > 0) {
        writeLines(paste0("Primary size estimated with an average of ", moqc32_mean,
          " individuals and ", moqc33_mean, " individual transitions."))
      } else {
        writeLines("Primary size transition not estimated.")
      }
    }
    if (!is.na(moqc42_vec[1])) {
      if (moqc42_mean > 0) {
        writeLines(paste0("Secondary size estimated with an average of ", moqc42_mean,
          " individuals and ", moqc43_mean, " individual transitions."))
      } else {
        writeLines("Secondary size transition not estimated.")
      }
    }
    if (!is.na(moqc52_vec[1])) {
      if (moqc52_mean > 0) {
        writeLines(paste0("Tertiary size estimated with an average of ", moqc52_mean,
          " individuals and ", moqc53_mean, " individual transitions."))
      } else {
        writeLines("Tertiary size transition not estimated.")
      }
    }
    if (!is.na(moqc62_vec[1])) {
      if (moqc62_mean > 0) {
        writeLines(paste0("Reproductive status estimated with an average of ",
          moqc62_mean, " individuals and ", moqc63_mean, " individual transitions."))
      } else {
        writeLines("Reproduction probability not estimated.")
      }
    }
    if (!is.na(moqc72_vec[1])) {
      if (moqc72_mean > 0) {
        writeLines(paste0("Fecundity estimated with an average of ", moqc72_mean,
          " individuals and ", moqc73_mean, " individual transitions."))
      } else {
        writeLines("Fecundity not estimated.")
      }
    }
    if (!is.na(moqc82_vec[1])) {
      if (moqc82_mean > 0) {
        writeLines(paste0("Juvenile survival estimated with an average of ", moqc82_mean,
          " individuals and ", moqc83_mean, " individual transitions."))
      } else {
        writeLines("Juvenile survival not estimated.")
      }
    }
    if (!is.na(moqc92_vec[1])) {
      if (moqc92_mean > 0) {
        writeLines(paste0("Juvenile observation estimated with an average of ", moqc92_mean,
          " individuals and ", moqc93_mean, " individual transitions."))
      } else {
        writeLines("Juvenile observation probability not estimated.")
      }
    }
    if (!is.na(moqc102_vec[1])) {
      if (moqc102_mean > 0) {
        writeLines(paste0("Juvenile primary size estimated with an average of ", moqc102_mean,
          " individuals and ", moqc103_mean, " individual transitions."))
      } else {
        writeLines("Juvenile primary size transition not estimated.")
      }
    }
    if (!is.na(moqc112_vec[1])) {
      if (moqc112_mean > 0) {
        writeLines(paste0("Juvenile secondary size estimated with an average of ", moqc112_mean,
          " individuals and ", moqc113_mean, " individual transitions."))
      } else {
        writeLines("Juvenile secondary size transition not estimated.")
      }
    }
    if (!is.na(moqc122_vec[1])) {
      if (moqc122_mean > 0) {
        writeLines(paste0("Juvenile tertiary size estimated with an average of ", moqc122_mean,
          " individuals and ", moqc123_mean, " individual transitions."))
      } else {
        writeLines("Juvenile tertiary size transition not estimated.")
      }
    }
    if (!is.na(moqc132_vec[1])) {
      if (moqc132_mean > 0) {
        writeLines(paste0("Juvenile reproduction estimated with an average of ", moqc132_mean,
          " individuals and ", moqc133_mean, " individual transitions."))
      } else {
        writeLines("Juvenile reproduction probability not estimated.")
      }
    }
    if (!is.na(moqc142_vec[1])) {
      if (moqc142_mean > 0) {
        writeLines(paste0("Juvenile maturity transition estimated with an average of ", moqc142_mean,
          " individuals and ", moqc143_mean, " individual transitions."))
      } else {
        writeLines("Juvenile maturity transition probability not estimated.")
      }
    }
  }
  
  writeLines("\n")
  
  if (elem_summaries[1] == TRUE) {
    for (i in c(1:lmatlist_length)) {
      writeLines(paste0("\nSUMMARY OF ELEMENT ", i))
      summary(object[[i]])
    }
  }
}

