diff --git a/DESCRIPTION b/DESCRIPTION index d0dc0a50f..368c97924 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -10,14 +10,18 @@ Authors@R: c( ), person( given = "Martin", family = "Brazeau", - role = c("cph"), - comment = c(ORCID = "0000-0002-0650-1282", "Morphy library") + role = c("ctb"), + comment = c(ORCID = "0000-0002-0650-1282", + "Brazeau-Guillerme-Smith inapplicable-data algorithm") + ), + person( + given = "Thomas", family = "Guillerme", + role = c("ctb"), + comment = c(ORCID = "0000-0003-4325-1275", + "Brazeau-Guillerme-Smith inapplicable-data algorithm") ) ) License: GPL (>= 3) -Copyright: Incorporates C/C++ code from - Morphy Phylogenetic Library by Martin Brazeau - (GPL3) Description: Reconstruct phylogenetic trees from discrete data using a high-performance C++ search engine with multi-replicate driven search. Supports equal weights, implied weights (Goloboff, 1993) @@ -127,8 +131,8 @@ Collate: 'data_manipulation.R' 'fractional-weights.R' 'length_range.R' - 'mpl_morphy_objects.R' - 'mpl_morphyex.R' + 'PrepareData.R' + 'morphy-deprecated.R' 'pp_info_extra_step.r' 'tree_length.R' 'tree_rearrangement.R' @@ -144,3 +148,4 @@ Encoding: UTF-8 Language: en-GB VignetteBuilder: knitr Roxygen: list(markdown = TRUE) +RoxygenNote: 7.3.3 diff --git a/NAMESPACE b/NAMESPACE index 73d477b1f..560c2a702 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -21,11 +21,10 @@ S3method(TreeLength,phylo) S3method(print,CharacterHierarchy) S3method(print,ScoreSpectrum) S3method(print,SearchControl) -S3method(summary,morphyPtr) export(.NonDuplicateRoot) export(.UniqueExceptHits) export(AdditionTree) -export(C_MorphyLength) +export(BootstrapTree) export(Carter1) export(CharacterHierarchy) export(CharacterLength) @@ -38,14 +37,13 @@ export(Consistency) export(DoNothing) export(EasyTrees) export(EasyTreesy) +export(EdgeListScore) export(EdgeListSearch) export(EmptyPhyDat) export(Evaluate) export(ExpectedLength) export(Fitch) export(FitchSteps) -export(GapHandler) -export(GetMorphyLength) export(IWScore) export(IWTreeSearch) export(JackLabels) @@ -61,12 +59,9 @@ export(MaximizeParsimony) export(MaximizeParsimony2) export(MaximumLength) export(MinimumLength) -export(Morphy) export(MorphyBootstrap) -export(MorphyErrorCheck) export(MorphyLength) export(MorphyTreeLength) -export(MorphyWeights) export(MostContradictedFreq) export(MultiRatchet) export(MutualClusteringConcordance) @@ -78,6 +73,7 @@ export(PhyDat2Morphy) export(PhylogeneticConcordance) export(PlotCharacter) export(PolEscapa) +export(PrepareData) export(PrepareDataIW) export(PrepareDataProfile) export(PresCont) @@ -87,10 +83,12 @@ export(QCol) export(QuartetConcordance) export(QuartetResolution) export(RandomMorphyTree) +export(RandomPostorderTree) export(RandomTreeScore) export(Ratchet) export(RatchetConsensus) export(RearrangeEdges) +export(ReleaseData) export(Resample) export(RootedNNI) export(RootedNNISwap) @@ -104,8 +102,8 @@ export(SPRSwap) export(SPRWarning) export(ScoreSpectrum) export(SearchControl) -export(SetMorphyWeights) export(SharedPhylogeneticConcordance) +export(SingleCharData) export(SingleCharMorphy) export(StepInformation) export(StopUnlessBifurcating) @@ -118,6 +116,7 @@ export(TBRSwap) export(TBRWarning) export(TaxonInfluence) export(TreeLength) +export(TreeScore) export(TreeSearch) export(UnloadMorphy) export(WhenFirstHit) @@ -130,31 +129,9 @@ export(hierarchy_chars) export(hierarchy_controlling) export(hierarchy_from_names) export(hierarchy_to_blocks) +export(is.ParsimonyData) export(is.morphyPtr) export(mc_fitch_scores) -export(mpl_apply_tipdata) -export(mpl_attach_rawdata) -export(mpl_attach_symbols) -export(mpl_delete_Morphy) -export(mpl_first_down_recon) -export(mpl_first_up_recon) -export(mpl_get_charac_weight) -export(mpl_get_gaphandl) -export(mpl_get_num_charac) -export(mpl_get_num_internal_nodes) -export(mpl_get_numtaxa) -export(mpl_get_symbols) -export(mpl_init_Morphy) -export(mpl_new_Morphy) -export(mpl_second_down_recon) -export(mpl_second_up_recon) -export(mpl_set_charac_weight) -export(mpl_set_gaphandl) -export(mpl_set_num_internal_nodes) -export(mpl_set_parsim_t) -export(mpl_translate_error) -export(mpl_update_lower_root) -export(mpl_update_tip) export(non_hierarchy_weights) export(recode_hierarchy) export(validate_hierarchy) @@ -167,19 +144,14 @@ importFrom(TreeDist,Entropy) importFrom(TreeDist,MutualClusteringInfo) importFrom(TreeDist,SharedPhylogeneticInfo) importFrom(TreeDist,entropy_int) -importFrom(TreeTools,AddUnconstrained) -importFrom(TreeTools,CharacterInformation) importFrom(TreeTools,CladeSizes) importFrom(TreeTools,CladisticInfo) importFrom(TreeTools,CompatibleSplits) importFrom(TreeTools,Consensus) -importFrom(TreeTools,ConstrainedNJ) importFrom(TreeTools,DescendantEdges) importFrom(TreeTools,DescendantTips) importFrom(TreeTools,DoubleFactorial) -importFrom(TreeTools,DropTip) importFrom(TreeTools,EdgeAncestry) -importFrom(TreeTools,ImposeConstraint) importFrom(TreeTools,KeepTip) importFrom(TreeTools,LnUnrooted) importFrom(TreeTools,Log2DoubleFactorial) @@ -198,7 +170,6 @@ importFrom(TreeTools,NexusTokens) importFrom(TreeTools,PaintTree) importFrom(TreeTools,PectinateTree) importFrom(TreeTools,PhyDatToMatrix) -importFrom(TreeTools,PhyToString) importFrom(TreeTools,PolarizeSplits) importFrom(TreeTools,Postorder) importFrom(TreeTools,PostorderOrder) @@ -229,13 +200,11 @@ importFrom(ape,read.nexus) importFrom(ape,root) importFrom(ape,write.nexus) importFrom(cli,cli_alert) -importFrom(cli,cli_alert_danger) importFrom(cli,cli_alert_info) importFrom(cli,cli_alert_success) importFrom(cli,cli_alert_warning) importFrom(cli,cli_h1) importFrom(cli,cli_progress_bar) -importFrom(cli,cli_progress_done) importFrom(cli,cli_progress_update) importFrom(colorspace,hex) importFrom(colorspace,max_chroma) @@ -254,7 +223,6 @@ importFrom(stats,cophenetic) importFrom(stats,cutree) importFrom(stats,dnorm) importFrom(stats,median) -importFrom(stats,runif) importFrom(stats,sd) importFrom(stats,setNames) importFrom(stats,weighted.mean) diff --git a/NEWS.md b/NEWS.md index faff9b537..bef09aa1e 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,5 +1,39 @@ # To integrate into 2.0.0 notes +- **MorphyLib removed.** The vendored Morphy Phylogenetic Library (C/C++) has + been dropped; all parsimony scoring now runs through the native C++ kernel, + which implements the Brazeau, Guillerme & Smith (2019) inapplicable-state + algorithm correctly — including ambiguous-with-inapplicable tokens such as + `{1-}`, which MorphyLib mis-scored. + +- **`concavity` argument for `TreeSearch()`, `Ratchet()` and `Jackknife()`.** + Implied-weights and profile searches with the custom-search functions no + longer need a hand-written scorer: pass `concavity = k` (a finite constant) + for implied weights, `concavity = "profile"` for profile parsimony, or the + default `Inf` for equal weights. (Adapted from the parallel T-200 work, + PR #216.) + +- **Custom-search scoring layer renamed** to drop the now-meaningless "Morphy" + branding. `PhyDat2Morphy()` → `PrepareData()`; `UnloadMorphy()` → + `ReleaseData()`; `is.morphyPtr()` → `is.ParsimonyData()`; `SingleCharMorphy()` + → `SingleCharData()`; `MorphyLength()` → `EdgeListScore()`; + `MorphyTreeLength()` → `TreeScore()`; `MorphyBootstrap()` → `BootstrapTree()`; + `RandomMorphyTree()` → `RandomPostorderTree()`. The old names remain as + deprecated aliases and will be removed in a future release. `PrepareData()` + returns a lightweight, garbage-collected `ParsimonyData` object; only the + default `"inapplicable"` gap treatment is supported (recode data for the + missing/extra-state treatments). + +- `Jackknife()` and `BootstrapTree()` (formerly `MorphyBootstrap()`) now + resample characters natively, scoring the resampled weights through the + native kernel rather than by mutating a MorphyLib object — fixing a case + where resampled weights could be silently ignored. + +- The low-level MorphyLib bindings (`mpl_*()`), together with the + `MorphyWeights()`, `SetMorphyWeights()`, `GapHandler()`, `MorphyErrorCheck()`, + `GetMorphyLength()` and `C_MorphyLength()` helpers and the + `summary.morphyPtr()` method, have been removed. + - `WideSample()` now dispatches to the appropriate Max-Min diversity (MMDP) solver from the \pkg{MaxMin} package, choosing the tier automatically from `length(trees)`: the exact node-packing optimum (Sayyady & Fathi, 2016) diff --git a/R/Bootstrap.R b/R/Bootstrap.R index fdd13f5df..de3c785f6 100644 --- a/R/Bootstrap.R +++ b/R/Bootstrap.R @@ -1,6 +1,6 @@ #' @inheritParams TreeSearch #' @inheritParams EdgeListSearch -#' @inheritParams MorphyTreeLength +#' @param dataset A `ParsimonyData` object from [`PrepareData()`]. #' @param maxIter Numeric specifying maximum number of iterations to perform in #' tree search. #' @param maxHits Numeric specifying maximum number of hits to accomplish in @@ -8,44 +8,27 @@ #' @param stopAtScore stop search as soon as this score is hit or beaten. #' @param \dots further parameters to send to `TreeScorer()` #' -#' @return `MorphyBootstrap()` returns a tree that is optimal under a random +#' @return `BootstrapTree()` returns a tree that is optimal under a random #' sampling of the original characters. -#' +#' #' @rdname Ratchet #' @export -MorphyBootstrap <- function (edgeList, morphyObj, EdgeSwapper = NNISwap, - maxIter, maxHits, verbosity = 1L, - stopAtPeak = FALSE, stopAtPlateau=0L, ...) { - startWeights <- MorphyWeights(morphyObj)["exact", ] +BootstrapTree <- function (edgeList, dataset, EdgeSwapper = NNISwap, + maxIter, maxHits, verbosity = 1L, + stopAtPeak = FALSE, stopAtPlateau = 0L, ...) { + startWeights <- dataset[["original_weight"]] eachChar <- seq_along(startWeights) deindexedChars <- rep.int(eachChar, startWeights) resampling <- tabulate(sample(deindexedChars, replace = TRUE), length(startWeights)) - errors <- vapply(eachChar, function (i) - mpl_set_charac_weight(i, resampling[i], morphyObj), integer(1)) - - if (any(errors)) { # nocov start - stop ("Error resampling morphy object: ", - mpl_translate_error(unique(errors[errors < 0L]))) - } - if (mpl_apply_tipdata(morphyObj) -> error) { - stop("Error applying tip data: ", mpl_translate_error(error)) - } # nocov end - - res <- EdgeListSearch(edgeList[1:2], morphyObj, EdgeSwapper = EdgeSwapper, + # R copy-on-modify: the caller's `dataset` is unchanged. + dataset[["weight"]] <- as.integer(resampling) + + res <- EdgeListSearch(edgeList[1:2], dataset, EdgeSwapper = EdgeSwapper, maxIter = maxIter, maxHits = maxHits, stopAtPeak = stopAtPeak, stopAtPlateau = stopAtPlateau, verbosity = verbosity - 1L, ...) - errors <- vapply(eachChar, function (i) - mpl_set_charac_weight(i, startWeights[i], morphyObj), integer(1)) - if (any(errors)) { # nocov start - stop ("Error resampling morphy object: ", - mpl_translate_error(unique(errors[errors < 0L]))) - } - if (mpl_apply_tipdata(morphyObj) -> error) { - stop("Error applying tip data: ", mpl_translate_error(error)) - } # nocov end - + # Return: res[1:2] } diff --git a/R/CustomSearch.R b/R/CustomSearch.R index eb16e198f..3d86efacc 100644 --- a/R/CustomSearch.R +++ b/R/CustomSearch.R @@ -12,7 +12,7 @@ #' @keywords internal #' @export EdgeListSearch <- function (edgeList, dataset, - TreeScorer = MorphyLength, + TreeScorer = EdgeListScore, EdgeSwapper = RootedTBRSwap, maxIter = 100, maxHits = 20, bestScore = NULL, stopAtScore = NULL, @@ -128,13 +128,19 @@ EdgeListSearch <- function (edgeList, dataset, #' Will be overridden if a passed function has an attribute `stopAtPlateau` set #' by `attr(FunctionName, "stopAtPlateau") <- TRUE`. #' -#' @param InitializeData Function that sets up data object to prepare for tree search. -#' The function will be passed the `dataset` parameter. +#' @param concavity Determines the optimality criterion when the default native +#' scorer is used: `Inf` (the default) for equal weights; a finite, positive +#' number for implied weighting with that concavity constant +#' \insertCite{Goloboff1993}{TreeSearch}; or `"profile"` for profile parsimony. +#' Ignored if a custom `InitializeData` is supplied (prepare the data yourself). +#' @param InitializeData Function that sets up data object to prepare for tree +#' search. The default, [`PrepareData()`], is called with `concavity`; +#' a custom function will be passed only the `dataset` parameter. #' Its return value will be passed to `TreeScorer()` and `CleanUpData()`. -#' @param CleanUpData Function to destroy data object on function exit. +#' @param CleanUpData Function to release the data object on function exit. #' The function will be passed the value returned by `InitializeData()`. #' @param TreeScorer function to score a given tree. -#' The function will be passed three parameters, corresponding to the +#' The function will be passed three parameters, corresponding to the #' `parent` and `child` entries of a tree's edge list, and a dataset. #' #' @param verbosity Numeric specifying level of detail to display in console: @@ -166,15 +172,18 @@ EdgeListSearch <- function (edgeList, dataset, #' TreeSearch(njtree, Lobo.phy, maxIter = 20, EdgeSwapper = NNISwap) #' TreeSearch(njtree, Lobo.phy, maxIter = 20, EdgeSwapper = RootedSPRSwap) #' TreeSearch(njtree, Lobo.phy, maxIter = 20, EdgeSwapper = TBRSwap) +#' +#' # Implied weighting (concavity constant k = 10): +#' TreeSearch(njtree, Lobo.phy, concavity = 10, maxIter = 20) #' } #' @template MRS #' @family custom search functions #' @importFrom TreeTools RenumberTips #' @export -TreeSearch <- function (tree, dataset, - InitializeData = PhyDat2Morphy, - CleanUpData = UnloadMorphy, - TreeScorer = MorphyLength, +TreeSearch <- function (tree, dataset, concavity = Inf, + InitializeData = PrepareData, + CleanUpData = ReleaseData, + TreeScorer = EdgeListScore, EdgeSwapper = RootedTBRSwap, maxIter = 100L, maxHits = 20L, stopAtPeak = FALSE, stopAtPlateau = 0L, @@ -186,7 +195,13 @@ TreeSearch <- function (tree, dataset, edgeList <- tree[["edge"]] edgeList <- RenumberEdges(edgeList[, 1], edgeList[, 2]) - initializedData <- InitializeData(dataset) + # `concavity` is honoured only by the default native `PrepareData`; a custom + # `InitializeData` receives the dataset unchanged. + if (identical(InitializeData, PrepareData)) { + initializedData <- PrepareData(dataset, concavity = concavity) + } else { + initializedData <- InitializeData(dataset) + } on.exit(initializedData <- CleanUpData(initializedData)) bestScore <- attr(tree, "score") diff --git a/R/Jackknife.R b/R/Jackknife.R index fce0b7941..e1dd716f7 100644 --- a/R/Jackknife.R +++ b/R/Jackknife.R @@ -19,29 +19,34 @@ #' @family split support functions #' @family custom search functions #' @export -Jackknife <- function(tree, dataset, resampleFreq = 2 / 3, - InitializeData = PhyDat2Morphy, - CleanUpData = UnloadMorphy, - TreeScorer = MorphyLength, +Jackknife <- function(tree, dataset, concavity = Inf, + resampleFreq = 2 / 3, + InitializeData = PrepareData, + CleanUpData = ReleaseData, + TreeScorer = EdgeListScore, EdgeSwapper = TBRSwap, jackIter = 5000L, searchIter = 4000L, searchHits = 42L, verbosity = 1L, ...) { if (dim(tree[["edge"]])[1] != 2 * tree[["Nnode"]]) { stop("tree must be bifurcating; try rooting with ape::root") } - + tree <- RenumberTips(tree, names(dataset)) edgeList <- tree[["edge"]] edgeList <- RenumberEdges(edgeList[, 1], edgeList[, 2]) - - morphyObj <- InitializeData(dataset) - on.exit(morphyObj <- CleanUpData(morphyObj)) - - startWeights <- MorphyWeights(morphyObj)["exact", ] + + if (identical(InitializeData, PrepareData)) { + initializedData <- PrepareData(dataset, concavity = concavity) + } else { + initializedData <- InitializeData(dataset) + } + on.exit(initializedData <- CleanUpData(initializedData)) + + startWeights <- initializedData[["original_weight"]] eachChar <- seq_along(startWeights) deindexedChars <- rep.int(eachChar, startWeights) charsToKeep <- ceiling(resampleFreq * length(deindexedChars)) - + if (charsToKeep < 1L) { stop("resampleFreq of ", resampleFreq, " is too low; can't keep 0 of ", length(deindexedChars), " characters.") @@ -49,11 +54,11 @@ Jackknife <- function(tree, dataset, resampleFreq = 2 / 3, stop("resampleFreq of ", resampleFreq, " is too high; can't keep all ", length(deindexedChars), " characters.") } - + if (verbosity > 10L) { #nocov start message(" * Beginning search:") } #nocov end - + # Conduct jackIter replicates: jackEdges <- vapply(seq_len(jackIter), function (x) { if (verbosity > 0L) { #nocov start @@ -61,16 +66,12 @@ Jackknife <- function(tree, dataset, resampleFreq = 2 / 3, } #nocov end resampling <- tabulate(sample(deindexedChars, charsToKeep, replace = FALSE), nbins = length(startWeights)) - errors <- vapply(eachChar, function (i) - mpl_set_charac_weight(i, resampling[i], morphyObj), integer(1)) - if (any(errors)) { #nocov start - stop ("Error resampling morphy object: ", - mpl_translate_error(unique(errors[errors < 0L]))) - } - if (mpl_apply_tipdata(morphyObj) -> error) { - stop("Error applying tip data: ", mpl_translate_error(error)) - } #nocov end - res <- EdgeListSearch(edgeList[1:2], morphyObj, EdgeSwapper = EdgeSwapper, + # R copy-on-modify: the prepared data is scored with resampled weights + # without mutating `initializedData`. + resampledData <- initializedData + resampledData[["weight"]] <- as.integer(resampling) + res <- EdgeListSearch(edgeList[1:2], resampledData, + TreeScorer = TreeScorer, EdgeSwapper = EdgeSwapper, maxIter = searchIter, maxHits = searchHits, verbosity = verbosity - 1L, ...) res[1:2] diff --git a/R/MaximizeParsimony.R b/R/MaximizeParsimony.R index 673d65a1a..de9db66cd 100644 --- a/R/MaximizeParsimony.R +++ b/R/MaximizeParsimony.R @@ -393,7 +393,7 @@ #' These override the corresponding `control` fields and the strategy #' preset. #' Legacy `Morphy()`-style parameters (e.g. `ratchIter`, `tbrIter`) are -#' detected and forwarded to [`Morphy()`] with a deprecation warning. +#' rejected with an error; use this function's own controls instead. #' #' @return A `multiPhylo` object containing the best tree(s) found, with #' attributes: @@ -432,8 +432,7 @@ #' #' @template MRS #' @family tree scoring -#' @seealso [`Morphy()`] for fine-grained control over the R-level search loop. -#' [`Resample()`] for jackknife and bootstrap resampling. +#' @seealso [`Resample()`] for jackknife and bootstrap resampling. #' [`SearchControl()`] for expert-level tuning of the search heuristics. #' @references #' \insertAllCited{} @@ -488,32 +487,20 @@ MaximizeParsimony <- function( dots[["maxTime"]] <- NULL } - # --- Backward compatibility: detect Morphy()-style parameters --- + # --- Reject legacy Morphy()-style parameters --- + # Morphy() (an R-loop MorphyLib search, never released on CRAN) has been + # removed; its functionality is superseded by this C++ engine. .morphyParams <- c("ratchIter", "tbrIter", "startIter", "finalIter", - "maxHits", "quickHits", "ratchEW", - "tolerance") + "maxHits", "quickHits", "ratchEW", "tolerance") legacyHits <- intersect(names(dots), .morphyParams) if (length(legacyHits)) { - .Deprecated( - "Morphy", - msg = paste0( - "Parameter", if (length(legacyHits) > 1L) "s", " ", - paste0(sQuote(legacyHits), collapse = ", "), - " belong", if (length(legacyHits) == 1L) "s", " to `Morphy()`,", - " not the new `MaximizeParsimony()`.\n", - " Delegating to `Morphy()`. ", - "Please update your code to call `Morphy()` directly ", - "or use the new MaximizeParsimony() parameters.\n", - " See ?Morphy and ?MaximizeParsimony for details." - ) - ) - morphyArgs <- dots - morphyArgs$dataset <- dataset - if (!missing(tree) && !is.null(tree)) morphyArgs$tree <- tree - if (!missing(concavity)) morphyArgs$concavity <- concavity - if (!missing(constraint)) morphyArgs$constraint <- constraint - if (!missing(verbosity)) morphyArgs$verbosity <- verbosity - return(do.call(Morphy, morphyArgs)) + stop("Parameter", if (length(legacyHits) > 1L) "s", " ", + paste0(sQuote(legacyHits), collapse = ", "), + " belong", if (length(legacyHits) == 1L) "s", + " to the removed `Morphy()` search, not `MaximizeParsimony()`.\n", + " Use this function's own controls instead ", + "(see `?SearchControl`, `maxReplicates`, `maxSeconds`).", + call. = FALSE) } # --- Resolve control: merge control + ... overrides --- diff --git a/R/Morphy.R b/R/Morphy.R index 474867204..23ff62b55 100644 --- a/R/Morphy.R +++ b/R/Morphy.R @@ -1,927 +1,3 @@ -#' Tree search using MorphyLib scoring -#' -#' Search for most parsimonious trees using the parsimony ratchet and -#' \acronym{TBR} rearrangements, scoring with the MorphyLib C library -#' \insertCite{Brazeau2017}{TreeSearch}. -#' Supports equal weights, implied weights, and profile parsimony. -#' Treats inapplicable data using the algorithm of -#' \insertCite{Brazeau2019;textual}{TreeSearch}. -#' -#' For most users, [`MaximizeParsimony()`] provides a faster search using the -#' C++ engine, with native support for equal weights, implied weights, profile -#' parsimony, and topological constraints. -#' `Morphy()` is retained for users who need fine-grained control over the -#' R-level search loop (e.g.\sspace{}custom stopping criteria, per-iteration -#' callbacks, or direct access to MorphyLib scoring). -#' -#' Tree search commences with `ratchIter` iterations of the parsimony ratchet -#' \insertCite{Nixon1999}{TreeSearch}, which bootstraps the input dataset -#' in order to escape local optima. -#' A final round of tree bisection and reconnection (\acronym{TBR}) -#' is conducted to broaden the sampling of trees. -#' -#' This function can be called using the R command line / terminal, or through -#' the "shiny" graphical user interface app (type `EasyTrees()` to launch). -#' -#' The optimal strategy for tree search depends in part on how close to optimal -#' the starting tree is, the size of the search space (which increases -#' super-exponentially with the number of leaves), and the complexity of the -#' search space (e.g. the existence of multiple local optima). -#' -#' One possible approach is to employ four phases: -#' -#' 1. Rapid search for local optimum: tree score is typically easy to improve -#' early in a search, because the initial tree is often far from optimal. -#' When many moves are likely to be accepted, running several rounds of search -#' with a low value of `maxHits` and a high value of `tbrIter` allows many -#' trees to be evaluated quickly, hopefully moving quickly to a more promising -#' region of tree space. -#' -#' 2. Identification of local optimum: -#' Once close to a local optimum, a more extensive search -#' with a higher value of `maxHits` allows a region to be explored in more -#' detail. Setting a high value of `tbrIter` will search a local -#' neighbourhood more completely -#' -#' 3. Search for nearby peaks: -#' Ratchet iterations allow escape from local optima. -#' Setting `ratchIter` to a high value searches the wider neighbourhood more -#' extensively for other nearby peaks; `ratchEW = TRUE` accelerates these -#' exploratory searches. Ratchet iterations can be ineffective when `maxHits` -#' is too low for the search to escape its initial location. -#' -#' 4. Extensive search of final optimum. As with step 2, it may be valuable to -#' fully explore the optimum that is found after ratchet searches to be sure -#' that the locally optimal score has been obtained. Setting a high value of -#' `finalIter` performs a thorough search that can give confidence that further -#' searches would not find better (local) trees. -#' -#' A search is unlikely to have found a global optimum if: -#' -#' - Tree score continues to improve on the final iteration. If a local optimum -#' has not yet been reached, it is unlikely that a global optimum has -#' been reached. -#' Try increasing `maxHits`. -#' -#' - Successive ratchet iterations continue to improve tree scores. -#' If a recent ratchet iteration improved the score, rather than finding -#' a different region of tree space with the same optimal score, it is likely -#' that still better global optima remain to be found. Try increasing -#' `ratchIter` (more iterations give more chance for improvement) and -#' `maxHits` (to get closer to the local optimum after each ratchet iteration). -#' -#' - Optimal areas of tree space are only visited by a single ratchet iteration. -#' (See vignette: [Exploring tree space]( -#' https://ms609.github.io/TreeSearch/articles/tree-space.html).) -#' If some areas of tree space are only found by one ratchet iteration, there -#' may well be other, better areas that have not yet been visited. -#' Try increasing `ratchIter`. -#' -#' When continuing a tree search, it is usually best to start from an optimal -#' tree found during the previous iteration - there is no need to start from -#' scratch. -#' -#' A more time consuming way of checking that a global optimum has been reached -#' is to repeat a search with the same parameters multiple times, starting -#' from a different, entirely random tree each time. If all searches obtain the -#' same optimal tree score despite their different starting points, -#' this score is likely to correspond to the global optimum. -#' -#' For detailed documentation of the "TreeSearch" package, including full -#' instructions for loading phylogenetic data into R and initiating and -#' configuring tree search, see the -#' [package documentation](https://ms609.github.io/TreeSearch/). -#' -#' -#' @param dataset A phylogenetic data matrix of \pkg{phangorn} class -#' \code{phyDat}, whose names correspond to the labels of any accompanying tree. -#' Perhaps load into R using \code{\link[TreeTools]{ReadAsPhyDat}()}. -#' Additive (ordered) characters can be handled using -#' \code{\link[TreeTools]{Decompose}()}. -#' @param tree (optional) A bifurcating tree of class \code{\link[ape]{phylo}}, -#' containing only the tips listed in `dataset`, from which the search -#' should begin. -#' If unspecified, an [addition tree][AdditionTree()] will be generated from -#' `dataset`, respecting any supplied `constraint`. -#' Edge lengths are not supported and will be deleted. -#' @param ratchIter Numeric specifying number of iterations of the -#' parsimony ratchet \insertCite{Nixon1999}{TreeSearch} to conduct. -#' @param tbrIter Numeric specifying the maximum number of \acronym{TBR} -#' break points on a given tree to evaluate before terminating the search. -#' One "iteration" comprises selecting a branch to break, and evaluating -#' each possible reconnection point in turn until a new tree improves the -#' score. If a better score is found, then the counter is reset to zero, -#' and tree search continues from the improved tree. -#' @param startIter Numeric: an initial round of tree search with -#' `startIter` × `tbrIter` \acronym{TBR} break points is conducted in -#' order to locate a local optimum before beginning ratchet searches. -#' @param finalIter Numeric: a final round of tree search will evaluate -#' `finalIter` × `tbrIter` \acronym{TBR} break points, in order to -#' sample the final optimal neighbourhood more intensely. -#' @param maxHits Numeric specifying the maximum times that an optimal -#' parsimony score may be hit before concluding a ratchet iteration or final -#' search concluded. -#' @param maxTime Numeric: after `maxTime` minutes, stop tree search at the -#' next opportunity. -#' @param quickHits Numeric: iterations on subsampled datasets -#' will retain `quickHits` × `maxHits` trees with the best score. -#' @param concavity Determines the degree to which extra steps beyond the first -#' are penalized. Specify a numeric value to use implied weighting -#' \insertCite{Goloboff1993}{TreeSearch}; `concavity` specifies _k_ in -#' _k_ / _e_ + _k_. A value of 10 is recommended; -#' TNT sets a default of 3, but this is too low in some circumstances -#' \insertCite{Goloboff2018,Smith2019}{TreeSearch}. -#' Better still explore the sensitivity of results under a range of -#' concavity values, e.g. `k = 2 ^ (1:7)`. -#' Specify `Inf` to weight each additional step equally, -#' (which underperforms step weighting approaches -#' \insertCite{Goloboff2008,Goloboff2018,Goloboff2019,Smith2019}{TreeSearch}). -#' Specify `"profile"` to employ an approximation of profile parsimony -#' \insertCite{Faith2001}{TreeSearch}. -#' @param ratchEW Logical specifying whether to use equal weighting during -#' ratchet iterations, improving search speed whilst still facilitating -#' escape from local optima. -#' @param tolerance Numeric specifying degree of suboptimality to tolerate -#' before rejecting a tree. The default, `sqrt(.Machine$double.eps)`, retains -#' trees that may be equally parsimonious but for rounding errors. -#' Setting to larger values will include trees suboptimal by up to `tolerance` -#' in search results, which may improve the accuracy of the consensus tree -#' (at the expense of resolution) \insertCite{Smith2019}{TreeSearch}. -#' @param constraint Either an object of class `phyDat`, in which case -#' returned trees will be perfectly compatible with each character in -#' `constraint`; or a tree of class `phylo`, all of whose nodes will occur -#' in any output tree. -#' See \code{\link[TreeTools:ImposeConstraint]{ImposeConstraint()}} and -#' [vignette](https://ms609.github.io/TreeSearch/articles/tree-search.html) -#' for further examples. -#' @param verbosity Integer specifying level of messaging; higher values give -#' more detailed commentary on search progress. Set to `0` to run silently. -#' @param \dots Additional parameters to `Morphy()`. -#' -#' @return `Morphy()` returns a list of trees with class -#' `multiPhylo`. This lists all trees found during each search step that -#' are within `tolerance` of the optimal score, listed in the sequence that -#' they were first visited, and named according to the step in which they were -#' first found; it may contain more than `maxHits` elements. -#' Note that the default search parameters may need to be increased in order for -#' these trees to be the globally optimal trees; examine the messages printed -#' during tree search to evaluate whether the optimal score has stabilized. -#' -#' The return value has the attribute `firstHit`, a named integer vector listing -#' the number of optimal trees visited for the first time in each stage of -#' the tree search. Stages are named: -#' - `seed`: starting trees; -#' - `start`: Initial TBR search; -#' - `ratchN`: Ratchet iteration `N`; -#' - `final`: Final TBR search. -#' The first tree hit for the first time in ratchet iteration three is named -#' `ratch3_1`. -#' -#' @examples -#' ## Only run examples in interactive R sessions -#' if (interactive()) { -#' # launch "shiny" point-and-click interface -#' EasyTrees() -#' -#' # Here too, use the "continue search" function to ensure that tree score -#' # has stabilized and a global optimum has been found -#' } -#' -#' -#' # Load data for analysis in R -#' library("TreeTools") -#' data("inapplicable.phyData", package = "TreeSearch") -#' dataset <- inapplicable.phyData[["Asher2005"]] -#' -#' \donttest{ -#' # A very quick run for demonstration purposes -#' trees <- Morphy(dataset, ratchIter = 0, startIter = 0, -#' tbrIter = 1, maxHits = 4, maxTime = 1/100, -#' concavity = 10, verbosity = 4) -#' names(trees) -#' cons <- Consensus(trees) -#' } -#' -#' # In actual use, be sure to check that the score has converged on a global -#' # optimum, conducting additional iterations and runs as necessary. -#' -#' if (interactive()) { -#' # Jackknife resampling -#' nReplicates <- 10 -#' jackTrees <- replicate(nReplicates, -#' #c() ensures that each replicate returns a list of trees -#' c(Resample(dataset, trees, ratchIter = 0, tbrIter = 2, startIter = 1, -#' maxHits = 5, maxTime = 1 / 10, -#' concavity = 10, verbosity = 0)) -#' ) -#' -#' # In a serious analysis, more replicates would be conducted, and each -#' # search would undergo more iterations. -#' -#' # Now we must decide what to do with the multiple optimal trees from -#' # each replicate. -#' -#' # Set graphical parameters for plotting -#' oPar <- par(mar = rep(0, 4), cex = 0.9) -#' -#' # Take the strict consensus of all trees for each replicate -#' # (May underestimate support) -#' JackLabels(cons, lapply(jackTrees, ape::consensus)) -#' -#' # Take a single tree from each replicate (here, the first) -#' # Potentially problematic if chosen tree is not representative -#' JackLabels(cons, lapply(jackTrees, `[[`, 1)) -#' -#' # Count iteration as support if all most parsimonious trees support a split; -#' # as contradiction if all trees contradict it; don't include replicates where -#' # not all trees agree on the resolution of a split. -#' labels <- JackLabels(cons, jackTrees) -#' -#' # How many iterations were decisive for each node? -#' attr(labels, "decisive") -#' -#' # Show as proportion of decisive iterations -#' JackLabels(cons, jackTrees, showFrac = TRUE) -#' -#' # Restore graphical parameters -#' par(oPar) -#' } -#' -#' # Tree search with a constraint -#' constraint <- MatrixToPhyDat(c(a = 1, b = 1, c = 0, d = 0, e = 0, f = 0)) -#' characters <- MatrixToPhyDat(matrix( -#' c(0, 1, 1, 1, 0, 0, -#' 1, 1, 1, 0, 0, 0), ncol = 2, -#' dimnames = list(letters[1:6], NULL))) -#' Morphy(characters, constraint = constraint, verbosity = 0) -#' -#' @template MRS -#' -#' @importFrom cli cli_alert cli_alert_danger cli_alert_info cli_alert_success -#' @importFrom cli cli_alert_warning cli_h1 cli_progress_bar cli_progress_done -#' @importFrom cli cli_progress_update -#' @importFrom fastmatch fmatch -#' @importFrom stats runif -#' @importFrom TreeTools AddUnconstrained CharacterInformation ConstrainedNJ -#' @importFrom TreeTools DropTip ImposeConstraint MakeTreeBinary MatrixToPhyDat -#' @importFrom TreeTools NTip -#' @references -#' \insertAllCited{} -#' @seealso -#' [`MaximizeParsimony()`] for the faster C++ driven search engine -#' (recommended for most analyses). -#' -#' Tree search _via_ graphical user interface: [`EasyTrees()`] -#' -#' @encoding UTF-8 -#' @export -Morphy <- function(dataset, tree, - ratchIter = 7L, - tbrIter = 2L, - startIter = 2L, finalIter = 1L, - maxHits = NTip(dataset) * 1.8, - maxTime = 60, - quickHits = 1 / 3, - concavity = Inf, - ratchEW = TRUE, - tolerance = sqrt(.Machine[["double.eps"]]), - constraint, - verbosity = 3L) { - - ### User messaging functions ### - .Message <- function (level, ...) { - if (level < verbosity) { - cli_alert(paste0(...)) - } - } - .Heading <- function (text, ...) { - if (0 < verbosity) { - cli_h1(text) - if (length(list(...))) { - cli_alert(paste0(...)) - } - } - } - .Info <- function (level, ...) { - if (level < verbosity) { - cli_alert_info(paste0(...)) - } - } - .Success <- function (level, ...) { - if (level < verbosity) { - cli_alert_success(paste0(...)) - } - } - - ### Tree score functions ### - .EWScore <- function (edge, morphyObj, ...) { - preorder_morphy(edge, morphyObj) - } - - .IWScore <- function (edge, morphyObjs, weight, charSeq, concavity, - minLength, target = Inf) { - morphy_iw(edge, morphyObjs, weight, minLength, charSeq, - concavity, target + epsilon) - } - - # Must have same order of parameters as .IWScore, even though minLength unused - .ProfileScore <- function (edge, morphyObjs, weight, charSeq, profiles, - minLength, target = Inf) { - morphy_profile(edge, morphyObjs, weight, charSeq, profiles, - target + epsilon) - } - - .Score <- function (edge) { - if (length(dim(edge)) == 3L) { - edge <- edge[, , 1] - } - if (profile) { - .ProfileScore(edge, morphyObjects, startWeights, charSeq, profiles) - } else if (iw) { - .IWScore(edge, morphyObjects, startWeights, charSeq, concavity, minLength) - } else { - preorder_morphy(edge, morphyObj) - } - } - - ### Tree search functions ### - .TBRSearch <- function (Score, name, - edge, morphyObjs, weight, - tbrIter, maxHits, - minLength = NULL, charSeq = NULL, concavity = NULL) { - - iter <- 0L - nHits <- 1L - hold <- array(NA, dim = c(dim(edge), max(maxHits * 1.1, maxHits + 10L))) - maxHits <- ceiling(maxHits) - hold[, , 1] <- edge - bestScore <- Score(edge, morphyObjs, weight, charSeq, concavity, minLength) - bestPlusEps <- bestScore + epsilon - cli_progress_bar(name, total = maxHits, - auto_terminate = FALSE, - clear = verbosity < 3L, - format_done = paste0(" - TBR rearrangement at depth {iter}", - " found score {signif(bestScore)}", - " {nHits} time{?s}.")) - - while (iter < tbrIter) { - iter <- iter + 1L - brkOptions <- sample(3:(nTip * 2 - 2)) - .Message(4L, " New TBR iteration (depth ", iter, - ", score ", signif(bestScore), ")") - cli_progress_update(set = 0, total = length(brkOptions)) - - for (brk in brkOptions) { - cli_progress_update(1, status = paste0("D", iter, ", score ", - signif(bestScore), ", hit ", - nHits, ".")) - .Message(7L, " Break ", brk) - moves <- TBRMoves(edge, brk) - improvedScore <- FALSE - nMoves <- length(moves) - moveList <- sample.int(nMoves) - for (i in seq_along(moveList)) { - move <- moves[[moveList[i]]] - if (.Forbidden(move)) { - .Message(10L, " Skipping prohibited topology") - next - } - moveScore <- Score(move, morphyObjs, weight, charSeq, concavity, - minLength, bestPlusEps) - if (moveScore < bestPlusEps) { - edge <- move - if (moveScore < bestScore) { - improvedScore <- TRUE - iter <- 0L - bestScore <- moveScore - bestPlusEps <- bestScore + epsilon - nHits <- 1L - hold[, , 1] <- edge - .Message(5L, " New best score ", signif(bestScore), - " at break ", fmatch(brk, brkOptions), "/", length(brkOptions)) - break - } else { - .Message(6L, " Best score ", signif(bestScore), - " hit again (", nHits, "/", ceiling(maxHits), ")") - nHits <- nHits + 1L - hold[, , nHits] <- edge - if (nHits >= maxHits) break - } - } - # If an early iteration improves the score, a later iteration will - # probably improve it even more; we may as well keep working through - # the list instead of calculating a new one (which takes time) - if (improvedScore && runif(1) < (i / nMoves) ^ 2) break - } - if (nHits >= maxHits) break - pNextTbr <- (fmatch(brk, brkOptions) / length(brkOptions)) ^ 2 - if (improvedScore && runif(1) < pNextTbr) break - } - if (nHits >= maxHits) break - } - cli_progress_done() - - # Return: - unique(hold[, , seq_len(nHits), drop = FALSE], MARGIN = 3L) - - } - - - .Search <- function (name = "TBR search", .edge = edge, .hits = searchHits, - .weight = startWeights, .forceEW = FALSE) { - if (length(dim(.edge)) == 3L) { - .edge <- .edge[, , 1] - } - .Message(4L, paste("<<< Begin:", name)) - on.exit(.Message(4L, paste(">>> Complete:", name))) - if (profile && isFALSE(.forceEW)) { - .TBRSearch(.ProfileScore, name, edge = .edge, morphyObjects, - tbrIter = searchIter, maxHits = .hits, - weight = .weight, minLength = minLength, charSeq = charSeq, - concavity = profiles) - - } else if (iw && isFALSE(.forceEW)) { - .TBRSearch(.IWScore, name, edge = .edge, morphyObjects, - tbrIter = searchIter, maxHits = .hits, - weight = .weight, minLength = minLength, charSeq = charSeq, - concavity = concavity) - } else { - .TBRSearch(.EWScore, name, edge = .edge, morphyObj, - tbrIter = searchIter, maxHits = .hits, - concavity = if(isTRUE(.forceEW)) Inf else concavity) - } - } - - .Timeout <- function() { - if (Sys.time() > stopTime) { - .Info(1L, "Stopping search at ", .DateTime(), ": ", maxTime, - " minutes have elapsed.", - " Best score was ", signif(.Score(bestEdges[, , 1])), ".", - if (maxTime == 60) "\nIncrease `maxTime` for longer runs.") - return (TRUE) - } - - FALSE - } - - .ReturnValue <- function(bestEdges) { - if (verbosity > 0L) { - cli_alert_success(paste0(.DateTime(), - ": Tree search terminated with score {.strong ", - "{signif(.Score(bestEdges[, , 1]))}}")) - } - firstHit <- attr(bestEdges, "firstHit") - structure(lapply(seq_len(dim(bestEdges)[3]), function (i) { - tr <- tree - tr[["edge"]] <- bestEdges[, , i] - if (any(is.na(outgroup))) { - tr - } else { - RootTree(tr, outgroup) - } - }), - firstHit = firstHit, - names = paste0(rep(names(firstHit), firstHit), "_", unlist(lapply(firstHit, seq_len))), - class = "multiPhylo") - } - - - # Define constants - epsilon <- tolerance - pNextTbr <- 0.33 - profile <- .UseProfile(concavity) - iw <- is.finite(concavity) - if (iw && concavity <= 0) { - stop("`concavity` must be positive (or Inf for equal weights, ", - "or \"profile\" for profile parsimony).") - } - constrained <- !missing(constraint) - startTime <- Sys.time() - stopTime <- startTime + as.difftime(maxTime, units = "mins") - - # Initialize tree - startTrees <- NULL - if (missing(tree)) { - tree <- AdditionTree(dataset, constraint = constraint, - concavity = concavity) - } else if (inherits(tree, "multiPhylo")) { - startTrees <- unique(tree) - sampledTree <- sample.int(length(tree), 1) - .Info(2L, paste0("Starting search from {.var tree[[", sampledTree, "]]}")) - tree <- tree[[sampledTree]] - } else if (inherits(tree, "phylo")) { - startTrees <- c(tree) - } - if (dim(tree[["edge"]])[1] != 2 * tree[["Nnode"]]) { - cli_alert_warning("`tree` is not bifurcating; collapsing polytomies at random") - tree <- MakeTreeBinary(tree) - if (dim(tree[["edge"]])[1] != 2 * tree[["Nnode"]]) { - cli_alert_warning("Rooting `tree` on first leaf") - tree <- RootTree(tree, 1) - } - if (dim(tree[["edge"]])[1] != 2 * tree[["Nnode"]]) { - stop("Could not make `tree` binary.") - } - } - - # Check tree labels matches dataset - leaves <- tree[["tip.label"]] - taxa <- names(dataset) - treeOnly <- setdiff(leaves, taxa) - datOnly <- setdiff(taxa, leaves) - if (length(treeOnly)) { - cli_alert_warning(paste0("Ignoring taxa on tree missing in dataset:\n> ", - paste0(treeOnly, collapse = ", "))) - warning("Ignored taxa on tree missing in dataset:\n ", - paste0(treeOnly, collapse = ", ")) - tree <- DropTip(tree, treeOnly) - startTrees <- DropTip(startTrees, treeOnly) - } - if (length(datOnly)) { - cli_alert_warning(paste0("Ignoring taxa in dataset missing on tree:\n> ", - paste0(datOnly, collapse = ", "))) - warning("Ignored taxa in dataset missing on tree:\n> ", - paste0(datOnly, collapse = ", ")) - dataset <- dataset[-fmatch(datOnly, taxa)] - } - if (constrained) { - if (!inherits(constraint, "phyDat")) { - constraint <- MatrixToPhyDat(t(as.matrix(constraint))) - } - consTaxa <- TipLabels(constraint) - treeOnly <- setdiff(tree[["tip.label"]], consTaxa) - if (length(treeOnly)) { - constraint <- AddUnconstrained(constraint, treeOnly) - } - consOnly <- setdiff(consTaxa, tree[["tip.label"]]) - if (length(consOnly)) { - cli_alert_warning( - paste0("Ignoring taxa in constraint missing on tree:\n> ", - paste0(consOnly, collapse = ", "))) - warning("Ignored taxa in constraint missing on tree:\n ", - paste0(consOnly, collapse = ", ")) - constraint <- constraint[-fmatch(consOnly, consTaxa)] - } - constraint <- constraint[names(dataset)] - } - - - tree <- Preorder(RenumberTips(tree, names(dataset))) - nTip <- NTip(tree) - edge <- tree[["edge"]] - - # Initialize constraints - if (constrained) { - morphyConstr <- PhyDat2Morphy(constraint) - on.exit(morphyConstr <- UnloadMorphy(morphyConstr), add = TRUE) - constraintWeight <- attr(constraint, "weight") - if (any(constraintWeight > 1)) { - cli_alert_warning("Some constraints are exact duplicates.") - } - # Calculate constraint minimum score - constraintLength <- sum(MinimumLength(constraint, compress = TRUE) * - constraintWeight) - - .Forbidden <- function (edges) { - preorder_morphy(edges, morphyConstr) != constraintLength - } - - # Check that starting tree is consistent with constraints - if (.Forbidden(edge)) { - cli_alert_warning("Modifying `tree` to match `constraint`...") - outgroup <- edge[ - DescendantEdges(parent = edge[, 1], child = edge[, 2])[1, ], - 2] - outgroup <- outgroup[outgroup <= nTip] - tree <- RootTree(ImposeConstraint(tree, constraint), outgroup) - # RootTree leaves `tree` in preorder - edge <- tree[["edge"]] - if (.Forbidden(edge)) { - stop("Could not reconcile starting tree with `constraint`. ", - "Are all constraints compatible?") - } - } - - cli_alert_success(paste0("Initialized ", length(constraintWeight), - " distinct constraints.")) - - } else { - .Forbidden <- function (edges) FALSE - } - - - if (edge[1, 2] > nTip) { - outgroup <- edge[ - DescendantEdges(parent = edge[, 1], child = edge[, 2])[1, ], - 2] - outgroup <- outgroup[outgroup <= nTip] - if (length(outgroup) > nTip / 2L) { - outgroup <- seq_len(nTip)[-outgroup] - } - tree <- RootTree(tree, 1) - edge <- tree[["edge"]] - } else { - outgroup <- NA - } - - # Initialize data - if (profile) { - dataset <- PrepareDataProfile(dataset) - originalLevels <- attr(dataset, "levels") - if ("-" %fin% originalLevels) { - #TODO Fixing this will require updating the counts table cleverly - # Or we could use approximate info amounts, e.g. by treating "-" as - # an extra token - cli_alert_info(paste0("Inapplicable tokens \"-\" treated as ambiguous ", - "\"?\" for profile parsimony")) - cont <- attr(dataset, "contrast") - cont[cont[, "-"] != 0, ] <- 1 - attr(dataset, "contrast") <- cont[, colnames(cont) != "-"] - attr(dataset, "levels") <- originalLevels[originalLevels != "-"] - } - profiles <- attr(dataset, "info.amounts") - } - - if ((!iw && !profile) || # Required for equal weights search - (isTRUE(ratchEW) && ratchIter > 0) # For EW ratchet searches - ) { - morphyObj <- PhyDat2Morphy(dataset) - on.exit(morphyObj <- UnloadMorphy(morphyObj), add = TRUE) - } - - if (iw || profile) { - at <- attributes(dataset) - characters <- PhyToString(dataset, ps = "", useIndex = FALSE, - byTaxon = FALSE, concatenate = FALSE) - startWeights <- at[["weight"]] - minLength <- MinimumLength(dataset, compress = TRUE) - morphyObjects <- lapply(characters, SingleCharMorphy) - on.exit(morphyObjects <- vapply(morphyObjects, UnloadMorphy, integer(1)), - add = TRUE) - - nLevel <- length(at[["level"]]) - nChar <- at[["nr"]] - nTip <- length(dataset) - cont <- at[["contrast"]] - if (is.null(colnames(cont))) colnames(cont) <- as.character(at[["levels"]]) - simpleCont <- ifelse(rowSums(cont) == 1, - apply(cont != 0, 1, function (x) colnames(cont)[x][1]), - "?") - - - unlisted <- unlist(dataset, use.names = FALSE) - tokenMatrix <- matrix(simpleCont[unlisted], nChar, nTip) - charInfo <- apply(tokenMatrix, 1, CharacterInformation) - needsInapp <- rowSums(tokenMatrix == "-") > 2 - inappSlowdown <- 3L # A guess - # Crude estimate of score added per unit processing time - rawPriority <- charInfo / ifelse(needsInapp, inappSlowdown, 1) - priority <- startWeights * rawPriority - informative <- needsInapp | charInfo > 0 - # Will work from end of sequence to start. - charSeq <- seq_along(charInfo)[informative][order(priority[informative])] - 1L - } else { - startWeights <- unlist(MorphyWeights(morphyObj)[1, ]) # exact == approx - } - - # Initialize variables and prepare search - - nHits <- 1L - tbrStart <- startIter > 0 - tbrEnd <- finalIter > 0 - if (is.null(startTrees)) { - bestEdges <- edge - dim(bestEdges) <- c(dim(bestEdges), 1) - bestScore <- .Score(edge) - } else { - starters <- RenumberTips(startTrees, names(dataset)) - startEdges <- vapply(lapply(starters, Preorder), - `[[`, startTrees[[1]][["edge"]], - "edge") - startScores <- apply(startEdges, 3, .Score) - bestScore <- min(startScores) - bestEdges <- startEdges[, , startScores == bestScore, drop = FALSE] - } - nStages <- sum(tbrStart, ratchIter, tbrEnd) - attr(bestEdges, "firstHit") <- c("seed" = dim(bestEdges)[3], - setNames(double(nStages), - c(if(tbrStart) "start", - if(ratchIter > 0) paste0("ratch", seq_len(ratchIter)), - if(tbrEnd) "final"))) - - .Heading(paste0("BEGIN TREE SEARCH (k = ", concavity, ")"), - "Initial score: {.strong {signif(bestScore)} }") - - - # Find a local optimum - - if (tbrStart) { - searchIter <- tbrIter * startIter - searchHits <- maxHits - - .Heading("Find local optimum", - " TBR depth ", as.integer(searchIter), - "; keeping max ", as.integer(searchHits), - " trees; k = ", concavity, ".") - initialScore <- bestScore - - newEdges <- .Search("TBR search 1") - - newBestScore <- .Score(newEdges) - scoreImproved <- newBestScore + epsilon < bestScore - bestEdges <- if (scoreImproved) { - .ReplaceResults(bestEdges, newEdges, 2) - } else { - .CombineResults(bestEdges, newEdges, 2) - } - if (.Timeout()) { - .Info(1L, .DateTime(), ": Timed out with score ", - signif(min(bestScore, newBestScore))) - return(.ReturnValue(bestEdges)) # nocov - } - edge <- bestEdges[, , 1L] - bestScore <- .Score(edge) - if (bestScore < initialScore) { - .Success(2L, "{.strong New best score: {signif(bestScore)} }") - } else { - .Info(1L, .DateTime(), ": Did not beat initial score: ", - "{signif(bestScore)}") - } - } - - searchIter <- tbrIter - searchHits <- maxHits * quickHits - bestPlusEps <- bestScore + epsilon - - - - # Use Parsimony Ratchet to escape local optimum - - if (ratchIter > 0L) { - - .Heading("Escape local optimum", "{ratchIter} ratchet iterations; ", - "TBR depth {ceiling(searchIter)}; ", - "max. {ceiling(searchHits)} hits; ", - "k = {concavity}.") - .Info(1L, "{ .DateTime()}: Score to beat: {.strong {signif(bestScore)}}") - - iter <- 0L - while (iter < ratchIter) { - iter <- iter + 1L - .Message(1L, "Ratchet iteration {iter} @ {(.Time())}", - "; score to beat: {.strong {signif(bestScore)} }") - verbosity <- verbosity - 1L - eachChar <- seq_along(startWeights) - deindexedChars <- rep.int(eachChar, startWeights) - resampling <- tabulate(sample(deindexedChars, replace = TRUE), - length(startWeights)) - if (!isTRUE(ratchEW) && (profile || iw)) { - priority <- resampling * rawPriority - sampled <- informative & resampling > 0 - ratchSeq <- seq_along(charInfo)[sampled][order(priority[sampled])] - 1L - ratchetTrees <- .Search("Bootstrapped search", .weight = resampling) - } else { - errors <- vapply(eachChar, function (i) - mpl_set_charac_weight(i, resampling[i], morphyObj), integer(1)) - if (any(errors)) { # nocov start - stop ("Error resampling morphy object: ", - mpl_translate_error(unique(errors[errors < 0L]))) - } - if (mpl_apply_tipdata(morphyObj) -> error) { - stop("Error applying tip data: ", mpl_translate_error(error)) - } # nocov end - - ratchetTrees <- if (ratchEW) { - .Search("EW Bootstrapped search", .forceEW = TRUE) - } else { - .Search("Bootstrapped search") - } - - errors <- vapply(eachChar, function (i) - mpl_set_charac_weight(i, startWeights[i], morphyObj), integer(1)) - if (any(errors)) stop ("Error resampling morphy object: ", - mpl_translate_error(unique(errors[errors < 0L]))) - if (mpl_apply_tipdata(morphyObj) -> error) { - stop("Error applying tip data: ", mpl_translate_error(error)) - } - } - - verbosity <- verbosity + 1L - ratchetStart <- ratchetTrees[, , sample.int(dim(ratchetTrees)[3], 1)] - ratchStartScore <- .Score(ratchetStart) - .Message(2L, "Obtained new starting tree @ {(.Time())}", - " with score: {signif(ratchStartScore)}") - - # nocov start - if (.Timeout()) { - if (ratchetScore + epsilon < bestScore) { - bestEdges <- .ReplaceResults(bestEdges, ratchetStart, - 1 + tbrStart + iter) - } - return(.ReturnValue(bestEdges)) - } - # nocov end - - ratchetImproved <- .Search("TBR search", .edge = ratchetStart, - .hits = maxHits) - ratchetScore <- .Score(ratchetImproved[, , 1]) - - if (ratchetScore < bestPlusEps) { - if (ratchetScore + epsilon < bestScore) { - .Success(2L, "{.strong New best score}: {signif(ratchetScore)}") - bestScore <- ratchetScore - bestPlusEps <- bestScore + epsilon - bestEdges <- .ReplaceResults(bestEdges, ratchetImproved, - 1 + tbrStart + iter) - edge <- ratchetImproved[, , sample.int(dim(ratchetImproved)[3], 1)] - } else { - .Info(3L, "Hit best score {.strong {signif(bestScore)}} again") - - edge <- ratchetImproved[, , sample.int(dim(ratchetImproved)[3], 1)] - bestEdges <- .CombineResults(bestEdges, ratchetImproved, - 1 + tbrStart + iter) - } - } else { - if (3L < verbosity) { - cli_alert_danger("Did not hit best score {signif(bestScore)}") - } - } - if (.Timeout()) { - return(.ReturnValue(bestEdges)) # nocov - } - } - } - - # Branch breaking - if (tbrEnd) { - searchIter <- tbrIter * finalIter - searchHits <- maxHits - - .Heading("Sample local optimum", - "TBR depth {searchIter}; keeping {searchHits}", - " trees; k = {concavity}") - .Info(1L, .DateTime(), ": Score: ", signif(bestScore)) - finalEdges <- .Search("Final search") - newBestScore <- .Score(finalEdges[, , 1]) - improved <- newBestScore + epsilon < bestScore - bestEdges <- if (improved) { - .ReplaceResults(bestEdges, finalEdges, 1 + tbrStart + ratchIter + 1) - } else { - .CombineResults(bestEdges, finalEdges, 1 + tbrStart + ratchIter + 1) - } - } - - # Return: - .ReturnValue(bestEdges) -} - -#' Combine two edge matrices -#' -#' @param x,y 3D arrays, each slice containing an edge matrix from a tree -#' of class `phylo`. `x` should not contain duplicates. -#' @return A single 3D array containing each unique edge matrix from (`x` and) -#' `y`, with a `firstHit` attribute as documented in [`Morphy()`]. -#' @template MRS -#' @keywords internal -.CombineResults <- function (x, y, stage) { - xDim <- dim(x) - if (length(xDim) == 2L) { - xDim <- c(xDim, 1L) - } - if (any(duplicated(x, MARGIN = 3L))) { - warning(".CombineResults(x) should not contain duplicates.") - } - - res <- unique(array(c(x, y), dim = xDim + c(0, 0, dim(y)[3])), MARGIN = 3L) - firstHit <- attr(x, "firstHit") - firstHit[stage] <- dim(res)[3] - xDim[3] - attr(res, "firstHit") <- firstHit - - # Return: - res -} - -#' @rdname dot-CombineResults -#' @param old old array of edge matrices with `firstHit` attribute. -#' @param new new array of edge matrices. -#' @param stage Integer specifying element of `firstHit` in which new hits -#' should be recorded. -#' @keywords internal -.ReplaceResults <- function (old, new, stage) { - hit <- attr(old, "firstHit") - hit[] <- 0 - hit[stage] <- dim(new)[3] - structure(new, "firstHit" = hit) -} - -.Time <- function() { - format(Sys.time(), "%H:%M:%S") -} - -.DateTime <- function() { - format(Sys.time(), "%Y-%m-%d %T") -} - # Hierarchy-aware resampling: generates hierarchical weights per replicate # and calls ts_driven_search with HSJ/xform scoring. # This is an internal helper called from Resample() when inapplicable != "bgs". @@ -1319,7 +395,7 @@ Resample <- function(dataset, tree, method = "jack", proportion = 2 / 3, #' exploration. #' #' @return Opens a Shiny application; does not return a value. -#' @seealso [`MaximizeParsimony()`], [`Morphy()`] +#' @seealso [`MaximizeParsimony()`] #' @importFrom TreeDist ClusteringInfoDistance #' @export EasyTrees <- function () {#nocov start diff --git a/R/PrepareData.R b/R/PrepareData.R new file mode 100644 index 000000000..afe863169 --- /dev/null +++ b/R/PrepareData.R @@ -0,0 +1,139 @@ +# TreeSearch 2.0 prepares a dataset for fast, repeated native-C++ parsimony +# scoring as a lightweight `ParsimonyData` object: pre-extracted data matrices +# plus a mutable integer weight vector (used by the custom-search resampling +# functions `Jackknife()` and `BootstrapTree()`). Equal weights, implied +# weights and profile parsimony are selected through the `concavity` argument. + +#' Prepare a dataset for tree scoring +#' +#' `PrepareData()` extracts the matrices that the native C++ Fitch engine needs +#' in order to score a tree repeatedly, for use with the custom-search +#' functions [`TreeSearch()`], [`Ratchet()`] and [`Jackknife()`] (as their +#' `InitializeData` argument). Once finished, release it with [`ReleaseData()`] +#' (a formality: the object holds no external resources). +#' +#' @param dataset An object of \pkg{phangorn} class `phyDat`. +#' @param concavity Determines the optimality criterion under which trees are +#' scored: +#' `Inf` (the default) for equal-weights parsimony; +#' a finite, positive number for implied weighting with that concavity constant +#' \insertCite{Goloboff1993}{TreeSearch}; +#' or the string `"profile"` for profile parsimony +#' \insertCite{Faith2001}{TreeSearch}. +#' @return `PrepareData()` returns an object of class `ParsimonyData`: a list of +#' pre-extracted scoring matrices suitable for [`EdgeListScore()`]. +#' @template MRS +#' @seealso +#' Custom searches that consume the object: [`TreeSearch()`], [`Ratchet()`], +#' [`Jackknife()`]. +#' @references \insertAllCited{} +#' @family custom search functions +#' @useDynLib TreeSearch, .registration = TRUE +#' @importFrom Rcpp compileAttributes +#' @export +PrepareData <- function(dataset, concavity = Inf) { + if (!inherits(dataset, "phyDat")) { + stop("`dataset` must be a phyDat object.") + } + + useProfile <- identical(concavity, "profile") + if (useProfile) { + dataset <- PrepareDataProfile(dataset) + infoAmounts <- attr(dataset, "info.amounts") + } else { + infoAmounts <- NULL + } + + iw <- !useProfile && is.finite(concavity) + if (iw) { + if (concavity <= 0) { + stop("`concavity` must be positive, `Inf` for equal weights, ", + "or \"profile\" for profile parsimony.") + } + if (!("min.length" %in% names(attributes(dataset)))) { + dataset <- PrepareDataIW(dataset) + } + minSteps <- as.integer(attr(dataset, "min.length")) + } else { + minSteps <- integer(0) + } + + at <- attributes(dataset) + # `original_weight` (integer pattern multiplicities) is the base for + # character resampling; `weight` is the rescaled score weight passed to the + # C++ engine (identical for the usual integer weights). + structure( + list( + contrast = at[["contrast"]], + tip_data = matrix(unlist(dataset, use.names = FALSE), + nrow = length(dataset), byrow = TRUE), + weight = .ScaleWeight(at[["weight"]]), + levels = at[["levels"]], + min_steps = minSteps, + concavity = if (iw) as.double(concavity) else Inf, + info_amounts = infoAmounts, + original_weight = as.integer(at[["weight"]]), + index = at[["index"]], + tip.label = names(dataset), + nTip = length(dataset) + ), + class = "ParsimonyData") +} + +#' @describeIn PrepareData Release a prepared dataset. A no-op retained for the +#' custom-search `CleanUpData` hook (the object is managed by R's garbage +#' collector). +#' @param x A `ParsimonyData` object. +#' @return `ReleaseData()` returns its argument invisibly. +#' @export +ReleaseData <- function(x) { + invisible(x) +} + +#' @describeIn PrepareData Test whether an object is a `ParsimonyData` handle. +#' @return `is.ParsimonyData()` returns `TRUE` or `FALSE`. +#' @export +is.ParsimonyData <- function(x) { + inherits(x, "ParsimonyData") +} + +#' Prepare a single character for scoring +#' +#' Builds a one-character [`ParsimonyData`][PrepareData] object, chiefly for +#' [`RandomTreeScore()`] and testing. +#' +#' @param char State of each tip in turn, in a format understood by +#' [`TreeTools::MatrixToPhyDat()`] (e.g. the Morphy token string `"-0-0"`). +#' @return `SingleCharData()` returns a `ParsimonyData` object. +#' @examples +#' obj <- SingleCharData("-0-0") +#' RandomTreeScore(obj) +#' @template MRS +#' @family custom search functions +#' @importFrom TreeTools MatrixToPhyDat +#' @export +SingleCharData <- function(char) { + charStr <- paste0(paste0(char, collapse = ""), ";") + entries <- regmatches( + charStr, gregexpr("\\{[^{}]+\\}|\\([^()]+\\)|[^;]", charStr))[[1]] + nTip <- length(entries) + if (nTip < 1L) { + stop("Could not parse character `", paste0(char, collapse = ""), "`.") + } + m <- matrix(entries, ncol = 1L, + dimnames = list(as.character(seq_len(nTip)), NULL)) + PrepareData(MatrixToPhyDat(m)) +} + +# Canonicalize a gap treatment. Only "inapplicable" is supported natively; +# used by the deprecated `PhyDat2Morphy()`/`SingleCharMorphy()` shims to reject +# the MorphyLib-era missing/extra-state treatments. +.GapHandler <- function(gap) { + handler <- pmatch(tolower(gap), + c("inapplicable", "missing", "ambiguous", "extra state")) + if (is.na(handler)) { + stop("`gap` must be an abbreviation of \"inapplicable\", \"missing\" ", + "or \"extra state\"") + } + switch(handler, "inapplicable", "missing", "missing", "newstate") +} diff --git a/R/RandomTreeScore.R b/R/RandomTreeScore.R index bc5dc8b31..235e1d7fc 100644 --- a/R/RandomTreeScore.R +++ b/R/RandomTreeScore.R @@ -1,13 +1,13 @@ #' Parsimony score of random tree -#' +#' #' Generates a random tree topology and returns its parsimony score under #' equal weights. -#' -#' @param dataset A `phyDat` object (recommended) or a Morphy object created -#' with [`PhyDat2Morphy()`] (legacy; deprecated). +#' +#' @param dataset A `phyDat` object (recommended), or a `ParsimonyData` object +#' created with [`PrepareData()`]. #' #' @return `RandomTreeScore()` returns a numeric parsimony score. -#' @examples +#' @examples #' tokens <- matrix(c( #' 0, "-", "-", 1, 1, 2, #' 0, 1, 0, 1, 2, 2, @@ -18,14 +18,16 @@ #' @importFrom TreeTools RandomTree #' @export RandomTreeScore <- function(dataset) { - if (inherits(dataset, "morphyPtr")) { - nTip <- mpl_get_numtaxa(dataset) - if (nTip < 2) { - return(0L) + if (is.ParsimonyData(dataset)) { + labels <- dataset[["tip.label"]] + if (length(labels) < 2L) { + return(0) } - return(.Call(`RANDOM_TREE_SCORE`, as.integer(nTip), dataset)) + tree <- RandomTree(labels, root = TRUE) + # Return: + return(TreeScore(tree, dataset)) } - + nTip <- length(dataset) if (nTip < 2) { return(0) @@ -35,22 +37,22 @@ RandomTreeScore <- function(dataset) { } #' Random postorder tree -#' +#' #' @param nTip Integer specifying the number of tips to include in the tree #' (minimum 2). #' -#' @return A list with three elements, each a vector of integers, respectively +#' @return A list with three elements, each a vector of integers, respectively #' containing: -#' +#' #' - The parent of each tip and node, in order -#' +#' #' - The left child of each node -#' +#' #' - The right child of each node. #' #' @family tree generation functions #' @export -RandomMorphyTree <- function (nTip) { +RandomPostorderTree <- function (nTip) { if (nTip < 2) { stop("nTip < 2 not implemented: a tip is not a tree.") } diff --git a/R/Ratchet.R b/R/Ratchet.R index 280a0b7b8..fe406bdad 100644 --- a/R/Ratchet.R +++ b/R/Ratchet.R @@ -69,11 +69,11 @@ #' @family custom search functions #' @importFrom TreeTools RenumberEdges RenumberTips #' @export -Ratchet <- function(tree, dataset, - InitializeData = PhyDat2Morphy, - CleanUpData = UnloadMorphy, - TreeScorer = MorphyLength, - Bootstrapper = MorphyBootstrap, +Ratchet <- function(tree, dataset, concavity = Inf, + InitializeData = PrepareData, + CleanUpData = ReleaseData, + TreeScorer = EdgeListScore, + Bootstrapper = BootstrapTree, swappers = list(TBRSwap, SPRSwap, NNISwap), BootstrapSwapper = if (is.list(swappers)) swappers[[length(swappers)]] else swappers, @@ -93,9 +93,13 @@ Ratchet <- function(tree, dataset, edgeList <- tree[["edge"]] edgeList <- RenumberEdges(edgeList[, 1], edgeList[, 2]) - initializedData <- InitializeData(dataset) + if (identical(InitializeData, PrepareData)) { + initializedData <- PrepareData(dataset, concavity = concavity) + } else { + initializedData <- InitializeData(dataset) + } on.exit(initializedData <- CleanUpData(initializedData)) - + bestScore <- TreeScorer(edgeList[[1]], edgeList[[2]], initializedData, ...) if (verbosity > 0L) { diff --git a/R/RcppExports.R b/R/RcppExports.R index 42bd2b19a..af601f457 100644 --- a/R/RcppExports.R +++ b/R/RcppExports.R @@ -28,22 +28,6 @@ mi_key <- function(ni, nj) { .Call(`_TreeSearch_mi_key`, ni, nj) } -preorder_morphy <- function(edge, MorphyHandl) { - .Call(`_TreeSearch_preorder_morphy`, edge, MorphyHandl) -} - -preorder_morphy_by_char <- function(edge, MorphyHandls) { - .Call(`_TreeSearch_preorder_morphy_by_char`, edge, MorphyHandls) -} - -morphy_iw <- function(edge, MorphyHandls, weight, minScore, sequence, concavity, target) { - .Call(`_TreeSearch_morphy_iw`, edge, MorphyHandls, weight, minScore, sequence, concavity, target) -} - -morphy_profile <- function(edge, MorphyHandls, weight, sequence, profiles, target) { - .Call(`_TreeSearch_morphy_profile`, edge, MorphyHandls, weight, sequence, profiles, target) -} - quartet_concordance <- function(splits, characters) { .Call(`_TreeSearch_quartet_concordance`, splits, characters) } diff --git a/R/WhenFirstHit.R b/R/WhenFirstHit.R index 048c8fff5..5e0fbad36 100644 --- a/R/WhenFirstHit.R +++ b/R/WhenFirstHit.R @@ -4,7 +4,7 @@ #' This information is read from the `firstHit` attribute if present. #' If not, trees are taken to be listed in the order in which they were found, #' and named according to the search iteration in which they were first hit - -#' the situation when trees found by [`Morphy()`] are saved to file. +#' the situation when trees found by [`MaximizeParsimony()`] are saved to file. #' #' @param trees A list of trees, or a `multiPhylo` object. #' @return `trees`, with a `firstHit` attribute listing the number of trees hit @@ -23,7 +23,7 @@ #' attr(WhenFirstHit(trees), "firstHit") #' @family utility functions #' @seealso -#' - [`Morphy()`] +#' - [`MaximizeParsimony()`] #' @export WhenFirstHit <- function(trees) { if (is.null(attr(trees, "firstHit"))) { diff --git a/R/morphy-deprecated.R b/R/morphy-deprecated.R new file mode 100644 index 000000000..301840b62 --- /dev/null +++ b/R/morphy-deprecated.R @@ -0,0 +1,98 @@ +# Deprecated MorphyLib-era names, retained as thin shims over the native +# scoring layer (PrepareData / EdgeListScore / TreeScore / BootstrapTree / +# ReleaseData / is.ParsimonyData / RandomPostorderTree). Scheduled for removal +# after 2.0.x. + +#' Deprecated MorphyLib functions +#' +#' These MorphyLib-era functions are retained as deprecated aliases of their +#' native-scoring replacements and will be removed in a future release: +#' \itemize{ +#' \item `PhyDat2Morphy()` -> [`PrepareData()`] +#' \item `SingleCharMorphy()` -> [`SingleCharData()`] +#' \item `UnloadMorphy()` -> [`ReleaseData()`] +#' \item `is.morphyPtr()` -> [`is.ParsimonyData()`] +#' \item `MorphyLength()` -> [`EdgeListScore()`] +#' \item `MorphyTreeLength()` -> [`TreeScore()`] +#' \item `MorphyBootstrap()` -> [`BootstrapTree()`] +#' \item `RandomMorphyTree()` -> [`RandomPostorderTree()`] +#' } +#' +#' @param phy,char,morphyObj,tree,parent,child,edgeList,nTip,gap,weight,inPostorder,nTaxa,\dots +#' Passed to the replacement function. +#' @return The value of the corresponding replacement function. +#' @name TreeSearch-deprecated +#' @keywords internal +NULL + +#' @rdname TreeSearch-deprecated +#' @export +PhyDat2Morphy <- function(phy, gap = "inapplicable", + weight = attr(phy, "weight")) { + .Deprecated("PrepareData") + if (!inherits(phy, "phyDat")) { + stop("Invalid data type ", class(phy), "; should be phyDat.") + } + if (.GapHandler(gap) != "inapplicable") { + stop("Only the `inapplicable` gap treatment is supported; recode your ", + "data to treat gaps as missing or as an extra state.") + } + if (!is.null(weight)) { + attr(phy, "weight") <- rep_len(weight, attr(phy, "nr")) + } + PrepareData(phy) +} + +#' @rdname TreeSearch-deprecated +#' @export +SingleCharMorphy <- function(char, gap = "inapp") { + .Deprecated("SingleCharData") + if (.GapHandler(gap) != "inapplicable") { + stop("Only the `inapplicable` gap treatment is supported.") + } + SingleCharData(char) +} + +#' @rdname TreeSearch-deprecated +#' @export +UnloadMorphy <- function(morphyObj) { + .Deprecated("ReleaseData") + ReleaseData(morphyObj) + invisible(0L) +} + +#' @rdname TreeSearch-deprecated +#' @export +is.morphyPtr <- function(morphyObj) { + .Deprecated("is.ParsimonyData") + is.ParsimonyData(morphyObj) +} + +#' @rdname TreeSearch-deprecated +#' @export +MorphyLength <- function(parent, child, morphyObj, inPostorder = FALSE, + nTaxa = NULL) { + .Deprecated("EdgeListScore") + EdgeListScore(parent, child, morphyObj, inPostorder = inPostorder) +} + +#' @rdname TreeSearch-deprecated +#' @export +MorphyTreeLength <- function(tree, morphyObj) { + .Deprecated("TreeScore") + TreeScore(tree, morphyObj) +} + +#' @rdname TreeSearch-deprecated +#' @export +MorphyBootstrap <- function(edgeList, morphyObj, ...) { + .Deprecated("BootstrapTree") + BootstrapTree(edgeList, morphyObj, ...) +} + +#' @rdname TreeSearch-deprecated +#' @export +RandomMorphyTree <- function(nTip) { + .Deprecated("RandomPostorderTree") + RandomPostorderTree(nTip) +} diff --git a/R/mpl_morphy_objects.R b/R/mpl_morphy_objects.R deleted file mode 100644 index d060a1559..000000000 --- a/R/mpl_morphy_objects.R +++ /dev/null @@ -1,277 +0,0 @@ -#' Details the attributes of a morphy object -#' -#' @param object A Morphy object -#' @param \dots any other parameters... -#' -#' @return A list detailing the number of taxa, internal nodes, and characters and their weights. -#' -#' @template MRS -#' @method summary morphyPtr -#' @family Morphy API functions -#' @importFrom Rcpp compileAttributes -#' @export -summary.morphyPtr <- function (object, ...) { - # Return: - structure(class = "summary.morphyPtr", list( - nTax = mpl_get_numtaxa(object), - nChar = mpl_get_num_charac(object), - nInternal = mpl_get_num_internal_nodes(object), - charWeights = MorphyWeights(object), - allStates = mpl_get_symbols(object) - )) -} - -#' Set and get the character weightings associated with a Morphy object. -#' -#' `MorphyWeights()` details the approximate and exact weights associated with -#' characters in a `Morphy` object; `SetMorphyWeights()` edits them. -#' -#' @inheritParams MorphyTreeLength -#' @return `MorphyWeights()` returns a data frame with two named rows and -#' one column per character pattern: -#' row 1, `approx`, is a list of integers specifying the approximate (integral) -#' weights used by MorphyLib; -#' row 2, `exact`, is a list of numerics specifying the exact weights specified -#' by the user. -#' -#' @examples -#' tokens <- matrix(c( -#' 0, 0, 0, 1, 1, 2, -#' 0, 0, 0, 0, 0, 0), byrow = TRUE, nrow = 2L, -#' dimnames = list(letters[1:2], NULL)) -#' pd <- TreeTools::MatrixToPhyDat(tokens) -#' morphyObj <- PhyDat2Morphy(pd) -#' MorphyWeights(morphyObj) -#' if (SetMorphyWeights(c(1, 1.5, 2/3), morphyObj) != 0L) message("Errored") -#' MorphyWeights(morphyObj) -#' morphyObj <- UnloadMorphy(morphyObj) -#' @template MRS -#' @family Morphy API functions -#' @export -MorphyWeights <- function (morphyObj) { - vapply(seq_len(mpl_get_num_charac(morphyObj)), mpl_get_charac_weight, - list("approx" = 0L, "exact" = 0), morphyobj = morphyObj) -} - -#' @rdname MorphyWeights -#' @param weight A vector listing the new weights to be applied to each character -#' @param checkInput Whether to sanity-check input data before applying. -#' Defaults to `TRUE` to protect the user from crashes. -#' -#' @return `SetMorphyWeights()` returns the Morphy error code generated when -#' applying `weight`. -#' @export -SetMorphyWeights <- function (weight, morphyObj, checkInput = TRUE) { - if (checkInput) if (length(weight) != mpl_get_num_charac(morphyObj)) { - stop("Number of weights not equal to number of character entries.") - } - errors <- vapply(seq_along(weight), - function (i) mpl_set_charac_weight(i, weight[i], morphyObj), - integer(1)) - if(any(errors != 0)) warning("Morphy Error encountered: ", - mpl_translate_error(errors[errors < 0])) - mpl_apply_tipdata(morphyObj) -} - -#' Read how a Morphy Object handles the inapplicable token -#' -#' Gaps represented by the inapplicable token can be treated as "missing data", -#' i.e. as equivalent to the ambiguous token `?`; as an extra state, equivalent -#' to other states such as `0` or `1`; or as "inapplicable data" using the -#' algorithm of Brazeau, Guillerme and Smith (2019). -#' -#' @inheritParams MorphyTreeLength -#' -#' @return `GapHandler()` returns a character string stating how -#' gaps are handled by `morphyObj`. -#' @examples -#' morphyObj <- SingleCharMorphy("-0-0", "Extra") -#' GapHandler(morphyObj) -#' morphyObj <- UnloadMorphy(morphyObj) -#' @family Morphy API functions -#' @template MRS -#' @export -GapHandler <- function (morphyObj) { - if (!is.morphyPtr(morphyObj)) { - stop("`morphyObj` is not a valid Morphy object") - } - - ret <- c("Inapplicable", "Missing data", "Extra state", "Unspecified") # 4 = GAP_MAX - handler <- mpl_get_gaphandl(morphyObj) - if (handler < 0L) { - stop("Morphy object error: ", mpl_translate_error(handler)) - } - # Return: - ret[1L + handler] -} - -#' Initialize a Morphy object from a `phyDat` object -#' -#' Creates a new Morphy object with the same size and characters as the -#' `phyDat` object. -#' Once finished with the object, it should be destroyed using -#' [`UnloadMorphy()`] to free the allocated memory. -#' -#' -#' @param phy An object of \pkg{phangorn} class \code{phyDat}. -#' @param gap An unambiguous abbreviation of `inapplicable`, `ambiguous` -#' (= `missing`), or `extra state`, specifying how gaps will be handled. -#' @param weight Numeric giving weight to apply to each character. -#' Will be recycled. -#' @return `PhyDat2Morphy()` returns a pointer to an initialized Morphy object. -#' -#' @examples -#' data("Lobo", package="TreeTools") -#' morphyObj <- PhyDat2Morphy(Lobo.phy) -#' # Set object to be destroyed at end of session or closure of function -#' # on.exit(morphyObj <- UnloadMorphy(morphyObj), add = TRUE) -#' -#' # Do something with pointer -#' # .... -#' -#' # Or, instead of on.exit, manually destroy morphy object and free memory: -#' morphyObj <- UnloadMorphy(morphyObj) -#' @template MRS -#' @family Morphy API functions -#' @importFrom TreeTools PhyToString -#' @export -PhyDat2Morphy <- function(phy, gap = "inapplicable", - weight = attr(phy, "weight")) { - - if (!inherits(phy, "phyDat")) { - stop("Invalid data type ", class(phy), "; should be phyDat.") - } - - morphyObj <- structure(mpl_new_Morphy(), class = "morphyPtr") - nTax <- length(phy) - nChar <- attr(phy, "nr") - weight <- rep_len(weight, nChar) - - if (mpl_init_Morphy(nTax, nChar, morphyObj) -> error) { - stop("Error ", mpl_translate_error(error), " in mpl_init_Morphy") #nocov - } - if (mpl_set_gaphandl(.GapHandler(gap), morphyObj) -> error) { - stop("Error ", mpl_translate_error(error), " in mpl_set_gaphandl") #nocov - } - if (mpl_attach_rawdata(PhyToString(phy, ps = ";", useIndex = FALSE, - byTaxon = TRUE, concatenate = TRUE), - morphyObj) -> error) { - stop("Error ", mpl_translate_error(error), " in mpl_attach_rawdata") #nocov - } - if (mpl_set_num_internal_nodes(nTax - 1L, morphyObj) -> error) { # One is the "dummy root" - stop("Error ", mpl_translate_error(error), " in mpl_set_num_internal_nodes") - } - if (any(vapply(seq_len(nChar), - function (i) mpl_set_parsim_t(i, "FITCH", morphyObj), - NA_integer_) -> error)) { - stop("Error ", mpl_translate_error(min(error)), "in mpl_set_parsim_t") #nocov - } - if (any(vapply(seq_len(nChar), - function (i) mpl_set_charac_weight(i, weight[[i]], morphyObj), - NA_integer_) -> error)) { - stop("Error ", mpl_translate_error(min(error)), "in mpl_set_charac_weight") #nocov - } - if (mpl_apply_tipdata(morphyObj) -> error) { - stop("Error ", mpl_translate_error(error), "in mpl_apply_tipdata") #nocov - } - # Return: - morphyObj -} - -#' Translate a gap treatment into a string in the format expected by Morphy -#' @param gap Character vector: how should gaps be handled? -#' @return Character string that can be translated into a gap handling strategy -#' by Morphy. -#' @keywords internal -.GapHandler <- function(gap) { - handler <- pmatch(tolower(gap), - c("inapplicable", "missing", "ambiguous", "extra state")) - if (is.na(handler)) { - stop("`treatment` must be an abbreviation of \"inapplicable\", ", - "\"missing\" or \"extra state\"") - } - - # Return: - switch(handler, "inapplicable", "missing", "missing", "newstate") -} - -#' Check for error whilst modifying Morphy object -#' @param action action to perform -#' -#' @family Morphy API functions -#' @keywords internal -#' @export -MorphyErrorCheck <- function(action) { - if (action) { - stop("Morphy object encountered error ", mpl_translate_error(action), "\n") - } -} - -#' Morphy object from single character -#' -#' @param char State of each character at each tip in turn, in a format that will be converted -#' to a character string by \code{\link{paste0}(char, ";", collapse="")}. -#' @inheritParams PhyDat2Morphy -#' -#' @return A pointer to an object of class `morphyObj`. -#' Don't forget to unload it when you've finished with it. -#' -#' @examples -#' morphyObj <- SingleCharMorphy("-0-0", gap = "Extra") -#' RandomTreeScore(morphyObj) -#' morphyObj <- UnloadMorphy(morphyObj) -#' @template MRS -#' @seealso -#' Score a tree: [`MorphyTreeLength()`] -#' -#' @family Morphy API functions -#' @export -SingleCharMorphy <- function (char, gap = "inapp") { - char <- paste0(char, ";") - entries <- gregexpr("\\{[^\\{]+\\}|\\([^\\()]+\\)|[^;]", char) - nTip <- length(entries[[1]]) - morphyObj <- mpl_new_Morphy() - MorphyErrorCheck(mpl_init_Morphy(nTip, 1, morphyObj)) - MorphyErrorCheck(mpl_set_gaphandl(.GapHandler(gap), morphyObj)) - MorphyErrorCheck(mpl_attach_rawdata(char, morphyObj)) - MorphyErrorCheck(mpl_set_num_internal_nodes(nTip - 1L, morphyObj)) - MorphyErrorCheck(mpl_set_parsim_t(1, "FITCH", morphyObj)) - MorphyErrorCheck(mpl_set_charac_weight(1, 1, morphyObj)) - MorphyErrorCheck(mpl_apply_tipdata(morphyObj)) - class(morphyObj) <- "morphyPtr" - morphyObj -} - -#' Is an object a valid Morphy object? -#' @inheritParams MorphyTreeLength -#' @return `is.morphyPtr()` returns `TRUE` if `morphyObj` is a valid morphy -#' pointer, `FALSE` otherwise. -#' @template MRS -#' @family Morphy API functions -#' @export -is.morphyPtr <- function (morphyObj) { - inherits(morphyObj, "morphyPtr") -} - -#' Destroy a Morphy object -#' -#' Destroys a previously-created Morphy object. -#' -#' Best practice is to call `morphyObj <- UnloadMorphy(morphyObj)` -#' Failure to do so will cause a crash if `UnloadMorphy()` is called on an -#' object that has already been destroyed -#' -#' @inheritParams MorphyTreeLength -#' @return Morphy error code, decipherable using \code{\link{mpl_translate_error}} -#' @author Martin R. Smith -#' @family Morphy API functions -#' @export -UnloadMorphy <- function (morphyObj) { - if (!is.morphyPtr(morphyObj)) { - stop ("Object is not a valid pointer; cannot destroy.") - } - if (mpl_delete_Morphy(morphyObj) -> error) { - stop("Error ", mpl_translate_error(error), "in mpl_delete_Morphy") #nocov - } - return (error) -} diff --git a/R/mpl_morphyex.R b/R/mpl_morphyex.R deleted file mode 100644 index 6a7ea0f1f..000000000 --- a/R/mpl_morphyex.R +++ /dev/null @@ -1,488 +0,0 @@ -#' Converts a numeric error code to human-readable format -#' -#' @param errorCode Non-positive integer to be converted -#' -#' @return A character string corresponding to the provided error code -#' -#' @examples mpl_translate_error(-1) # "ERR_INVALID_SYMBOL" -#' -#' @template MRS -#' @family Morphy API functions -#' @keywords internal -#' @export - -mpl_translate_error <- function (errorCode) { - mplErrorCodes <- rev(c( - "ERR_EX_DATA_CONF", - "ERR_OUT_OF_BOUNDS", - "ERR_CASE_NOT_IMPL", - "ERR_UNKNOWN_CHTYPE", - "ERR_SYMBOL_MISMATCH", - "ERR_MATCHING_PARENTHS", - "ERR_ATTEMPT_OVERWRITE", - "ERR_NO_DIMENSIONS", - "ERR_DIMENS_UNDER", - "ERR_DIMENS_OVER", - "ERR_NO_DATA", - "ERR_BAD_MALLOC", - "ERR_BAD_PARAM", - "ERR_UNEXP_NULLPTR", - "ERR_INVALID_SYMBOL", - "ERR_NO_ERROR")) - return (mplErrorCodes[1-errorCode]) -} - -#' Creates a new instance of a Morphy object -#' -#' Creates a new empty Morphy object. All fields are unpopulated -#' and uninitialised. -#' -#' -#' @return A void pointer to the Morphy instance. NULL if unsuccessful. -#' -#' @examples morphyObj <- mpl_new_Morphy() # Create new object -#' ## Do some stuff ... ## -#' mpl_delete_Morphy(morphyObj) # Delete when done -#' -#' @author Martin Brazeau -#' @useDynLib TreeSearch, .registration = TRUE -#' @keywords internal -#' @family Morphy API functions -#' @export -mpl_new_Morphy <- function() { - .Call(`_R_wrap_mpl_new_Morphy`) -} - -#' Destroys an instance of a Morphy object. -#' -#' Destroys an instance of the Morphy object, calling all -#' destructor for internal object completely returning the memory to the system. -#' -#' @param morphyobj A Morphy object to be destroyed. -#' -#' @return A Morphy error code. -#' -#' @author Martin Brazeau -#' @family Morphy API functions -#' @keywords internal -#' @export -mpl_delete_Morphy <- function(morphyobj) { - .Call(`_R_wrap_mpl_delete_Morphy`, morphyobj) -} - - -#' Get / set gap handler from a Morphy object. -#' -#' 0 = inapplicable; 1 = missing; 2 = extra -#' -#' @return `mpl_get_gaphandl()` returns an integer corresponding to the gap -#' handling approach. -#' -#' -#' @family Morphy API functions -#' @keywords internal -#' @export -mpl_get_gaphandl <- function (morphyobj) { - .Call(`_R_wrap_mpl_get_gaphandl`, morphyobj) -} -#' @rdname mpl_get_gaphandl -#' @keywords internal -#' @return `mpl_set_gaphandl()` returns a Morphy error code. -#' @export -mpl_set_gaphandl <- function (handl, morphyobj) { - .Call(`_R_wrap_mpl_set_gaphandl`, handl, morphyobj) -} - -#' Sets up the dimensions of the dataset. -#' -#' Provides initial dimensions for the dataset, which will -#' constrain any input matrix supplied to Morphy. -#' -#' @param morphyobj An instance of the Morphy object. -#' @param numtaxa The number of taxa (or tips/terminals). -#' @param numchars The number of characters (i.e. transformation series) in the -#' data set. -#' -#' @return Morphy error code. -#' -#' @author Martin Brazeau -#' @family Morphy API functions -#' @keywords internal -#' @export -mpl_init_Morphy <- function(numtaxa, numchars, morphyobj) { - .Call(`_R_wrap_mpl_init_Morphy`, as.integer(numtaxa), as.integer(numchars), - morphyobj) -} - -#' Retrieve the number of taxa (rows) in the dataset. -#' -#' Retrieves the number of taxa (rows) in the dataset. -#' -#' @param morphyobj An instance of the Morphy object. -#' -#' @return The number of taxa if success, otherwise an error code. -#' -#' @author Martin Brazeau -#' @family Morphy API functions -#' @keywords internal -#' @export -mpl_get_numtaxa <- function(morphyobj) { - .Call(`_R_wrap_mpl_get_numtaxa`, morphyobj) -} - -#' Set the weight of a character in the dataset -#' -#' Sets the weight of a character in the dataset. -#' -#' @param charID Number of the character (i.e. first character is number 1) -#' @param weight Weight to assign -#' @param morphyobj An instance of the Morphy object. -#' -#' @return An error code. -#' -#' @template MRS -#' @family Morphy API functions -#' @keywords internal -#' @export -mpl_set_charac_weight <- function (charID, weight, morphyobj) { - .Call(`_R_wrap_mpl_set_charac_weight`, as.integer(charID - 1L), - as.numeric(weight), morphyobj) -} - -#' Retrieve the weight of a character in the dataset -#' -#' Gets the weights of a character in the dataset. -#' -#' @param charID Number of the character (i.e. first character is number 1) -#' @param morphyobj An instance of the Morphy object. -#' -#' @return A list, detailing (item 1) the exact weight of the character; -#' (item 2) the integer approximation used by Morphy. -#' -#' @template MRS -#' @family Morphy API functions -#' @keywords internal -#' @export -mpl_get_charac_weight <- function (charID, morphyobj) { - .Call(`_R_wrap_mpl_get_charac_weight`, as.integer(charID) - 1L, morphyobj) -} - -#' Retrieve the number of character (columns) in the dataset. -#' -#' Retrieves the number of character (columns) in the dataset. -#' -#' @param morphyobj An instance of the Morphy object. -#' -#' @return The number of internal nodes. -#' -#' @author Martin Brazeau -#' @family Morphy API functions -#' @keywords internal -#' @export -mpl_get_num_charac <- function(morphyobj) { - .Call(`_R_wrap_mpl_get_num_charac`, morphyobj) -} - -#' Attach a caller-specified list of symbols. -#' -#' Allows the caller to specify a list of symbols in the data matrix, -#' otherwise, the symbols list used by Morphy will be extracted from the matrix. -#' The symbols list must match the symbols provided in the matrix. When Morphy -#' extracts symbols from the matrix, their ordering is alphanumeric, according to -#' their ASCII codes (i.e. "+0123...ABCD...abcd..."). Loading a user-specified -#' symbols list will override this ordering. Symbols loaded in either the list or -#' the matrix must be valid Morphy character state symbols as defined in the -#' statedata.h header file. The list must end with a semicolon. -#' -#' @param symbols A C-style (i.e. NULL-terminated) string of valid state symbols. -#' @param morphyobj An instance of the Morphy object. -#' -#' @return Morphy error code. -#' -#' @author Martin Brazeau -#' @family Morphy API functions -#' @keywords internal -#' @export -mpl_attach_symbols <- function(symbols, morphyobj) { - .Call(`_R_wrap_mpl_attach_symbols`, symbols, morphyobj) -} - -#' Attach raw character state data (i.e. tip data). -#' -#' Attaches a raw data character state matrix in the form of a C-style -#' (i.e. NULL-terminated) string. This can be the matrix block extracted from a -#' Nexus file or an `xread` table format. -#' The matrix should contain no leaf labels. -#' -#' @param rawdata C-style string corresponding to the tip data for each taxon in -#' turn. -#' @param morphyobj An instance of the Morphy object. -#' -#' @return Morphy error code. -#' -#' @author Martin Brazeau -#' @family Morphy API functions -#' @keywords internal -#' @export -mpl_attach_rawdata <- function(rawdata, morphyobj) { - .Call(`_R_wrap_mpl_attach_rawdata`, rawdata, morphyobj) -} - -#' Retrieves the current list of symbols. -#' -#' Returns a pointer to the string of character state symbols -#' currently being used by Morphy (i.e. either the list of symbols extracted -#' from the matrix, or the caller-specified values). -#' -#' @param morphyobj An instance of the Morphy object. -#' -#' @return A C-style (null-terminated) string of the character state symbols -#' being used. NULL if failure. -#' -#' @author Martin Brazeau -#' @family Morphy API functions -#' @keywords internal -#' @export - -mpl_get_symbols <- function(morphyobj) { - .Call(`_R_wrap_mpl_get_symbols`, morphyobj) -} - -#' Sets a character's parsimony function type -#' -#' Set the parsimony function type to one defined in the -#' morphydefs.h header file. Setting the character to type NONE_T will also -#' cause it to be excluded from any further calculations. -#' -#' @param char_id The number of the character (transformation series) as defined -#' in the input matrix. The first character is numbered 1 (one). -#' @param tname The parsimony function type as defined in morphydefs.h -#' @param morphyobj An instance of the Morphy object. -#' -#' @return A Morphy error code. -#' -#' @author Martin Brazeau -#' @family Morphy API functions -#' @keywords internal -#' @export -mpl_set_parsim_t <- function(char_id, tname = "typename", morphyobj) { - .Call(`_R_wrap_mpl_set_parsim_t`, as.integer(char_id - 1L), tname, morphyobj) -} - -#' Sets the number of internal nodes in the dataset -#' -#' This specifies the number of internal nodes over which -#' reconstruction sets need to be made. It is up to the caller to ensure the -#' correct number of nodes and the relationships between them. -#' -#' @param numnodes The desired number of internal nodes. -#' @param morphyobj An instance of the Morphy object. -#' -#' @return A Morphy error code. -#' -#' @author Martin Brazeau -#' @family Morphy API functions -#' @keywords internal -#' @export -mpl_set_num_internal_nodes <- function(numnodes, morphyobj) { - .Call(`_R_wrap_mpl_set_num_internal_nodes`, as.integer(numnodes), morphyobj) -} - -#' Gets the number of internal nodal reconstruction sets being used by -#' MorphyLib. -#' -#' Gets the number of internal nodal reconstruction sets being used -#' by MorphyLib. -#' -#' @param morphyobj An instance of the Morphy object. -#' -#' @return The number of internal nodes. -#' -#' @author Martin Brazeau -#' @family Morphy API functions -#' @keywords internal -#' @export - -mpl_get_num_internal_nodes <- function(morphyobj) { - .Call(`_R_wrap_mpl_get_num_internal_nodes`, morphyobj) -} - -#' Commits parameters prior to nodal set calculations. -#' -#' Once the caller is satisfied with the setup of types, weights, -#' and partitioning, this function must be called, thereby committing the -#' parameters until any changes are made. If no character types have been -#' assigned, the function will fail with an error code. -#' -#' @param morphyobj An instance of the Morphy object. -#' -#' @return A Morphy error code. -#' @family Morphy API functions -#' -#' @author Martin Brazeau -#' @keywords internal -#' @export -mpl_apply_tipdata <- function(morphyobj) { - .Call(`_R_wrap_mpl_apply_tipdata`, morphyobj) -} - -#' Reconstructs the first (downpass) nodal reconstructions -#' -#' Reconstructs the preliminary nodal set for all characters for a -#' particular node. This function is called over a postorder sequence of internal -#' nodes where left and right descendants are known. -#' Because this function needs to be fairly high-performance, it does not do much -#' checking for parameter validity, thus unsafe usage of this function might not -#' be caught. It is up to calling functions to ensure that the appropriate -#' parameters have been set before use. -#' -#' @param node_id The index of the node being reconstructed. -#' @param left_id The index of the left descendant. -#' @param right_id The index of the right descendant. -#' @param morphyobj An instance of the Morphy object. -#' -#' @return The integral parsimony length (right now) -#' -#' @author Martin Brazeau -#' @family Morphy API functions -#' @keywords internal -#' @export -mpl_first_down_recon <- function(node_id, left_id, right_id, morphyobj) { - .Call(`_R_wrap_mpl_first_down_recon`, as.integer(node_id), as.integer(left_id), as.integer(right_id), morphyobj) -} - -#' Reconstructs the second (uppass) nodal reconstructions. -#' -#' Reconstructs second-pass nodal sets. For normal (all-applicable) -#' characters, this is the final pass. This function is called over a preorder -#' sequence of nodes where left, right, and ancestral nodes are known. -#' Because this function needs to be fairly high-performance, it does not do much -#' checking for parameter validity, thus unsafe usage of this function might not -#' be caught. It is up to calling functions to ensure that the appropriate -#' parameters have been set before use. -#' -#' @param node_id The index of the node being reconstructed. -#' @param left_id The index of the left descendant. -#' @param right_id The index of the right descendant. -#' @param anc_id The index of the immediate ancestor of the node. -#' @param morphyobj An instance of the Morphy object. -#' -#' @return A null value (for now). -#' -#' @author Thomas Guillerme -#' @family Morphy API functions -#' @keywords internal -#' @export -mpl_first_up_recon <- function(node_id, left_id, right_id, anc_id, morphyobj) { - .Call(`_R_wrap_mpl_first_up_recon`, as.integer(node_id), as.integer(left_id), - as.integer(right_id), as.integer(anc_id), morphyobj) -} - -#' Performs the second nodal reconstructions for characters with -#' inapplicability. -#' -#' Updates the nodal sets that had ambiguous unions with the -#' inapplicable state and calculates steps involving applicable states after -#' the update. -#' Because this function needs to be fairly high-performance, it does not do much -#' checking for parameter validity, thus unsafe usage of this function might not -#' be caught. It is up to calling functions to ensure that the appropriate -#' parameters have been set before use. -#' -#' @param node_id The index of the node being reconstructed. -#' @param left_id The index of the left descendant. -#' @param right_id The index of the right descendant. -#' @param morphyobj An instance of the Morphy object. -#' -#' @return The integral parsimony length (right now) -#' -#' @author Thomas Guillerme -#' @family Morphy API functions -#' @keywords internal -#' @export -mpl_second_down_recon <- function(node_id, left_id, right_id, morphyobj) { - .Call(`_R_wrap_mpl_second_down_recon`, as.integer(node_id), as.integer(left_id), - as.integer(right_id), morphyobj) -} - -#' Finalises the ancestral state reconstructions for characters with -#' inapplicable values. -#' -#' Finalises the nodal sets for any characters that may have involved -#' the inapplicable token and counts excess regions of applicability at nodes -#' having at least two descendant subtrees that possess any applicable characters. -#' Because this function needs to be fairly high-performance, it does not do much -#' checking for parameter validity, thus unsafe usage of this function might not -#' be caught. It is up to calling functions to ensure that the appropriate -#' parameters have been set before use. -#' -#' @param node_id The index of the node being reconstructed. -#' @param left_id The index of the left descendant. -#' @param right_id The index of the right descendant. -#' @param anc_id The index of the immediate ancestor of the node. -#' @param morphyobj An instance of the Morphy object. -#' -#' @return The integral parsimony length (right now) -#' -#' @author Thomas Guillerme -#' @family Morphy API functions -#' @keywords internal -#' @export -mpl_second_up_recon <- function(node_id, left_id, right_id, anc_id, morphyobj) { - .Call(`_R_wrap_mpl_second_up_recon`, as.integer(node_id), as.integer(left_id), - as.integer(right_id), as.integer(anc_id), morphyobj) -} - -#' Initial update of tip values following uppass reconstruction. -#' -#' Ambiguous terminal state sets need to be resolved after the first uppass -#' based on descendant state values in order for local reoptimisation procedures -#' to be accurate and for inapplicable step counting to proceed accurately. This -#' function calls updaters for the records of states active on the subtrees, -#' thereby allowing the second downpass to accurately reconstruct subtree state -#' activity. -#' Because this function needs to be fairly high-performance, it does not do much -#' checking for parameter validity, thus unsafe usage of this function might not -#' be caught. It is up to calling functions to ensure that the appropriate -#' parameters have been set before use. -#' -#' @param tip_id The index of the tip being updated. -#' @param anc_id The index of the tip's immediate ancestor. -#' @param morphyobj An instance of the Morphy object. -#' -#' @return The integral parsimony length (right now) -#' -#' @seealso A null value (for now). -#' -#' @author Thomas Guillerme -#' @family Morphy API functions -#' @keywords internal -#' @export -mpl_update_tip <- function(tip_id, anc_id, morphyobj) { - .Call(`_R_wrap_mpl_update_tip`, as.integer(tip_id), as.integer(anc_id), morphyobj) -} - -#' Updates the nodal sets for a lower ("dummy") root node -#' -#' If trees are rooted, then Morphy uppass functions -#' require a lower or "dummy" root in order to function properly. This -#' function should be called to set the nodal state sets to the dummy -#' root. The nodal set will be equal to the set of the root node, unless -#' there is an ambiguous union of applicable and gap tokens when gaps are -#' treated as in applicable. In which case, the set union is resolved in -#' favour of any applicable tokens in the set. -#' -#' @param l_root_id The index of the lower root. -#' @param root_id The index of the upper root node. -#' @param morphyobj An instance of the Morphy object. -#' -#' @return A Morphy error code. -#' -#' @author Thomas Guillerme -#' @family Morphy API functions -#' @keywords internal -#' @export -mpl_update_lower_root <- function(l_root_id, root_id, morphyobj) { - .Call(`_R_wrap_mpl_update_lower_root`, as.integer(l_root_id), as.integer(root_id), - morphyobj) -} diff --git a/R/tree_length.R b/R/tree_length.R index ad39303e4..28b1cd47e 100644 --- a/R/tree_length.R +++ b/R/tree_length.R @@ -504,108 +504,69 @@ FastCharacterLength <- function(tree, dataset) { .ScaleWeight(at$weight), at$levels) } -#' Calculate parsimony score from Morphy object -#' -#' This function must be passed a valid Morphy object, or R may crash. -#' For most users, the function [`TreeLength()`] will be more appropriate. -#' +#' Score a tree from prepared data +#' +#' `TreeScore()` and `EdgeListScore()` compute the parsimony score of a tree +#' with the native C++ Fitch engine, using a dataset prepared by +#' [`PrepareData()`]. +#' `EdgeListScore()` is the low-level scorer used as the default `TreeScorer` +#' by the custom-search functions; `TreeScore()` is a convenience wrapper that +#' takes a `phylo` tree. Most users want the higher-level [`TreeLength()`]. +#' #' @template labelledTreeParam -#' @param morphyObj Object of class `morphy`, perhaps created with -#' [`PhyDat2Morphy()`]. +#' @param dataset A `ParsimonyData` object from [`PrepareData()`]. #' -#' @return `MorphyTreeLength()` returns the length of the tree, -#' after applying weighting. +#' @return `TreeScore()` returns the parsimony score of `tree` under the +#' optimality criterion baked into `dataset` (equal weights, implied weights or +#' profile parsimony). #' -#' @seealso PhyDat2Morphy +#' @seealso [`PrepareData()`]; user-facing scoring with [`TreeLength()`]. #' #' @family tree scoring #' @author Martin R. Smith #' @keywords internal +#' @importFrom TreeTools RenumberEdges RenumberTips #' @export -MorphyTreeLength <- function(tree, morphyObj) { - if (!is.morphyPtr(morphyObj)) { - stop("`morphyObj` must be a valid Morphy pointer") +TreeScore <- function(tree, dataset) { + if (!is.ParsimonyData(dataset)) { + stop("`dataset` must be a ParsimonyData object; see ?PrepareData.") } - nTaxa <- mpl_get_numtaxa(morphyObj) + nTaxa <- dataset[["nTip"]] if (nTaxa != length(tree[["tip.label"]])) { - stop ("Number of taxa in Morphy object (", nTaxa, - ") not equal to number of tips in tree") + stop("Number of taxa in dataset (", nTaxa, + ") not equal to number of tips in tree") } - treeOrder <- attr(tree, "order") - inPostorder <- (!is.null(treeOrder) && treeOrder == "postorder") - treeEdge <- tree[["edge"]] - + tree <- RenumberTips(tree, dataset[["tip.label"]]) + el <- RenumberEdges(tree[["edge"]][, 1], tree[["edge"]][, 2]) # Return: - MorphyLength(treeEdge[, 1], treeEdge[, 2], morphyObj, inPostorder, nTaxa) + EdgeListScore(el[[1]], el[[2]], dataset) } -#' @describeIn MorphyTreeLength Faster function that requires internal tree -#' parameters. Node numbering must increase monotonically away from root. +#' @describeIn TreeScore Low-level scorer taking parent and child vectors; the +#' default `TreeScorer` for [`TreeSearch()`], [`Ratchet()`] and +#' [`Jackknife()`]. Scores via the native `ts_fitch_score()` kernel, which +#' handles the Brazeau-Guillerme-Smith inapplicable algorithm correctly +#' (including the `{1-}` case that MorphyLib mis-scored). #' @inheritParams RearrangeEdges -#' @author Martin R. Smith -#' @keywords internal -#' @importFrom TreeTools PostorderOrder Preorder -#' @importFrom fastmatch fmatch +#' @param inPostorder Logical: are the edges already in postorder? If `FALSE` +#' (the default) they are reordered before scoring. +#' @param \dots Unused; for interface compatibility with custom `TreeScorer`s. +#' @return `EdgeListScore()` returns the parsimony score (a numeric). +#' @importFrom TreeTools Preorder PostorderOrder #' @export -MorphyLength <- function(parent, child, morphyObj, inPostorder = FALSE, - nTaxa = mpl_get_numtaxa(morphyObj)) { +EdgeListScore <- function(parent, child, dataset, inPostorder = FALSE, ...) { if (!inPostorder) { edgeList <- Preorder(cbind(parent, child)) - edgeList <- edgeList[PostorderOrder(edgeList), ] + edgeList <- edgeList[PostorderOrder(edgeList), , drop = FALSE] parent <- edgeList[, 1] child <- edgeList[, 2] } - if (!inherits(morphyObj, "morphyPtr")) { - stop("`morphyObj` must be a Morphy pointer. See ?LoadMorphy().") - } - if (nTaxa < 1L) { - # Run this test after we're sure that morphyObj is a morphyPtr, or lazy - # evaluation of nTaxa will cause a crash. - stop("Error: ", mpl_translate_error(nTaxa)) - } - - maxNode <- nTaxa + mpl_get_num_internal_nodes(morphyObj) - rootNode <- nTaxa + 1L - allNodes <- rootNode:maxNode - - parentOf <- parent[fmatch(seq_len(maxNode), child)] - parentOf[rootNode] <- rootNode # Root node's parent is a dummy node - leftChild <- child[length(parent) + 1L - fmatch(allNodes, rev(parent))] - rightChild <- child[fmatch(allNodes, parent)] - # Return: - .Call(`MORPHYLENGTH`, as.integer(parentOf - 1L), as.integer(leftChild - 1L), - as.integer(rightChild - 1L), morphyObj) + ts_fitch_score(cbind(parent, child), + dataset[["contrast"]], dataset[["tip_data"]], + dataset[["weight"]], dataset[["levels"]], + min_steps = dataset[["min_steps"]], + concavity = dataset[["concavity"]], + infoAmounts = dataset[["info_amounts"]]) } -#' @describeIn MorphyTreeLength Fastest function that requires internal tree parameters -#' @param parentOf Integer vector containing, for each tip and each node in -#' sequential order, the integer index its parent node. -#' The root node should be its own parent. -#' @param leftChild integer vector containing, for each node, starting at the -#' root and proceeding in sequential order, the integer corresponding to its -#' left child. Tip numbering begins at 0; the root node is numbered `nTip`. -#' @param rightChild integer vector containing, for each node, the index -#' of its right child. -#' @family tree scoring -#' @author Martin R. Smith -#' @keywords internal -#' @export -GetMorphyLength <- function(parentOf, leftChild, rightChild, morphyObj) { - # Return: - .Call(`MORPHYLENGTH`, as.integer(parentOf), as.integer(leftChild), - as.integer(rightChild), morphyObj) -} - -#' @describeIn MorphyTreeLength Direct call to C function. Use with caution. -#' @param parentOf For each node, numbered in postorder, the number of its parent node. -#' @param leftChild For each internal node, numbered in postorder, the number of its left -#' child node or tip. -#' @param rightChild For each internal node, numbered in postorder, the number of its right -#' child node or tip. -#' @keywords internal -#' @export -C_MorphyLength <- function(parentOf, leftChild, rightChild, morphyObj) { - .Call(`MORPHYLENGTH`, as.integer(parentOf - 1L), as.integer(leftChild - 1L), - as.integer(rightChild - 1L), morphyObj) -} diff --git a/R/tree_rearrangement.R b/R/tree_rearrangement.R index 65c748d1c..84af0c8f5 100644 --- a/R/tree_rearrangement.R +++ b/R/tree_rearrangement.R @@ -30,12 +30,10 @@ #' edge <- tree$edge #' parent <- edge[, 1] #' child <- edge[, 2] -#' dataset <- PhyDat2Morphy(Lobo.phy) +#' dataset <- PrepareData(Lobo.phy) #' RearrangeEdges(parent, child, dataset, EdgeSwapper = RootedNNISwap) -#' # Remember to free memory: -#' dataset <- UnloadMorphy(dataset) #' @export -RearrangeEdges <- function (parent, child, dataset, TreeScorer = MorphyLength, +RearrangeEdges <- function (parent, child, dataset, TreeScorer = EdgeListScore, EdgeSwapper, scoreToBeat = TreeScorer(parent, child, dataset, ...), iter = "?", hits = 0L, verbosity = 0L, ...) { diff --git a/dev/plans/2026-06-15-morphylib-removal-stages.md b/dev/plans/2026-06-15-morphylib-removal-stages.md new file mode 100644 index 000000000..66c226c0d --- /dev/null +++ b/dev/plans/2026-06-15-morphylib-removal-stages.md @@ -0,0 +1,92 @@ +# Dropping MorphyLib entirely from TreeSearch 2.0 + +Goal (maintainer decision, 2026-06-15): route ALL scoring through the native +Fitch kernel and **delete vendored MorphyLib**. Native scores are the correct +v2.0 behaviour — we are NOT preserving MorphyLib equivalence (MorphyLib mis- +scores `{1-}` ambiguous-with-inapplicable tokens; see +`memory/native-morphy-bgs-discrepancy.md`). + +## Stage 1 — native `MorphyLength` for the inapplicable mode ✅ (PR #251) +`MorphyLength()`/`MorphyTreeLength()` score the default (inapplicable) gap mode +via the native kernel (`FastCharacterLength`). Pointer retained so `Morphy()`'s +C-loop + introspection are untouched. Fixes `{1-}` for `TreeSearch`/`Ratchet`/ +`Jackknife`/custom.Rmd. Verified `== TreeLength` across Lobo + CL datasets. + +## Stage 2 — axe `Morphy()` entirely ✅ (done on this branch) + +Originally scoped as "migrate `Morphy()`'s C-loop", but `Morphy()` turned out to +be redundant and unreleased, so it was deleted instead. For reference, it scored +through three closures in its hot loop (former R/Morphy.R:317-345): +`Morphy()` (R/Morphy.R) scores through three closures called in the hot search +loop (R/Morphy.R:317-345): +- `.EWScore` -> `preorder_morphy(edge, morphyObj)` +- `.IWScore` -> `morphy_iw(edge, morphyObjs, weight, minLength, charSeq, concavity, target)` +- `.ProfileScore` -> `morphy_profile(edge, morphyObjs, weight, charSeq, profiles, target)` + +**DECISION (MRS, 2026-06-15): axe `Morphy()` entirely** rather than migrate it. +It was never on CRAN (not in 1.8.0) and is the redundant middle between +`MaximizeParsimony()` (native EW/IW/profile + constraints + ratchet) and +`TreeSearch()` (custom-criteria R-loop). Functionally nothing is lost. + +Done on this branch: deleted `Morphy()` + its private helpers +(`.EWScore`/`.IWScore`/`.ProfileScore`/`.TBRSearch`/`.CombineResults`/ +`.ReplaceResults`/`.Time`/`.DateTime`) from `R/Morphy.R`; dropped +`export(Morphy)`; replaced `MaximizeParsimony()`'s legacy-param delegation +(`do.call(Morphy, …)`) with an informative error; deleted `test-Morphy.R` +(+ snapshots) and the `Morphy()` calls in `test-CustomSearch.R`; fixed the +dangling `[Morphy()]` doc links; regenerated NAMESPACE/man. + +Consequence: `morphy_iw`/`morphy_profile` are now dead (Morphy() was their only +caller), and the rare `ambiguous`/`extra` gap modes no longer need a native +reimplementation (nothing in production uses them; `.NativeMorphyData` still +falls back to MorphyLib for them via `PhyDat2Morphy`, removed in Stage 3). + +## Stage 3 — delete vendored MorphyLib ⚠ LARGE, all-or-nothing +Once nothing calls MorphyLib: +- Make `PhyDat2Morphy()`/`SingleCharMorphy()` native-only (return the native + handle, no pointer); `UnloadMorphy()` a no-op; `is.morphyPtr()` accepts it. +- Migrate `RandomTreeScore()` (uses `preorder_morphy`/`RandomMorphyTree`) to native. +- Remove: `preorder_morphy`/`morphy_iw`/`morphy_profile`, the `MORPHYLENGTH` + C routine + `GetMorphyLength`/`C_MorphyLength`/`MorphyTreeLength` raw variants, + all ~28 `mpl_*` bindings (R/mpl_morphyex.R), the introspection helpers + (`MorphyWeights`/`SetMorphyWeights`/`GapHandler`/`summary.morphyPtr`/ + `MorphyErrorCheck`), and `RandomMorphyTree`. +- Delete the vendored MorphyLib C/C++ sources under `src/`; update Makevars / + `R_init` registration; drop the MorphyLib copyright/attribution from + DESCRIPTION (keep historical credit per GPL as appropriate). +- Update/replace tests: `test-RMorphy.R`, `test-mpl_morphy_objects.R`, + `test-pp-random-tree.R`, `test-RandomTreeScore.R`, and any `Morphy()` test + asserting exact trees/scores on inapplicable data. + +### Stage 3 findings (resolved) +- **Wagner is NOT a MorphyLib dependency.** The native engine has its own + self-contained addition-tree builder (`src/ts_wagner.cpp`: + `wagner_tree`/`random_wagner_tree`/`biased_wagner_tree`, used by + `ts_driven`). MorphyLib's `src/wagner.c` (`mpl_wagner_*`, `MPLstate`) is + internal MorphyLib plumbing, reachable only through `morphy.c` → the deleted + R bridge. `MPLstate`/`MPLndsets`/`MPLpartition` appear ONLY in MorphyLib + files; no `ts_*` source uses them. So MorphyLib deletes wholesale — no + `MPLstate` extraction, no Wagner rebuild. +- **Resampling weight coupling (the real gating issue).** `Jackknife()` and + `MorphyBootstrap()` resampled by mutating character weights in place on the + MorphyLib pointer (`mpl_set_charac_weight`) and re-scoring. Stage 1's native + `MorphyLength` reads weights frozen into `attr(morphyObj,"native")` at + construction, so those mutations were ignored — a latent regression. + Fixed by **functional native resampling**: `.SetMorphyWeight()` returns a + copy of the handle carrying the resampled weight vector; the custom-search + framework (`EdgeListSearch` + `TreeScorer`/`EdgeSwapper`) is unchanged. + Regression covered by a new test (doubling weights doubles the score). + Custom-search resampling is preserved; `Resample()` (no custom TreeScorer) + is a separate path and was not a substitute. + +## Status +Stage 3 IMPLEMENTED on this branch: `PhyDat2Morphy`/`SingleCharMorphy` +native-only; `UnloadMorphy` a no-op; `RandomTreeScore` native (kept +`RandomMorphyTree` + the pure C `RANDOM_TREE`); removed `mpl_*` bindings, +introspection helpers, `MORPHYLENGTH`/`RANDOM_TREE_SCORE`/`GetMorphyLength`/ +`C_MorphyLength`, `morphy_iw`/`morphy_profile`/`preorder_morphy`; deleted all +17 vendored MorphyLib C/C++ sources; trimmed `TreeSearch-init.c` + +`build_postorder.h`; regenerated RcppExports/NAMESPACE/man. Package compiles, +installs, and the test suite is green. Outstanding: DESCRIPTION MorphyLib +copyright/attribution (sensitive — Brazeau/BGS credit) left for maintainer +decision. diff --git a/man/AdditionTree.Rd b/man/AdditionTree.Rd index 970c18804..1721f12d3 100644 --- a/man/AdditionTree.Rd +++ b/man/AdditionTree.Rd @@ -50,8 +50,8 @@ Impose a constraint: \href{https://ms609.github.io/TreeTools/reference/ImposeCon Neighbour-joining trees: \href{https://ms609.github.io/TreeTools/reference/NJTree.html}{\code{TreeTools::NJTree()}}; \href{https://ms609.github.io/TreeTools/reference/ConstrainedNJ}{\code{TreeTools::ConstrainedNJ()}} -Other tree generation functions: -\code{\link[=RandomMorphyTree]{RandomMorphyTree()}} +Other tree generation functions: +\code{\link{RandomPostorderTree}()} } \author{ \href{https://smithlabdurham.github.io/}{Martin R. Smith} diff --git a/man/Carter1.Rd b/man/Carter1.Rd index 1f9e71d5d..f2c1b1295 100644 --- a/man/Carter1.Rd +++ b/man/Carter1.Rd @@ -69,10 +69,10 @@ cumsum(sapply(1:3, Carter1, 3, 3)) \insertAllCited{} } \seealso{ -Other profile parsimony functions: -\code{\link[=PrepareDataProfile]{PrepareDataProfile()}}, -\code{\link[=StepInformation]{StepInformation()}}, -\code{\link[=WithOneExtraStep]{WithOneExtraStep()}}, +Other profile parsimony functions: +\code{\link{PrepareDataProfile}()}, +\code{\link{StepInformation}()}, +\code{\link{WithOneExtraStep}()}, \code{\link{profiles}} } \author{ diff --git a/man/CharacterHierarchy.Rd b/man/CharacterHierarchy.Rd index 1bd2a6ebf..c1deff06f 100644 --- a/man/CharacterHierarchy.Rd +++ b/man/CharacterHierarchy.Rd @@ -46,18 +46,18 @@ h <- CharacterHierarchy("1" = list(2, 3, 4, 5, "3" = 9:10)) \seealso{ \code{\link[=MaximizeParsimony]{MaximizeParsimony()}}, \code{\link[=hierarchy_from_names]{hierarchy_from_names()}} -Other tree scoring: -\code{\link[=CharacterLength]{CharacterLength()}}, -\code{\link[=ExpectedLength]{ExpectedLength()}}, -\code{\link[=IWScore]{IWScore()}}, -\code{\link[=LengthAdded]{LengthAdded()}}, -\code{\link[=MaximizeParsimony]{MaximizeParsimony()}}, -\code{\link[=MinimumLength]{MinimumLength()}}, -\code{\link[=MorphyTreeLength]{MorphyTreeLength()}}, -\code{\link[=ParsSim]{ParsSim()}}, -\code{\link[=TaxonInfluence]{TaxonInfluence()}}, -\code{\link[=WideSample]{WideSample()}}, -\code{\link[=hierarchy_from_names]{hierarchy_from_names()}}, -\code{\link[=recode_hierarchy]{recode_hierarchy()}} +Other tree scoring: +\code{\link{CharacterLength}()}, +\code{\link{ExpectedLength}()}, +\code{\link{IWScore}()}, +\code{\link{LengthAdded}()}, +\code{\link{MaximizeParsimony}()}, +\code{\link{MinimumLength}()}, +\code{\link{ParsSim}()}, +\code{\link{TaxonInfluence}()}, +\code{\link{TreeScore}()}, +\code{\link{WideSample}()}, +\code{\link{hierarchy_from_names}()}, +\code{\link{recode_hierarchy}()} } \concept{tree scoring} diff --git a/man/CharacterLength.Rd b/man/CharacterLength.Rd index 99f0f242e..a70badc19 100644 --- a/man/CharacterLength.Rd +++ b/man/CharacterLength.Rd @@ -44,19 +44,19 @@ CharacterLength(tree, dataset, compress = TRUE) \insertAllCited{} } \seealso{ -Other tree scoring: -\code{\link[=CharacterHierarchy]{CharacterHierarchy()}}, -\code{\link[=ExpectedLength]{ExpectedLength()}}, -\code{\link[=IWScore]{IWScore()}}, -\code{\link[=LengthAdded]{LengthAdded()}}, -\code{\link[=MaximizeParsimony]{MaximizeParsimony()}}, -\code{\link[=MinimumLength]{MinimumLength()}}, -\code{\link[=MorphyTreeLength]{MorphyTreeLength()}}, -\code{\link[=ParsSim]{ParsSim()}}, -\code{\link[=TaxonInfluence]{TaxonInfluence()}}, -\code{\link[=WideSample]{WideSample()}}, -\code{\link[=hierarchy_from_names]{hierarchy_from_names()}}, -\code{\link[=recode_hierarchy]{recode_hierarchy()}} +Other tree scoring: +\code{\link{CharacterHierarchy}()}, +\code{\link{ExpectedLength}()}, +\code{\link{IWScore}()}, +\code{\link{LengthAdded}()}, +\code{\link{MaximizeParsimony}()}, +\code{\link{MinimumLength}()}, +\code{\link{ParsSim}()}, +\code{\link{TaxonInfluence}()}, +\code{\link{TreeScore}()}, +\code{\link{WideSample}()}, +\code{\link{hierarchy_from_names}()}, +\code{\link{recode_hierarchy}()} } \author{ \href{https://smithlabdurham.github.io/}{Martin R. Smith} diff --git a/man/ClusterStrings.Rd b/man/ClusterStrings.Rd index 9f5aba13f..f81988edf 100644 --- a/man/ClusterStrings.Rd +++ b/man/ClusterStrings.Rd @@ -29,10 +29,10 @@ ClusterStrings(c(paste0("FirstCluster ", 1:5), paste0("AnotherCluster_", letters[1:6]))) } \seealso{ -Other utility functions: -\code{\link[=QACol]{QACol()}}, -\code{\link[=QuartetResolution]{QuartetResolution()}}, -\code{\link[=WhenFirstHit]{WhenFirstHit()}} +Other utility functions: +\code{\link{QACol}()}, +\code{\link{QuartetResolution}()}, +\code{\link{WhenFirstHit}()} } \author{ \href{https://smithlabdurham.github.io/}{Martin R. Smith} diff --git a/man/ConcordanceTable.Rd b/man/ConcordanceTable.Rd index 3cae0d982..1d0af28d6 100644 --- a/man/ConcordanceTable.Rd +++ b/man/ConcordanceTable.Rd @@ -122,13 +122,13 @@ image(t(`mode<-`(PhyDatToMatrix(dataset), "numeric")), axes = FALSE, \item \code{\link[=SiteConcordance]{SiteConcordance()}}: compute underlying concordance values. } -Other split support functions: -\code{\link[=JackLabels]{JackLabels()}}, -\code{\link[=Jackknife]{Jackknife()}}, -\code{\link[=Morphy]{Morphy()}}, -\code{\link[=MostContradictedFreq]{MostContradictedFreq()}}, -\code{\link[=PaintCharacters]{PaintCharacters()}}, -\code{\link[=PresCont]{PresCont()}}, +Other split support functions: +\code{\link{JackLabels}()}, +\code{\link{Jackknife}()}, +\code{\link{MostContradictedFreq}()}, +\code{\link{PaintCharacters}()}, +\code{\link{PresCont}()}, +\code{\link{Resample}()}, \code{\link{SiteConcordance}} } \concept{split support functions} diff --git a/man/EasyTrees.Rd b/man/EasyTrees.Rd index fd7f72150..5082ac254 100644 --- a/man/EasyTrees.Rd +++ b/man/EasyTrees.Rd @@ -17,5 +17,5 @@ Opens a "shiny" app for interactive parsimony tree search and results exploration. } \seealso{ -\code{\link[=MaximizeParsimony]{MaximizeParsimony()}}, \code{\link[=Morphy]{Morphy()}} +\code{\link[=MaximizeParsimony]{MaximizeParsimony()}} } diff --git a/man/ExpectedLength.Rd b/man/ExpectedLength.Rd index 00a681252..1b6a5dda8 100644 --- a/man/ExpectedLength.Rd +++ b/man/ExpectedLength.Rd @@ -36,19 +36,19 @@ across the leaves. \insertAllCited{} } \seealso{ -Other tree scoring: -\code{\link[=CharacterHierarchy]{CharacterHierarchy()}}, -\code{\link[=CharacterLength]{CharacterLength()}}, -\code{\link[=IWScore]{IWScore()}}, -\code{\link[=LengthAdded]{LengthAdded()}}, -\code{\link[=MaximizeParsimony]{MaximizeParsimony()}}, -\code{\link[=MinimumLength]{MinimumLength()}}, -\code{\link[=MorphyTreeLength]{MorphyTreeLength()}}, -\code{\link[=ParsSim]{ParsSim()}}, -\code{\link[=TaxonInfluence]{TaxonInfluence()}}, -\code{\link[=WideSample]{WideSample()}}, -\code{\link[=hierarchy_from_names]{hierarchy_from_names()}}, -\code{\link[=recode_hierarchy]{recode_hierarchy()}} +Other tree scoring: +\code{\link{CharacterHierarchy}()}, +\code{\link{CharacterLength}()}, +\code{\link{IWScore}()}, +\code{\link{LengthAdded}()}, +\code{\link{MaximizeParsimony}()}, +\code{\link{MinimumLength}()}, +\code{\link{ParsSim}()}, +\code{\link{TaxonInfluence}()}, +\code{\link{TreeScore}()}, +\code{\link{WideSample}()}, +\code{\link{hierarchy_from_names}()}, +\code{\link{recode_hierarchy}()} } \author{ \href{https://smithlabdurham.github.io/}{Martin R. Smith} diff --git a/man/GapHandler.Rd b/man/GapHandler.Rd deleted file mode 100644 index f00c106bc..000000000 --- a/man/GapHandler.Rd +++ /dev/null @@ -1,64 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/mpl_morphy_objects.R -\name{GapHandler} -\alias{GapHandler} -\title{Read how a Morphy Object handles the inapplicable token} -\usage{ -GapHandler(morphyObj) -} -\arguments{ -\item{morphyObj}{Object of class \code{morphy}, perhaps created with -\code{\link[=PhyDat2Morphy]{PhyDat2Morphy()}}.} -} -\value{ -\code{GapHandler()} returns a character string stating how -gaps are handled by \code{morphyObj}. -} -\description{ -Gaps represented by the inapplicable token can be treated as "missing data", -i.e. as equivalent to the ambiguous token \verb{?}; as an extra state, equivalent -to other states such as \code{0} or \code{1}; or as "inapplicable data" using the -algorithm of Brazeau, Guillerme and Smith (2019). -} -\examples{ -morphyObj <- SingleCharMorphy("-0-0", "Extra") -GapHandler(morphyObj) -morphyObj <- UnloadMorphy(morphyObj) -} -\seealso{ -Other Morphy API functions: -\code{\link[=MorphyErrorCheck]{MorphyErrorCheck()}}, -\code{\link[=MorphyWeights]{MorphyWeights()}}, -\code{\link[=PhyDat2Morphy]{PhyDat2Morphy()}}, -\code{\link[=SingleCharMorphy]{SingleCharMorphy()}}, -\code{\link[=UnloadMorphy]{UnloadMorphy()}}, -\code{\link[=is.morphyPtr]{is.morphyPtr()}}, -\code{\link[=mpl_apply_tipdata]{mpl_apply_tipdata()}}, -\code{\link[=mpl_attach_rawdata]{mpl_attach_rawdata()}}, -\code{\link[=mpl_attach_symbols]{mpl_attach_symbols()}}, -\code{\link[=mpl_delete_Morphy]{mpl_delete_Morphy()}}, -\code{\link[=mpl_first_down_recon]{mpl_first_down_recon()}}, -\code{\link[=mpl_first_up_recon]{mpl_first_up_recon()}}, -\code{\link[=mpl_get_charac_weight]{mpl_get_charac_weight()}}, -\code{\link[=mpl_get_gaphandl]{mpl_get_gaphandl()}}, -\code{\link[=mpl_get_num_charac]{mpl_get_num_charac()}}, -\code{\link[=mpl_get_num_internal_nodes]{mpl_get_num_internal_nodes()}}, -\code{\link[=mpl_get_numtaxa]{mpl_get_numtaxa()}}, -\code{\link[=mpl_get_symbols]{mpl_get_symbols()}}, -\code{\link[=mpl_init_Morphy]{mpl_init_Morphy()}}, -\code{\link[=mpl_new_Morphy]{mpl_new_Morphy()}}, -\code{\link[=mpl_second_down_recon]{mpl_second_down_recon()}}, -\code{\link[=mpl_second_up_recon]{mpl_second_up_recon()}}, -\code{\link[=mpl_set_charac_weight]{mpl_set_charac_weight()}}, -\code{\link[=mpl_set_num_internal_nodes]{mpl_set_num_internal_nodes()}}, -\code{\link[=mpl_set_parsim_t]{mpl_set_parsim_t()}}, -\code{\link[=mpl_translate_error]{mpl_translate_error()}}, -\code{\link[=mpl_update_lower_root]{mpl_update_lower_root()}}, -\code{\link[=mpl_update_tip]{mpl_update_tip()}}, -\code{\link[=summary.morphyPtr]{summary.morphyPtr()}} -} -\author{ -\href{https://smithlabdurham.github.io/}{Martin R. Smith} -(\href{mailto:martin.smith@durham.ac.uk}{martin.smith@durham.ac.uk}) -} -\concept{Morphy API functions} diff --git a/man/JackLabels.Rd b/man/JackLabels.Rd index e11dfa48e..252d450e2 100644 --- a/man/JackLabels.Rd +++ b/man/JackLabels.Rd @@ -84,13 +84,13 @@ ape::write.tree(tree) Generate trees by jackknife resampling using \code{\link[=Resample]{Resample()}} for standard parsimony searches, or \code{\link[=Jackknife]{Jackknife()}} for custom search criteria. -Other split support functions: -\code{\link[=ConcordanceTable]{ConcordanceTable()}}, -\code{\link[=Jackknife]{Jackknife()}}, -\code{\link[=Morphy]{Morphy()}}, -\code{\link[=MostContradictedFreq]{MostContradictedFreq()}}, -\code{\link[=PaintCharacters]{PaintCharacters()}}, -\code{\link[=PresCont]{PresCont()}}, +Other split support functions: +\code{\link{ConcordanceTable}()}, +\code{\link{Jackknife}()}, +\code{\link{MostContradictedFreq}()}, +\code{\link{PaintCharacters}()}, +\code{\link{PresCont}()}, +\code{\link{Resample}()}, \code{\link{SiteConcordance}} } \author{ diff --git a/man/Jackknife.Rd b/man/Jackknife.Rd index 888a5b037..fa718ed20 100644 --- a/man/Jackknife.Rd +++ b/man/Jackknife.Rd @@ -7,10 +7,11 @@ Jackknife( tree, dataset, + concavity = Inf, resampleFreq = 2/3, - InitializeData = PhyDat2Morphy, - CleanUpData = UnloadMorphy, - TreeScorer = MorphyLength, + InitializeData = PrepareData, + CleanUpData = ReleaseData, + TreeScorer = EdgeListScore, EdgeSwapper = TBRSwap, jackIter = 5000L, searchIter = 4000L, @@ -26,14 +27,21 @@ Edge lengths are not supported and will be removed.} \item{dataset}{a dataset in the format required by \code{TreeScorer()}.} +\item{concavity}{Determines the optimality criterion when the default native +scorer is used: \code{Inf} (the default) for equal weights; a finite, positive +number for implied weighting with that concavity constant +\insertCite{Goloboff1993}{TreeSearch}; or \code{"profile"} for profile parsimony. +Ignored if a custom \code{InitializeData} is supplied (prepare the data yourself).} + \item{resampleFreq}{Double between 0 and 1 stating proportion of characters to resample.} -\item{InitializeData}{Function that sets up data object to prepare for tree search. -The function will be passed the \code{dataset} parameter. +\item{InitializeData}{Function that sets up data object to prepare for tree +search. The default, \code{\link[=PrepareData]{PrepareData()}}, is called with \code{concavity}; +a custom function will be passed only the \code{dataset} parameter. Its return value will be passed to \code{TreeScorer()} and \code{CleanUpData()}.} -\item{CleanUpData}{Function to destroy data object on function exit. +\item{CleanUpData}{Function to release the data object on function exit. The function will be passed the value returned by \code{InitializeData()}.} \item{TreeScorer}{function to score a given tree. @@ -76,19 +84,21 @@ engine. \item \code{\link[=JackLabels]{JackLabels()}}: Label nodes of a tree with jackknife supports. } -Other split support functions: -\code{\link[=ConcordanceTable]{ConcordanceTable()}}, -\code{\link[=JackLabels]{JackLabels()}}, -\code{\link[=Morphy]{Morphy()}}, -\code{\link[=MostContradictedFreq]{MostContradictedFreq()}}, -\code{\link[=PaintCharacters]{PaintCharacters()}}, -\code{\link[=PresCont]{PresCont()}}, +Other split support functions: +\code{\link{ConcordanceTable}()}, +\code{\link{JackLabels}()}, +\code{\link{MostContradictedFreq}()}, +\code{\link{PaintCharacters}()}, +\code{\link{PresCont}()}, +\code{\link{Resample}()}, \code{\link{SiteConcordance}} -Other custom search functions: -\code{\link[=EdgeListSearch]{EdgeListSearch()}}, -\code{\link[=MorphyBootstrap]{MorphyBootstrap()}}, -\code{\link[=SuccessiveApproximations]{SuccessiveApproximations()}} +Other custom search functions: +\code{\link{BootstrapTree}()}, +\code{\link{EdgeListSearch}()}, +\code{\link{PrepareData}()}, +\code{\link{SingleCharData}()}, +\code{\link{SuccessiveApproximations}()} } \author{ \href{https://smithlabdurham.github.io/}{Martin R. Smith} diff --git a/man/LeastSquaresFit.Rd b/man/LeastSquaresFit.Rd index 876170dc4..b7ac96f32 100644 --- a/man/LeastSquaresFit.Rd +++ b/man/LeastSquaresFit.Rd @@ -14,7 +14,7 @@ lengths, if any, are ignored and refitted.} symmetric matrix with tip labels) over the tips of \code{tree}.} \item{method}{Either \code{"nnls"} (non-negative least squares; branch lengths are -constrained to be \eqn{\ge 0}, matching \code{\link[phangorn:nnls.tree]{phangorn::nnls.tree()}} and Lapointe +constrained to be \eqn{\ge 0}, matching \code{\link[phangorn:designTree]{phangorn::nnls.tree()}} and Lapointe & Cucumel) or \code{"ols"} (ordinary least squares; faster, closed form, but may return negative lengths).} @@ -32,7 +32,7 @@ Fits branch lengths on a fixed tree topology that minimise the (optionally weighted) least-squares discrepancy between the tree's patristic distances and a target distance matrix, using the package's C++ kernel. This is the fixed-topology counterpart of \code{\link[=LeastSquaresTree]{LeastSquaresTree()}}, and the direct analogue -of \code{\link[phangorn:nnls.tree]{phangorn::nnls.tree()}}. +of \code{\link[phangorn:designTree]{phangorn::nnls.tree()}}. } \examples{ tree <- ape::rtree(8) @@ -42,10 +42,10 @@ attr(fit, "RSS") # ~ 0: D is additive on this topology } \seealso{ -\code{\link[=LeastSquaresTree]{LeastSquaresTree()}} to search topologies; \code{\link[phangorn:nnls.tree]{phangorn::nnls.tree()}}. +\code{\link[=LeastSquaresTree]{LeastSquaresTree()}} to search topologies; \code{\link[phangorn:designTree]{phangorn::nnls.tree()}}. -Other least-squares functions: -\code{\link[=LeastSquaresTree]{LeastSquaresTree()}} +Other least-squares functions: +\code{\link{LeastSquaresTree}()} } \author{ \href{https://smithlabdurham.github.io/}{Martin R. Smith} diff --git a/man/LeastSquaresTree.Rd b/man/LeastSquaresTree.Rd index a86dcf033..fafbc86b0 100644 --- a/man/LeastSquaresTree.Rd +++ b/man/LeastSquaresTree.Rd @@ -23,7 +23,7 @@ neighbour-joining tree of \code{dist}. When several trees are supplied the sear is run from each and the best-fitting result is returned.} \item{method}{Either \code{"nnls"} (non-negative least squares; branch lengths are -constrained to be \eqn{\ge 0}, matching \code{\link[phangorn:nnls.tree]{phangorn::nnls.tree()}} and Lapointe +constrained to be \eqn{\ge 0}, matching \code{\link[phangorn:designTree]{phangorn::nnls.tree()}} and Lapointe & Cucumel) or \code{"ols"} (ordinary least squares; faster, closed form, but may return negative lengths).} @@ -70,8 +70,8 @@ attr(found, "RSS") # ~ 0 \code{\link[=LeastSquaresFit]{LeastSquaresFit()}} for fixed-topology fitting; \code{\link[=MaximizeParsimony]{MaximizeParsimony()}} for the parsimony analogue. -Other least-squares functions: -\code{\link[=LeastSquaresFit]{LeastSquaresFit()}} +Other least-squares functions: +\code{\link{LeastSquaresFit}()} } \author{ \href{https://smithlabdurham.github.io/}{Martin R. Smith} diff --git a/man/LengthAdded.Rd b/man/LengthAdded.Rd index 127473007..f10d2382a 100644 --- a/man/LengthAdded.Rd +++ b/man/LengthAdded.Rd @@ -66,19 +66,19 @@ PlotCharacter( \insertAllCited{} } \seealso{ -Other tree scoring: -\code{\link[=CharacterHierarchy]{CharacterHierarchy()}}, -\code{\link[=CharacterLength]{CharacterLength()}}, -\code{\link[=ExpectedLength]{ExpectedLength()}}, -\code{\link[=IWScore]{IWScore()}}, -\code{\link[=MaximizeParsimony]{MaximizeParsimony()}}, -\code{\link[=MinimumLength]{MinimumLength()}}, -\code{\link[=MorphyTreeLength]{MorphyTreeLength()}}, -\code{\link[=ParsSim]{ParsSim()}}, -\code{\link[=TaxonInfluence]{TaxonInfluence()}}, -\code{\link[=WideSample]{WideSample()}}, -\code{\link[=hierarchy_from_names]{hierarchy_from_names()}}, -\code{\link[=recode_hierarchy]{recode_hierarchy()}} +Other tree scoring: +\code{\link{CharacterHierarchy}()}, +\code{\link{CharacterLength}()}, +\code{\link{ExpectedLength}()}, +\code{\link{IWScore}()}, +\code{\link{MaximizeParsimony}()}, +\code{\link{MinimumLength}()}, +\code{\link{ParsSim}()}, +\code{\link{TaxonInfluence}()}, +\code{\link{TreeScore}()}, +\code{\link{WideSample}()}, +\code{\link{hierarchy_from_names}()}, +\code{\link{recode_hierarchy}()} } \author{ \href{https://smithlabdurham.github.io/}{Martin R. Smith} diff --git a/man/MaximizeParsimony.Rd b/man/MaximizeParsimony.Rd index 83af9d990..43acb8d2a 100644 --- a/man/MaximizeParsimony.Rd +++ b/man/MaximizeParsimony.Rd @@ -178,7 +178,7 @@ The list includes elements: \code{replicate}, \code{max_replicates}, \code{phase} (character), \code{elapsed} (seconds), and \code{phase_score}. When \code{NULL} (default) and \code{verbosity >= 1} in an interactive session, a \code{cli} progress bar is created automatically. -Supply a custom function (e.g. using \code{\link[shiny:setProgress]{shiny::setProgress()}}) +Supply a custom function (e.g. using \code{\link[shiny:withProgress]{shiny::setProgress()}}) to control progress display.} \item{control}{A \code{\link{SearchControl}} object (or a named list) of low-level @@ -191,7 +191,7 @@ of individual fields.} These override the corresponding \code{control} fields and the strategy preset. Legacy \code{Morphy()}-style parameters (e.g. \code{ratchIter}, \code{tbrIter}) are -detected and forwarded to \code{\link[=Morphy]{Morphy()}} with a deprecation warning.} +rejected with an error; use this function's own controls instead.} } \value{ A \code{multiPhylo} object containing the best tree(s) found, with @@ -270,23 +270,22 @@ attr(result, "score") \insertAllCited{} } \seealso{ -\code{\link[=Morphy]{Morphy()}} for fine-grained control over the R-level search loop. \code{\link[=Resample]{Resample()}} for jackknife and bootstrap resampling. \code{\link[=SearchControl]{SearchControl()}} for expert-level tuning of the search heuristics. -Other tree scoring: -\code{\link[=CharacterHierarchy]{CharacterHierarchy()}}, -\code{\link[=CharacterLength]{CharacterLength()}}, -\code{\link[=ExpectedLength]{ExpectedLength()}}, -\code{\link[=IWScore]{IWScore()}}, -\code{\link[=LengthAdded]{LengthAdded()}}, -\code{\link[=MinimumLength]{MinimumLength()}}, -\code{\link[=MorphyTreeLength]{MorphyTreeLength()}}, -\code{\link[=ParsSim]{ParsSim()}}, -\code{\link[=TaxonInfluence]{TaxonInfluence()}}, -\code{\link[=WideSample]{WideSample()}}, -\code{\link[=hierarchy_from_names]{hierarchy_from_names()}}, -\code{\link[=recode_hierarchy]{recode_hierarchy()}} +Other tree scoring: +\code{\link{CharacterHierarchy}()}, +\code{\link{CharacterLength}()}, +\code{\link{ExpectedLength}()}, +\code{\link{IWScore}()}, +\code{\link{LengthAdded}()}, +\code{\link{MinimumLength}()}, +\code{\link{ParsSim}()}, +\code{\link{TaxonInfluence}()}, +\code{\link{TreeScore}()}, +\code{\link{WideSample}()}, +\code{\link{hierarchy_from_names}()}, +\code{\link{recode_hierarchy}()} } \author{ \href{https://smithlabdurham.github.io/}{Martin R. Smith} diff --git a/man/MinimumLength.Rd b/man/MinimumLength.Rd index 29ca662b9..b8385c772 100644 --- a/man/MinimumLength.Rd +++ b/man/MinimumLength.Rd @@ -30,7 +30,7 @@ MaximumLength(x, compress = TRUE) \arguments{ \item{x}{An object of class \code{phyDat}; or a string to be coerced to a \code{phyDat} object via -\code{\link[TreeTools:StringToPhyDat]{TreeTools::StringToPhyDat()}}; +\code{\link[TreeTools:PhyToString]{TreeTools::StringToPhyDat()}}; or an integer vector listing the tokens that may be present at each tip along a single character, with each token represented as a binary digit; e.g. a value of 11 ( = 2^0 + 2^1 + 2^3) means that @@ -80,19 +80,19 @@ MinimumLength("-{-1}{-2}{-3}2233") MaximumLength("----0011") } \seealso{ -Other tree scoring: -\code{\link[=CharacterHierarchy]{CharacterHierarchy()}}, -\code{\link[=CharacterLength]{CharacterLength()}}, -\code{\link[=ExpectedLength]{ExpectedLength()}}, -\code{\link[=IWScore]{IWScore()}}, -\code{\link[=LengthAdded]{LengthAdded()}}, -\code{\link[=MaximizeParsimony]{MaximizeParsimony()}}, -\code{\link[=MorphyTreeLength]{MorphyTreeLength()}}, -\code{\link[=ParsSim]{ParsSim()}}, -\code{\link[=TaxonInfluence]{TaxonInfluence()}}, -\code{\link[=WideSample]{WideSample()}}, -\code{\link[=hierarchy_from_names]{hierarchy_from_names()}}, -\code{\link[=recode_hierarchy]{recode_hierarchy()}} +Other tree scoring: +\code{\link{CharacterHierarchy}()}, +\code{\link{CharacterLength}()}, +\code{\link{ExpectedLength}()}, +\code{\link{IWScore}()}, +\code{\link{LengthAdded}()}, +\code{\link{MaximizeParsimony}()}, +\code{\link{ParsSim}()}, +\code{\link{TaxonInfluence}()}, +\code{\link{TreeScore}()}, +\code{\link{WideSample}()}, +\code{\link{hierarchy_from_names}()}, +\code{\link{recode_hierarchy}()} } \author{ \href{https://smithlabdurham.github.io/}{Martin R. Smith} diff --git a/man/Morphy.Rd b/man/Morphy.Rd deleted file mode 100644 index 0bbd579de..000000000 --- a/man/Morphy.Rd +++ /dev/null @@ -1,411 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/Morphy.R -\encoding{UTF-8} -\name{Morphy} -\alias{Morphy} -\alias{Resample} -\title{Tree search using MorphyLib scoring} -\usage{ -Morphy( - dataset, - tree, - ratchIter = 7L, - tbrIter = 2L, - startIter = 2L, - finalIter = 1L, - maxHits = NTip(dataset) * 1.8, - maxTime = 60, - quickHits = 1/3, - concavity = Inf, - ratchEW = TRUE, - tolerance = sqrt(.Machine[["double.eps"]]), - constraint, - verbosity = 3L -) - -Resample( - dataset, - tree, - method = "jack", - proportion = 2/3, - ratchIter = 1L, - tbrIter = 8L, - finalIter = 3L, - maxHits = 12L, - concavity = Inf, - tolerance = sqrt(.Machine[["double.eps"]]), - constraint, - verbosity = 2L, - nReplicates = 1L, - nThreads = 1L, - hierarchy = NULL, - inapplicable = "bgs", - hsj_alpha = 1, - extended_iw = TRUE, - xpiwe_r = 0.5, - xpiwe_max_f = 5, - ... -) -} -\arguments{ -\item{dataset}{A phylogenetic data matrix of \pkg{phangorn} class -\code{phyDat}, whose names correspond to the labels of any accompanying tree. -Perhaps load into R using \code{\link[TreeTools]{ReadAsPhyDat}()}. -Additive (ordered) characters can be handled using -\code{\link[TreeTools]{Decompose}()}.} - -\item{tree}{(optional) A bifurcating tree of class \code{\link[ape]{phylo}}, -containing only the tips listed in \code{dataset}, from which the search -should begin. -If unspecified, an \link[=AdditionTree]{addition tree} will be generated from -\code{dataset}, respecting any supplied \code{constraint}. -Edge lengths are not supported and will be deleted.} - -\item{ratchIter}{Numeric specifying number of iterations of the -parsimony ratchet \insertCite{Nixon1999}{TreeSearch} to conduct.} - -\item{tbrIter}{Numeric specifying the maximum number of \acronym{TBR} -break points on a given tree to evaluate before terminating the search. -One "iteration" comprises selecting a branch to break, and evaluating -each possible reconnection point in turn until a new tree improves the -score. If a better score is found, then the counter is reset to zero, -and tree search continues from the improved tree.} - -\item{startIter}{Numeric: an initial round of tree search with -\code{startIter} × \code{tbrIter} \acronym{TBR} break points is conducted in -order to locate a local optimum before beginning ratchet searches.} - -\item{finalIter}{Numeric: a final round of tree search will evaluate -\code{finalIter} × \code{tbrIter} \acronym{TBR} break points, in order to -sample the final optimal neighbourhood more intensely.} - -\item{maxHits}{Numeric specifying the maximum times that an optimal -parsimony score may be hit before concluding a ratchet iteration or final -search concluded.} - -\item{maxTime}{Numeric: after \code{maxTime} minutes, stop tree search at the -next opportunity.} - -\item{quickHits}{Numeric: iterations on subsampled datasets -will retain \code{quickHits} × \code{maxHits} trees with the best score.} - -\item{concavity}{Determines the degree to which extra steps beyond the first -are penalized. Specify a numeric value to use implied weighting -\insertCite{Goloboff1993}{TreeSearch}; \code{concavity} specifies \emph{k} in -\emph{k} / \emph{e} + \emph{k}. A value of 10 is recommended; -TNT sets a default of 3, but this is too low in some circumstances -\insertCite{Goloboff2018,Smith2019}{TreeSearch}. -Better still explore the sensitivity of results under a range of -concavity values, e.g. \code{k = 2 ^ (1:7)}. -Specify \code{Inf} to weight each additional step equally, -(which underperforms step weighting approaches -\insertCite{Goloboff2008,Goloboff2018,Goloboff2019,Smith2019}{TreeSearch}). -Specify \code{"profile"} to employ an approximation of profile parsimony -\insertCite{Faith2001}{TreeSearch}.} - -\item{ratchEW}{Logical specifying whether to use equal weighting during -ratchet iterations, improving search speed whilst still facilitating -escape from local optima.} - -\item{tolerance}{Numeric specifying degree of suboptimality to tolerate -before rejecting a tree. The default, \code{sqrt(.Machine$double.eps)}, retains -trees that may be equally parsimonious but for rounding errors. -Setting to larger values will include trees suboptimal by up to \code{tolerance} -in search results, which may improve the accuracy of the consensus tree -(at the expense of resolution) \insertCite{Smith2019}{TreeSearch}.} - -\item{constraint}{Either an object of class \code{phyDat}, in which case -returned trees will be perfectly compatible with each character in -\code{constraint}; or a tree of class \code{phylo}, all of whose nodes will occur -in any output tree. -See \code{\link[TreeTools:ImposeConstraint]{ImposeConstraint()}} and -\href{https://ms609.github.io/TreeSearch/articles/tree-search.html}{vignette} -for further examples.} - -\item{verbosity}{Integer specifying level of messaging; higher values give -more detailed commentary on search progress. Set to \code{0} to run silently.} - -\item{method}{Unambiguous abbreviation of \code{jackknife} or \code{bootstrap} -specifying how to resample characters. Note that jackknife is considered -to give more meaningful results.} - -\item{proportion}{Numeric between 0 and 1 specifying what proportion of -characters to retain under jackknife resampling.} - -\item{nReplicates}{Integer specifying how many resample replicates to run. -Default \code{1L} runs a single replicate (original behaviour). -When \verb{> 1}, all replicates are run in a single call, optionally in parallel.} - -\item{nThreads}{Integer specifying the number of threads for parallel -resampling. Default \code{1L} runs serially. Use \code{0L} for auto-detect. -Only effective when \code{nReplicates > 1}.} - -\item{hierarchy}{A \code{\link{CharacterHierarchy}} object specifying which characters -are controlled by which primary characters. Required when -\code{inapplicable} is \code{"hsj"} or \code{"xform"}. When provided, resampling -operates on "units" rather than individual characters: each non-hierarchy -character is one unit, and each top-level hierarchy block (primary + -all dependents) is one unit. See \code{\link[=CharacterHierarchy]{CharacterHierarchy()}}.} - -\item{inapplicable}{Character string specifying the inapplicable-character -handling method: \code{"bgs"} (default), \code{"hsj"}, or \code{"xform"}. -Case-insensitive; \code{"brazeau"} is accepted as an alias for \code{"bgs"}. -See \code{\link[=MaximizeParsimony]{MaximizeParsimony()}} and \code{vignette("inapplicable")} for details.} - -\item{hsj_alpha}{Numeric in [0, 1] controlling the weight of secondary -character variation in HSJ scoring. Default \code{1.0}. Only used when -\code{inapplicable = "hsj"}.} - -\item{extended_iw}{Logical; if \code{TRUE} (default), use extended implied -weighting (XPIWE; \insertCite{Goloboff2014;textual}{TreeSearch}), -which adjusts per-character concavity for missing entries. -Ignored when \code{concavity = Inf} or \code{"profile"}.} - -\item{xpiwe_r}{Numeric; proportion of homoplasy assumed in missing entries. -Default \code{0.5}. Only used when \code{extended_iw = TRUE}.} - -\item{xpiwe_max_f}{Numeric; maximum extrapolation factor. -Default \code{5}. Only used when \code{extended_iw = TRUE}.} - -\item{\dots}{Additional parameters to \code{Morphy()}.} -} -\value{ -\code{Morphy()} returns a list of trees with class -\code{multiPhylo}. This lists all trees found during each search step that -are within \code{tolerance} of the optimal score, listed in the sequence that -they were first visited, and named according to the step in which they were -first found; it may contain more than \code{maxHits} elements. -Note that the default search parameters may need to be increased in order for -these trees to be the globally optimal trees; examine the messages printed -during tree search to evaluate whether the optimal score has stabilized. - -The return value has the attribute \code{firstHit}, a named integer vector listing -the number of optimal trees visited for the first time in each stage of -the tree search. Stages are named: -\itemize{ -\item \code{seed}: starting trees; -\item \code{start}: Initial TBR search; -\item \code{ratchN}: Ratchet iteration \code{N}; -\item \code{final}: Final TBR search. -The first tree hit for the first time in ratchet iteration three is named -\code{ratch3_1}. -} - -\code{Resample()} returns a \code{multiPhylo} object containing one best tree -per resample replicate. -} -\description{ -Search for most parsimonious trees using the parsimony ratchet and -\acronym{TBR} rearrangements, scoring with the MorphyLib C library -\insertCite{Brazeau2017}{TreeSearch}. -Supports equal weights, implied weights, and profile parsimony. -Treats inapplicable data using the algorithm of -\insertCite{Brazeau2019;textual}{TreeSearch}. -} -\details{ -For most users, \code{\link[=MaximizeParsimony]{MaximizeParsimony()}} provides a faster search using the -C++ engine, with native support for equal weights, implied weights, profile -parsimony, and topological constraints. -\code{Morphy()} is retained for users who need fine-grained control over the -R-level search loop (e.g.\sspace{}custom stopping criteria, per-iteration -callbacks, or direct access to MorphyLib scoring). - -Tree search commences with \code{ratchIter} iterations of the parsimony ratchet -\insertCite{Nixon1999}{TreeSearch}, which bootstraps the input dataset -in order to escape local optima. -A final round of tree bisection and reconnection (\acronym{TBR}) -is conducted to broaden the sampling of trees. - -This function can be called using the R command line / terminal, or through -the "shiny" graphical user interface app (type \code{EasyTrees()} to launch). - -The optimal strategy for tree search depends in part on how close to optimal -the starting tree is, the size of the search space (which increases -super-exponentially with the number of leaves), and the complexity of the -search space (e.g. the existence of multiple local optima). - -One possible approach is to employ four phases: -\enumerate{ -\item Rapid search for local optimum: tree score is typically easy to improve -early in a search, because the initial tree is often far from optimal. -When many moves are likely to be accepted, running several rounds of search -with a low value of \code{maxHits} and a high value of \code{tbrIter} allows many -trees to be evaluated quickly, hopefully moving quickly to a more promising -region of tree space. -\item Identification of local optimum: -Once close to a local optimum, a more extensive search -with a higher value of \code{maxHits} allows a region to be explored in more -detail. Setting a high value of \code{tbrIter} will search a local -neighbourhood more completely -\item Search for nearby peaks: -Ratchet iterations allow escape from local optima. -Setting \code{ratchIter} to a high value searches the wider neighbourhood more -extensively for other nearby peaks; \code{ratchEW = TRUE} accelerates these -exploratory searches. Ratchet iterations can be ineffective when \code{maxHits} -is too low for the search to escape its initial location. -\item Extensive search of final optimum. As with step 2, it may be valuable to -fully explore the optimum that is found after ratchet searches to be sure -that the locally optimal score has been obtained. Setting a high value of -\code{finalIter} performs a thorough search that can give confidence that further -searches would not find better (local) trees. -} - -A search is unlikely to have found a global optimum if: -\itemize{ -\item Tree score continues to improve on the final iteration. If a local optimum -has not yet been reached, it is unlikely that a global optimum has -been reached. -Try increasing \code{maxHits}. -\item Successive ratchet iterations continue to improve tree scores. -If a recent ratchet iteration improved the score, rather than finding -a different region of tree space with the same optimal score, it is likely -that still better global optima remain to be found. Try increasing -\code{ratchIter} (more iterations give more chance for improvement) and -\code{maxHits} (to get closer to the local optimum after each ratchet iteration). -\item Optimal areas of tree space are only visited by a single ratchet iteration. -(See vignette: \href{https://ms609.github.io/TreeSearch/articles/tree-space.html}{Exploring tree space}.) -If some areas of tree space are only found by one ratchet iteration, there -may well be other, better areas that have not yet been visited. -Try increasing \code{ratchIter}. -} - -When continuing a tree search, it is usually best to start from an optimal -tree found during the previous iteration - there is no need to start from -scratch. - -A more time consuming way of checking that a global optimum has been reached -is to repeat a search with the same parameters multiple times, starting -from a different, entirely random tree each time. If all searches obtain the -same optimal tree score despite their different starting points, -this score is likely to correspond to the global optimum. - -For detailed documentation of the "TreeSearch" package, including full -instructions for loading phylogenetic data into R and initiating and -configuring tree search, see the -\href{https://ms609.github.io/TreeSearch/}{package documentation}. -} -\section{Resampling}{ - -Note that bootstrap support is a measure of the amount of data supporting -a split, rather than the amount of confidence that should be afforded the -grouping. -"Bootstrap support of 100\% is not enough, the tree must also be correct" -\insertCite{Phillips2004}{TreeSearch}. -See discussion in \insertCite{Egan2006;textual}{TreeSearch}; -\insertCite{Wagele2009;textual}{TreeSearch}; -\insertCite{Simmons2011}{TreeSearch}; -\insertCite{Kumar2012;textual}{TreeSearch}. - -For a discussion of suitable search parameters in resampling estimates, see -\insertCite{Muller2005;textual}{TreeSearch}. -The user should decide whether to start each resampling -from the optimal tree (which may be quicker, but result in overestimated -support values as searches get stuck in local optima close to the -optimal tree) or a random tree (which may take longer as more rearrangements -are necessary to find an optimal tree on each iteration). - -For other ways to estimate clade concordance, see \code{\link[=SiteConcordance]{SiteConcordance()}}. -} - -\examples{ -## Only run examples in interactive R sessions -if (interactive()) { - # launch "shiny" point-and-click interface - EasyTrees() - - # Here too, use the "continue search" function to ensure that tree score - # has stabilized and a global optimum has been found -} - - -# Load data for analysis in R -library("TreeTools") -data("inapplicable.phyData", package = "TreeSearch") -dataset <- inapplicable.phyData[["Asher2005"]] - -\donttest{ -# A very quick run for demonstration purposes -trees <- Morphy(dataset, ratchIter = 0, startIter = 0, - tbrIter = 1, maxHits = 4, maxTime = 1/100, - concavity = 10, verbosity = 4) -names(trees) -cons <- Consensus(trees) -} - -# In actual use, be sure to check that the score has converged on a global -# optimum, conducting additional iterations and runs as necessary. - -if (interactive()) { -# Jackknife resampling -nReplicates <- 10 -jackTrees <- replicate(nReplicates, - #c() ensures that each replicate returns a list of trees - c(Resample(dataset, trees, ratchIter = 0, tbrIter = 2, startIter = 1, - maxHits = 5, maxTime = 1 / 10, - concavity = 10, verbosity = 0)) - ) - -# In a serious analysis, more replicates would be conducted, and each -# search would undergo more iterations. - -# Now we must decide what to do with the multiple optimal trees from -# each replicate. - -# Set graphical parameters for plotting -oPar <- par(mar = rep(0, 4), cex = 0.9) - -# Take the strict consensus of all trees for each replicate -# (May underestimate support) -JackLabels(cons, lapply(jackTrees, ape::consensus)) - -# Take a single tree from each replicate (here, the first) -# Potentially problematic if chosen tree is not representative -JackLabels(cons, lapply(jackTrees, `[[`, 1)) - -# Count iteration as support if all most parsimonious trees support a split; -# as contradiction if all trees contradict it; don't include replicates where -# not all trees agree on the resolution of a split. -labels <- JackLabels(cons, jackTrees) - -# How many iterations were decisive for each node? -attr(labels, "decisive") - -# Show as proportion of decisive iterations -JackLabels(cons, jackTrees, showFrac = TRUE) - -# Restore graphical parameters -par(oPar) -} - -# Tree search with a constraint -constraint <- MatrixToPhyDat(c(a = 1, b = 1, c = 0, d = 0, e = 0, f = 0)) -characters <- MatrixToPhyDat(matrix( - c(0, 1, 1, 1, 0, 0, - 1, 1, 1, 0, 0, 0), ncol = 2, - dimnames = list(letters[1:6], NULL))) -Morphy(characters, constraint = constraint, verbosity = 0) - -} -\references{ -\insertAllCited{} -} -\seealso{ -\code{\link[=MaximizeParsimony]{MaximizeParsimony()}} for the faster C++ driven search engine -(recommended for most analyses). - -Tree search \emph{via} graphical user interface: \code{\link[=EasyTrees]{EasyTrees()}} - -Other split support functions: -\code{\link[=ConcordanceTable]{ConcordanceTable()}}, -\code{\link[=JackLabels]{JackLabels()}}, -\code{\link[=Jackknife]{Jackknife()}}, -\code{\link[=MostContradictedFreq]{MostContradictedFreq()}}, -\code{\link[=PaintCharacters]{PaintCharacters()}}, -\code{\link[=PresCont]{PresCont()}}, -\code{\link{SiteConcordance}} -} -\author{ -\href{https://smithlabdurham.github.io/}{Martin R. Smith} -(\href{mailto:martin.smith@durham.ac.uk}{martin.smith@durham.ac.uk}) -} -\concept{split support functions} diff --git a/man/MorphyErrorCheck.Rd b/man/MorphyErrorCheck.Rd deleted file mode 100644 index e8eb1ff71..000000000 --- a/man/MorphyErrorCheck.Rd +++ /dev/null @@ -1,48 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/mpl_morphy_objects.R -\name{MorphyErrorCheck} -\alias{MorphyErrorCheck} -\title{Check for error whilst modifying Morphy object} -\usage{ -MorphyErrorCheck(action) -} -\arguments{ -\item{action}{action to perform} -} -\description{ -Check for error whilst modifying Morphy object -} -\seealso{ -Other Morphy API functions: -\code{\link[=GapHandler]{GapHandler()}}, -\code{\link[=MorphyWeights]{MorphyWeights()}}, -\code{\link[=PhyDat2Morphy]{PhyDat2Morphy()}}, -\code{\link[=SingleCharMorphy]{SingleCharMorphy()}}, -\code{\link[=UnloadMorphy]{UnloadMorphy()}}, -\code{\link[=is.morphyPtr]{is.morphyPtr()}}, -\code{\link[=mpl_apply_tipdata]{mpl_apply_tipdata()}}, -\code{\link[=mpl_attach_rawdata]{mpl_attach_rawdata()}}, -\code{\link[=mpl_attach_symbols]{mpl_attach_symbols()}}, -\code{\link[=mpl_delete_Morphy]{mpl_delete_Morphy()}}, -\code{\link[=mpl_first_down_recon]{mpl_first_down_recon()}}, -\code{\link[=mpl_first_up_recon]{mpl_first_up_recon()}}, -\code{\link[=mpl_get_charac_weight]{mpl_get_charac_weight()}}, -\code{\link[=mpl_get_gaphandl]{mpl_get_gaphandl()}}, -\code{\link[=mpl_get_num_charac]{mpl_get_num_charac()}}, -\code{\link[=mpl_get_num_internal_nodes]{mpl_get_num_internal_nodes()}}, -\code{\link[=mpl_get_numtaxa]{mpl_get_numtaxa()}}, -\code{\link[=mpl_get_symbols]{mpl_get_symbols()}}, -\code{\link[=mpl_init_Morphy]{mpl_init_Morphy()}}, -\code{\link[=mpl_new_Morphy]{mpl_new_Morphy()}}, -\code{\link[=mpl_second_down_recon]{mpl_second_down_recon()}}, -\code{\link[=mpl_second_up_recon]{mpl_second_up_recon()}}, -\code{\link[=mpl_set_charac_weight]{mpl_set_charac_weight()}}, -\code{\link[=mpl_set_num_internal_nodes]{mpl_set_num_internal_nodes()}}, -\code{\link[=mpl_set_parsim_t]{mpl_set_parsim_t()}}, -\code{\link[=mpl_translate_error]{mpl_translate_error()}}, -\code{\link[=mpl_update_lower_root]{mpl_update_lower_root()}}, -\code{\link[=mpl_update_tip]{mpl_update_tip()}}, -\code{\link[=summary.morphyPtr]{summary.morphyPtr()}} -} -\concept{Morphy API functions} -\keyword{internal} diff --git a/man/MorphyTreeLength.Rd b/man/MorphyTreeLength.Rd deleted file mode 100644 index 0d570a336..000000000 --- a/man/MorphyTreeLength.Rd +++ /dev/null @@ -1,87 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/tree_length.R -\name{MorphyTreeLength} -\alias{MorphyTreeLength} -\alias{MorphyLength} -\alias{GetMorphyLength} -\alias{C_MorphyLength} -\title{Calculate parsimony score from Morphy object} -\usage{ -MorphyTreeLength(tree, morphyObj) - -MorphyLength( - parent, - child, - morphyObj, - inPostorder = FALSE, - nTaxa = mpl_get_numtaxa(morphyObj) -) - -GetMorphyLength(parentOf, leftChild, rightChild, morphyObj) - -C_MorphyLength(parentOf, leftChild, rightChild, morphyObj) -} -\arguments{ -\item{tree}{A tree of class \code{\link[ape:read.tree]{phylo}}, with tip -labels in the order generated by \code{\link[TreeTools]{RenumberTips}}, -i.e. corresponding to the sequence of taxa in the corresponding Morphy object.} - -\item{morphyObj}{Object of class \code{morphy}, perhaps created with -\code{\link[=PhyDat2Morphy]{PhyDat2Morphy()}}.} - -\item{parent}{Integer vector corresponding to the first column of the edge -matrix of a tree of class \code{\link[ape]{phylo}}, i.e. -\code{tree[["edge"]][, 1]}} - -\item{child}{Integer vector corresponding to the second column of the edge -matrix of a tree of class \code{\link[ape]{phylo}}, i.e. -\code{tree[["edge"]][, 2]}.} - -\item{parentOf}{For each node, numbered in postorder, the number of its parent node.} - -\item{leftChild}{For each internal node, numbered in postorder, the number of its left -child node or tip.} - -\item{rightChild}{For each internal node, numbered in postorder, the number of its right -child node or tip.} -} -\value{ -\code{MorphyTreeLength()} returns the length of the tree, -after applying weighting. -} -\description{ -This function must be passed a valid Morphy object, or R may crash. -For most users, the function \code{\link[=TreeLength]{TreeLength()}} will be more appropriate. -} -\section{Functions}{ -\itemize{ -\item \code{MorphyLength()}: Faster function that requires internal tree -parameters. Node numbering must increase monotonically away from root. - -\item \code{GetMorphyLength()}: Fastest function that requires internal tree parameters - -\item \code{C_MorphyLength()}: Direct call to C function. Use with caution. - -}} -\seealso{ -PhyDat2Morphy - -Other tree scoring: -\code{\link[=CharacterHierarchy]{CharacterHierarchy()}}, -\code{\link[=CharacterLength]{CharacterLength()}}, -\code{\link[=ExpectedLength]{ExpectedLength()}}, -\code{\link[=IWScore]{IWScore()}}, -\code{\link[=LengthAdded]{LengthAdded()}}, -\code{\link[=MaximizeParsimony]{MaximizeParsimony()}}, -\code{\link[=MinimumLength]{MinimumLength()}}, -\code{\link[=ParsSim]{ParsSim()}}, -\code{\link[=TaxonInfluence]{TaxonInfluence()}}, -\code{\link[=WideSample]{WideSample()}}, -\code{\link[=hierarchy_from_names]{hierarchy_from_names()}}, -\code{\link[=recode_hierarchy]{recode_hierarchy()}} -} -\author{ -Martin R. Smith -} -\concept{tree scoring} -\keyword{internal} diff --git a/man/MorphyWeights.Rd b/man/MorphyWeights.Rd deleted file mode 100644 index fc39e9cc0..000000000 --- a/man/MorphyWeights.Rd +++ /dev/null @@ -1,84 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/mpl_morphy_objects.R -\name{MorphyWeights} -\alias{MorphyWeights} -\alias{SetMorphyWeights} -\title{Set and get the character weightings associated with a Morphy object.} -\usage{ -MorphyWeights(morphyObj) - -SetMorphyWeights(weight, morphyObj, checkInput = TRUE) -} -\arguments{ -\item{morphyObj}{Object of class \code{morphy}, perhaps created with -\code{\link[=PhyDat2Morphy]{PhyDat2Morphy()}}.} - -\item{weight}{A vector listing the new weights to be applied to each character} - -\item{checkInput}{Whether to sanity-check input data before applying. -Defaults to \code{TRUE} to protect the user from crashes.} -} -\value{ -\code{MorphyWeights()} returns a data frame with two named rows and -one column per character pattern: -row 1, \code{approx}, is a list of integers specifying the approximate (integral) -weights used by MorphyLib; -row 2, \code{exact}, is a list of numerics specifying the exact weights specified -by the user. - -\code{SetMorphyWeights()} returns the Morphy error code generated when -applying \code{weight}. -} -\description{ -\code{MorphyWeights()} details the approximate and exact weights associated with -characters in a \code{Morphy} object; \code{SetMorphyWeights()} edits them. -} -\examples{ -tokens <- matrix(c( - 0, 0, 0, 1, 1, 2, - 0, 0, 0, 0, 0, 0), byrow = TRUE, nrow = 2L, - dimnames = list(letters[1:2], NULL)) -pd <- TreeTools::MatrixToPhyDat(tokens) -morphyObj <- PhyDat2Morphy(pd) -MorphyWeights(morphyObj) -if (SetMorphyWeights(c(1, 1.5, 2/3), morphyObj) != 0L) message("Errored") -MorphyWeights(morphyObj) -morphyObj <- UnloadMorphy(morphyObj) -} -\seealso{ -Other Morphy API functions: -\code{\link[=GapHandler]{GapHandler()}}, -\code{\link[=MorphyErrorCheck]{MorphyErrorCheck()}}, -\code{\link[=PhyDat2Morphy]{PhyDat2Morphy()}}, -\code{\link[=SingleCharMorphy]{SingleCharMorphy()}}, -\code{\link[=UnloadMorphy]{UnloadMorphy()}}, -\code{\link[=is.morphyPtr]{is.morphyPtr()}}, -\code{\link[=mpl_apply_tipdata]{mpl_apply_tipdata()}}, -\code{\link[=mpl_attach_rawdata]{mpl_attach_rawdata()}}, -\code{\link[=mpl_attach_symbols]{mpl_attach_symbols()}}, -\code{\link[=mpl_delete_Morphy]{mpl_delete_Morphy()}}, -\code{\link[=mpl_first_down_recon]{mpl_first_down_recon()}}, -\code{\link[=mpl_first_up_recon]{mpl_first_up_recon()}}, -\code{\link[=mpl_get_charac_weight]{mpl_get_charac_weight()}}, -\code{\link[=mpl_get_gaphandl]{mpl_get_gaphandl()}}, -\code{\link[=mpl_get_num_charac]{mpl_get_num_charac()}}, -\code{\link[=mpl_get_num_internal_nodes]{mpl_get_num_internal_nodes()}}, -\code{\link[=mpl_get_numtaxa]{mpl_get_numtaxa()}}, -\code{\link[=mpl_get_symbols]{mpl_get_symbols()}}, -\code{\link[=mpl_init_Morphy]{mpl_init_Morphy()}}, -\code{\link[=mpl_new_Morphy]{mpl_new_Morphy()}}, -\code{\link[=mpl_second_down_recon]{mpl_second_down_recon()}}, -\code{\link[=mpl_second_up_recon]{mpl_second_up_recon()}}, -\code{\link[=mpl_set_charac_weight]{mpl_set_charac_weight()}}, -\code{\link[=mpl_set_num_internal_nodes]{mpl_set_num_internal_nodes()}}, -\code{\link[=mpl_set_parsim_t]{mpl_set_parsim_t()}}, -\code{\link[=mpl_translate_error]{mpl_translate_error()}}, -\code{\link[=mpl_update_lower_root]{mpl_update_lower_root()}}, -\code{\link[=mpl_update_tip]{mpl_update_tip()}}, -\code{\link[=summary.morphyPtr]{summary.morphyPtr()}} -} -\author{ -\href{https://smithlabdurham.github.io/}{Martin R. Smith} -(\href{mailto:martin.smith@durham.ac.uk}{martin.smith@durham.ac.uk}) -} -\concept{Morphy API functions} diff --git a/man/MostContradictedFreq.Rd b/man/MostContradictedFreq.Rd index 31404191c..2b2c0a8a8 100644 --- a/man/MostContradictedFreq.Rd +++ b/man/MostContradictedFreq.Rd @@ -35,13 +35,13 @@ contradicted" score. \seealso{ \code{PresCont()} calculates the "groups present / contradicted" score. -Other split support functions: -\code{\link[=ConcordanceTable]{ConcordanceTable()}}, -\code{\link[=JackLabels]{JackLabels()}}, -\code{\link[=Jackknife]{Jackknife()}}, -\code{\link[=Morphy]{Morphy()}}, -\code{\link[=PaintCharacters]{PaintCharacters()}}, -\code{\link[=PresCont]{PresCont()}}, +Other split support functions: +\code{\link{ConcordanceTable}()}, +\code{\link{JackLabels}()}, +\code{\link{Jackknife}()}, +\code{\link{PaintCharacters}()}, +\code{\link{PresCont}()}, +\code{\link{Resample}()}, \code{\link{SiteConcordance}} } \concept{split support functions} diff --git a/man/NNI.Rd b/man/NNI.Rd index b4196b6d4..92f088c3f 100644 --- a/man/NNI.Rd +++ b/man/NNI.Rd @@ -111,9 +111,9 @@ tree <- TreeTools::Preorder(tree) \insertAllCited{} } \seealso{ -Other tree rearrangement functions: -\code{\link[=SPR]{SPR()}}, -\code{\link[=TBR]{TBR()}} +Other tree rearrangement functions: +\code{\link{SPR}()}, +\code{\link{TBR}()} } \author{ \href{https://smithlabdurham.github.io/}{Martin R. Smith} diff --git a/man/PaintCharacters.Rd b/man/PaintCharacters.Rd index bef233339..ab6e2883a 100644 --- a/man/PaintCharacters.Rd +++ b/man/PaintCharacters.Rd @@ -64,13 +64,13 @@ plot(tree, edge.color = paint$edgeCol, edge.width = 2) \seealso{ \code{\link[TreeTools:PaintTree]{TreeTools::PaintTree()}}, \code{\link[=ConcordanceTable]{ConcordanceTable()}} -Other split support functions: -\code{\link[=ConcordanceTable]{ConcordanceTable()}}, -\code{\link[=JackLabels]{JackLabels()}}, -\code{\link[=Jackknife]{Jackknife()}}, -\code{\link[=Morphy]{Morphy()}}, -\code{\link[=MostContradictedFreq]{MostContradictedFreq()}}, -\code{\link[=PresCont]{PresCont()}}, +Other split support functions: +\code{\link{ConcordanceTable}()}, +\code{\link{JackLabels}()}, +\code{\link{Jackknife}()}, +\code{\link{MostContradictedFreq}()}, +\code{\link{PresCont}()}, +\code{\link{Resample}()}, \code{\link{SiteConcordance}} } \concept{split support functions} diff --git a/man/ParsSim.Rd b/man/ParsSim.Rd index 7269d5bc5..3eefb2157 100644 --- a/man/ParsSim.Rd +++ b/man/ParsSim.Rd @@ -114,18 +114,18 @@ dataset_taxon <- ParsSim(tree, nChar = c(20L), nExtraSteps = 10L, \insertAllCited{} } \seealso{ -Other tree scoring: -\code{\link[=CharacterHierarchy]{CharacterHierarchy()}}, -\code{\link[=CharacterLength]{CharacterLength()}}, -\code{\link[=ExpectedLength]{ExpectedLength()}}, -\code{\link[=IWScore]{IWScore()}}, -\code{\link[=LengthAdded]{LengthAdded()}}, -\code{\link[=MaximizeParsimony]{MaximizeParsimony()}}, -\code{\link[=MinimumLength]{MinimumLength()}}, -\code{\link[=MorphyTreeLength]{MorphyTreeLength()}}, -\code{\link[=TaxonInfluence]{TaxonInfluence()}}, -\code{\link[=WideSample]{WideSample()}}, -\code{\link[=hierarchy_from_names]{hierarchy_from_names()}}, -\code{\link[=recode_hierarchy]{recode_hierarchy()}} +Other tree scoring: +\code{\link{CharacterHierarchy}()}, +\code{\link{CharacterLength}()}, +\code{\link{ExpectedLength}()}, +\code{\link{IWScore}()}, +\code{\link{LengthAdded}()}, +\code{\link{MaximizeParsimony}()}, +\code{\link{MinimumLength}()}, +\code{\link{TaxonInfluence}()}, +\code{\link{TreeScore}()}, +\code{\link{WideSample}()}, +\code{\link{hierarchy_from_names}()}, +\code{\link{recode_hierarchy}()} } \concept{tree scoring} diff --git a/man/PhyDat2Morphy.Rd b/man/PhyDat2Morphy.Rd deleted file mode 100644 index 5bb171c29..000000000 --- a/man/PhyDat2Morphy.Rd +++ /dev/null @@ -1,75 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/mpl_morphy_objects.R -\name{PhyDat2Morphy} -\alias{PhyDat2Morphy} -\title{Initialize a Morphy object from a \code{phyDat} object} -\usage{ -PhyDat2Morphy(phy, gap = "inapplicable", weight = attr(phy, "weight")) -} -\arguments{ -\item{phy}{An object of \pkg{phangorn} class \code{phyDat}.} - -\item{gap}{An unambiguous abbreviation of \code{inapplicable}, \code{ambiguous} -(= \code{missing}), or \verb{extra state}, specifying how gaps will be handled.} - -\item{weight}{Numeric giving weight to apply to each character. -Will be recycled.} -} -\value{ -\code{PhyDat2Morphy()} returns a pointer to an initialized Morphy object. -} -\description{ -Creates a new Morphy object with the same size and characters as the -\code{phyDat} object. -Once finished with the object, it should be destroyed using -\code{\link[=UnloadMorphy]{UnloadMorphy()}} to free the allocated memory. -} -\examples{ -data("Lobo", package="TreeTools") -morphyObj <- PhyDat2Morphy(Lobo.phy) -# Set object to be destroyed at end of session or closure of function -# on.exit(morphyObj <- UnloadMorphy(morphyObj), add = TRUE) - -# Do something with pointer -# .... - -# Or, instead of on.exit, manually destroy morphy object and free memory: -morphyObj <- UnloadMorphy(morphyObj) -} -\seealso{ -Other Morphy API functions: -\code{\link[=GapHandler]{GapHandler()}}, -\code{\link[=MorphyErrorCheck]{MorphyErrorCheck()}}, -\code{\link[=MorphyWeights]{MorphyWeights()}}, -\code{\link[=SingleCharMorphy]{SingleCharMorphy()}}, -\code{\link[=UnloadMorphy]{UnloadMorphy()}}, -\code{\link[=is.morphyPtr]{is.morphyPtr()}}, -\code{\link[=mpl_apply_tipdata]{mpl_apply_tipdata()}}, -\code{\link[=mpl_attach_rawdata]{mpl_attach_rawdata()}}, -\code{\link[=mpl_attach_symbols]{mpl_attach_symbols()}}, -\code{\link[=mpl_delete_Morphy]{mpl_delete_Morphy()}}, -\code{\link[=mpl_first_down_recon]{mpl_first_down_recon()}}, -\code{\link[=mpl_first_up_recon]{mpl_first_up_recon()}}, -\code{\link[=mpl_get_charac_weight]{mpl_get_charac_weight()}}, -\code{\link[=mpl_get_gaphandl]{mpl_get_gaphandl()}}, -\code{\link[=mpl_get_num_charac]{mpl_get_num_charac()}}, -\code{\link[=mpl_get_num_internal_nodes]{mpl_get_num_internal_nodes()}}, -\code{\link[=mpl_get_numtaxa]{mpl_get_numtaxa()}}, -\code{\link[=mpl_get_symbols]{mpl_get_symbols()}}, -\code{\link[=mpl_init_Morphy]{mpl_init_Morphy()}}, -\code{\link[=mpl_new_Morphy]{mpl_new_Morphy()}}, -\code{\link[=mpl_second_down_recon]{mpl_second_down_recon()}}, -\code{\link[=mpl_second_up_recon]{mpl_second_up_recon()}}, -\code{\link[=mpl_set_charac_weight]{mpl_set_charac_weight()}}, -\code{\link[=mpl_set_num_internal_nodes]{mpl_set_num_internal_nodes()}}, -\code{\link[=mpl_set_parsim_t]{mpl_set_parsim_t()}}, -\code{\link[=mpl_translate_error]{mpl_translate_error()}}, -\code{\link[=mpl_update_lower_root]{mpl_update_lower_root()}}, -\code{\link[=mpl_update_tip]{mpl_update_tip()}}, -\code{\link[=summary.morphyPtr]{summary.morphyPtr()}} -} -\author{ -\href{https://smithlabdurham.github.io/}{Martin R. Smith} -(\href{mailto:martin.smith@durham.ac.uk}{martin.smith@durham.ac.uk}) -} -\concept{Morphy API functions} diff --git a/man/PrepareData.Rd b/man/PrepareData.Rd new file mode 100644 index 000000000..c0728e3f9 --- /dev/null +++ b/man/PrepareData.Rd @@ -0,0 +1,70 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/PrepareData.R +\name{PrepareData} +\alias{PrepareData} +\alias{ReleaseData} +\alias{is.ParsimonyData} +\title{Prepare a dataset for tree scoring} +\usage{ +PrepareData(dataset, concavity = Inf) + +ReleaseData(x) + +is.ParsimonyData(x) +} +\arguments{ +\item{dataset}{An object of \pkg{phangorn} class \code{phyDat}.} + +\item{concavity}{Determines the optimality criterion under which trees are +scored: +\code{Inf} (the default) for equal-weights parsimony; +a finite, positive number for implied weighting with that concavity constant +\insertCite{Goloboff1993}{TreeSearch}; +or the string \code{"profile"} for profile parsimony +\insertCite{Faith2001}{TreeSearch}.} + +\item{x}{A \code{ParsimonyData} object.} +} +\value{ +\code{PrepareData()} returns an object of class \code{ParsimonyData}: a list of +pre-extracted scoring matrices suitable for \code{\link[=EdgeListScore]{EdgeListScore()}}. + +\code{ReleaseData()} returns its argument invisibly. + +\code{is.ParsimonyData()} returns \code{TRUE} or \code{FALSE}. +} +\description{ +\code{PrepareData()} extracts the matrices that the native C++ Fitch engine needs +in order to score a tree repeatedly, for use with the custom-search +functions \code{\link[=TreeSearch]{TreeSearch()}}, \code{\link[=Ratchet]{Ratchet()}} and \code{\link[=Jackknife]{Jackknife()}} (as their +\code{InitializeData} argument). Once finished, release it with \code{\link[=ReleaseData]{ReleaseData()}} +(a formality: the object holds no external resources). +} +\section{Functions}{ +\itemize{ +\item \code{ReleaseData()}: Release a prepared dataset. A no-op retained for the +custom-search \code{CleanUpData} hook (the object is managed by R's garbage +collector). + +\item \code{is.ParsimonyData()}: Test whether an object is a \code{ParsimonyData} handle. + +}} +\references{ +\insertAllCited{} +} +\seealso{ +Custom searches that consume the object: \code{\link[=TreeSearch]{TreeSearch()}}, \code{\link[=Ratchet]{Ratchet()}}, +\code{\link[=Jackknife]{Jackknife()}}. + +Other custom search functions: +\code{\link{BootstrapTree}()}, +\code{\link{EdgeListSearch}()}, +\code{\link{Jackknife}()}, +\code{\link{SingleCharData}()}, +\code{\link{SuccessiveApproximations}()} +} +\author{ +\href{https://smithlabdurham.github.io/}{Martin R. Smith} +(\href{mailto:martin.smith@durham.ac.uk}{martin.smith@durham.ac.uk}) +} +\concept{custom search functions} diff --git a/man/PrepareDataProfile.Rd b/man/PrepareDataProfile.Rd index 072f2e65b..c4afd6713 100644 --- a/man/PrepareDataProfile.Rd +++ b/man/PrepareDataProfile.Rd @@ -71,10 +71,10 @@ dataset <- congreveLamsdellMatrices[[42]] PrepareDataProfile(dataset) } \seealso{ -Other profile parsimony functions: -\code{\link[=MaddisonSlatkin]{MaddisonSlatkin()}}, -\code{\link[=StepInformation]{StepInformation()}}, -\code{\link[=WithOneExtraStep]{WithOneExtraStep()}}, +Other profile parsimony functions: +\code{\link{MaddisonSlatkin}()}, +\code{\link{StepInformation}()}, +\code{\link{WithOneExtraStep}()}, \code{\link{profiles}} } \author{ diff --git a/man/PresCont.Rd b/man/PresCont.Rd index 5e1b38546..23b2f7153 100644 --- a/man/PresCont.Rd +++ b/man/PresCont.Rd @@ -102,13 +102,13 @@ gpc of trees that contain the split, and the frequency of the most contradicted split, respectively. -Other split support functions: -\code{\link[=ConcordanceTable]{ConcordanceTable()}}, -\code{\link[=JackLabels]{JackLabels()}}, -\code{\link[=Jackknife]{Jackknife()}}, -\code{\link[=Morphy]{Morphy()}}, -\code{\link[=MostContradictedFreq]{MostContradictedFreq()}}, -\code{\link[=PaintCharacters]{PaintCharacters()}}, +Other split support functions: +\code{\link{ConcordanceTable}()}, +\code{\link{JackLabels}()}, +\code{\link{Jackknife}()}, +\code{\link{MostContradictedFreq}()}, +\code{\link{PaintCharacters}()}, +\code{\link{Resample}()}, \code{\link{SiteConcordance}} } \author{ diff --git a/man/QACol.Rd b/man/QACol.Rd index 3256f257d..f7baeabbd 100644 --- a/man/QACol.Rd +++ b/man/QACol.Rd @@ -60,10 +60,10 @@ plot(quality, amount, col = QACol(quality, amount), pch = 15) abline(v = 0) } \seealso{ -Other utility functions: -\code{\link[=ClusterStrings]{ClusterStrings()}}, -\code{\link[=QuartetResolution]{QuartetResolution()}}, -\code{\link[=WhenFirstHit]{WhenFirstHit()}} +Other utility functions: +\code{\link{ClusterStrings}()}, +\code{\link{QuartetResolution}()}, +\code{\link{WhenFirstHit}()} } \author{ \href{https://smithlabdurham.github.io/}{Martin R. Smith} diff --git a/man/QuartetResolution.Rd b/man/QuartetResolution.Rd index 01fb495df..f3c780e5b 100644 --- a/man/QuartetResolution.Rd +++ b/man/QuartetResolution.Rd @@ -25,9 +25,9 @@ tips <- c("Lingula", "Halkieria", "Wiwaxia", "Acaenoplax") QuartetResolution(trees, tips) } \seealso{ -Other utility functions: -\code{\link[=ClusterStrings]{ClusterStrings()}}, -\code{\link[=QACol]{QACol()}}, -\code{\link[=WhenFirstHit]{WhenFirstHit()}} +Other utility functions: +\code{\link{ClusterStrings}()}, +\code{\link{QACol}()}, +\code{\link{WhenFirstHit}()} } \concept{utility functions} diff --git a/man/RandomMorphyTree.Rd b/man/RandomPostorderTree.Rd similarity index 78% rename from man/RandomMorphyTree.Rd rename to man/RandomPostorderTree.Rd index 543fd8646..84841d78c 100644 --- a/man/RandomMorphyTree.Rd +++ b/man/RandomPostorderTree.Rd @@ -1,10 +1,10 @@ % Generated by roxygen2: do not edit by hand % Please edit documentation in R/RandomTreeScore.R -\name{RandomMorphyTree} -\alias{RandomMorphyTree} +\name{RandomPostorderTree} +\alias{RandomPostorderTree} \title{Random postorder tree} \usage{ -RandomMorphyTree(nTip) +RandomPostorderTree(nTip) } \arguments{ \item{nTip}{Integer specifying the number of tips to include in the tree @@ -23,7 +23,7 @@ containing: Random postorder tree } \seealso{ -Other tree generation functions: -\code{\link[=AdditionTree]{AdditionTree()}} +Other tree generation functions: +\code{\link{AdditionTree}()} } \concept{tree generation functions} diff --git a/man/RandomTreeScore.Rd b/man/RandomTreeScore.Rd index b87ea057f..db1fb6c10 100644 --- a/man/RandomTreeScore.Rd +++ b/man/RandomTreeScore.Rd @@ -7,8 +7,8 @@ RandomTreeScore(dataset) } \arguments{ -\item{dataset}{A \code{phyDat} object (recommended) or a Morphy object created -with \code{\link[=PhyDat2Morphy]{PhyDat2Morphy()}} (legacy; deprecated).} +\item{dataset}{A \code{phyDat} object (recommended), or a \code{ParsimonyData} object +created with \code{\link[=PrepareData]{PrepareData()}}.} } \value{ \code{RandomTreeScore()} returns a numeric parsimony score. diff --git a/man/Ratchet.Rd b/man/Ratchet.Rd index 0cf2d2e98..dd3a54e95 100644 --- a/man/Ratchet.Rd +++ b/man/Ratchet.Rd @@ -1,15 +1,15 @@ % Generated by roxygen2: do not edit by hand % Please edit documentation in R/Bootstrap.R, R/Ratchet.R -\name{MorphyBootstrap} -\alias{MorphyBootstrap} +\name{BootstrapTree} +\alias{BootstrapTree} \alias{Ratchet} \alias{MultiRatchet} \alias{RatchetConsensus} \title{Parsimony Ratchet} \usage{ -MorphyBootstrap( +BootstrapTree( edgeList, - morphyObj, + dataset, EdgeSwapper = NNISwap, maxIter, maxHits, @@ -22,10 +22,11 @@ MorphyBootstrap( Ratchet( tree, dataset, - InitializeData = PhyDat2Morphy, - CleanUpData = UnloadMorphy, - TreeScorer = MorphyLength, - Bootstrapper = MorphyBootstrap, + concavity = Inf, + InitializeData = PrepareData, + CleanUpData = ReleaseData, + TreeScorer = EdgeListScore, + Bootstrapper = BootstrapTree, swappers = list(TBRSwap, SPRSwap, NNISwap), BootstrapSwapper = if (is.list(swappers)) swappers[[length(swappers)]] else swappers, returnAll = FALSE, @@ -78,8 +79,7 @@ RatchetConsensus( \item (optionally, if score provided) number of times this score has been hit }} -\item{morphyObj}{Object of class \code{morphy}, perhaps created with -\code{\link[=PhyDat2Morphy]{PhyDat2Morphy()}}.} +\item{dataset}{a dataset in the format required by \code{TreeScorer()}.} \item{EdgeSwapper}{a function that rearranges a parent and child vector, and returns a list with modified vectors; for example \code{\link[=SPRSwap]{SPRSwap()}}.} @@ -109,13 +109,18 @@ by \code{attr(FunctionName, "stopAtPlateau") <- TRUE}.} with the desired outgroup. Edge lengths are not supported and will be removed.} -\item{dataset}{a dataset in the format required by \code{TreeScorer()}.} +\item{concavity}{Determines the optimality criterion when the default native +scorer is used: \code{Inf} (the default) for equal weights; a finite, positive +number for implied weighting with that concavity constant +\insertCite{Goloboff1993}{TreeSearch}; or \code{"profile"} for profile parsimony. +Ignored if a custom \code{InitializeData} is supplied (prepare the data yourself).} -\item{InitializeData}{Function that sets up data object to prepare for tree search. -The function will be passed the \code{dataset} parameter. +\item{InitializeData}{Function that sets up data object to prepare for tree +search. The default, \code{\link[=PrepareData]{PrepareData()}}, is called with \code{concavity}; +a custom function will be passed only the \code{dataset} parameter. Its return value will be passed to \code{TreeScorer()} and \code{CleanUpData()}.} -\item{CleanUpData}{Function to destroy data object on function exit. +\item{CleanUpData}{Function to release the data object on function exit. The function will be passed the value returned by \code{InitializeData()}.} \item{TreeScorer}{function to score a given tree. @@ -171,7 +176,7 @@ Defaults to a small value that will counter rounding errors.} (for \code{RatchetConsensus()})} } \value{ -\code{MorphyBootstrap()} returns a tree that is optimal under a random +\code{BootstrapTree()} returns a tree that is optimal under a random sampling of the original characters. \code{Ratchet()} returns a tree modified by parsimony ratchet iterations. @@ -215,10 +220,12 @@ par(oldPar) \pkg{phangorn} package. } -Other custom search functions: -\code{\link[=EdgeListSearch]{EdgeListSearch()}}, -\code{\link[=Jackknife]{Jackknife()}}, -\code{\link[=SuccessiveApproximations]{SuccessiveApproximations()}} +Other custom search functions: +\code{\link{EdgeListSearch}()}, +\code{\link{Jackknife}()}, +\code{\link{PrepareData}()}, +\code{\link{SingleCharData}()}, +\code{\link{SuccessiveApproximations}()} } \author{ \href{https://smithlabdurham.github.io/}{Martin R. Smith} diff --git a/man/RearrangeEdges.Rd b/man/RearrangeEdges.Rd index 1b951f58c..67b61e7f8 100644 --- a/man/RearrangeEdges.Rd +++ b/man/RearrangeEdges.Rd @@ -8,7 +8,7 @@ RearrangeEdges( parent, child, dataset, - TreeScorer = MorphyLength, + TreeScorer = EdgeListScore, EdgeSwapper, scoreToBeat = TreeScorer(parent, child, dataset, ...), iter = "?", @@ -71,10 +71,8 @@ tree <- TreeTools::NJTree(Lobo.phy) edge <- tree$edge parent <- edge[, 1] child <- edge[, 2] -dataset <- PhyDat2Morphy(Lobo.phy) +dataset <- PrepareData(Lobo.phy) RearrangeEdges(parent, child, dataset, EdgeSwapper = RootedNNISwap) -# Remember to free memory: -dataset <- UnloadMorphy(dataset) } \author{ \href{https://smithlabdurham.github.io/}{Martin R. Smith} diff --git a/man/SPR.Rd b/man/SPR.Rd index ca49e66dd..4d4a6876d 100644 --- a/man/SPR.Rd +++ b/man/SPR.Rd @@ -107,9 +107,9 @@ SPR(tree) \item \code{\link[=RootedSPR]{RootedSPR()}}: useful when the position of the root node should be retained. } -Other tree rearrangement functions: -\code{\link[=NNI]{NNI()}}, -\code{\link[=TBR]{TBR()}} +Other tree rearrangement functions: +\code{\link{NNI}()}, +\code{\link{TBR}()} } \author{ Martin R. Smith diff --git a/man/SingleCharData.Rd b/man/SingleCharData.Rd new file mode 100644 index 000000000..7ad4c61d7 --- /dev/null +++ b/man/SingleCharData.Rd @@ -0,0 +1,36 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/PrepareData.R +\name{SingleCharData} +\alias{SingleCharData} +\title{Prepare a single character for scoring} +\usage{ +SingleCharData(char) +} +\arguments{ +\item{char}{State of each tip in turn, in a format understood by +\code{\link[TreeTools:MatrixToPhyDat]{TreeTools::MatrixToPhyDat()}} (e.g. the Morphy token string \code{"-0-0"}).} +} +\value{ +\code{SingleCharData()} returns a \code{ParsimonyData} object. +} +\description{ +Builds a one-character \code{\link[=PrepareData]{ParsimonyData}} object, chiefly for +\code{\link[=RandomTreeScore]{RandomTreeScore()}} and testing. +} +\examples{ +obj <- SingleCharData("-0-0") +RandomTreeScore(obj) +} +\seealso{ +Other custom search functions: +\code{\link{BootstrapTree}()}, +\code{\link{EdgeListSearch}()}, +\code{\link{Jackknife}()}, +\code{\link{PrepareData}()}, +\code{\link{SuccessiveApproximations}()} +} +\author{ +\href{https://smithlabdurham.github.io/}{Martin R. Smith} +(\href{mailto:martin.smith@durham.ac.uk}{martin.smith@durham.ac.uk}) +} +\concept{custom search functions} diff --git a/man/SingleCharMorphy.Rd b/man/SingleCharMorphy.Rd deleted file mode 100644 index fca070c76..000000000 --- a/man/SingleCharMorphy.Rd +++ /dev/null @@ -1,66 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/mpl_morphy_objects.R -\name{SingleCharMorphy} -\alias{SingleCharMorphy} -\title{Morphy object from single character} -\usage{ -SingleCharMorphy(char, gap = "inapp") -} -\arguments{ -\item{char}{State of each character at each tip in turn, in a format that will be converted -to a character string by \code{\link{paste0}(char, ";", collapse="")}.} - -\item{gap}{An unambiguous abbreviation of \code{inapplicable}, \code{ambiguous} -(= \code{missing}), or \verb{extra state}, specifying how gaps will be handled.} -} -\value{ -A pointer to an object of class \code{morphyObj}. -Don't forget to unload it when you've finished with it. -} -\description{ -Morphy object from single character -} -\examples{ -morphyObj <- SingleCharMorphy("-0-0", gap = "Extra") -RandomTreeScore(morphyObj) -morphyObj <- UnloadMorphy(morphyObj) -} -\seealso{ -Score a tree: \code{\link[=MorphyTreeLength]{MorphyTreeLength()}} - -Other Morphy API functions: -\code{\link[=GapHandler]{GapHandler()}}, -\code{\link[=MorphyErrorCheck]{MorphyErrorCheck()}}, -\code{\link[=MorphyWeights]{MorphyWeights()}}, -\code{\link[=PhyDat2Morphy]{PhyDat2Morphy()}}, -\code{\link[=UnloadMorphy]{UnloadMorphy()}}, -\code{\link[=is.morphyPtr]{is.morphyPtr()}}, -\code{\link[=mpl_apply_tipdata]{mpl_apply_tipdata()}}, -\code{\link[=mpl_attach_rawdata]{mpl_attach_rawdata()}}, -\code{\link[=mpl_attach_symbols]{mpl_attach_symbols()}}, -\code{\link[=mpl_delete_Morphy]{mpl_delete_Morphy()}}, -\code{\link[=mpl_first_down_recon]{mpl_first_down_recon()}}, -\code{\link[=mpl_first_up_recon]{mpl_first_up_recon()}}, -\code{\link[=mpl_get_charac_weight]{mpl_get_charac_weight()}}, -\code{\link[=mpl_get_gaphandl]{mpl_get_gaphandl()}}, -\code{\link[=mpl_get_num_charac]{mpl_get_num_charac()}}, -\code{\link[=mpl_get_num_internal_nodes]{mpl_get_num_internal_nodes()}}, -\code{\link[=mpl_get_numtaxa]{mpl_get_numtaxa()}}, -\code{\link[=mpl_get_symbols]{mpl_get_symbols()}}, -\code{\link[=mpl_init_Morphy]{mpl_init_Morphy()}}, -\code{\link[=mpl_new_Morphy]{mpl_new_Morphy()}}, -\code{\link[=mpl_second_down_recon]{mpl_second_down_recon()}}, -\code{\link[=mpl_second_up_recon]{mpl_second_up_recon()}}, -\code{\link[=mpl_set_charac_weight]{mpl_set_charac_weight()}}, -\code{\link[=mpl_set_num_internal_nodes]{mpl_set_num_internal_nodes()}}, -\code{\link[=mpl_set_parsim_t]{mpl_set_parsim_t()}}, -\code{\link[=mpl_translate_error]{mpl_translate_error()}}, -\code{\link[=mpl_update_lower_root]{mpl_update_lower_root()}}, -\code{\link[=mpl_update_tip]{mpl_update_tip()}}, -\code{\link[=summary.morphyPtr]{summary.morphyPtr()}} -} -\author{ -\href{https://smithlabdurham.github.io/}{Martin R. Smith} -(\href{mailto:martin.smith@durham.ac.uk}{martin.smith@durham.ac.uk}) -} -\concept{Morphy API functions} diff --git a/man/SiteConcordance.Rd b/man/SiteConcordance.Rd index 0139ea63f..8d96dcf95 100644 --- a/man/SiteConcordance.Rd +++ b/man/SiteConcordance.Rd @@ -244,14 +244,14 @@ ClusteringConcordance(TreeTools::NJTree(myMatrix), myMatrix) \item \code{\link[=Consistency]{Consistency()}}: Measure consistency of characters with dataset. } -Other split support functions: -\code{\link[=ConcordanceTable]{ConcordanceTable()}}, -\code{\link[=JackLabels]{JackLabels()}}, -\code{\link[=Jackknife]{Jackknife()}}, -\code{\link[=Morphy]{Morphy()}}, -\code{\link[=MostContradictedFreq]{MostContradictedFreq()}}, -\code{\link[=PaintCharacters]{PaintCharacters()}}, -\code{\link[=PresCont]{PresCont()}} +Other split support functions: +\code{\link{ConcordanceTable}()}, +\code{\link{JackLabels}()}, +\code{\link{Jackknife}()}, +\code{\link{MostContradictedFreq}()}, +\code{\link{PaintCharacters}()}, +\code{\link{PresCont}()}, +\code{\link{Resample}()} } \author{ \href{https://smithlabdurham.github.io/}{Martin R. Smith} diff --git a/man/StepInformation.Rd b/man/StepInformation.Rd index 14235d586..e0def9791 100644 --- a/man/StepInformation.Rd +++ b/man/StepInformation.Rd @@ -72,10 +72,10 @@ character <- rep(c(0:3, "?", "-"), c(8, 5, 1, 1, 2, 2)) StepInformation(character) } \seealso{ -Other profile parsimony functions: -\code{\link[=MaddisonSlatkin]{MaddisonSlatkin()}}, -\code{\link[=PrepareDataProfile]{PrepareDataProfile()}}, -\code{\link[=WithOneExtraStep]{WithOneExtraStep()}}, +Other profile parsimony functions: +\code{\link{MaddisonSlatkin}()}, +\code{\link{PrepareDataProfile}()}, +\code{\link{WithOneExtraStep}()}, \code{\link{profiles}} } \author{ diff --git a/man/SuccessiveApproximations.Rd b/man/SuccessiveApproximations.Rd index 0adf4a584..665557d44 100644 --- a/man/SuccessiveApproximations.Rd +++ b/man/SuccessiveApproximations.Rd @@ -109,10 +109,12 @@ criterion \insertCite{Farris1969}{TreeSearch}. \insertAllCited{} } \seealso{ -Other custom search functions: -\code{\link[=EdgeListSearch]{EdgeListSearch()}}, -\code{\link[=Jackknife]{Jackknife()}}, -\code{\link[=MorphyBootstrap]{MorphyBootstrap()}} +Other custom search functions: +\code{\link{BootstrapTree}()}, +\code{\link{EdgeListSearch}()}, +\code{\link{Jackknife}()}, +\code{\link{PrepareData}()}, +\code{\link{SingleCharData}()} } \concept{custom search functions} \keyword{internal} diff --git a/man/TBR.Rd b/man/TBR.Rd index 2df173d4b..f5e6c8596 100644 --- a/man/TBR.Rd +++ b/man/TBR.Rd @@ -102,9 +102,9 @@ TBR(tree) \seealso{ \code{\link[=RootedTBR]{RootedTBR()}}: useful when the position of the root node should be retained. -Other tree rearrangement functions: -\code{\link[=NNI]{NNI()}}, -\code{\link[=SPR]{SPR()}} +Other tree rearrangement functions: +\code{\link{NNI}()}, +\code{\link{SPR}()} } \author{ \href{https://smithlabdurham.github.io/}{Martin R. Smith} diff --git a/man/TaxonInfluence.Rd b/man/TaxonInfluence.Rd index 93de7fc39..90d0d5776 100644 --- a/man/TaxonInfluence.Rd +++ b/man/TaxonInfluence.Rd @@ -132,19 +132,19 @@ PlotTools::SpectrumLegend( \insertAllCited{} } \seealso{ -Other tree scoring: -\code{\link[=CharacterHierarchy]{CharacterHierarchy()}}, -\code{\link[=CharacterLength]{CharacterLength()}}, -\code{\link[=ExpectedLength]{ExpectedLength()}}, -\code{\link[=IWScore]{IWScore()}}, -\code{\link[=LengthAdded]{LengthAdded()}}, -\code{\link[=MaximizeParsimony]{MaximizeParsimony()}}, -\code{\link[=MinimumLength]{MinimumLength()}}, -\code{\link[=MorphyTreeLength]{MorphyTreeLength()}}, -\code{\link[=ParsSim]{ParsSim()}}, -\code{\link[=WideSample]{WideSample()}}, -\code{\link[=hierarchy_from_names]{hierarchy_from_names()}}, -\code{\link[=recode_hierarchy]{recode_hierarchy()}} +Other tree scoring: +\code{\link{CharacterHierarchy}()}, +\code{\link{CharacterLength}()}, +\code{\link{ExpectedLength}()}, +\code{\link{IWScore}()}, +\code{\link{LengthAdded}()}, +\code{\link{MaximizeParsimony}()}, +\code{\link{MinimumLength}()}, +\code{\link{ParsSim}()}, +\code{\link{TreeScore}()}, +\code{\link{WideSample}()}, +\code{\link{hierarchy_from_names}()}, +\code{\link{recode_hierarchy}()} } \author{ \href{https://smithlabdurham.github.io/}{Martin R. Smith} diff --git a/man/TreeLength.Rd b/man/TreeLength.Rd index 37e59531a..3af591bcd 100644 --- a/man/TreeLength.Rd +++ b/man/TreeLength.Rd @@ -185,19 +185,19 @@ TreeLength(tree6, dataset6, hierarchy = hier, inapplicable = "hsj") \item See score for each character: \code{\link[=CharacterLength]{CharacterLength()}}. } -Other tree scoring: -\code{\link[=CharacterHierarchy]{CharacterHierarchy()}}, -\code{\link[=CharacterLength]{CharacterLength()}}, -\code{\link[=ExpectedLength]{ExpectedLength()}}, -\code{\link[=LengthAdded]{LengthAdded()}}, -\code{\link[=MaximizeParsimony]{MaximizeParsimony()}}, -\code{\link[=MinimumLength]{MinimumLength()}}, -\code{\link[=MorphyTreeLength]{MorphyTreeLength()}}, -\code{\link[=ParsSim]{ParsSim()}}, -\code{\link[=TaxonInfluence]{TaxonInfluence()}}, -\code{\link[=WideSample]{WideSample()}}, -\code{\link[=hierarchy_from_names]{hierarchy_from_names()}}, -\code{\link[=recode_hierarchy]{recode_hierarchy()}} +Other tree scoring: +\code{\link{CharacterHierarchy}()}, +\code{\link{CharacterLength}()}, +\code{\link{ExpectedLength}()}, +\code{\link{LengthAdded}()}, +\code{\link{MaximizeParsimony}()}, +\code{\link{MinimumLength}()}, +\code{\link{ParsSim}()}, +\code{\link{TaxonInfluence}()}, +\code{\link{TreeScore}()}, +\code{\link{WideSample}()}, +\code{\link{hierarchy_from_names}()}, +\code{\link{recode_hierarchy}()} } \author{ Martin R. Smith diff --git a/man/TreeScore.Rd b/man/TreeScore.Rd new file mode 100644 index 000000000..7a9ae66a9 --- /dev/null +++ b/man/TreeScore.Rd @@ -0,0 +1,77 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/tree_length.R +\name{TreeScore} +\alias{TreeScore} +\alias{EdgeListScore} +\title{Score a tree from prepared data} +\usage{ +TreeScore(tree, dataset) + +EdgeListScore(parent, child, dataset, inPostorder = FALSE, ...) +} +\arguments{ +\item{tree}{A tree of class \code{\link[ape:read.tree]{phylo}}, with tip +labels in the order generated by \code{\link[TreeTools]{RenumberTips}}, +i.e. corresponding to the sequence of taxa in the corresponding Morphy object.} + +\item{dataset}{A \code{ParsimonyData} object from \code{\link[=PrepareData]{PrepareData()}}.} + +\item{parent}{Integer vector corresponding to the first column of the edge +matrix of a tree of class \code{\link[ape]{phylo}}, i.e. +\code{tree[["edge"]][, 1]}} + +\item{child}{Integer vector corresponding to the second column of the edge +matrix of a tree of class \code{\link[ape]{phylo}}, i.e. +\code{tree[["edge"]][, 2]}.} + +\item{inPostorder}{Logical: are the edges already in postorder? If \code{FALSE} +(the default) they are reordered before scoring.} + +\item{\dots}{Unused; for interface compatibility with custom \code{TreeScorer}s.} +} +\value{ +\code{TreeScore()} returns the parsimony score of \code{tree} under the +optimality criterion baked into \code{dataset} (equal weights, implied weights or +profile parsimony). + +\code{EdgeListScore()} returns the parsimony score (a numeric). +} +\description{ +\code{TreeScore()} and \code{EdgeListScore()} compute the parsimony score of a tree +with the native C++ Fitch engine, using a dataset prepared by +\code{\link[=PrepareData]{PrepareData()}}. +\code{EdgeListScore()} is the low-level scorer used as the default \code{TreeScorer} +by the custom-search functions; \code{TreeScore()} is a convenience wrapper that +takes a \code{phylo} tree. Most users want the higher-level \code{\link[=TreeLength]{TreeLength()}}. +} +\section{Functions}{ +\itemize{ +\item \code{EdgeListScore()}: Low-level scorer taking parent and child vectors; the +default \code{TreeScorer} for \code{\link[=TreeSearch]{TreeSearch()}}, \code{\link[=Ratchet]{Ratchet()}} and +\code{\link[=Jackknife]{Jackknife()}}. Scores via the native \code{ts_fitch_score()} kernel, which +handles the Brazeau-Guillerme-Smith inapplicable algorithm correctly +(including the \verb{\{1-\}} case that MorphyLib mis-scored). + +}} +\seealso{ +\code{\link[=PrepareData]{PrepareData()}}; user-facing scoring with \code{\link[=TreeLength]{TreeLength()}}. + +Other tree scoring: +\code{\link{CharacterHierarchy}()}, +\code{\link{CharacterLength}()}, +\code{\link{ExpectedLength}()}, +\code{\link{IWScore}()}, +\code{\link{LengthAdded}()}, +\code{\link{MaximizeParsimony}()}, +\code{\link{MinimumLength}()}, +\code{\link{ParsSim}()}, +\code{\link{TaxonInfluence}()}, +\code{\link{WideSample}()}, +\code{\link{hierarchy_from_names}()}, +\code{\link{recode_hierarchy}()} +} +\author{ +Martin R. Smith +} +\concept{tree scoring} +\keyword{internal} diff --git a/man/TreeSearch-deprecated.Rd b/man/TreeSearch-deprecated.Rd new file mode 100644 index 000000000..f5e096e7e --- /dev/null +++ b/man/TreeSearch-deprecated.Rd @@ -0,0 +1,51 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/morphy-deprecated.R +\name{TreeSearch-deprecated} +\alias{TreeSearch-deprecated} +\alias{PhyDat2Morphy} +\alias{SingleCharMorphy} +\alias{UnloadMorphy} +\alias{is.morphyPtr} +\alias{MorphyLength} +\alias{MorphyTreeLength} +\alias{MorphyBootstrap} +\alias{RandomMorphyTree} +\title{Deprecated MorphyLib functions} +\usage{ +PhyDat2Morphy(phy, gap = "inapplicable", weight = attr(phy, "weight")) + +SingleCharMorphy(char, gap = "inapp") + +UnloadMorphy(morphyObj) + +is.morphyPtr(morphyObj) + +MorphyLength(parent, child, morphyObj, inPostorder = FALSE, nTaxa = NULL) + +MorphyTreeLength(tree, morphyObj) + +MorphyBootstrap(edgeList, morphyObj, ...) + +RandomMorphyTree(nTip) +} +\arguments{ +\item{phy, char, morphyObj, tree, parent, child, edgeList, nTip, gap, weight, inPostorder, nTaxa, \dots}{Passed to the replacement function.} +} +\value{ +The value of the corresponding replacement function. +} +\description{ +These MorphyLib-era functions are retained as deprecated aliases of their +native-scoring replacements and will be removed in a future release: +\itemize{ +\item \code{PhyDat2Morphy()} -> \code{\link[=PrepareData]{PrepareData()}} +\item \code{SingleCharMorphy()} -> \code{\link[=SingleCharData]{SingleCharData()}} +\item \code{UnloadMorphy()} -> \code{\link[=ReleaseData]{ReleaseData()}} +\item \code{is.morphyPtr()} -> \code{\link[=is.ParsimonyData]{is.ParsimonyData()}} +\item \code{MorphyLength()} -> \code{\link[=EdgeListScore]{EdgeListScore()}} +\item \code{MorphyTreeLength()} -> \code{\link[=TreeScore]{TreeScore()}} +\item \code{MorphyBootstrap()} -> \code{\link[=BootstrapTree]{BootstrapTree()}} +\item \code{RandomMorphyTree()} -> \code{\link[=RandomPostorderTree]{RandomPostorderTree()}} +} +} +\keyword{internal} diff --git a/man/TreeSearch.Rd b/man/TreeSearch.Rd index cb852b507..6eab24547 100644 --- a/man/TreeSearch.Rd +++ b/man/TreeSearch.Rd @@ -12,7 +12,7 @@ EdgeListSearch( edgeList, dataset, - TreeScorer = MorphyLength, + TreeScorer = EdgeListScore, EdgeSwapper = RootedTBRSwap, maxIter = 100, maxHits = 20, @@ -27,9 +27,10 @@ EdgeListSearch( TreeSearch( tree, dataset, - InitializeData = PhyDat2Morphy, - CleanUpData = UnloadMorphy, - TreeScorer = MorphyLength, + concavity = Inf, + InitializeData = PrepareData, + CleanUpData = ReleaseData, + TreeScorer = EdgeListScore, EdgeSwapper = RootedTBRSwap, maxIter = 100L, maxHits = 20L, @@ -88,11 +89,18 @@ larger numbers provide more verbose feedback to the user.} with the desired outgroup. Edge lengths are not supported and will be removed.} -\item{InitializeData}{Function that sets up data object to prepare for tree search. -The function will be passed the \code{dataset} parameter. +\item{concavity}{Determines the optimality criterion when the default native +scorer is used: \code{Inf} (the default) for equal weights; a finite, positive +number for implied weighting with that concavity constant +\insertCite{Goloboff1993}{TreeSearch}; or \code{"profile"} for profile parsimony. +Ignored if a custom \code{InitializeData} is supplied (prepare the data yourself).} + +\item{InitializeData}{Function that sets up data object to prepare for tree +search. The default, \code{\link[=PrepareData]{PrepareData()}}, is called with \code{concavity}; +a custom function will be passed only the \code{dataset} parameter. Its return value will be passed to \code{TreeScorer()} and \code{CleanUpData()}.} -\item{CleanUpData}{Function to destroy data object on function exit. +\item{CleanUpData}{Function to release the data object on function exit. The function will be passed the value returned by \code{InitializeData()}.} } \value{ @@ -130,6 +138,9 @@ if (interactive()) { TreeSearch(njtree, Lobo.phy, maxIter = 20, EdgeSwapper = NNISwap) TreeSearch(njtree, Lobo.phy, maxIter = 20, EdgeSwapper = RootedSPRSwap) TreeSearch(njtree, Lobo.phy, maxIter = 20, EdgeSwapper = TBRSwap) + + # Implied weighting (concavity constant k = 10): + TreeSearch(njtree, Lobo.phy, concavity = 10, maxIter = 20) } } \seealso{ @@ -140,10 +151,12 @@ if (interactive()) { optima. } -Other custom search functions: -\code{\link[=Jackknife]{Jackknife()}}, -\code{\link[=MorphyBootstrap]{MorphyBootstrap()}}, -\code{\link[=SuccessiveApproximations]{SuccessiveApproximations()}} +Other custom search functions: +\code{\link{BootstrapTree}()}, +\code{\link{Jackknife}()}, +\code{\link{PrepareData}()}, +\code{\link{SingleCharData}()}, +\code{\link{SuccessiveApproximations}()} } \author{ \href{https://smithlabdurham.github.io/}{Martin R. Smith} diff --git a/man/UnloadMorphy.Rd b/man/UnloadMorphy.Rd deleted file mode 100644 index e9fab8c71..000000000 --- a/man/UnloadMorphy.Rd +++ /dev/null @@ -1,59 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/mpl_morphy_objects.R -\name{UnloadMorphy} -\alias{UnloadMorphy} -\title{Destroy a Morphy object} -\usage{ -UnloadMorphy(morphyObj) -} -\arguments{ -\item{morphyObj}{Object of class \code{morphy}, perhaps created with -\code{\link[=PhyDat2Morphy]{PhyDat2Morphy()}}.} -} -\value{ -Morphy error code, decipherable using \code{\link{mpl_translate_error}} -} -\description{ -Destroys a previously-created Morphy object. -} -\details{ -Best practice is to call \code{morphyObj <- UnloadMorphy(morphyObj)} -Failure to do so will cause a crash if \code{UnloadMorphy()} is called on an -object that has already been destroyed -} -\seealso{ -Other Morphy API functions: -\code{\link[=GapHandler]{GapHandler()}}, -\code{\link[=MorphyErrorCheck]{MorphyErrorCheck()}}, -\code{\link[=MorphyWeights]{MorphyWeights()}}, -\code{\link[=PhyDat2Morphy]{PhyDat2Morphy()}}, -\code{\link[=SingleCharMorphy]{SingleCharMorphy()}}, -\code{\link[=is.morphyPtr]{is.morphyPtr()}}, -\code{\link[=mpl_apply_tipdata]{mpl_apply_tipdata()}}, -\code{\link[=mpl_attach_rawdata]{mpl_attach_rawdata()}}, -\code{\link[=mpl_attach_symbols]{mpl_attach_symbols()}}, -\code{\link[=mpl_delete_Morphy]{mpl_delete_Morphy()}}, -\code{\link[=mpl_first_down_recon]{mpl_first_down_recon()}}, -\code{\link[=mpl_first_up_recon]{mpl_first_up_recon()}}, -\code{\link[=mpl_get_charac_weight]{mpl_get_charac_weight()}}, -\code{\link[=mpl_get_gaphandl]{mpl_get_gaphandl()}}, -\code{\link[=mpl_get_num_charac]{mpl_get_num_charac()}}, -\code{\link[=mpl_get_num_internal_nodes]{mpl_get_num_internal_nodes()}}, -\code{\link[=mpl_get_numtaxa]{mpl_get_numtaxa()}}, -\code{\link[=mpl_get_symbols]{mpl_get_symbols()}}, -\code{\link[=mpl_init_Morphy]{mpl_init_Morphy()}}, -\code{\link[=mpl_new_Morphy]{mpl_new_Morphy()}}, -\code{\link[=mpl_second_down_recon]{mpl_second_down_recon()}}, -\code{\link[=mpl_second_up_recon]{mpl_second_up_recon()}}, -\code{\link[=mpl_set_charac_weight]{mpl_set_charac_weight()}}, -\code{\link[=mpl_set_num_internal_nodes]{mpl_set_num_internal_nodes()}}, -\code{\link[=mpl_set_parsim_t]{mpl_set_parsim_t()}}, -\code{\link[=mpl_translate_error]{mpl_translate_error()}}, -\code{\link[=mpl_update_lower_root]{mpl_update_lower_root()}}, -\code{\link[=mpl_update_tip]{mpl_update_tip()}}, -\code{\link[=summary.morphyPtr]{summary.morphyPtr()}} -} -\author{ -Martin R. Smith -} -\concept{Morphy API functions} diff --git a/man/WhenFirstHit.Rd b/man/WhenFirstHit.Rd index b2f067c2b..428e99700 100644 --- a/man/WhenFirstHit.Rd +++ b/man/WhenFirstHit.Rd @@ -18,7 +18,7 @@ Reports when each tree in a list was first found by tree search. This information is read from the \code{firstHit} attribute if present. If not, trees are taken to be listed in the order in which they were found, and named according to the search iteration in which they were first hit - -the situation when trees found by \code{\link[=Morphy]{Morphy()}} are saved to file. +the situation when trees found by \code{\link[=MaximizeParsimony]{MaximizeParsimony()}} are saved to file. } \examples{ library("TreeTools", quietly = TRUE) @@ -33,13 +33,13 @@ attr(WhenFirstHit(trees), "firstHit") } \seealso{ \itemize{ -\item \code{\link[=Morphy]{Morphy()}} +\item \code{\link[=MaximizeParsimony]{MaximizeParsimony()}} } -Other utility functions: -\code{\link[=ClusterStrings]{ClusterStrings()}}, -\code{\link[=QACol]{QACol()}}, -\code{\link[=QuartetResolution]{QuartetResolution()}} +Other utility functions: +\code{\link{ClusterStrings}()}, +\code{\link{QACol}()}, +\code{\link{QuartetResolution}()} } \author{ \href{https://smithlabdurham.github.io/}{Martin R. Smith} diff --git a/man/WideSample.Rd b/man/WideSample.Rd index ca089b3ad..ab05c100d 100644 --- a/man/WideSample.Rd +++ b/man/WideSample.Rd @@ -22,7 +22,7 @@ trees are returned unchanged. If \code{n == 1}, the single most central tree \item{dist}{Either: \itemize{ \item A function giving pairwise distances (default: -\code{\link[TreeDist:ClusteringInfoDistance]{TreeDist::ClusteringInfoDistance()}}). It must support the form +\code{\link[TreeDist:TreeDistance]{TreeDist::ClusteringInfoDistance()}}). It must support the form \code{dist(trees)} returning a \code{dist} object; for the largest tree sets it is additionally called as \code{dist(trees[[i]], trees)} and must then return a numeric vector of length \code{length(trees)} (the distances from @@ -149,19 +149,19 @@ if (requireNamespace("highs", quietly = TRUE)) { \insertRef{Sayyady2016}{TreeSearch} } \seealso{ -Other tree scoring: -\code{\link[=CharacterHierarchy]{CharacterHierarchy()}}, -\code{\link[=CharacterLength]{CharacterLength()}}, -\code{\link[=ExpectedLength]{ExpectedLength()}}, -\code{\link[=IWScore]{IWScore()}}, -\code{\link[=LengthAdded]{LengthAdded()}}, -\code{\link[=MaximizeParsimony]{MaximizeParsimony()}}, -\code{\link[=MinimumLength]{MinimumLength()}}, -\code{\link[=MorphyTreeLength]{MorphyTreeLength()}}, -\code{\link[=ParsSim]{ParsSim()}}, -\code{\link[=TaxonInfluence]{TaxonInfluence()}}, -\code{\link[=hierarchy_from_names]{hierarchy_from_names()}}, -\code{\link[=recode_hierarchy]{recode_hierarchy()}} +Other tree scoring: +\code{\link{CharacterHierarchy}()}, +\code{\link{CharacterLength}()}, +\code{\link{ExpectedLength}()}, +\code{\link{IWScore}()}, +\code{\link{LengthAdded}()}, +\code{\link{MaximizeParsimony}()}, +\code{\link{MinimumLength}()}, +\code{\link{ParsSim}()}, +\code{\link{TaxonInfluence}()}, +\code{\link{TreeScore}()}, +\code{\link{hierarchy_from_names}()}, +\code{\link{recode_hierarchy}()} } \author{ \href{https://smithlabdurham.github.io/}{Martin R. Smith} diff --git a/man/WithOneExtraStep.Rd b/man/WithOneExtraStep.Rd index 75cbee579..0821352e0 100644 --- a/man/WithOneExtraStep.Rd +++ b/man/WithOneExtraStep.Rd @@ -17,10 +17,10 @@ Number of trees with one extra step WithOneExtraStep(1, 2, 3) } \seealso{ -Other profile parsimony functions: -\code{\link[=MaddisonSlatkin]{MaddisonSlatkin()}}, -\code{\link[=PrepareDataProfile]{PrepareDataProfile()}}, -\code{\link[=StepInformation]{StepInformation()}}, +Other profile parsimony functions: +\code{\link{MaddisonSlatkin}()}, +\code{\link{PrepareDataProfile}()}, +\code{\link{StepInformation}()}, \code{\link{profiles}} } \concept{profile parsimony functions} diff --git a/man/dot-CombineResults.Rd b/man/dot-CombineResults.Rd deleted file mode 100644 index e29377568..000000000 --- a/man/dot-CombineResults.Rd +++ /dev/null @@ -1,34 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/Morphy.R -\name{.CombineResults} -\alias{.CombineResults} -\alias{.ReplaceResults} -\title{Combine two edge matrices} -\usage{ -.CombineResults(x, y, stage) - -.ReplaceResults(old, new, stage) -} -\arguments{ -\item{x, y}{3D arrays, each slice containing an edge matrix from a tree -of class \code{phylo}. \code{x} should not contain duplicates.} - -\item{stage}{Integer specifying element of \code{firstHit} in which new hits -should be recorded.} - -\item{old}{old array of edge matrices with \code{firstHit} attribute.} - -\item{new}{new array of edge matrices.} -} -\value{ -A single 3D array containing each unique edge matrix from (\code{x} and) -\code{y}, with a \code{firstHit} attribute as documented in \code{\link[=Morphy]{Morphy()}}. -} -\description{ -Combine two edge matrices -} -\author{ -\href{https://smithlabdurham.github.io/}{Martin R. Smith} -(\href{mailto:martin.smith@durham.ac.uk}{martin.smith@durham.ac.uk}) -} -\keyword{internal} diff --git a/man/dot-GapHandler.Rd b/man/dot-GapHandler.Rd deleted file mode 100644 index 71c2e38a1..000000000 --- a/man/dot-GapHandler.Rd +++ /dev/null @@ -1,19 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/mpl_morphy_objects.R -\name{.GapHandler} -\alias{.GapHandler} -\title{Translate a gap treatment into a string in the format expected by Morphy} -\usage{ -.GapHandler(gap) -} -\arguments{ -\item{gap}{Character vector: how should gaps be handled?} -} -\value{ -Character string that can be translated into a gap handling strategy -by Morphy. -} -\description{ -Translate a gap treatment into a string in the format expected by Morphy -} -\keyword{internal} diff --git a/man/dot-WideSampleMedoid.Rd b/man/dot-WideSampleMedoid.Rd index 28c5de101..c42347a0a 100644 --- a/man/dot-WideSampleMedoid.Rd +++ b/man/dot-WideSampleMedoid.Rd @@ -14,7 +14,7 @@ Returns the index of the most central tree -- the medoid, minimizing summed distance to all others. Uses the distance matrix when one is available or affordable to build; when only a distance function is supplied for a set too large to build a matrix, the central medoid is not affordable, so the -deterministic peripheral seed (\code{\link[MaxMin:FarFirst]{MaxMin::FarFirst()}} with \code{m = 1}) is returned +deterministic peripheral seed (\code{\link[MaxMin:FarFirst]{MaxMin::FarFirst()}} with \code{k = 1}) is returned as a matrix-free fallback. } \keyword{internal} diff --git a/man/hierarchy_from_names.Rd b/man/hierarchy_from_names.Rd index 88832a2de..828e0a999 100644 --- a/man/hierarchy_from_names.Rd +++ b/man/hierarchy_from_names.Rd @@ -29,18 +29,18 @@ hierarchy_from_names(names) \seealso{ \code{\link[=CharacterHierarchy]{CharacterHierarchy()}} -Other tree scoring: -\code{\link[=CharacterHierarchy]{CharacterHierarchy()}}, -\code{\link[=CharacterLength]{CharacterLength()}}, -\code{\link[=ExpectedLength]{ExpectedLength()}}, -\code{\link[=IWScore]{IWScore()}}, -\code{\link[=LengthAdded]{LengthAdded()}}, -\code{\link[=MaximizeParsimony]{MaximizeParsimony()}}, -\code{\link[=MinimumLength]{MinimumLength()}}, -\code{\link[=MorphyTreeLength]{MorphyTreeLength()}}, -\code{\link[=ParsSim]{ParsSim()}}, -\code{\link[=TaxonInfluence]{TaxonInfluence()}}, -\code{\link[=WideSample]{WideSample()}}, -\code{\link[=recode_hierarchy]{recode_hierarchy()}} +Other tree scoring: +\code{\link{CharacterHierarchy}()}, +\code{\link{CharacterLength}()}, +\code{\link{ExpectedLength}()}, +\code{\link{IWScore}()}, +\code{\link{LengthAdded}()}, +\code{\link{MaximizeParsimony}()}, +\code{\link{MinimumLength}()}, +\code{\link{ParsSim}()}, +\code{\link{TaxonInfluence}()}, +\code{\link{TreeScore}()}, +\code{\link{WideSample}()}, +\code{\link{recode_hierarchy}()} } \concept{tree scoring} diff --git a/man/is.morphyPtr.Rd b/man/is.morphyPtr.Rd deleted file mode 100644 index 4f88bf74d..000000000 --- a/man/is.morphyPtr.Rd +++ /dev/null @@ -1,56 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/mpl_morphy_objects.R -\name{is.morphyPtr} -\alias{is.morphyPtr} -\title{Is an object a valid Morphy object?} -\usage{ -is.morphyPtr(morphyObj) -} -\arguments{ -\item{morphyObj}{Object of class \code{morphy}, perhaps created with -\code{\link[=PhyDat2Morphy]{PhyDat2Morphy()}}.} -} -\value{ -\code{is.morphyPtr()} returns \code{TRUE} if \code{morphyObj} is a valid morphy -pointer, \code{FALSE} otherwise. -} -\description{ -Is an object a valid Morphy object? -} -\seealso{ -Other Morphy API functions: -\code{\link[=GapHandler]{GapHandler()}}, -\code{\link[=MorphyErrorCheck]{MorphyErrorCheck()}}, -\code{\link[=MorphyWeights]{MorphyWeights()}}, -\code{\link[=PhyDat2Morphy]{PhyDat2Morphy()}}, -\code{\link[=SingleCharMorphy]{SingleCharMorphy()}}, -\code{\link[=UnloadMorphy]{UnloadMorphy()}}, -\code{\link[=mpl_apply_tipdata]{mpl_apply_tipdata()}}, -\code{\link[=mpl_attach_rawdata]{mpl_attach_rawdata()}}, -\code{\link[=mpl_attach_symbols]{mpl_attach_symbols()}}, -\code{\link[=mpl_delete_Morphy]{mpl_delete_Morphy()}}, -\code{\link[=mpl_first_down_recon]{mpl_first_down_recon()}}, -\code{\link[=mpl_first_up_recon]{mpl_first_up_recon()}}, -\code{\link[=mpl_get_charac_weight]{mpl_get_charac_weight()}}, -\code{\link[=mpl_get_gaphandl]{mpl_get_gaphandl()}}, -\code{\link[=mpl_get_num_charac]{mpl_get_num_charac()}}, -\code{\link[=mpl_get_num_internal_nodes]{mpl_get_num_internal_nodes()}}, -\code{\link[=mpl_get_numtaxa]{mpl_get_numtaxa()}}, -\code{\link[=mpl_get_symbols]{mpl_get_symbols()}}, -\code{\link[=mpl_init_Morphy]{mpl_init_Morphy()}}, -\code{\link[=mpl_new_Morphy]{mpl_new_Morphy()}}, -\code{\link[=mpl_second_down_recon]{mpl_second_down_recon()}}, -\code{\link[=mpl_second_up_recon]{mpl_second_up_recon()}}, -\code{\link[=mpl_set_charac_weight]{mpl_set_charac_weight()}}, -\code{\link[=mpl_set_num_internal_nodes]{mpl_set_num_internal_nodes()}}, -\code{\link[=mpl_set_parsim_t]{mpl_set_parsim_t()}}, -\code{\link[=mpl_translate_error]{mpl_translate_error()}}, -\code{\link[=mpl_update_lower_root]{mpl_update_lower_root()}}, -\code{\link[=mpl_update_tip]{mpl_update_tip()}}, -\code{\link[=summary.morphyPtr]{summary.morphyPtr()}} -} -\author{ -\href{https://smithlabdurham.github.io/}{Martin R. Smith} -(\href{mailto:martin.smith@durham.ac.uk}{martin.smith@durham.ac.uk}) -} -\concept{Morphy API functions} diff --git a/man/mpl_apply_tipdata.Rd b/man/mpl_apply_tipdata.Rd deleted file mode 100644 index 9f958a063..000000000 --- a/man/mpl_apply_tipdata.Rd +++ /dev/null @@ -1,57 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/mpl_morphyex.R -\name{mpl_apply_tipdata} -\alias{mpl_apply_tipdata} -\title{Commits parameters prior to nodal set calculations.} -\usage{ -mpl_apply_tipdata(morphyobj) -} -\arguments{ -\item{morphyobj}{An instance of the Morphy object.} -} -\value{ -A Morphy error code. -} -\description{ -Once the caller is satisfied with the setup of types, weights, -and partitioning, this function must be called, thereby committing the -parameters until any changes are made. If no character types have been -assigned, the function will fail with an error code. -} -\seealso{ -Other Morphy API functions: -\code{\link[=GapHandler]{GapHandler()}}, -\code{\link[=MorphyErrorCheck]{MorphyErrorCheck()}}, -\code{\link[=MorphyWeights]{MorphyWeights()}}, -\code{\link[=PhyDat2Morphy]{PhyDat2Morphy()}}, -\code{\link[=SingleCharMorphy]{SingleCharMorphy()}}, -\code{\link[=UnloadMorphy]{UnloadMorphy()}}, -\code{\link[=is.morphyPtr]{is.morphyPtr()}}, -\code{\link[=mpl_attach_rawdata]{mpl_attach_rawdata()}}, -\code{\link[=mpl_attach_symbols]{mpl_attach_symbols()}}, -\code{\link[=mpl_delete_Morphy]{mpl_delete_Morphy()}}, -\code{\link[=mpl_first_down_recon]{mpl_first_down_recon()}}, -\code{\link[=mpl_first_up_recon]{mpl_first_up_recon()}}, -\code{\link[=mpl_get_charac_weight]{mpl_get_charac_weight()}}, -\code{\link[=mpl_get_gaphandl]{mpl_get_gaphandl()}}, -\code{\link[=mpl_get_num_charac]{mpl_get_num_charac()}}, -\code{\link[=mpl_get_num_internal_nodes]{mpl_get_num_internal_nodes()}}, -\code{\link[=mpl_get_numtaxa]{mpl_get_numtaxa()}}, -\code{\link[=mpl_get_symbols]{mpl_get_symbols()}}, -\code{\link[=mpl_init_Morphy]{mpl_init_Morphy()}}, -\code{\link[=mpl_new_Morphy]{mpl_new_Morphy()}}, -\code{\link[=mpl_second_down_recon]{mpl_second_down_recon()}}, -\code{\link[=mpl_second_up_recon]{mpl_second_up_recon()}}, -\code{\link[=mpl_set_charac_weight]{mpl_set_charac_weight()}}, -\code{\link[=mpl_set_num_internal_nodes]{mpl_set_num_internal_nodes()}}, -\code{\link[=mpl_set_parsim_t]{mpl_set_parsim_t()}}, -\code{\link[=mpl_translate_error]{mpl_translate_error()}}, -\code{\link[=mpl_update_lower_root]{mpl_update_lower_root()}}, -\code{\link[=mpl_update_tip]{mpl_update_tip()}}, -\code{\link[=summary.morphyPtr]{summary.morphyPtr()}} -} -\author{ -Martin Brazeau -} -\concept{Morphy API functions} -\keyword{internal} diff --git a/man/mpl_attach_rawdata.Rd b/man/mpl_attach_rawdata.Rd deleted file mode 100644 index c5de9678f..000000000 --- a/man/mpl_attach_rawdata.Rd +++ /dev/null @@ -1,60 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/mpl_morphyex.R -\name{mpl_attach_rawdata} -\alias{mpl_attach_rawdata} -\title{Attach raw character state data (i.e. tip data).} -\usage{ -mpl_attach_rawdata(rawdata, morphyobj) -} -\arguments{ -\item{rawdata}{C-style string corresponding to the tip data for each taxon in -turn.} - -\item{morphyobj}{An instance of the Morphy object.} -} -\value{ -Morphy error code. -} -\description{ -Attaches a raw data character state matrix in the form of a C-style -(i.e. NULL-terminated) string. This can be the matrix block extracted from a -Nexus file or an \code{xread} table format. -The matrix should contain no leaf labels. -} -\seealso{ -Other Morphy API functions: -\code{\link[=GapHandler]{GapHandler()}}, -\code{\link[=MorphyErrorCheck]{MorphyErrorCheck()}}, -\code{\link[=MorphyWeights]{MorphyWeights()}}, -\code{\link[=PhyDat2Morphy]{PhyDat2Morphy()}}, -\code{\link[=SingleCharMorphy]{SingleCharMorphy()}}, -\code{\link[=UnloadMorphy]{UnloadMorphy()}}, -\code{\link[=is.morphyPtr]{is.morphyPtr()}}, -\code{\link[=mpl_apply_tipdata]{mpl_apply_tipdata()}}, -\code{\link[=mpl_attach_symbols]{mpl_attach_symbols()}}, -\code{\link[=mpl_delete_Morphy]{mpl_delete_Morphy()}}, -\code{\link[=mpl_first_down_recon]{mpl_first_down_recon()}}, -\code{\link[=mpl_first_up_recon]{mpl_first_up_recon()}}, -\code{\link[=mpl_get_charac_weight]{mpl_get_charac_weight()}}, -\code{\link[=mpl_get_gaphandl]{mpl_get_gaphandl()}}, -\code{\link[=mpl_get_num_charac]{mpl_get_num_charac()}}, -\code{\link[=mpl_get_num_internal_nodes]{mpl_get_num_internal_nodes()}}, -\code{\link[=mpl_get_numtaxa]{mpl_get_numtaxa()}}, -\code{\link[=mpl_get_symbols]{mpl_get_symbols()}}, -\code{\link[=mpl_init_Morphy]{mpl_init_Morphy()}}, -\code{\link[=mpl_new_Morphy]{mpl_new_Morphy()}}, -\code{\link[=mpl_second_down_recon]{mpl_second_down_recon()}}, -\code{\link[=mpl_second_up_recon]{mpl_second_up_recon()}}, -\code{\link[=mpl_set_charac_weight]{mpl_set_charac_weight()}}, -\code{\link[=mpl_set_num_internal_nodes]{mpl_set_num_internal_nodes()}}, -\code{\link[=mpl_set_parsim_t]{mpl_set_parsim_t()}}, -\code{\link[=mpl_translate_error]{mpl_translate_error()}}, -\code{\link[=mpl_update_lower_root]{mpl_update_lower_root()}}, -\code{\link[=mpl_update_tip]{mpl_update_tip()}}, -\code{\link[=summary.morphyPtr]{summary.morphyPtr()}} -} -\author{ -Martin Brazeau -} -\concept{Morphy API functions} -\keyword{internal} diff --git a/man/mpl_attach_symbols.Rd b/man/mpl_attach_symbols.Rd deleted file mode 100644 index dfebf4d31..000000000 --- a/man/mpl_attach_symbols.Rd +++ /dev/null @@ -1,63 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/mpl_morphyex.R -\name{mpl_attach_symbols} -\alias{mpl_attach_symbols} -\title{Attach a caller-specified list of symbols.} -\usage{ -mpl_attach_symbols(symbols, morphyobj) -} -\arguments{ -\item{symbols}{A C-style (i.e. NULL-terminated) string of valid state symbols.} - -\item{morphyobj}{An instance of the Morphy object.} -} -\value{ -Morphy error code. -} -\description{ -Allows the caller to specify a list of symbols in the data matrix, -otherwise, the symbols list used by Morphy will be extracted from the matrix. -The symbols list must match the symbols provided in the matrix. When Morphy -extracts symbols from the matrix, their ordering is alphanumeric, according to -their ASCII codes (i.e. "+0123...ABCD...abcd..."). Loading a user-specified -symbols list will override this ordering. Symbols loaded in either the list or -the matrix must be valid Morphy character state symbols as defined in the -statedata.h header file. The list must end with a semicolon. -} -\seealso{ -Other Morphy API functions: -\code{\link[=GapHandler]{GapHandler()}}, -\code{\link[=MorphyErrorCheck]{MorphyErrorCheck()}}, -\code{\link[=MorphyWeights]{MorphyWeights()}}, -\code{\link[=PhyDat2Morphy]{PhyDat2Morphy()}}, -\code{\link[=SingleCharMorphy]{SingleCharMorphy()}}, -\code{\link[=UnloadMorphy]{UnloadMorphy()}}, -\code{\link[=is.morphyPtr]{is.morphyPtr()}}, -\code{\link[=mpl_apply_tipdata]{mpl_apply_tipdata()}}, -\code{\link[=mpl_attach_rawdata]{mpl_attach_rawdata()}}, -\code{\link[=mpl_delete_Morphy]{mpl_delete_Morphy()}}, -\code{\link[=mpl_first_down_recon]{mpl_first_down_recon()}}, -\code{\link[=mpl_first_up_recon]{mpl_first_up_recon()}}, -\code{\link[=mpl_get_charac_weight]{mpl_get_charac_weight()}}, -\code{\link[=mpl_get_gaphandl]{mpl_get_gaphandl()}}, -\code{\link[=mpl_get_num_charac]{mpl_get_num_charac()}}, -\code{\link[=mpl_get_num_internal_nodes]{mpl_get_num_internal_nodes()}}, -\code{\link[=mpl_get_numtaxa]{mpl_get_numtaxa()}}, -\code{\link[=mpl_get_symbols]{mpl_get_symbols()}}, -\code{\link[=mpl_init_Morphy]{mpl_init_Morphy()}}, -\code{\link[=mpl_new_Morphy]{mpl_new_Morphy()}}, -\code{\link[=mpl_second_down_recon]{mpl_second_down_recon()}}, -\code{\link[=mpl_second_up_recon]{mpl_second_up_recon()}}, -\code{\link[=mpl_set_charac_weight]{mpl_set_charac_weight()}}, -\code{\link[=mpl_set_num_internal_nodes]{mpl_set_num_internal_nodes()}}, -\code{\link[=mpl_set_parsim_t]{mpl_set_parsim_t()}}, -\code{\link[=mpl_translate_error]{mpl_translate_error()}}, -\code{\link[=mpl_update_lower_root]{mpl_update_lower_root()}}, -\code{\link[=mpl_update_tip]{mpl_update_tip()}}, -\code{\link[=summary.morphyPtr]{summary.morphyPtr()}} -} -\author{ -Martin Brazeau -} -\concept{Morphy API functions} -\keyword{internal} diff --git a/man/mpl_delete_Morphy.Rd b/man/mpl_delete_Morphy.Rd deleted file mode 100644 index 1baf55afc..000000000 --- a/man/mpl_delete_Morphy.Rd +++ /dev/null @@ -1,55 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/mpl_morphyex.R -\name{mpl_delete_Morphy} -\alias{mpl_delete_Morphy} -\title{Destroys an instance of a Morphy object.} -\usage{ -mpl_delete_Morphy(morphyobj) -} -\arguments{ -\item{morphyobj}{A Morphy object to be destroyed.} -} -\value{ -A Morphy error code. -} -\description{ -Destroys an instance of the Morphy object, calling all -destructor for internal object completely returning the memory to the system. -} -\seealso{ -Other Morphy API functions: -\code{\link[=GapHandler]{GapHandler()}}, -\code{\link[=MorphyErrorCheck]{MorphyErrorCheck()}}, -\code{\link[=MorphyWeights]{MorphyWeights()}}, -\code{\link[=PhyDat2Morphy]{PhyDat2Morphy()}}, -\code{\link[=SingleCharMorphy]{SingleCharMorphy()}}, -\code{\link[=UnloadMorphy]{UnloadMorphy()}}, -\code{\link[=is.morphyPtr]{is.morphyPtr()}}, -\code{\link[=mpl_apply_tipdata]{mpl_apply_tipdata()}}, -\code{\link[=mpl_attach_rawdata]{mpl_attach_rawdata()}}, -\code{\link[=mpl_attach_symbols]{mpl_attach_symbols()}}, -\code{\link[=mpl_first_down_recon]{mpl_first_down_recon()}}, -\code{\link[=mpl_first_up_recon]{mpl_first_up_recon()}}, -\code{\link[=mpl_get_charac_weight]{mpl_get_charac_weight()}}, -\code{\link[=mpl_get_gaphandl]{mpl_get_gaphandl()}}, -\code{\link[=mpl_get_num_charac]{mpl_get_num_charac()}}, -\code{\link[=mpl_get_num_internal_nodes]{mpl_get_num_internal_nodes()}}, -\code{\link[=mpl_get_numtaxa]{mpl_get_numtaxa()}}, -\code{\link[=mpl_get_symbols]{mpl_get_symbols()}}, -\code{\link[=mpl_init_Morphy]{mpl_init_Morphy()}}, -\code{\link[=mpl_new_Morphy]{mpl_new_Morphy()}}, -\code{\link[=mpl_second_down_recon]{mpl_second_down_recon()}}, -\code{\link[=mpl_second_up_recon]{mpl_second_up_recon()}}, -\code{\link[=mpl_set_charac_weight]{mpl_set_charac_weight()}}, -\code{\link[=mpl_set_num_internal_nodes]{mpl_set_num_internal_nodes()}}, -\code{\link[=mpl_set_parsim_t]{mpl_set_parsim_t()}}, -\code{\link[=mpl_translate_error]{mpl_translate_error()}}, -\code{\link[=mpl_update_lower_root]{mpl_update_lower_root()}}, -\code{\link[=mpl_update_tip]{mpl_update_tip()}}, -\code{\link[=summary.morphyPtr]{summary.morphyPtr()}} -} -\author{ -Martin Brazeau -} -\concept{Morphy API functions} -\keyword{internal} diff --git a/man/mpl_first_down_recon.Rd b/man/mpl_first_down_recon.Rd deleted file mode 100644 index 6f7d179bd..000000000 --- a/man/mpl_first_down_recon.Rd +++ /dev/null @@ -1,66 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/mpl_morphyex.R -\name{mpl_first_down_recon} -\alias{mpl_first_down_recon} -\title{Reconstructs the first (downpass) nodal reconstructions} -\usage{ -mpl_first_down_recon(node_id, left_id, right_id, morphyobj) -} -\arguments{ -\item{node_id}{The index of the node being reconstructed.} - -\item{left_id}{The index of the left descendant.} - -\item{right_id}{The index of the right descendant.} - -\item{morphyobj}{An instance of the Morphy object.} -} -\value{ -The integral parsimony length (right now) -} -\description{ -Reconstructs the preliminary nodal set for all characters for a -particular node. This function is called over a postorder sequence of internal -nodes where left and right descendants are known. -Because this function needs to be fairly high-performance, it does not do much -checking for parameter validity, thus unsafe usage of this function might not -be caught. It is up to calling functions to ensure that the appropriate -parameters have been set before use. -} -\seealso{ -Other Morphy API functions: -\code{\link[=GapHandler]{GapHandler()}}, -\code{\link[=MorphyErrorCheck]{MorphyErrorCheck()}}, -\code{\link[=MorphyWeights]{MorphyWeights()}}, -\code{\link[=PhyDat2Morphy]{PhyDat2Morphy()}}, -\code{\link[=SingleCharMorphy]{SingleCharMorphy()}}, -\code{\link[=UnloadMorphy]{UnloadMorphy()}}, -\code{\link[=is.morphyPtr]{is.morphyPtr()}}, -\code{\link[=mpl_apply_tipdata]{mpl_apply_tipdata()}}, -\code{\link[=mpl_attach_rawdata]{mpl_attach_rawdata()}}, -\code{\link[=mpl_attach_symbols]{mpl_attach_symbols()}}, -\code{\link[=mpl_delete_Morphy]{mpl_delete_Morphy()}}, -\code{\link[=mpl_first_up_recon]{mpl_first_up_recon()}}, -\code{\link[=mpl_get_charac_weight]{mpl_get_charac_weight()}}, -\code{\link[=mpl_get_gaphandl]{mpl_get_gaphandl()}}, -\code{\link[=mpl_get_num_charac]{mpl_get_num_charac()}}, -\code{\link[=mpl_get_num_internal_nodes]{mpl_get_num_internal_nodes()}}, -\code{\link[=mpl_get_numtaxa]{mpl_get_numtaxa()}}, -\code{\link[=mpl_get_symbols]{mpl_get_symbols()}}, -\code{\link[=mpl_init_Morphy]{mpl_init_Morphy()}}, -\code{\link[=mpl_new_Morphy]{mpl_new_Morphy()}}, -\code{\link[=mpl_second_down_recon]{mpl_second_down_recon()}}, -\code{\link[=mpl_second_up_recon]{mpl_second_up_recon()}}, -\code{\link[=mpl_set_charac_weight]{mpl_set_charac_weight()}}, -\code{\link[=mpl_set_num_internal_nodes]{mpl_set_num_internal_nodes()}}, -\code{\link[=mpl_set_parsim_t]{mpl_set_parsim_t()}}, -\code{\link[=mpl_translate_error]{mpl_translate_error()}}, -\code{\link[=mpl_update_lower_root]{mpl_update_lower_root()}}, -\code{\link[=mpl_update_tip]{mpl_update_tip()}}, -\code{\link[=summary.morphyPtr]{summary.morphyPtr()}} -} -\author{ -Martin Brazeau -} -\concept{Morphy API functions} -\keyword{internal} diff --git a/man/mpl_first_up_recon.Rd b/man/mpl_first_up_recon.Rd deleted file mode 100644 index 0d6c2898b..000000000 --- a/man/mpl_first_up_recon.Rd +++ /dev/null @@ -1,68 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/mpl_morphyex.R -\name{mpl_first_up_recon} -\alias{mpl_first_up_recon} -\title{Reconstructs the second (uppass) nodal reconstructions.} -\usage{ -mpl_first_up_recon(node_id, left_id, right_id, anc_id, morphyobj) -} -\arguments{ -\item{node_id}{The index of the node being reconstructed.} - -\item{left_id}{The index of the left descendant.} - -\item{right_id}{The index of the right descendant.} - -\item{anc_id}{The index of the immediate ancestor of the node.} - -\item{morphyobj}{An instance of the Morphy object.} -} -\value{ -A null value (for now). -} -\description{ -Reconstructs second-pass nodal sets. For normal (all-applicable) -characters, this is the final pass. This function is called over a preorder -sequence of nodes where left, right, and ancestral nodes are known. -Because this function needs to be fairly high-performance, it does not do much -checking for parameter validity, thus unsafe usage of this function might not -be caught. It is up to calling functions to ensure that the appropriate -parameters have been set before use. -} -\seealso{ -Other Morphy API functions: -\code{\link[=GapHandler]{GapHandler()}}, -\code{\link[=MorphyErrorCheck]{MorphyErrorCheck()}}, -\code{\link[=MorphyWeights]{MorphyWeights()}}, -\code{\link[=PhyDat2Morphy]{PhyDat2Morphy()}}, -\code{\link[=SingleCharMorphy]{SingleCharMorphy()}}, -\code{\link[=UnloadMorphy]{UnloadMorphy()}}, -\code{\link[=is.morphyPtr]{is.morphyPtr()}}, -\code{\link[=mpl_apply_tipdata]{mpl_apply_tipdata()}}, -\code{\link[=mpl_attach_rawdata]{mpl_attach_rawdata()}}, -\code{\link[=mpl_attach_symbols]{mpl_attach_symbols()}}, -\code{\link[=mpl_delete_Morphy]{mpl_delete_Morphy()}}, -\code{\link[=mpl_first_down_recon]{mpl_first_down_recon()}}, -\code{\link[=mpl_get_charac_weight]{mpl_get_charac_weight()}}, -\code{\link[=mpl_get_gaphandl]{mpl_get_gaphandl()}}, -\code{\link[=mpl_get_num_charac]{mpl_get_num_charac()}}, -\code{\link[=mpl_get_num_internal_nodes]{mpl_get_num_internal_nodes()}}, -\code{\link[=mpl_get_numtaxa]{mpl_get_numtaxa()}}, -\code{\link[=mpl_get_symbols]{mpl_get_symbols()}}, -\code{\link[=mpl_init_Morphy]{mpl_init_Morphy()}}, -\code{\link[=mpl_new_Morphy]{mpl_new_Morphy()}}, -\code{\link[=mpl_second_down_recon]{mpl_second_down_recon()}}, -\code{\link[=mpl_second_up_recon]{mpl_second_up_recon()}}, -\code{\link[=mpl_set_charac_weight]{mpl_set_charac_weight()}}, -\code{\link[=mpl_set_num_internal_nodes]{mpl_set_num_internal_nodes()}}, -\code{\link[=mpl_set_parsim_t]{mpl_set_parsim_t()}}, -\code{\link[=mpl_translate_error]{mpl_translate_error()}}, -\code{\link[=mpl_update_lower_root]{mpl_update_lower_root()}}, -\code{\link[=mpl_update_tip]{mpl_update_tip()}}, -\code{\link[=summary.morphyPtr]{summary.morphyPtr()}} -} -\author{ -Thomas Guillerme -} -\concept{Morphy API functions} -\keyword{internal} diff --git a/man/mpl_get_charac_weight.Rd b/man/mpl_get_charac_weight.Rd deleted file mode 100644 index 2a120a71f..000000000 --- a/man/mpl_get_charac_weight.Rd +++ /dev/null @@ -1,58 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/mpl_morphyex.R -\name{mpl_get_charac_weight} -\alias{mpl_get_charac_weight} -\title{Retrieve the weight of a character in the dataset} -\usage{ -mpl_get_charac_weight(charID, morphyobj) -} -\arguments{ -\item{charID}{Number of the character (i.e. first character is number 1)} - -\item{morphyobj}{An instance of the Morphy object.} -} -\value{ -A list, detailing (item 1) the exact weight of the character; -(item 2) the integer approximation used by Morphy. -} -\description{ -Gets the weights of a character in the dataset. -} -\seealso{ -Other Morphy API functions: -\code{\link[=GapHandler]{GapHandler()}}, -\code{\link[=MorphyErrorCheck]{MorphyErrorCheck()}}, -\code{\link[=MorphyWeights]{MorphyWeights()}}, -\code{\link[=PhyDat2Morphy]{PhyDat2Morphy()}}, -\code{\link[=SingleCharMorphy]{SingleCharMorphy()}}, -\code{\link[=UnloadMorphy]{UnloadMorphy()}}, -\code{\link[=is.morphyPtr]{is.morphyPtr()}}, -\code{\link[=mpl_apply_tipdata]{mpl_apply_tipdata()}}, -\code{\link[=mpl_attach_rawdata]{mpl_attach_rawdata()}}, -\code{\link[=mpl_attach_symbols]{mpl_attach_symbols()}}, -\code{\link[=mpl_delete_Morphy]{mpl_delete_Morphy()}}, -\code{\link[=mpl_first_down_recon]{mpl_first_down_recon()}}, -\code{\link[=mpl_first_up_recon]{mpl_first_up_recon()}}, -\code{\link[=mpl_get_gaphandl]{mpl_get_gaphandl()}}, -\code{\link[=mpl_get_num_charac]{mpl_get_num_charac()}}, -\code{\link[=mpl_get_num_internal_nodes]{mpl_get_num_internal_nodes()}}, -\code{\link[=mpl_get_numtaxa]{mpl_get_numtaxa()}}, -\code{\link[=mpl_get_symbols]{mpl_get_symbols()}}, -\code{\link[=mpl_init_Morphy]{mpl_init_Morphy()}}, -\code{\link[=mpl_new_Morphy]{mpl_new_Morphy()}}, -\code{\link[=mpl_second_down_recon]{mpl_second_down_recon()}}, -\code{\link[=mpl_second_up_recon]{mpl_second_up_recon()}}, -\code{\link[=mpl_set_charac_weight]{mpl_set_charac_weight()}}, -\code{\link[=mpl_set_num_internal_nodes]{mpl_set_num_internal_nodes()}}, -\code{\link[=mpl_set_parsim_t]{mpl_set_parsim_t()}}, -\code{\link[=mpl_translate_error]{mpl_translate_error()}}, -\code{\link[=mpl_update_lower_root]{mpl_update_lower_root()}}, -\code{\link[=mpl_update_tip]{mpl_update_tip()}}, -\code{\link[=summary.morphyPtr]{summary.morphyPtr()}} -} -\author{ -\href{https://smithlabdurham.github.io/}{Martin R. Smith} -(\href{mailto:martin.smith@durham.ac.uk}{martin.smith@durham.ac.uk}) -} -\concept{Morphy API functions} -\keyword{internal} diff --git a/man/mpl_get_gaphandl.Rd b/man/mpl_get_gaphandl.Rd deleted file mode 100644 index 2ab8eecee..000000000 --- a/man/mpl_get_gaphandl.Rd +++ /dev/null @@ -1,54 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/mpl_morphyex.R -\name{mpl_get_gaphandl} -\alias{mpl_get_gaphandl} -\alias{mpl_set_gaphandl} -\title{Get / set gap handler from a Morphy object.} -\usage{ -mpl_get_gaphandl(morphyobj) - -mpl_set_gaphandl(handl, morphyobj) -} -\value{ -\code{mpl_get_gaphandl()} returns an integer corresponding to the gap -handling approach. - -\code{mpl_set_gaphandl()} returns a Morphy error code. -} -\description{ -0 = inapplicable; 1 = missing; 2 = extra -} -\seealso{ -Other Morphy API functions: -\code{\link[=GapHandler]{GapHandler()}}, -\code{\link[=MorphyErrorCheck]{MorphyErrorCheck()}}, -\code{\link[=MorphyWeights]{MorphyWeights()}}, -\code{\link[=PhyDat2Morphy]{PhyDat2Morphy()}}, -\code{\link[=SingleCharMorphy]{SingleCharMorphy()}}, -\code{\link[=UnloadMorphy]{UnloadMorphy()}}, -\code{\link[=is.morphyPtr]{is.morphyPtr()}}, -\code{\link[=mpl_apply_tipdata]{mpl_apply_tipdata()}}, -\code{\link[=mpl_attach_rawdata]{mpl_attach_rawdata()}}, -\code{\link[=mpl_attach_symbols]{mpl_attach_symbols()}}, -\code{\link[=mpl_delete_Morphy]{mpl_delete_Morphy()}}, -\code{\link[=mpl_first_down_recon]{mpl_first_down_recon()}}, -\code{\link[=mpl_first_up_recon]{mpl_first_up_recon()}}, -\code{\link[=mpl_get_charac_weight]{mpl_get_charac_weight()}}, -\code{\link[=mpl_get_num_charac]{mpl_get_num_charac()}}, -\code{\link[=mpl_get_num_internal_nodes]{mpl_get_num_internal_nodes()}}, -\code{\link[=mpl_get_numtaxa]{mpl_get_numtaxa()}}, -\code{\link[=mpl_get_symbols]{mpl_get_symbols()}}, -\code{\link[=mpl_init_Morphy]{mpl_init_Morphy()}}, -\code{\link[=mpl_new_Morphy]{mpl_new_Morphy()}}, -\code{\link[=mpl_second_down_recon]{mpl_second_down_recon()}}, -\code{\link[=mpl_second_up_recon]{mpl_second_up_recon()}}, -\code{\link[=mpl_set_charac_weight]{mpl_set_charac_weight()}}, -\code{\link[=mpl_set_num_internal_nodes]{mpl_set_num_internal_nodes()}}, -\code{\link[=mpl_set_parsim_t]{mpl_set_parsim_t()}}, -\code{\link[=mpl_translate_error]{mpl_translate_error()}}, -\code{\link[=mpl_update_lower_root]{mpl_update_lower_root()}}, -\code{\link[=mpl_update_tip]{mpl_update_tip()}}, -\code{\link[=summary.morphyPtr]{summary.morphyPtr()}} -} -\concept{Morphy API functions} -\keyword{internal} diff --git a/man/mpl_get_num_charac.Rd b/man/mpl_get_num_charac.Rd deleted file mode 100644 index 84f31d3a9..000000000 --- a/man/mpl_get_num_charac.Rd +++ /dev/null @@ -1,54 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/mpl_morphyex.R -\name{mpl_get_num_charac} -\alias{mpl_get_num_charac} -\title{Retrieve the number of character (columns) in the dataset.} -\usage{ -mpl_get_num_charac(morphyobj) -} -\arguments{ -\item{morphyobj}{An instance of the Morphy object.} -} -\value{ -The number of internal nodes. -} -\description{ -Retrieves the number of character (columns) in the dataset. -} -\seealso{ -Other Morphy API functions: -\code{\link[=GapHandler]{GapHandler()}}, -\code{\link[=MorphyErrorCheck]{MorphyErrorCheck()}}, -\code{\link[=MorphyWeights]{MorphyWeights()}}, -\code{\link[=PhyDat2Morphy]{PhyDat2Morphy()}}, -\code{\link[=SingleCharMorphy]{SingleCharMorphy()}}, -\code{\link[=UnloadMorphy]{UnloadMorphy()}}, -\code{\link[=is.morphyPtr]{is.morphyPtr()}}, -\code{\link[=mpl_apply_tipdata]{mpl_apply_tipdata()}}, -\code{\link[=mpl_attach_rawdata]{mpl_attach_rawdata()}}, -\code{\link[=mpl_attach_symbols]{mpl_attach_symbols()}}, -\code{\link[=mpl_delete_Morphy]{mpl_delete_Morphy()}}, -\code{\link[=mpl_first_down_recon]{mpl_first_down_recon()}}, -\code{\link[=mpl_first_up_recon]{mpl_first_up_recon()}}, -\code{\link[=mpl_get_charac_weight]{mpl_get_charac_weight()}}, -\code{\link[=mpl_get_gaphandl]{mpl_get_gaphandl()}}, -\code{\link[=mpl_get_num_internal_nodes]{mpl_get_num_internal_nodes()}}, -\code{\link[=mpl_get_numtaxa]{mpl_get_numtaxa()}}, -\code{\link[=mpl_get_symbols]{mpl_get_symbols()}}, -\code{\link[=mpl_init_Morphy]{mpl_init_Morphy()}}, -\code{\link[=mpl_new_Morphy]{mpl_new_Morphy()}}, -\code{\link[=mpl_second_down_recon]{mpl_second_down_recon()}}, -\code{\link[=mpl_second_up_recon]{mpl_second_up_recon()}}, -\code{\link[=mpl_set_charac_weight]{mpl_set_charac_weight()}}, -\code{\link[=mpl_set_num_internal_nodes]{mpl_set_num_internal_nodes()}}, -\code{\link[=mpl_set_parsim_t]{mpl_set_parsim_t()}}, -\code{\link[=mpl_translate_error]{mpl_translate_error()}}, -\code{\link[=mpl_update_lower_root]{mpl_update_lower_root()}}, -\code{\link[=mpl_update_tip]{mpl_update_tip()}}, -\code{\link[=summary.morphyPtr]{summary.morphyPtr()}} -} -\author{ -Martin Brazeau -} -\concept{Morphy API functions} -\keyword{internal} diff --git a/man/mpl_get_num_internal_nodes.Rd b/man/mpl_get_num_internal_nodes.Rd deleted file mode 100644 index 5d5cb0b84..000000000 --- a/man/mpl_get_num_internal_nodes.Rd +++ /dev/null @@ -1,56 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/mpl_morphyex.R -\name{mpl_get_num_internal_nodes} -\alias{mpl_get_num_internal_nodes} -\title{Gets the number of internal nodal reconstruction sets being used by -MorphyLib.} -\usage{ -mpl_get_num_internal_nodes(morphyobj) -} -\arguments{ -\item{morphyobj}{An instance of the Morphy object.} -} -\value{ -The number of internal nodes. -} -\description{ -Gets the number of internal nodal reconstruction sets being used -by MorphyLib. -} -\seealso{ -Other Morphy API functions: -\code{\link[=GapHandler]{GapHandler()}}, -\code{\link[=MorphyErrorCheck]{MorphyErrorCheck()}}, -\code{\link[=MorphyWeights]{MorphyWeights()}}, -\code{\link[=PhyDat2Morphy]{PhyDat2Morphy()}}, -\code{\link[=SingleCharMorphy]{SingleCharMorphy()}}, -\code{\link[=UnloadMorphy]{UnloadMorphy()}}, -\code{\link[=is.morphyPtr]{is.morphyPtr()}}, -\code{\link[=mpl_apply_tipdata]{mpl_apply_tipdata()}}, -\code{\link[=mpl_attach_rawdata]{mpl_attach_rawdata()}}, -\code{\link[=mpl_attach_symbols]{mpl_attach_symbols()}}, -\code{\link[=mpl_delete_Morphy]{mpl_delete_Morphy()}}, -\code{\link[=mpl_first_down_recon]{mpl_first_down_recon()}}, -\code{\link[=mpl_first_up_recon]{mpl_first_up_recon()}}, -\code{\link[=mpl_get_charac_weight]{mpl_get_charac_weight()}}, -\code{\link[=mpl_get_gaphandl]{mpl_get_gaphandl()}}, -\code{\link[=mpl_get_num_charac]{mpl_get_num_charac()}}, -\code{\link[=mpl_get_numtaxa]{mpl_get_numtaxa()}}, -\code{\link[=mpl_get_symbols]{mpl_get_symbols()}}, -\code{\link[=mpl_init_Morphy]{mpl_init_Morphy()}}, -\code{\link[=mpl_new_Morphy]{mpl_new_Morphy()}}, -\code{\link[=mpl_second_down_recon]{mpl_second_down_recon()}}, -\code{\link[=mpl_second_up_recon]{mpl_second_up_recon()}}, -\code{\link[=mpl_set_charac_weight]{mpl_set_charac_weight()}}, -\code{\link[=mpl_set_num_internal_nodes]{mpl_set_num_internal_nodes()}}, -\code{\link[=mpl_set_parsim_t]{mpl_set_parsim_t()}}, -\code{\link[=mpl_translate_error]{mpl_translate_error()}}, -\code{\link[=mpl_update_lower_root]{mpl_update_lower_root()}}, -\code{\link[=mpl_update_tip]{mpl_update_tip()}}, -\code{\link[=summary.morphyPtr]{summary.morphyPtr()}} -} -\author{ -Martin Brazeau -} -\concept{Morphy API functions} -\keyword{internal} diff --git a/man/mpl_get_numtaxa.Rd b/man/mpl_get_numtaxa.Rd deleted file mode 100644 index fa2664ccb..000000000 --- a/man/mpl_get_numtaxa.Rd +++ /dev/null @@ -1,54 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/mpl_morphyex.R -\name{mpl_get_numtaxa} -\alias{mpl_get_numtaxa} -\title{Retrieve the number of taxa (rows) in the dataset.} -\usage{ -mpl_get_numtaxa(morphyobj) -} -\arguments{ -\item{morphyobj}{An instance of the Morphy object.} -} -\value{ -The number of taxa if success, otherwise an error code. -} -\description{ -Retrieves the number of taxa (rows) in the dataset. -} -\seealso{ -Other Morphy API functions: -\code{\link[=GapHandler]{GapHandler()}}, -\code{\link[=MorphyErrorCheck]{MorphyErrorCheck()}}, -\code{\link[=MorphyWeights]{MorphyWeights()}}, -\code{\link[=PhyDat2Morphy]{PhyDat2Morphy()}}, -\code{\link[=SingleCharMorphy]{SingleCharMorphy()}}, -\code{\link[=UnloadMorphy]{UnloadMorphy()}}, -\code{\link[=is.morphyPtr]{is.morphyPtr()}}, -\code{\link[=mpl_apply_tipdata]{mpl_apply_tipdata()}}, -\code{\link[=mpl_attach_rawdata]{mpl_attach_rawdata()}}, -\code{\link[=mpl_attach_symbols]{mpl_attach_symbols()}}, -\code{\link[=mpl_delete_Morphy]{mpl_delete_Morphy()}}, -\code{\link[=mpl_first_down_recon]{mpl_first_down_recon()}}, -\code{\link[=mpl_first_up_recon]{mpl_first_up_recon()}}, -\code{\link[=mpl_get_charac_weight]{mpl_get_charac_weight()}}, -\code{\link[=mpl_get_gaphandl]{mpl_get_gaphandl()}}, -\code{\link[=mpl_get_num_charac]{mpl_get_num_charac()}}, -\code{\link[=mpl_get_num_internal_nodes]{mpl_get_num_internal_nodes()}}, -\code{\link[=mpl_get_symbols]{mpl_get_symbols()}}, -\code{\link[=mpl_init_Morphy]{mpl_init_Morphy()}}, -\code{\link[=mpl_new_Morphy]{mpl_new_Morphy()}}, -\code{\link[=mpl_second_down_recon]{mpl_second_down_recon()}}, -\code{\link[=mpl_second_up_recon]{mpl_second_up_recon()}}, -\code{\link[=mpl_set_charac_weight]{mpl_set_charac_weight()}}, -\code{\link[=mpl_set_num_internal_nodes]{mpl_set_num_internal_nodes()}}, -\code{\link[=mpl_set_parsim_t]{mpl_set_parsim_t()}}, -\code{\link[=mpl_translate_error]{mpl_translate_error()}}, -\code{\link[=mpl_update_lower_root]{mpl_update_lower_root()}}, -\code{\link[=mpl_update_tip]{mpl_update_tip()}}, -\code{\link[=summary.morphyPtr]{summary.morphyPtr()}} -} -\author{ -Martin Brazeau -} -\concept{Morphy API functions} -\keyword{internal} diff --git a/man/mpl_get_symbols.Rd b/man/mpl_get_symbols.Rd deleted file mode 100644 index ecd0dff45..000000000 --- a/man/mpl_get_symbols.Rd +++ /dev/null @@ -1,57 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/mpl_morphyex.R -\name{mpl_get_symbols} -\alias{mpl_get_symbols} -\title{Retrieves the current list of symbols.} -\usage{ -mpl_get_symbols(morphyobj) -} -\arguments{ -\item{morphyobj}{An instance of the Morphy object.} -} -\value{ -A C-style (null-terminated) string of the character state symbols -being used. NULL if failure. -} -\description{ -Returns a pointer to the string of character state symbols -currently being used by Morphy (i.e. either the list of symbols extracted -from the matrix, or the caller-specified values). -} -\seealso{ -Other Morphy API functions: -\code{\link[=GapHandler]{GapHandler()}}, -\code{\link[=MorphyErrorCheck]{MorphyErrorCheck()}}, -\code{\link[=MorphyWeights]{MorphyWeights()}}, -\code{\link[=PhyDat2Morphy]{PhyDat2Morphy()}}, -\code{\link[=SingleCharMorphy]{SingleCharMorphy()}}, -\code{\link[=UnloadMorphy]{UnloadMorphy()}}, -\code{\link[=is.morphyPtr]{is.morphyPtr()}}, -\code{\link[=mpl_apply_tipdata]{mpl_apply_tipdata()}}, -\code{\link[=mpl_attach_rawdata]{mpl_attach_rawdata()}}, -\code{\link[=mpl_attach_symbols]{mpl_attach_symbols()}}, -\code{\link[=mpl_delete_Morphy]{mpl_delete_Morphy()}}, -\code{\link[=mpl_first_down_recon]{mpl_first_down_recon()}}, -\code{\link[=mpl_first_up_recon]{mpl_first_up_recon()}}, -\code{\link[=mpl_get_charac_weight]{mpl_get_charac_weight()}}, -\code{\link[=mpl_get_gaphandl]{mpl_get_gaphandl()}}, -\code{\link[=mpl_get_num_charac]{mpl_get_num_charac()}}, -\code{\link[=mpl_get_num_internal_nodes]{mpl_get_num_internal_nodes()}}, -\code{\link[=mpl_get_numtaxa]{mpl_get_numtaxa()}}, -\code{\link[=mpl_init_Morphy]{mpl_init_Morphy()}}, -\code{\link[=mpl_new_Morphy]{mpl_new_Morphy()}}, -\code{\link[=mpl_second_down_recon]{mpl_second_down_recon()}}, -\code{\link[=mpl_second_up_recon]{mpl_second_up_recon()}}, -\code{\link[=mpl_set_charac_weight]{mpl_set_charac_weight()}}, -\code{\link[=mpl_set_num_internal_nodes]{mpl_set_num_internal_nodes()}}, -\code{\link[=mpl_set_parsim_t]{mpl_set_parsim_t()}}, -\code{\link[=mpl_translate_error]{mpl_translate_error()}}, -\code{\link[=mpl_update_lower_root]{mpl_update_lower_root()}}, -\code{\link[=mpl_update_tip]{mpl_update_tip()}}, -\code{\link[=summary.morphyPtr]{summary.morphyPtr()}} -} -\author{ -Martin Brazeau -} -\concept{Morphy API functions} -\keyword{internal} diff --git a/man/mpl_init_Morphy.Rd b/man/mpl_init_Morphy.Rd deleted file mode 100644 index f1a9c8ace..000000000 --- a/man/mpl_init_Morphy.Rd +++ /dev/null @@ -1,60 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/mpl_morphyex.R -\name{mpl_init_Morphy} -\alias{mpl_init_Morphy} -\title{Sets up the dimensions of the dataset.} -\usage{ -mpl_init_Morphy(numtaxa, numchars, morphyobj) -} -\arguments{ -\item{numtaxa}{The number of taxa (or tips/terminals).} - -\item{numchars}{The number of characters (i.e. transformation series) in the -data set.} - -\item{morphyobj}{An instance of the Morphy object.} -} -\value{ -Morphy error code. -} -\description{ -Provides initial dimensions for the dataset, which will -constrain any input matrix supplied to Morphy. -} -\seealso{ -Other Morphy API functions: -\code{\link[=GapHandler]{GapHandler()}}, -\code{\link[=MorphyErrorCheck]{MorphyErrorCheck()}}, -\code{\link[=MorphyWeights]{MorphyWeights()}}, -\code{\link[=PhyDat2Morphy]{PhyDat2Morphy()}}, -\code{\link[=SingleCharMorphy]{SingleCharMorphy()}}, -\code{\link[=UnloadMorphy]{UnloadMorphy()}}, -\code{\link[=is.morphyPtr]{is.morphyPtr()}}, -\code{\link[=mpl_apply_tipdata]{mpl_apply_tipdata()}}, -\code{\link[=mpl_attach_rawdata]{mpl_attach_rawdata()}}, -\code{\link[=mpl_attach_symbols]{mpl_attach_symbols()}}, -\code{\link[=mpl_delete_Morphy]{mpl_delete_Morphy()}}, -\code{\link[=mpl_first_down_recon]{mpl_first_down_recon()}}, -\code{\link[=mpl_first_up_recon]{mpl_first_up_recon()}}, -\code{\link[=mpl_get_charac_weight]{mpl_get_charac_weight()}}, -\code{\link[=mpl_get_gaphandl]{mpl_get_gaphandl()}}, -\code{\link[=mpl_get_num_charac]{mpl_get_num_charac()}}, -\code{\link[=mpl_get_num_internal_nodes]{mpl_get_num_internal_nodes()}}, -\code{\link[=mpl_get_numtaxa]{mpl_get_numtaxa()}}, -\code{\link[=mpl_get_symbols]{mpl_get_symbols()}}, -\code{\link[=mpl_new_Morphy]{mpl_new_Morphy()}}, -\code{\link[=mpl_second_down_recon]{mpl_second_down_recon()}}, -\code{\link[=mpl_second_up_recon]{mpl_second_up_recon()}}, -\code{\link[=mpl_set_charac_weight]{mpl_set_charac_weight()}}, -\code{\link[=mpl_set_num_internal_nodes]{mpl_set_num_internal_nodes()}}, -\code{\link[=mpl_set_parsim_t]{mpl_set_parsim_t()}}, -\code{\link[=mpl_translate_error]{mpl_translate_error()}}, -\code{\link[=mpl_update_lower_root]{mpl_update_lower_root()}}, -\code{\link[=mpl_update_tip]{mpl_update_tip()}}, -\code{\link[=summary.morphyPtr]{summary.morphyPtr()}} -} -\author{ -Martin Brazeau -} -\concept{Morphy API functions} -\keyword{internal} diff --git a/man/mpl_new_Morphy.Rd b/man/mpl_new_Morphy.Rd deleted file mode 100644 index 81ce5b565..000000000 --- a/man/mpl_new_Morphy.Rd +++ /dev/null @@ -1,58 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/mpl_morphyex.R -\name{mpl_new_Morphy} -\alias{mpl_new_Morphy} -\title{Creates a new instance of a Morphy object} -\usage{ -mpl_new_Morphy() -} -\value{ -A void pointer to the Morphy instance. NULL if unsuccessful. -} -\description{ -Creates a new empty Morphy object. All fields are unpopulated -and uninitialised. -} -\examples{ -morphyObj <- mpl_new_Morphy() # Create new object -## Do some stuff ... ## -mpl_delete_Morphy(morphyObj) # Delete when done - -} -\seealso{ -Other Morphy API functions: -\code{\link[=GapHandler]{GapHandler()}}, -\code{\link[=MorphyErrorCheck]{MorphyErrorCheck()}}, -\code{\link[=MorphyWeights]{MorphyWeights()}}, -\code{\link[=PhyDat2Morphy]{PhyDat2Morphy()}}, -\code{\link[=SingleCharMorphy]{SingleCharMorphy()}}, -\code{\link[=UnloadMorphy]{UnloadMorphy()}}, -\code{\link[=is.morphyPtr]{is.morphyPtr()}}, -\code{\link[=mpl_apply_tipdata]{mpl_apply_tipdata()}}, -\code{\link[=mpl_attach_rawdata]{mpl_attach_rawdata()}}, -\code{\link[=mpl_attach_symbols]{mpl_attach_symbols()}}, -\code{\link[=mpl_delete_Morphy]{mpl_delete_Morphy()}}, -\code{\link[=mpl_first_down_recon]{mpl_first_down_recon()}}, -\code{\link[=mpl_first_up_recon]{mpl_first_up_recon()}}, -\code{\link[=mpl_get_charac_weight]{mpl_get_charac_weight()}}, -\code{\link[=mpl_get_gaphandl]{mpl_get_gaphandl()}}, -\code{\link[=mpl_get_num_charac]{mpl_get_num_charac()}}, -\code{\link[=mpl_get_num_internal_nodes]{mpl_get_num_internal_nodes()}}, -\code{\link[=mpl_get_numtaxa]{mpl_get_numtaxa()}}, -\code{\link[=mpl_get_symbols]{mpl_get_symbols()}}, -\code{\link[=mpl_init_Morphy]{mpl_init_Morphy()}}, -\code{\link[=mpl_second_down_recon]{mpl_second_down_recon()}}, -\code{\link[=mpl_second_up_recon]{mpl_second_up_recon()}}, -\code{\link[=mpl_set_charac_weight]{mpl_set_charac_weight()}}, -\code{\link[=mpl_set_num_internal_nodes]{mpl_set_num_internal_nodes()}}, -\code{\link[=mpl_set_parsim_t]{mpl_set_parsim_t()}}, -\code{\link[=mpl_translate_error]{mpl_translate_error()}}, -\code{\link[=mpl_update_lower_root]{mpl_update_lower_root()}}, -\code{\link[=mpl_update_tip]{mpl_update_tip()}}, -\code{\link[=summary.morphyPtr]{summary.morphyPtr()}} -} -\author{ -Martin Brazeau -} -\concept{Morphy API functions} -\keyword{internal} diff --git a/man/mpl_second_down_recon.Rd b/man/mpl_second_down_recon.Rd deleted file mode 100644 index 1ff60e741..000000000 --- a/man/mpl_second_down_recon.Rd +++ /dev/null @@ -1,67 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/mpl_morphyex.R -\name{mpl_second_down_recon} -\alias{mpl_second_down_recon} -\title{Performs the second nodal reconstructions for characters with -inapplicability.} -\usage{ -mpl_second_down_recon(node_id, left_id, right_id, morphyobj) -} -\arguments{ -\item{node_id}{The index of the node being reconstructed.} - -\item{left_id}{The index of the left descendant.} - -\item{right_id}{The index of the right descendant.} - -\item{morphyobj}{An instance of the Morphy object.} -} -\value{ -The integral parsimony length (right now) -} -\description{ -Updates the nodal sets that had ambiguous unions with the -inapplicable state and calculates steps involving applicable states after -the update. -Because this function needs to be fairly high-performance, it does not do much -checking for parameter validity, thus unsafe usage of this function might not -be caught. It is up to calling functions to ensure that the appropriate -parameters have been set before use. -} -\seealso{ -Other Morphy API functions: -\code{\link[=GapHandler]{GapHandler()}}, -\code{\link[=MorphyErrorCheck]{MorphyErrorCheck()}}, -\code{\link[=MorphyWeights]{MorphyWeights()}}, -\code{\link[=PhyDat2Morphy]{PhyDat2Morphy()}}, -\code{\link[=SingleCharMorphy]{SingleCharMorphy()}}, -\code{\link[=UnloadMorphy]{UnloadMorphy()}}, -\code{\link[=is.morphyPtr]{is.morphyPtr()}}, -\code{\link[=mpl_apply_tipdata]{mpl_apply_tipdata()}}, -\code{\link[=mpl_attach_rawdata]{mpl_attach_rawdata()}}, -\code{\link[=mpl_attach_symbols]{mpl_attach_symbols()}}, -\code{\link[=mpl_delete_Morphy]{mpl_delete_Morphy()}}, -\code{\link[=mpl_first_down_recon]{mpl_first_down_recon()}}, -\code{\link[=mpl_first_up_recon]{mpl_first_up_recon()}}, -\code{\link[=mpl_get_charac_weight]{mpl_get_charac_weight()}}, -\code{\link[=mpl_get_gaphandl]{mpl_get_gaphandl()}}, -\code{\link[=mpl_get_num_charac]{mpl_get_num_charac()}}, -\code{\link[=mpl_get_num_internal_nodes]{mpl_get_num_internal_nodes()}}, -\code{\link[=mpl_get_numtaxa]{mpl_get_numtaxa()}}, -\code{\link[=mpl_get_symbols]{mpl_get_symbols()}}, -\code{\link[=mpl_init_Morphy]{mpl_init_Morphy()}}, -\code{\link[=mpl_new_Morphy]{mpl_new_Morphy()}}, -\code{\link[=mpl_second_up_recon]{mpl_second_up_recon()}}, -\code{\link[=mpl_set_charac_weight]{mpl_set_charac_weight()}}, -\code{\link[=mpl_set_num_internal_nodes]{mpl_set_num_internal_nodes()}}, -\code{\link[=mpl_set_parsim_t]{mpl_set_parsim_t()}}, -\code{\link[=mpl_translate_error]{mpl_translate_error()}}, -\code{\link[=mpl_update_lower_root]{mpl_update_lower_root()}}, -\code{\link[=mpl_update_tip]{mpl_update_tip()}}, -\code{\link[=summary.morphyPtr]{summary.morphyPtr()}} -} -\author{ -Thomas Guillerme -} -\concept{Morphy API functions} -\keyword{internal} diff --git a/man/mpl_second_up_recon.Rd b/man/mpl_second_up_recon.Rd deleted file mode 100644 index ff77d5bd2..000000000 --- a/man/mpl_second_up_recon.Rd +++ /dev/null @@ -1,69 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/mpl_morphyex.R -\name{mpl_second_up_recon} -\alias{mpl_second_up_recon} -\title{Finalises the ancestral state reconstructions for characters with -inapplicable values.} -\usage{ -mpl_second_up_recon(node_id, left_id, right_id, anc_id, morphyobj) -} -\arguments{ -\item{node_id}{The index of the node being reconstructed.} - -\item{left_id}{The index of the left descendant.} - -\item{right_id}{The index of the right descendant.} - -\item{anc_id}{The index of the immediate ancestor of the node.} - -\item{morphyobj}{An instance of the Morphy object.} -} -\value{ -The integral parsimony length (right now) -} -\description{ -Finalises the nodal sets for any characters that may have involved -the inapplicable token and counts excess regions of applicability at nodes -having at least two descendant subtrees that possess any applicable characters. -Because this function needs to be fairly high-performance, it does not do much -checking for parameter validity, thus unsafe usage of this function might not -be caught. It is up to calling functions to ensure that the appropriate -parameters have been set before use. -} -\seealso{ -Other Morphy API functions: -\code{\link[=GapHandler]{GapHandler()}}, -\code{\link[=MorphyErrorCheck]{MorphyErrorCheck()}}, -\code{\link[=MorphyWeights]{MorphyWeights()}}, -\code{\link[=PhyDat2Morphy]{PhyDat2Morphy()}}, -\code{\link[=SingleCharMorphy]{SingleCharMorphy()}}, -\code{\link[=UnloadMorphy]{UnloadMorphy()}}, -\code{\link[=is.morphyPtr]{is.morphyPtr()}}, -\code{\link[=mpl_apply_tipdata]{mpl_apply_tipdata()}}, -\code{\link[=mpl_attach_rawdata]{mpl_attach_rawdata()}}, -\code{\link[=mpl_attach_symbols]{mpl_attach_symbols()}}, -\code{\link[=mpl_delete_Morphy]{mpl_delete_Morphy()}}, -\code{\link[=mpl_first_down_recon]{mpl_first_down_recon()}}, -\code{\link[=mpl_first_up_recon]{mpl_first_up_recon()}}, -\code{\link[=mpl_get_charac_weight]{mpl_get_charac_weight()}}, -\code{\link[=mpl_get_gaphandl]{mpl_get_gaphandl()}}, -\code{\link[=mpl_get_num_charac]{mpl_get_num_charac()}}, -\code{\link[=mpl_get_num_internal_nodes]{mpl_get_num_internal_nodes()}}, -\code{\link[=mpl_get_numtaxa]{mpl_get_numtaxa()}}, -\code{\link[=mpl_get_symbols]{mpl_get_symbols()}}, -\code{\link[=mpl_init_Morphy]{mpl_init_Morphy()}}, -\code{\link[=mpl_new_Morphy]{mpl_new_Morphy()}}, -\code{\link[=mpl_second_down_recon]{mpl_second_down_recon()}}, -\code{\link[=mpl_set_charac_weight]{mpl_set_charac_weight()}}, -\code{\link[=mpl_set_num_internal_nodes]{mpl_set_num_internal_nodes()}}, -\code{\link[=mpl_set_parsim_t]{mpl_set_parsim_t()}}, -\code{\link[=mpl_translate_error]{mpl_translate_error()}}, -\code{\link[=mpl_update_lower_root]{mpl_update_lower_root()}}, -\code{\link[=mpl_update_tip]{mpl_update_tip()}}, -\code{\link[=summary.morphyPtr]{summary.morphyPtr()}} -} -\author{ -Thomas Guillerme -} -\concept{Morphy API functions} -\keyword{internal} diff --git a/man/mpl_set_charac_weight.Rd b/man/mpl_set_charac_weight.Rd deleted file mode 100644 index 6cd4d01f7..000000000 --- a/man/mpl_set_charac_weight.Rd +++ /dev/null @@ -1,59 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/mpl_morphyex.R -\name{mpl_set_charac_weight} -\alias{mpl_set_charac_weight} -\title{Set the weight of a character in the dataset} -\usage{ -mpl_set_charac_weight(charID, weight, morphyobj) -} -\arguments{ -\item{charID}{Number of the character (i.e. first character is number 1)} - -\item{weight}{Weight to assign} - -\item{morphyobj}{An instance of the Morphy object.} -} -\value{ -An error code. -} -\description{ -Sets the weight of a character in the dataset. -} -\seealso{ -Other Morphy API functions: -\code{\link[=GapHandler]{GapHandler()}}, -\code{\link[=MorphyErrorCheck]{MorphyErrorCheck()}}, -\code{\link[=MorphyWeights]{MorphyWeights()}}, -\code{\link[=PhyDat2Morphy]{PhyDat2Morphy()}}, -\code{\link[=SingleCharMorphy]{SingleCharMorphy()}}, -\code{\link[=UnloadMorphy]{UnloadMorphy()}}, -\code{\link[=is.morphyPtr]{is.morphyPtr()}}, -\code{\link[=mpl_apply_tipdata]{mpl_apply_tipdata()}}, -\code{\link[=mpl_attach_rawdata]{mpl_attach_rawdata()}}, -\code{\link[=mpl_attach_symbols]{mpl_attach_symbols()}}, -\code{\link[=mpl_delete_Morphy]{mpl_delete_Morphy()}}, -\code{\link[=mpl_first_down_recon]{mpl_first_down_recon()}}, -\code{\link[=mpl_first_up_recon]{mpl_first_up_recon()}}, -\code{\link[=mpl_get_charac_weight]{mpl_get_charac_weight()}}, -\code{\link[=mpl_get_gaphandl]{mpl_get_gaphandl()}}, -\code{\link[=mpl_get_num_charac]{mpl_get_num_charac()}}, -\code{\link[=mpl_get_num_internal_nodes]{mpl_get_num_internal_nodes()}}, -\code{\link[=mpl_get_numtaxa]{mpl_get_numtaxa()}}, -\code{\link[=mpl_get_symbols]{mpl_get_symbols()}}, -\code{\link[=mpl_init_Morphy]{mpl_init_Morphy()}}, -\code{\link[=mpl_new_Morphy]{mpl_new_Morphy()}}, -\code{\link[=mpl_second_down_recon]{mpl_second_down_recon()}}, -\code{\link[=mpl_second_up_recon]{mpl_second_up_recon()}}, -\code{\link[=mpl_set_num_internal_nodes]{mpl_set_num_internal_nodes()}}, -\code{\link[=mpl_set_parsim_t]{mpl_set_parsim_t()}}, -\code{\link[=mpl_translate_error]{mpl_translate_error()}}, -\code{\link[=mpl_update_lower_root]{mpl_update_lower_root()}}, -\code{\link[=mpl_update_tip]{mpl_update_tip()}}, -\code{\link[=summary.morphyPtr]{summary.morphyPtr()}} -} -\author{ -\href{https://smithlabdurham.github.io/}{Martin R. Smith} -(\href{mailto:martin.smith@durham.ac.uk}{martin.smith@durham.ac.uk}) -} -\concept{Morphy API functions} -\keyword{internal} diff --git a/man/mpl_set_num_internal_nodes.Rd b/man/mpl_set_num_internal_nodes.Rd deleted file mode 100644 index 1b8d99872..000000000 --- a/man/mpl_set_num_internal_nodes.Rd +++ /dev/null @@ -1,58 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/mpl_morphyex.R -\name{mpl_set_num_internal_nodes} -\alias{mpl_set_num_internal_nodes} -\title{Sets the number of internal nodes in the dataset} -\usage{ -mpl_set_num_internal_nodes(numnodes, morphyobj) -} -\arguments{ -\item{numnodes}{The desired number of internal nodes.} - -\item{morphyobj}{An instance of the Morphy object.} -} -\value{ -A Morphy error code. -} -\description{ -This specifies the number of internal nodes over which -reconstruction sets need to be made. It is up to the caller to ensure the -correct number of nodes and the relationships between them. -} -\seealso{ -Other Morphy API functions: -\code{\link[=GapHandler]{GapHandler()}}, -\code{\link[=MorphyErrorCheck]{MorphyErrorCheck()}}, -\code{\link[=MorphyWeights]{MorphyWeights()}}, -\code{\link[=PhyDat2Morphy]{PhyDat2Morphy()}}, -\code{\link[=SingleCharMorphy]{SingleCharMorphy()}}, -\code{\link[=UnloadMorphy]{UnloadMorphy()}}, -\code{\link[=is.morphyPtr]{is.morphyPtr()}}, -\code{\link[=mpl_apply_tipdata]{mpl_apply_tipdata()}}, -\code{\link[=mpl_attach_rawdata]{mpl_attach_rawdata()}}, -\code{\link[=mpl_attach_symbols]{mpl_attach_symbols()}}, -\code{\link[=mpl_delete_Morphy]{mpl_delete_Morphy()}}, -\code{\link[=mpl_first_down_recon]{mpl_first_down_recon()}}, -\code{\link[=mpl_first_up_recon]{mpl_first_up_recon()}}, -\code{\link[=mpl_get_charac_weight]{mpl_get_charac_weight()}}, -\code{\link[=mpl_get_gaphandl]{mpl_get_gaphandl()}}, -\code{\link[=mpl_get_num_charac]{mpl_get_num_charac()}}, -\code{\link[=mpl_get_num_internal_nodes]{mpl_get_num_internal_nodes()}}, -\code{\link[=mpl_get_numtaxa]{mpl_get_numtaxa()}}, -\code{\link[=mpl_get_symbols]{mpl_get_symbols()}}, -\code{\link[=mpl_init_Morphy]{mpl_init_Morphy()}}, -\code{\link[=mpl_new_Morphy]{mpl_new_Morphy()}}, -\code{\link[=mpl_second_down_recon]{mpl_second_down_recon()}}, -\code{\link[=mpl_second_up_recon]{mpl_second_up_recon()}}, -\code{\link[=mpl_set_charac_weight]{mpl_set_charac_weight()}}, -\code{\link[=mpl_set_parsim_t]{mpl_set_parsim_t()}}, -\code{\link[=mpl_translate_error]{mpl_translate_error()}}, -\code{\link[=mpl_update_lower_root]{mpl_update_lower_root()}}, -\code{\link[=mpl_update_tip]{mpl_update_tip()}}, -\code{\link[=summary.morphyPtr]{summary.morphyPtr()}} -} -\author{ -Martin Brazeau -} -\concept{Morphy API functions} -\keyword{internal} diff --git a/man/mpl_set_parsim_t.Rd b/man/mpl_set_parsim_t.Rd deleted file mode 100644 index 090b3f0a1..000000000 --- a/man/mpl_set_parsim_t.Rd +++ /dev/null @@ -1,61 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/mpl_morphyex.R -\name{mpl_set_parsim_t} -\alias{mpl_set_parsim_t} -\title{Sets a character's parsimony function type} -\usage{ -mpl_set_parsim_t(char_id, tname = "typename", morphyobj) -} -\arguments{ -\item{char_id}{The number of the character (transformation series) as defined -in the input matrix. The first character is numbered 1 (one).} - -\item{tname}{The parsimony function type as defined in morphydefs.h} - -\item{morphyobj}{An instance of the Morphy object.} -} -\value{ -A Morphy error code. -} -\description{ -Set the parsimony function type to one defined in the -morphydefs.h header file. Setting the character to type NONE_T will also -cause it to be excluded from any further calculations. -} -\seealso{ -Other Morphy API functions: -\code{\link[=GapHandler]{GapHandler()}}, -\code{\link[=MorphyErrorCheck]{MorphyErrorCheck()}}, -\code{\link[=MorphyWeights]{MorphyWeights()}}, -\code{\link[=PhyDat2Morphy]{PhyDat2Morphy()}}, -\code{\link[=SingleCharMorphy]{SingleCharMorphy()}}, -\code{\link[=UnloadMorphy]{UnloadMorphy()}}, -\code{\link[=is.morphyPtr]{is.morphyPtr()}}, -\code{\link[=mpl_apply_tipdata]{mpl_apply_tipdata()}}, -\code{\link[=mpl_attach_rawdata]{mpl_attach_rawdata()}}, -\code{\link[=mpl_attach_symbols]{mpl_attach_symbols()}}, -\code{\link[=mpl_delete_Morphy]{mpl_delete_Morphy()}}, -\code{\link[=mpl_first_down_recon]{mpl_first_down_recon()}}, -\code{\link[=mpl_first_up_recon]{mpl_first_up_recon()}}, -\code{\link[=mpl_get_charac_weight]{mpl_get_charac_weight()}}, -\code{\link[=mpl_get_gaphandl]{mpl_get_gaphandl()}}, -\code{\link[=mpl_get_num_charac]{mpl_get_num_charac()}}, -\code{\link[=mpl_get_num_internal_nodes]{mpl_get_num_internal_nodes()}}, -\code{\link[=mpl_get_numtaxa]{mpl_get_numtaxa()}}, -\code{\link[=mpl_get_symbols]{mpl_get_symbols()}}, -\code{\link[=mpl_init_Morphy]{mpl_init_Morphy()}}, -\code{\link[=mpl_new_Morphy]{mpl_new_Morphy()}}, -\code{\link[=mpl_second_down_recon]{mpl_second_down_recon()}}, -\code{\link[=mpl_second_up_recon]{mpl_second_up_recon()}}, -\code{\link[=mpl_set_charac_weight]{mpl_set_charac_weight()}}, -\code{\link[=mpl_set_num_internal_nodes]{mpl_set_num_internal_nodes()}}, -\code{\link[=mpl_translate_error]{mpl_translate_error()}}, -\code{\link[=mpl_update_lower_root]{mpl_update_lower_root()}}, -\code{\link[=mpl_update_tip]{mpl_update_tip()}}, -\code{\link[=summary.morphyPtr]{summary.morphyPtr()}} -} -\author{ -Martin Brazeau -} -\concept{Morphy API functions} -\keyword{internal} diff --git a/man/mpl_translate_error.Rd b/man/mpl_translate_error.Rd deleted file mode 100644 index 4f2c20c7f..000000000 --- a/man/mpl_translate_error.Rd +++ /dev/null @@ -1,59 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/mpl_morphyex.R -\name{mpl_translate_error} -\alias{mpl_translate_error} -\title{Converts a numeric error code to human-readable format} -\usage{ -mpl_translate_error(errorCode) -} -\arguments{ -\item{errorCode}{Non-positive integer to be converted} -} -\value{ -A character string corresponding to the provided error code -} -\description{ -Converts a numeric error code to human-readable format -} -\examples{ -mpl_translate_error(-1) # "ERR_INVALID_SYMBOL" - -} -\seealso{ -Other Morphy API functions: -\code{\link[=GapHandler]{GapHandler()}}, -\code{\link[=MorphyErrorCheck]{MorphyErrorCheck()}}, -\code{\link[=MorphyWeights]{MorphyWeights()}}, -\code{\link[=PhyDat2Morphy]{PhyDat2Morphy()}}, -\code{\link[=SingleCharMorphy]{SingleCharMorphy()}}, -\code{\link[=UnloadMorphy]{UnloadMorphy()}}, -\code{\link[=is.morphyPtr]{is.morphyPtr()}}, -\code{\link[=mpl_apply_tipdata]{mpl_apply_tipdata()}}, -\code{\link[=mpl_attach_rawdata]{mpl_attach_rawdata()}}, -\code{\link[=mpl_attach_symbols]{mpl_attach_symbols()}}, -\code{\link[=mpl_delete_Morphy]{mpl_delete_Morphy()}}, -\code{\link[=mpl_first_down_recon]{mpl_first_down_recon()}}, -\code{\link[=mpl_first_up_recon]{mpl_first_up_recon()}}, -\code{\link[=mpl_get_charac_weight]{mpl_get_charac_weight()}}, -\code{\link[=mpl_get_gaphandl]{mpl_get_gaphandl()}}, -\code{\link[=mpl_get_num_charac]{mpl_get_num_charac()}}, -\code{\link[=mpl_get_num_internal_nodes]{mpl_get_num_internal_nodes()}}, -\code{\link[=mpl_get_numtaxa]{mpl_get_numtaxa()}}, -\code{\link[=mpl_get_symbols]{mpl_get_symbols()}}, -\code{\link[=mpl_init_Morphy]{mpl_init_Morphy()}}, -\code{\link[=mpl_new_Morphy]{mpl_new_Morphy()}}, -\code{\link[=mpl_second_down_recon]{mpl_second_down_recon()}}, -\code{\link[=mpl_second_up_recon]{mpl_second_up_recon()}}, -\code{\link[=mpl_set_charac_weight]{mpl_set_charac_weight()}}, -\code{\link[=mpl_set_num_internal_nodes]{mpl_set_num_internal_nodes()}}, -\code{\link[=mpl_set_parsim_t]{mpl_set_parsim_t()}}, -\code{\link[=mpl_update_lower_root]{mpl_update_lower_root()}}, -\code{\link[=mpl_update_tip]{mpl_update_tip()}}, -\code{\link[=summary.morphyPtr]{summary.morphyPtr()}} -} -\author{ -\href{https://smithlabdurham.github.io/}{Martin R. Smith} -(\href{mailto:martin.smith@durham.ac.uk}{martin.smith@durham.ac.uk}) -} -\concept{Morphy API functions} -\keyword{internal} diff --git a/man/mpl_update_lower_root.Rd b/man/mpl_update_lower_root.Rd deleted file mode 100644 index a23c1aa7a..000000000 --- a/man/mpl_update_lower_root.Rd +++ /dev/null @@ -1,64 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/mpl_morphyex.R -\name{mpl_update_lower_root} -\alias{mpl_update_lower_root} -\title{Updates the nodal sets for a lower ("dummy") root node} -\usage{ -mpl_update_lower_root(l_root_id, root_id, morphyobj) -} -\arguments{ -\item{l_root_id}{The index of the lower root.} - -\item{root_id}{The index of the upper root node.} - -\item{morphyobj}{An instance of the Morphy object.} -} -\value{ -A Morphy error code. -} -\description{ -If trees are rooted, then Morphy uppass functions -require a lower or "dummy" root in order to function properly. This -function should be called to set the nodal state sets to the dummy -root. The nodal set will be equal to the set of the root node, unless -there is an ambiguous union of applicable and gap tokens when gaps are -treated as in applicable. In which case, the set union is resolved in -favour of any applicable tokens in the set. -} -\seealso{ -Other Morphy API functions: -\code{\link[=GapHandler]{GapHandler()}}, -\code{\link[=MorphyErrorCheck]{MorphyErrorCheck()}}, -\code{\link[=MorphyWeights]{MorphyWeights()}}, -\code{\link[=PhyDat2Morphy]{PhyDat2Morphy()}}, -\code{\link[=SingleCharMorphy]{SingleCharMorphy()}}, -\code{\link[=UnloadMorphy]{UnloadMorphy()}}, -\code{\link[=is.morphyPtr]{is.morphyPtr()}}, -\code{\link[=mpl_apply_tipdata]{mpl_apply_tipdata()}}, -\code{\link[=mpl_attach_rawdata]{mpl_attach_rawdata()}}, -\code{\link[=mpl_attach_symbols]{mpl_attach_symbols()}}, -\code{\link[=mpl_delete_Morphy]{mpl_delete_Morphy()}}, -\code{\link[=mpl_first_down_recon]{mpl_first_down_recon()}}, -\code{\link[=mpl_first_up_recon]{mpl_first_up_recon()}}, -\code{\link[=mpl_get_charac_weight]{mpl_get_charac_weight()}}, -\code{\link[=mpl_get_gaphandl]{mpl_get_gaphandl()}}, -\code{\link[=mpl_get_num_charac]{mpl_get_num_charac()}}, -\code{\link[=mpl_get_num_internal_nodes]{mpl_get_num_internal_nodes()}}, -\code{\link[=mpl_get_numtaxa]{mpl_get_numtaxa()}}, -\code{\link[=mpl_get_symbols]{mpl_get_symbols()}}, -\code{\link[=mpl_init_Morphy]{mpl_init_Morphy()}}, -\code{\link[=mpl_new_Morphy]{mpl_new_Morphy()}}, -\code{\link[=mpl_second_down_recon]{mpl_second_down_recon()}}, -\code{\link[=mpl_second_up_recon]{mpl_second_up_recon()}}, -\code{\link[=mpl_set_charac_weight]{mpl_set_charac_weight()}}, -\code{\link[=mpl_set_num_internal_nodes]{mpl_set_num_internal_nodes()}}, -\code{\link[=mpl_set_parsim_t]{mpl_set_parsim_t()}}, -\code{\link[=mpl_translate_error]{mpl_translate_error()}}, -\code{\link[=mpl_update_tip]{mpl_update_tip()}}, -\code{\link[=summary.morphyPtr]{summary.morphyPtr()}} -} -\author{ -Thomas Guillerme -} -\concept{Morphy API functions} -\keyword{internal} diff --git a/man/mpl_update_tip.Rd b/man/mpl_update_tip.Rd deleted file mode 100644 index de379eb9b..000000000 --- a/man/mpl_update_tip.Rd +++ /dev/null @@ -1,69 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/mpl_morphyex.R -\name{mpl_update_tip} -\alias{mpl_update_tip} -\title{Initial update of tip values following uppass reconstruction.} -\usage{ -mpl_update_tip(tip_id, anc_id, morphyobj) -} -\arguments{ -\item{tip_id}{The index of the tip being updated.} - -\item{anc_id}{The index of the tip's immediate ancestor.} - -\item{morphyobj}{An instance of the Morphy object.} -} -\value{ -The integral parsimony length (right now) -} -\description{ -Ambiguous terminal state sets need to be resolved after the first uppass -based on descendant state values in order for local reoptimisation procedures -to be accurate and for inapplicable step counting to proceed accurately. This -function calls updaters for the records of states active on the subtrees, -thereby allowing the second downpass to accurately reconstruct subtree state -activity. -Because this function needs to be fairly high-performance, it does not do much -checking for parameter validity, thus unsafe usage of this function might not -be caught. It is up to calling functions to ensure that the appropriate -parameters have been set before use. -} -\seealso{ -A null value (for now). - -Other Morphy API functions: -\code{\link[=GapHandler]{GapHandler()}}, -\code{\link[=MorphyErrorCheck]{MorphyErrorCheck()}}, -\code{\link[=MorphyWeights]{MorphyWeights()}}, -\code{\link[=PhyDat2Morphy]{PhyDat2Morphy()}}, -\code{\link[=SingleCharMorphy]{SingleCharMorphy()}}, -\code{\link[=UnloadMorphy]{UnloadMorphy()}}, -\code{\link[=is.morphyPtr]{is.morphyPtr()}}, -\code{\link[=mpl_apply_tipdata]{mpl_apply_tipdata()}}, -\code{\link[=mpl_attach_rawdata]{mpl_attach_rawdata()}}, -\code{\link[=mpl_attach_symbols]{mpl_attach_symbols()}}, -\code{\link[=mpl_delete_Morphy]{mpl_delete_Morphy()}}, -\code{\link[=mpl_first_down_recon]{mpl_first_down_recon()}}, -\code{\link[=mpl_first_up_recon]{mpl_first_up_recon()}}, -\code{\link[=mpl_get_charac_weight]{mpl_get_charac_weight()}}, -\code{\link[=mpl_get_gaphandl]{mpl_get_gaphandl()}}, -\code{\link[=mpl_get_num_charac]{mpl_get_num_charac()}}, -\code{\link[=mpl_get_num_internal_nodes]{mpl_get_num_internal_nodes()}}, -\code{\link[=mpl_get_numtaxa]{mpl_get_numtaxa()}}, -\code{\link[=mpl_get_symbols]{mpl_get_symbols()}}, -\code{\link[=mpl_init_Morphy]{mpl_init_Morphy()}}, -\code{\link[=mpl_new_Morphy]{mpl_new_Morphy()}}, -\code{\link[=mpl_second_down_recon]{mpl_second_down_recon()}}, -\code{\link[=mpl_second_up_recon]{mpl_second_up_recon()}}, -\code{\link[=mpl_set_charac_weight]{mpl_set_charac_weight()}}, -\code{\link[=mpl_set_num_internal_nodes]{mpl_set_num_internal_nodes()}}, -\code{\link[=mpl_set_parsim_t]{mpl_set_parsim_t()}}, -\code{\link[=mpl_translate_error]{mpl_translate_error()}}, -\code{\link[=mpl_update_lower_root]{mpl_update_lower_root()}}, -\code{\link[=summary.morphyPtr]{summary.morphyPtr()}} -} -\author{ -Thomas Guillerme -} -\concept{Morphy API functions} -\keyword{internal} diff --git a/man/profiles.Rd b/man/profiles.Rd index 5ed3cbeaf..bc28a28b5 100644 --- a/man/profiles.Rd +++ b/man/profiles.Rd @@ -27,11 +27,11 @@ profile3.5 <- profiles[[8]][[2]][[3]] TreeTools::NUnrooted(8) * 2 ^ profile3.5 } \seealso{ -Other profile parsimony functions: -\code{\link[=MaddisonSlatkin]{MaddisonSlatkin()}}, -\code{\link[=PrepareDataProfile]{PrepareDataProfile()}}, -\code{\link[=StepInformation]{StepInformation()}}, -\code{\link[=WithOneExtraStep]{WithOneExtraStep()}} +Other profile parsimony functions: +\code{\link{MaddisonSlatkin}()}, +\code{\link{PrepareDataProfile}()}, +\code{\link{StepInformation}()}, +\code{\link{WithOneExtraStep}()} } \concept{profile parsimony functions} \keyword{datasets} diff --git a/man/recode_hierarchy.Rd b/man/recode_hierarchy.Rd index ade13bd79..f87e5c894 100644 --- a/man/recode_hierarchy.Rd +++ b/man/recode_hierarchy.Rd @@ -7,7 +7,7 @@ recode_hierarchy(dataset, hierarchy) } \arguments{ -\item{dataset}{A \code{\link[phangorn:phyDat]{phyDat}} object.} +\item{dataset}{A \code{\link[phangorn:as.phyDat]{phyDat}} object.} \item{hierarchy}{A \code{\link{CharacterHierarchy}} object.} } @@ -64,19 +64,19 @@ different states). \seealso{ \code{\link[=CharacterHierarchy]{CharacterHierarchy()}}, \code{\link[=MaximizeParsimony]{MaximizeParsimony()}} -Other tree scoring: -\code{\link[=CharacterHierarchy]{CharacterHierarchy()}}, -\code{\link[=CharacterLength]{CharacterLength()}}, -\code{\link[=ExpectedLength]{ExpectedLength()}}, -\code{\link[=IWScore]{IWScore()}}, -\code{\link[=LengthAdded]{LengthAdded()}}, -\code{\link[=MaximizeParsimony]{MaximizeParsimony()}}, -\code{\link[=MinimumLength]{MinimumLength()}}, -\code{\link[=MorphyTreeLength]{MorphyTreeLength()}}, -\code{\link[=ParsSim]{ParsSim()}}, -\code{\link[=TaxonInfluence]{TaxonInfluence()}}, -\code{\link[=WideSample]{WideSample()}}, -\code{\link[=hierarchy_from_names]{hierarchy_from_names()}} +Other tree scoring: +\code{\link{CharacterHierarchy}()}, +\code{\link{CharacterLength}()}, +\code{\link{ExpectedLength}()}, +\code{\link{IWScore}()}, +\code{\link{LengthAdded}()}, +\code{\link{MaximizeParsimony}()}, +\code{\link{MinimumLength}()}, +\code{\link{ParsSim}()}, +\code{\link{TaxonInfluence}()}, +\code{\link{TreeScore}()}, +\code{\link{WideSample}()}, +\code{\link{hierarchy_from_names}()} } \concept{tree scoring} \keyword{internal} diff --git a/man/summary.morphyPtr.Rd b/man/summary.morphyPtr.Rd deleted file mode 100644 index e3c74dc34..000000000 --- a/man/summary.morphyPtr.Rd +++ /dev/null @@ -1,56 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/mpl_morphy_objects.R -\name{summary.morphyPtr} -\alias{summary.morphyPtr} -\title{Details the attributes of a morphy object} -\usage{ -\method{summary}{morphyPtr}(object, ...) -} -\arguments{ -\item{object}{A Morphy object} - -\item{\dots}{any other parameters...} -} -\value{ -A list detailing the number of taxa, internal nodes, and characters and their weights. -} -\description{ -Details the attributes of a morphy object -} -\seealso{ -Other Morphy API functions: -\code{\link[=GapHandler]{GapHandler()}}, -\code{\link[=MorphyErrorCheck]{MorphyErrorCheck()}}, -\code{\link[=MorphyWeights]{MorphyWeights()}}, -\code{\link[=PhyDat2Morphy]{PhyDat2Morphy()}}, -\code{\link[=SingleCharMorphy]{SingleCharMorphy()}}, -\code{\link[=UnloadMorphy]{UnloadMorphy()}}, -\code{\link[=is.morphyPtr]{is.morphyPtr()}}, -\code{\link[=mpl_apply_tipdata]{mpl_apply_tipdata()}}, -\code{\link[=mpl_attach_rawdata]{mpl_attach_rawdata()}}, -\code{\link[=mpl_attach_symbols]{mpl_attach_symbols()}}, -\code{\link[=mpl_delete_Morphy]{mpl_delete_Morphy()}}, -\code{\link[=mpl_first_down_recon]{mpl_first_down_recon()}}, -\code{\link[=mpl_first_up_recon]{mpl_first_up_recon()}}, -\code{\link[=mpl_get_charac_weight]{mpl_get_charac_weight()}}, -\code{\link[=mpl_get_gaphandl]{mpl_get_gaphandl()}}, -\code{\link[=mpl_get_num_charac]{mpl_get_num_charac()}}, -\code{\link[=mpl_get_num_internal_nodes]{mpl_get_num_internal_nodes()}}, -\code{\link[=mpl_get_numtaxa]{mpl_get_numtaxa()}}, -\code{\link[=mpl_get_symbols]{mpl_get_symbols()}}, -\code{\link[=mpl_init_Morphy]{mpl_init_Morphy()}}, -\code{\link[=mpl_new_Morphy]{mpl_new_Morphy()}}, -\code{\link[=mpl_second_down_recon]{mpl_second_down_recon()}}, -\code{\link[=mpl_second_up_recon]{mpl_second_up_recon()}}, -\code{\link[=mpl_set_charac_weight]{mpl_set_charac_weight()}}, -\code{\link[=mpl_set_num_internal_nodes]{mpl_set_num_internal_nodes()}}, -\code{\link[=mpl_set_parsim_t]{mpl_set_parsim_t()}}, -\code{\link[=mpl_translate_error]{mpl_translate_error()}}, -\code{\link[=mpl_update_lower_root]{mpl_update_lower_root()}}, -\code{\link[=mpl_update_tip]{mpl_update_tip()}} -} -\author{ -\href{https://smithlabdurham.github.io/}{Martin R. Smith} -(\href{mailto:martin.smith@durham.ac.uk}{martin.smith@durham.ac.uk}) -} -\concept{Morphy API functions} diff --git a/man/validate_hierarchy.Rd b/man/validate_hierarchy.Rd index 14d5bfcd0..077986b21 100644 --- a/man/validate_hierarchy.Rd +++ b/man/validate_hierarchy.Rd @@ -17,7 +17,7 @@ informative error if validation fails). } \description{ Check that a \code{\link{CharacterHierarchy}} object is consistent with a -\code{\link[phangorn:phyDat]{phyDat}} dataset: character indices exist, +\code{\link[phangorn:as.phyDat]{phyDat}} dataset: character indices exist, controlling characters are binary (absent/present), secondaries are coded inapplicable where expected, and no character appears in multiple blocks. diff --git a/src/RMorphy.c b/src/RMorphy.c deleted file mode 100644 index fcc4d1a96..000000000 --- a/src/RMorphy.c +++ /dev/null @@ -1,338 +0,0 @@ -#ifdef HAVE_CONFIG_H -# include -#endif - -#include -#include -#include -#include "mpl.h" -#include "RMorphyUtils.h" -#include "RMorphy.h" - -SEXP _R_wrap_mpl_new_Morphy(void) { - Morphy new_Morphy = mpl_new_Morphy(); - SEXP result = PROTECT(R_MakeExternalPtr(new_Morphy, R_NilValue, R_NilValue)); - R_PreserveObject(result); - R_RegisterCFinalizerEx(result, _finalize_Morphy, TRUE); - UNPROTECT(1); - - return result; -} - -void _finalize_Morphy (SEXP MorphyHandl) { - Morphy handl = R_ExternalPtrAddr(MorphyHandl); - if (handl == NULL) return; - mpl_delete_Morphy(handl); - R_ClearExternalPtr(MorphyHandl); - R_ReleaseObject(MorphyHandl); -} - -SEXP _R_wrap_mpl_delete_Morphy(SEXP MorphyHandl) { - SEXP Rret = PROTECT(allocVector(INTSXP, 1)); - - Morphy handl = R_ExternalPtrAddr(MorphyHandl); - if (handl == NULL) { - INTEGER(Rret)[0] = NA_INTEGER; - } else { - INTEGER(Rret)[0] = mpl_delete_Morphy(handl); - R_ReleaseObject(MorphyHandl); - R_ClearExternalPtr(MorphyHandl); - } - UNPROTECT(1); - - return Rret; -} - -SEXP _R_wrap_mpl_init_Morphy(SEXP Rntax, SEXP Rnchar, SEXP MorphHandl) { - int ret = 0; - SEXP Rret = PROTECT(allocVector(INTSXP, 1)); - - Morphy handl = R_ExternalPtrAddr(MorphHandl); - int ntax = INTEGER(Rntax)[0]; - int nchar = INTEGER(Rnchar)[0]; - - ret = mpl_init_Morphy(ntax, nchar, handl); - - INTEGER(Rret)[0] = ret; - UNPROTECT(1); - return Rret; -} - -SEXP _R_wrap_mpl_get_numtaxa(SEXP MorphHandl) { - SEXP Rret = PROTECT(allocVector(INTSXP, 1)); - - INTEGER(Rret)[0] = mpl_get_numtaxa(R_ExternalPtrAddr(MorphHandl)); - - UNPROTECT(1); - return Rret; -} - -SEXP _R_wrap_mpl_get_num_charac(SEXP MorphHandl) { - SEXP Rret = PROTECT(allocVector(INTSXP, 1)); - - INTEGER(Rret)[0] = mpl_get_num_charac(R_ExternalPtrAddr(MorphHandl)); - - UNPROTECT(1); - return Rret; -} - -SEXP _R_wrap_mpl_attach_symbols(SEXP Rsymbols, SEXP MorphyHandl) { - SEXP Rret = PROTECT(allocVector(INTSXP, 1)); - - int Mret = 0; - const char *Msymbols = CHAR(asChar(Rsymbols)); - - Mret = mpl_attach_symbols(Msymbols, R_ExternalPtrAddr(MorphyHandl)); - INTEGER(Rret)[0] = Mret; - - UNPROTECT(1); - return Rret; -} - -SEXP _R_wrap_mpl_get_symbols(SEXP MorphyHandl) { - SEXP Rret = PROTECT(allocVector(STRSXP, 1)); - - char* symbols = mpl_get_symbols(R_ExternalPtrAddr(MorphyHandl)); - - Rret = mkString(symbols); - - UNPROTECT(1); - return Rret; -} - -SEXP _R_wrap_mpl_attach_rawdata(SEXP Rmatrix, SEXP MorphyHandl) { - SEXP Rret = PROTECT(allocVector(INTSXP, 1)); - - int Mret = 0; - const char *Mmatrix = CHAR(asChar(Rmatrix)); - - Mret = mpl_attach_rawdata(Mmatrix, R_ExternalPtrAddr(MorphyHandl)); - - INTEGER(Rret)[0] = Mret; - UNPROTECT(1); - - return Rret; -} - -SEXP _R_wrap_mpl_set_parsim_t(SEXP RcharID, SEXP Rchtype, SEXP MorphyHandl) { - SEXP Rret = PROTECT(allocVector(INTSXP, 1)); - MPLchtype chtype; - int Mret = 0; - - const char* chtypename = CHAR(asChar(Rchtype)); - - chtype = _R_mpl_str2chtype(chtypename); - Mret = mpl_set_parsim_t(INTEGER(RcharID)[0], chtype, - R_ExternalPtrAddr(MorphyHandl)); - - INTEGER(Rret)[0] = Mret; - - UNPROTECT(1); - return Rret; -} - -SEXP _R_wrap_mpl_set_gaphandl(SEXP Rgaptype, SEXP MorphyHandl) { - SEXP Rret = PROTECT(allocVector(INTSXP, 1)); - MPLgap_t gaptype; - int Mret = 0; - - const char* gaptypename = CHAR(asChar(Rgaptype)); - - gaptype = _R_mpl_str2gaptype(gaptypename); - Mret = mpl_set_gaphandl(gaptype, R_ExternalPtrAddr(MorphyHandl)); - - INTEGER(Rret)[0] = Mret; - - UNPROTECT(1); - return Rret; -} - -SEXP _R_wrap_mpl_get_gaphandl(SEXP MorphyHandl) { - SEXP Rret = PROTECT(allocVector(INTSXP, 1)); - int Mret = 0; - - Mret = mpl_query_gaphandl(R_ExternalPtrAddr(MorphyHandl)); - - INTEGER(Rret)[0] = Mret; - - UNPROTECT(1); - return Rret; -} - -SEXP _R_wrap_mpl_set_num_internal_nodes(SEXP Rnnodes, SEXP MorphyHandl) { - SEXP Rret = PROTECT(allocVector(INTSXP, 1)); - - INTEGER(Rret)[0] = mpl_set_num_internal_nodes - (INTEGER(Rnnodes)[0], - R_ExternalPtrAddr(MorphyHandl)); - - UNPROTECT(1); - return Rret; -} - -SEXP _R_wrap_mpl_get_num_internal_nodes(SEXP MorphyHandl) { - SEXP Rret = PROTECT(allocVector(INTSXP, 1)); - - INTEGER(Rret)[0] = mpl_get_num_internal_nodes - (R_ExternalPtrAddr(MorphyHandl)); - - UNPROTECT(1); - return Rret; -} - -SEXP _R_wrap_mpl_apply_tipdata(SEXP MorphyHandl) { - SEXP Rret = PROTECT(allocVector(INTSXP, 1)); - - INTEGER(Rret)[0] = mpl_apply_tipdata(R_ExternalPtrAddr(MorphyHandl)); - - UNPROTECT(1); - return Rret; -} - - -SEXP _R_wrap_mpl_set_charac_weight(SEXP RcharID, SEXP Rweight, - SEXP MorphyHandl) { - SEXP Rret = PROTECT(allocVector(INTSXP, 1)); - INTEGER(Rret)[0] = mpl_set_charac_weight(INTEGER(RcharID)[0], REAL(Rweight)[0], - R_ExternalPtrAddr(MorphyHandl)); - UNPROTECT(1); - return Rret; -} - -SEXP _R_wrap_mpl_get_charac_weight(SEXP RcharID, SEXP MorphyHandl) { - SEXP Rret, Wapprox, Wexact; - PROTECT(Rret = allocVector(VECSXP, 2)); - PROTECT(Wapprox = allocVector(INTSXP, 1)); - PROTECT(Wexact = allocVector(REALSXP, 1)); - - INTEGER(Wapprox)[0] = mpl_get_charac_weight(REAL(Wexact), INTEGER(RcharID)[0], - R_ExternalPtrAddr(MorphyHandl)); - SET_VECTOR_ELT(Rret, 0, Wapprox); - SET_VECTOR_ELT(Rret, 1, Wexact); - UNPROTECT(3); - return Rret; -} - -SEXP _R_wrap_mpl_first_down_recon(SEXP Rnode_id, SEXP Rleft_id, SEXP Rright_id, - SEXP MorphyHandl) { - SEXP Rret = PROTECT(allocVector(INTSXP, 1)); - - INTEGER(Rret)[0] = - mpl_first_down_recon(INTEGER(Rnode_id)[0], INTEGER(Rleft_id)[0], - INTEGER(Rright_id)[0], - R_ExternalPtrAddr(MorphyHandl)); - UNPROTECT(1); - return Rret; -} - -SEXP _R_wrap_mpl_first_up_recon(SEXP Rnode_id, SEXP Rleft_id, SEXP Rright_id, - SEXP Ranc_id, SEXP MorphyHandl) { - SEXP Rret = PROTECT(allocVector(INTSXP, 1)); - - INTEGER(Rret)[0] = - mpl_first_up_recon(INTEGER(Rnode_id)[0], INTEGER(Rleft_id)[0], - INTEGER(Rright_id)[0], INTEGER(Ranc_id)[0], - R_ExternalPtrAddr(MorphyHandl)); - UNPROTECT(1); - return Rret; -} - -SEXP _R_wrap_mpl_second_down_recon(SEXP Rnode_id, SEXP Rleft_id, SEXP Rright_id, - SEXP MorphyHandl) { - SEXP Rret = PROTECT(allocVector(INTSXP, 1)); - - INTEGER(Rret)[0] = - mpl_second_down_recon(INTEGER(Rnode_id)[0], INTEGER(Rleft_id)[0], - INTEGER(Rright_id)[0], - R_ExternalPtrAddr(MorphyHandl)); - UNPROTECT(1); - return Rret; -} - -SEXP _R_wrap_mpl_second_up_recon(SEXP Rnode_id, SEXP Rleft_id, SEXP Rright_id, - SEXP Ranc_id, SEXP MorphyHandl) { - SEXP Rret = PROTECT(allocVector(INTSXP, 1)); - - INTEGER(Rret)[0] = - mpl_second_up_recon(INTEGER(Rnode_id)[0], INTEGER(Rleft_id)[0], - INTEGER(Rright_id)[0], INTEGER(Ranc_id)[0], - R_ExternalPtrAddr(MorphyHandl)); - UNPROTECT(1); - return Rret; -} - -SEXP _R_wrap_mpl_update_tip(SEXP tip_id, SEXP anc_id, SEXP MorphyHandl) { - SEXP Rret = PROTECT(allocVector(INTSXP, 1)); - - INTEGER(Rret)[0] = - mpl_update_tip(INTEGER(tip_id)[0], INTEGER(anc_id)[0], - R_ExternalPtrAddr(MorphyHandl)); - UNPROTECT(1); - return Rret; -} - -SEXP _R_wrap_mpl_update_lower_root(SEXP lower_id, SEXP upper_id, - SEXP MorphyHandl) { - SEXP Rret = PROTECT(allocVector(INTSXP, 1)); - - INTEGER(Rret)[0] = - mpl_update_lower_root(INTEGER(lower_id)[0], INTEGER(upper_id)[0], - R_ExternalPtrAddr(MorphyHandl)); - UNPROTECT(1); - return Rret; -} - -void morphy_length (const int *ancestor, const int *left, const int *right, - Morphy handl, int *score) { - int i; - const int n_taxa = mpl_get_numtaxa(handl); - const int n_internal = mpl_get_num_internal_nodes(handl); - const int root_node = n_taxa; - const int max_node = n_taxa + n_internal; - - for (i = max_node - 1; i >= n_taxa; i--) { /* First Downpass */ - *score += mpl_first_down_recon(i, left[i - n_taxa], right[i - n_taxa], - handl); - } - /* We could use a spare internal node with index = max_node as a dummy root node. - * Instead: just pass the root node as its own ancestor. */ - mpl_update_lower_root(root_node, root_node, handl); - - for (i = root_node; i != max_node; i++) { /* First uppass: internal nodes */ - *score += mpl_first_up_recon(i, left[i - n_taxa], right[i - n_taxa], - ancestor[i], handl); - } - for (i = 0; i != n_taxa; i++) { /* First uppass: update tips */ - mpl_update_tip(i, ancestor[i], handl); - } - - for (i = max_node - 1; i >= n_taxa; i--) { /* Second Downpass */ - *score += mpl_second_down_recon(i, left[i - n_taxa], right[i - n_taxa], - handl); - } - -} - -SEXP MORPHYLENGTH(SEXP R_ancestors, SEXP R_left, SEXP R_right, SEXP MorphyHandl) { - Morphy handl = R_ExternalPtrAddr(MorphyHandl); - /* R_descendants and R_ancestors have already had one subtracted to convert - * them to an index */ - const int - /* INTEGER gives pointer to first element of an R vector*/ - *ancestor = INTEGER(R_ancestors), - *left = INTEGER(R_left), - *right = INTEGER(R_right) - ; - - /* Declare and protect result, to return to R */ - SEXP Rres = PROTECT(allocVector(INTSXP, 1)); - - /* Initialize return variables */ - int *score; - score = INTEGER(Rres); - *score = 0; - morphy_length(ancestor, left, right, handl, score); /* Updates score */ - - UNPROTECT(1); - return Rres; -} diff --git a/src/RMorphy.h b/src/RMorphy.h deleted file mode 100644 index 838dd96d7..000000000 --- a/src/RMorphy.h +++ /dev/null @@ -1,35 +0,0 @@ -#ifdef HAVE_CONFIG_H -# include -#endif - -#include -#include -#include -#include "mpl.h" -#include "RMorphyUtils.h" - -SEXP _R_wrap_mpl_new_Morphy(void); -void _finalize_Morphy(SEXP MorphyHandl); -SEXP _R_wrap_mpl_delete_Morphy(SEXP MorphyHandl); -SEXP _R_wrap_mpl_init_Morphy(SEXP Rntax, SEXP Rnchar, SEXP MorphHandl); -SEXP _R_wrap_mpl_get_numtaxa(SEXP MorphHandl); -SEXP _R_wrap_mpl_get_num_charac(SEXP MorphHandl); -SEXP _R_wrap_mpl_attach_symbols(SEXP Rsymbols, SEXP MorphyHandl); -SEXP _R_wrap_mpl_get_symbols(SEXP MorphyHandl); -SEXP _R_wrap_mpl_attach_rawdata(SEXP Rmatrix, SEXP MorphyHandl); -SEXP _R_wrap_mpl_set_parsim_t(SEXP RcharID, SEXP Rchtype, SEXP MorphyHandl); -SEXP _R_wrap_mpl_get_gaphandl(SEXP MorphyHandl); -SEXP _R_wrap_mpl_set_gaphandl(SEXP Rgaptype, SEXP MorphyHandl); -SEXP _R_wrap_mpl_set_num_internal_nodes(SEXP Rnnodes, SEXP MorphyHandl); -SEXP _R_wrap_mpl_get_num_internal_nodes(SEXP MorphyHandl); -SEXP _R_wrap_mpl_apply_tipdata(SEXP MorphyHandl); -SEXP _R_wrap_mpl_set_charac_weight(SEXP RcharID, SEXP Rweight, SEXP MorphyHandl); -SEXP _R_wrap_mpl_get_charac_weight(SEXP RcharID, SEXP MorphyHandl); -SEXP _R_wrap_mpl_first_down_recon(SEXP Rnode_id, SEXP Rleft_id, SEXP Rright_id, SEXP MorphyHandl); -SEXP _R_wrap_mpl_first_up_recon(SEXP Rnode_id, SEXP Rleft_id, SEXP Rright_id, SEXP Ranc_id, SEXP MorphyHandl); -SEXP _R_wrap_mpl_second_down_recon(SEXP Rnode_id, SEXP Rleft_id, SEXP Rright_id, SEXP MorphyHandl); -SEXP _R_wrap_mpl_second_up_recon(SEXP Rnode_id, SEXP Rleft_id, SEXP Rright_id, SEXP Ranc_id, SEXP MorphyHandl); -SEXP _R_wrap_mpl_update_tip(SEXP tip_id, SEXP anc_id, SEXP MorphyHandl); -SEXP _R_wrap_mpl_update_lower_root(SEXP lower_id, SEXP upper_id, SEXP MorphyHandl); -void morphy_length(const int *ancestor, const int *left, const int *right, Morphy handl, int *score); -SEXP MORPHYLENGTH(SEXP R_ancestors, SEXP R_left, SEXP R_right, SEXP MorphyHandl); diff --git a/src/RMorphyUtils.c b/src/RMorphyUtils.c deleted file mode 100644 index 0c3994136..000000000 --- a/src/RMorphyUtils.c +++ /dev/null @@ -1,40 +0,0 @@ -#include "mpl.h" -#include "RMorphyUtils.h" - -MPLchtype _R_mpl_str2chtype(const char *chtypename) -{ - - if(!strcasecmp(chtypename, "fitch")){ - return FITCH_T; - } - else if(!strcasecmp(chtypename, "wagner")){ - return WAGNER_T; - } - else if(!strcasecmp(chtypename, "dollo")){ - return DOLLO_T; - } - else if(!strcasecmp(chtypename, "irreversible")){ - return IRREVERSIBLE_T; - } - else if(!strcasecmp(chtypename, "user")){ - return USERTYPE_T; - } - - return MAX_CTYPE; -} - -MPLgap_t _R_mpl_str2gaptype(const char *chtypename) -{ - - if(!strcasecmp(chtypename, "inapplicable")){ - return GAP_INAPPLIC; - } - else if(!strcasecmp(chtypename, "missing")){ - return GAP_MISSING; - } - else if(!strcasecmp(chtypename, "newstate")){ - return GAP_NEWSTATE; - } - - return GAP_MAX; -} diff --git a/src/RMorphyUtils.h b/src/RMorphyUtils.h deleted file mode 100644 index 0e0f10f85..000000000 --- a/src/RMorphyUtils.h +++ /dev/null @@ -1,9 +0,0 @@ -#include -#include "mpl.h" - -#if defined (_WIN32) || defined(_WIN64) || defined(_WINDOWS) -#define strcasecmp _stricmp -#endif - -MPLchtype _R_mpl_str2chtype(const char *chtypename); -MPLgap_t _R_mpl_str2gaptype(const char *chtypename); diff --git a/src/RcppExports.cpp b/src/RcppExports.cpp index c445980ef..eab6d878b 100644 --- a/src/RcppExports.cpp +++ b/src/RcppExports.cpp @@ -55,63 +55,6 @@ BEGIN_RCPP return rcpp_result_gen; END_RCPP } -// preorder_morphy -int preorder_morphy(IntegerMatrix edge, SEXP MorphyHandl); -RcppExport SEXP _TreeSearch_preorder_morphy(SEXP edgeSEXP, SEXP MorphyHandlSEXP) { -BEGIN_RCPP - Rcpp::RObject rcpp_result_gen; - Rcpp::RNGScope rcpp_rngScope_gen; - Rcpp::traits::input_parameter< IntegerMatrix >::type edge(edgeSEXP); - Rcpp::traits::input_parameter< SEXP >::type MorphyHandl(MorphyHandlSEXP); - rcpp_result_gen = Rcpp::wrap(preorder_morphy(edge, MorphyHandl)); - return rcpp_result_gen; -END_RCPP -} -// preorder_morphy_by_char -IntegerVector preorder_morphy_by_char(IntegerMatrix edge, List MorphyHandls); -RcppExport SEXP _TreeSearch_preorder_morphy_by_char(SEXP edgeSEXP, SEXP MorphyHandlsSEXP) { -BEGIN_RCPP - Rcpp::RObject rcpp_result_gen; - Rcpp::RNGScope rcpp_rngScope_gen; - Rcpp::traits::input_parameter< IntegerMatrix >::type edge(edgeSEXP); - Rcpp::traits::input_parameter< List >::type MorphyHandls(MorphyHandlsSEXP); - rcpp_result_gen = Rcpp::wrap(preorder_morphy_by_char(edge, MorphyHandls)); - return rcpp_result_gen; -END_RCPP -} -// morphy_iw -double morphy_iw(IntegerMatrix edge, List MorphyHandls, NumericVector weight, IntegerVector minScore, IntegerVector sequence, NumericVector concavity, NumericVector target); -RcppExport SEXP _TreeSearch_morphy_iw(SEXP edgeSEXP, SEXP MorphyHandlsSEXP, SEXP weightSEXP, SEXP minScoreSEXP, SEXP sequenceSEXP, SEXP concavitySEXP, SEXP targetSEXP) { -BEGIN_RCPP - Rcpp::RObject rcpp_result_gen; - Rcpp::RNGScope rcpp_rngScope_gen; - Rcpp::traits::input_parameter< IntegerMatrix >::type edge(edgeSEXP); - Rcpp::traits::input_parameter< List >::type MorphyHandls(MorphyHandlsSEXP); - Rcpp::traits::input_parameter< NumericVector >::type weight(weightSEXP); - Rcpp::traits::input_parameter< IntegerVector >::type minScore(minScoreSEXP); - Rcpp::traits::input_parameter< IntegerVector >::type sequence(sequenceSEXP); - Rcpp::traits::input_parameter< NumericVector >::type concavity(concavitySEXP); - Rcpp::traits::input_parameter< NumericVector >::type target(targetSEXP); - rcpp_result_gen = Rcpp::wrap(morphy_iw(edge, MorphyHandls, weight, minScore, sequence, concavity, target)); - return rcpp_result_gen; -END_RCPP -} -// morphy_profile -double morphy_profile(IntegerMatrix edge, List MorphyHandls, NumericVector weight, IntegerVector sequence, NumericMatrix profiles, NumericVector target); -RcppExport SEXP _TreeSearch_morphy_profile(SEXP edgeSEXP, SEXP MorphyHandlsSEXP, SEXP weightSEXP, SEXP sequenceSEXP, SEXP profilesSEXP, SEXP targetSEXP) { -BEGIN_RCPP - Rcpp::RObject rcpp_result_gen; - Rcpp::RNGScope rcpp_rngScope_gen; - Rcpp::traits::input_parameter< IntegerMatrix >::type edge(edgeSEXP); - Rcpp::traits::input_parameter< List >::type MorphyHandls(MorphyHandlsSEXP); - Rcpp::traits::input_parameter< NumericVector >::type weight(weightSEXP); - Rcpp::traits::input_parameter< IntegerVector >::type sequence(sequenceSEXP); - Rcpp::traits::input_parameter< NumericMatrix >::type profiles(profilesSEXP); - Rcpp::traits::input_parameter< NumericVector >::type target(targetSEXP); - rcpp_result_gen = Rcpp::wrap(morphy_profile(edge, MorphyHandls, weight, sequence, profiles, target)); - return rcpp_result_gen; -END_RCPP -} // quartet_concordance List quartet_concordance(const LogicalMatrix splits, const IntegerMatrix characters); RcppExport SEXP _TreeSearch_quartet_concordance(SEXP splitsSEXP, SEXP charactersSEXP) { diff --git a/src/TreeSearch-init.c b/src/TreeSearch-init.c index f92ad2c68..cb3e60c44 100644 --- a/src/TreeSearch-init.c +++ b/src/TreeSearch-init.c @@ -6,9 +6,6 @@ #include /* for NULL */ #include -#include "mpl.h" -#include "RMorphyUtils.h" -#include "RMorphy.h" #include "build_postorder.h" extern SEXP _TreeSearch_nni(SEXP, SEXP, SEXP); @@ -18,10 +15,6 @@ extern SEXP _TreeSearch_tbr(SEXP, SEXP); // extern SEXP _TreeSearch_tbr_moves(SEXP); extern SEXP _TreeSearch_all_spr(SEXP, SEXP); extern SEXP _TreeSearch_all_tbr(SEXP, SEXP); -extern SEXP _TreeSearch_preorder_morphy(SEXP, SEXP); -extern SEXP _TreeSearch_preorder_morphy_by_char(SEXP, SEXP); -extern SEXP _TreeSearch_morphy_iw(SEXP, SEXP, SEXP, SEXP, SEXP, SEXP, SEXP); -extern SEXP _TreeSearch_morphy_profile(SEXP, SEXP, SEXP, SEXP, SEXP, SEXP); extern SEXP _TreeSearch_expected_mi(SEXP, SEXP); extern SEXP _TreeSearch_mi_key(SEXP, SEXP); @@ -67,28 +60,6 @@ extern SEXP _TreeSearch_ts_ls_fit(SEXP, SEXP, SEXP, SEXP); extern SEXP _TreeSearch_ts_ls_search(SEXP, SEXP, SEXP, SEXP, SEXP, SEXP); static const R_CallMethodDef callMethods[] = { - {"_R_wrap_mpl_new_Morphy", (DL_FUNC) &_R_wrap_mpl_new_Morphy, 0}, - {"_R_wrap_mpl_delete_Morphy", (DL_FUNC) &_R_wrap_mpl_delete_Morphy, 1}, - {"_R_wrap_mpl_init_Morphy", (DL_FUNC) &_R_wrap_mpl_init_Morphy, 3}, - {"_R_wrap_mpl_get_numtaxa", (DL_FUNC) &_R_wrap_mpl_get_numtaxa, 1}, - {"_R_wrap_mpl_get_num_charac", (DL_FUNC) &_R_wrap_mpl_get_num_charac, 1}, - {"_R_wrap_mpl_attach_symbols", (DL_FUNC) &_R_wrap_mpl_attach_symbols, 2}, - {"_R_wrap_mpl_get_symbols", (DL_FUNC) &_R_wrap_mpl_get_symbols, 1}, - {"_R_wrap_mpl_attach_rawdata", (DL_FUNC) &_R_wrap_mpl_attach_rawdata, 2}, - {"_R_wrap_mpl_set_parsim_t", (DL_FUNC) &_R_wrap_mpl_set_parsim_t, 3}, - {"_R_wrap_mpl_get_gaphandl", (DL_FUNC) &_R_wrap_mpl_get_gaphandl, 1}, - {"_R_wrap_mpl_set_gaphandl", (DL_FUNC) &_R_wrap_mpl_set_gaphandl, 2}, - {"_R_wrap_mpl_set_num_internal_nodes", (DL_FUNC) &_R_wrap_mpl_set_num_internal_nodes, 2}, - {"_R_wrap_mpl_get_num_internal_nodes", (DL_FUNC) &_R_wrap_mpl_get_num_internal_nodes, 1}, - {"_R_wrap_mpl_apply_tipdata", (DL_FUNC) &_R_wrap_mpl_apply_tipdata, 1}, - {"_R_wrap_mpl_set_charac_weight", (DL_FUNC) &_R_wrap_mpl_set_charac_weight, 3}, - {"_R_wrap_mpl_get_charac_weight", (DL_FUNC) &_R_wrap_mpl_get_charac_weight, 2}, - {"_R_wrap_mpl_first_down_recon", (DL_FUNC) &_R_wrap_mpl_first_down_recon, 4}, - {"_R_wrap_mpl_first_up_recon", (DL_FUNC) &_R_wrap_mpl_first_up_recon, 5}, - {"_R_wrap_mpl_second_down_recon", (DL_FUNC) &_R_wrap_mpl_second_down_recon, 4}, - {"_R_wrap_mpl_second_up_recon", (DL_FUNC) &_R_wrap_mpl_second_up_recon, 5}, - {"_R_wrap_mpl_update_tip", (DL_FUNC) &_R_wrap_mpl_update_tip, 3}, - {"_R_wrap_mpl_update_lower_root", (DL_FUNC) &_R_wrap_mpl_update_lower_root, 3}, {"_TreeSearch_nni", (DL_FUNC) &_TreeSearch_nni, 3}, {"_TreeSearch_spr", (DL_FUNC) &_TreeSearch_spr, 2}, {"_TreeSearch_all_spr", (DL_FUNC) &_TreeSearch_all_spr, 2}, @@ -96,11 +67,6 @@ static const R_CallMethodDef callMethods[] = { {"_TreeSearch_tbr", (DL_FUNC) &_TreeSearch_tbr, 2}, {"_TreeSearch_all_tbr", (DL_FUNC) &_TreeSearch_all_tbr, 2}, // {"_TreeSearch_tbr_moves", (DL_FUNC) &_TreeSearch_tbr_moves, 1}, - {"_TreeSearch_preorder_morphy", (DL_FUNC) &_TreeSearch_preorder_morphy, 2}, - {"_TreeSearch_preorder_morphy_by_char", (DL_FUNC) &_TreeSearch_preorder_morphy_by_char, 2}, - - {"_TreeSearch_morphy_iw", (DL_FUNC) &_TreeSearch_morphy_iw, 7}, - {"_TreeSearch_morphy_profile", (DL_FUNC) &_TreeSearch_morphy_profile, 6}, {"_TreeSearch_expected_mi", (DL_FUNC) &_TreeSearch_expected_mi, 2}, {"_TreeSearch_mi_key", (DL_FUNC) &_TreeSearch_mi_key, 2}, @@ -140,9 +106,7 @@ static const R_CallMethodDef callMethods[] = { /* ts_stochastic_tbr (9) and ts_parallel_temper (10) removed */ {"_TreeSearch_mc_fitch_scores", (DL_FUNC) &_TreeSearch_mc_fitch_scores, 2}, - {"MORPHYLENGTH", (DL_FUNC) &MORPHYLENGTH, 4}, {"RANDOM_TREE", (DL_FUNC) &RANDOM_TREE, 1}, - {"RANDOM_TREE_SCORE", (DL_FUNC) &RANDOM_TREE_SCORE, 2}, {"_TreeSearch_ts_test_strategy_tracker", (DL_FUNC) &_TreeSearch_ts_test_strategy_tracker, 2}, {"_TreeSearch_ts_tbr_diagnostics", (DL_FUNC) &_TreeSearch_ts_tbr_diagnostics, 11}, {"_TreeSearch_ts_ls_fit", (DL_FUNC) &_TreeSearch_ts_ls_fit, 4}, diff --git a/src/build_postorder.h b/src/build_postorder.h index d36ced70a..a2b1028f6 100644 --- a/src/build_postorder.h +++ b/src/build_postorder.h @@ -1,5 +1,6 @@ #include -#include "RMorphy.h" +#include +#include /* Random number generator from http://www.cse.yorku.ca/~oz/marsaglia-rng.html / 1+random_int%10 generates an integer from 1 to 10 [MWC renamed to random_int] @@ -151,34 +152,3 @@ extern SEXP RANDOM_TREE(SEXP ntip) { UNPROTECT(4); return(RESULT); } - -extern SEXP RANDOM_TREE_SCORE(SEXP ntip, SEXP MorphyHandl) { - const int n_tip = INTEGER(ntip)[0]; - if (n_tip < 2) { - (Rf_error)("n_tip must be at least two"); - } - Morphy handl = R_ExternalPtrAddr(MorphyHandl); - SEXP RESULT = PROTECT(allocVector(INTSXP, 1)); - int *score, - *parent_of = calloc(n_tip + n_tip - 1 , sizeof(int)), - *left = calloc(n_tip - 1 , sizeof(int)), - *right = calloc(n_tip - 1 , sizeof(int)); - - score = INTEGER(RESULT); - *score = 0; - if (n_tip < 2) { - INTEGER(RESULT)[0] = 0; - UNPROTECT(1); - return(RESULT); - } - - - random_tree(parent_of, left, right, &n_tip); - morphy_length(parent_of, left, right, handl, score); - - free(parent_of); - free(left); - free(right); - UNPROTECT(1); - return(RESULT); -} diff --git a/src/fitch.c b/src/fitch.c deleted file mode 100644 index 1e3d4bedf..000000000 --- a/src/fitch.c +++ /dev/null @@ -1,1052 +0,0 @@ -/* -// fitch.c -// MorPhy2 -// -// Created by mbrazeau on 02/05/2017. -// Copyright © 2017 brazeaulab. All rights reserved. -*/ -#include "mpl.h" -#include "morphydefs.h" -#include "morphy.h" -#include "mplerror.h" -#include "fitch.h" -#include "statedata.h" - -int mpl_fitch_downpass - (MPLndsets* lset, MPLndsets* rset, MPLndsets* nset, MPLpartition* part) -{ - int i = 0; - int j = 0; - int steps = 0; - const int* indices = part->charindices; - int nchars = part->ncharsinpart; - MPLstate* left = lset->downpass1; - MPLstate* right = rset->downpass1; - MPLstate* n = nset->downpass1; - - unsigned long* weights = part->intwts; - - for (i = 0; i < nchars; ++i) { - j = indices[i]; - - n[j] = left[j] & right[j]; - - if (n[j] == 0) { - n[j] = left[j] | right[j]; - steps += weights[i]; - } - } - - return steps; -} - - -int mpl_fitch_uppass - (MPLndsets* lset, MPLndsets* rset, MPLndsets* nset, MPLndsets* ancset, - MPLpartition* part) -{ - int i = 0; - int j = 0; - const int* indices = part->charindices; - int nchars = part->ncharsinpart; - MPLstate* left = lset->downpass1; - MPLstate* right = rset->downpass1; - MPLstate* npre = nset->downpass1; - MPLstate* nfin = nset->uppass1; - MPLstate* anc = ancset->uppass1; - - for (i = 0; i < nchars; ++i) { - - j = indices[i]; - - nfin[j] = anc[j] & npre[j]; - - if (nfin[j] != anc[j]) { - - if (left[j] & right[j]) { - nfin[j] = (npre[j] | (anc[j] & (left[j] | right[j]))); - } - else { - nfin[j] = npre[j] | anc[j]; - } - } - } - - return 0; -} - - -int mpl_fitch_local_reopt - (MPLndsets* srcset, MPLndsets* tgt1set, MPLndsets* tgt2set, MPLpartition* part, - int maxlen, bool domaxlen) -{ - - int i = 0; - int j = 0; - int steps = 0; - const int* indices = part->charindices; - int nchars = part->ncharsinpart; - MPLstate* tgt1 = tgt1set->uppass1; - MPLstate* tgt2 = tgt2set->uppass1; - MPLstate* src = srcset->downpass1; - - unsigned long* weights = part->intwts; - - for (i = 0; i < nchars; ++i) { - - j = indices[i]; - - if (!(src[j] & (tgt1[j] | tgt2[j]))) { - - steps += weights[i]; - - if (steps > maxlen && domaxlen == true) - { - return steps; - } - } - } - - return steps; -} - - -int mpl_NA_fitch_first_downpass - (MPLndsets* lset, MPLndsets* rset, MPLndsets* nset, MPLpartition* part) -{ - int i = 0; - int j = 0; - const int* indices = part->charindices; - int nchars = part->ncharsinpart; - MPLstate* left = lset->downpass1; - MPLstate* right = rset->downpass1; - MPLstate* n = nset->downpass1; - MPLstate* nt = nset->temp_downpass1; - - for (i = 0; i < nchars; ++i) { - - j = indices[i]; - - nset->changes[j] = false; - - n[j] = (left[j] & right[j]); - - if (n[j] == 0) { - n[j] = (left[j] | right[j]); - - if ((left[j] & ISAPPLIC) && (right[j] & ISAPPLIC)) { - n[j] = n[j] & ISAPPLIC; - } - } - else { - if (n[j] == NA) { - if ((left[j] & ISAPPLIC) && (right[j] & ISAPPLIC)) { - n[j] = (left[j] | right[j]); - } - } - } - - nt[j] = n[j]; - } - - return 0; -} - -int mpl_nadown1_simpl - (MPLndsets* lset, MPLndsets* rset, MPLndsets* nset, MPLpartition* part) -{ - int i = 0; - int j = 0; - const int* indices = part->charindices; - int nchars = part->ncharsinpart; - MPLstate* left = lset->downpass1; - MPLstate* right = rset->downpass1; - MPLstate* n = nset->downpass1; - MPLstate* nt = nset->temp_downpass1; - - for (i = 0; i < nchars; ++i) { - - j = indices[i]; - - if (left[j] & ISAPPLIC && right[j] & ISAPPLIC) { - n[j] = (left[j] | right[j]) & ISAPPLIC; - } - else { - n[j] = (left[j] & right[j]); - if (n[j] != NA) { - n[j] = (left[j] | right[j]); - } - } - - nt[j] = n[j]; - } - - return 0; -} - - -int mpl_nadown2_simpl - (MPLndsets* lset, MPLndsets* rset, MPLndsets* nset, MPLpartition* part) -{ - int i = 0; - int j = 0; - int steps = 0; - const int* indices = part->charindices; - int nchars = part->ncharsinpart; - MPLstate* left = lset->downpass2; - MPLstate* right = rset->downpass2; - MPLstate* setstat = nset->uppass1; - MPLstate* npre = nset->downpass2; - MPLstate temp = 0; - unsigned long* weights = part->intwts; - - for (i = 0; i < nchars; ++i) { - - j = indices[i]; - - - if (setstat[j] != NA) { - if ((temp = (left[j] & right[j]) & ISAPPLIC)) { - npre[j] = temp; - } - else { - npre[j] = (left[j] | right[j]); - if (left[j] & ISAPPLIC && right[j] & ISAPPLIC) { - if (!(npre[j] & NA)) { - steps += weights[j]; - } - } - } - } - else { - npre[j] = NA; - } - -#ifdef DEBUG - assert(npre[j]); -#endif - } - - return 0; -} - - -int mpl_NA_fitch_first_update_downpass - (MPLndsets* lset, MPLndsets* rset, MPLndsets* nset, MPLpartition* part) -{ - /*------------------------------------------------------------------------* - | This function is for doing a partial downpass when proposing a | - | subtree reinsertion during branchswapping. Its purpose is to | - | (partially) correct any character state sets that are affected by | - | the proposed reinsertion. It is nearly identical to its original- | - | pass counterpart except that it does not overwrite the temp state | - | storage. | - *------------------------------------------------------------------------*/ - int i = 0; - int j = 0; - const int* indices = part->update_NA_indices; - int nchars = part->nNAtoupdate; - MPLstate* left = lset->downpass1; - MPLstate* right = rset->downpass1; - MPLstate* n = nset->downpass1; - MPLstate* ntemp = nset->temp_downpass1; - - for (i = 0; i < nchars; ++i) { - - j = indices[i]; - - n[j] = (left[j] & right[j]); - - if (n[j] == 0) { - n[j] = (left[j] | right[j]); - - if ((left[j] & ISAPPLIC) && (right[j] & ISAPPLIC)) { - n[j] = n[j] & ISAPPLIC; - } - } - else { - if (n[j] == NA) { - if ((left[j] & ISAPPLIC) && (right[j] & ISAPPLIC)) { - n[j] = (left[j] | right[j]); - } - } - } - - if (n[j] != ntemp[j]) { - nset->updated = true; - } - - } - - return 0; -} - - -int mpl_NA_fitch_first_uppass - (MPLndsets* lset, MPLndsets* rset, MPLndsets* nset, MPLndsets* ancset, - MPLpartition* part) -{ - int i = 0; - int j = 0; - const int* indices = part->charindices; - int nchars = part->ncharsinpart; - MPLstate* left = lset->downpass1; - MPLstate* right = rset->downpass1; - MPLstate* npre = nset->downpass1; - MPLstate* nifin = nset->uppass1; - MPLstate* anc = ancset->uppass1; - MPLstate* nfint = nset->temp_uppass1; - - for (i = 0; i < nchars; ++i) { - - j = indices[i]; - - if (npre[j] & NA) { - if (npre[j] & ISAPPLIC) { - if (anc[j] == NA) { - nifin[j] = NA; - } - else { - nifin[j] = npre[j] & ISAPPLIC; - } - } - else { - if (anc[j] == NA) { - nifin[j] = NA; - } - else { - if ((left[j] | right[j]) & ISAPPLIC) { - nifin[j] = ((left[j] | right[j]) & ISAPPLIC); - } - else { - nifin[j] = NA; - } - } - } - } - else { - nifin[j] = npre[j]; - } - - nfint[j] = nifin[j]; - -#ifdef DEBUG - assert(nifin[j]); -#endif - } - - return 0; -} - -int mpl_naupp1_simpl - (MPLndsets* lset, MPLndsets* rset, MPLndsets* nset, MPLndsets* ancset, - MPLpartition* part) -{ - int i = 0; - int j = 0; - const int* indices = part->charindices; - int nchars = part->ncharsinpart; - MPLstate* npre = nset->downpass1; - MPLstate* nifin = nset->uppass1; - MPLstate* anc = ancset->uppass1; - MPLstate* nfint = nset->temp_uppass1; - - for (i = 0; i < nchars; ++i) { - - j = indices[i]; - - if (anc[j] == NA && npre[j] & NA) { - nifin[j] = NA; - } - else { - nifin[j] = nifin[j] & ISAPPLIC; - } - nfint[j] = nifin[j]; - } - - return 0; -} - - -int mpl_NA_fitch_first_update_uppass - (MPLndsets* lset, MPLndsets* rset, MPLndsets* nset, MPLndsets* ancset, - MPLpartition* part) -{ - /*------------------------------------------------------------------------* - | This function is for doing a partial uppsass when proposing a subtree | - | reinsertion during branchswapping. Its purpose is to (partially) | - | correct any character state sets that are affected by the proposed | - | reinsertion. | - *------------------------------------------------------------------------*/ - int i = 0; - int j = 0; - const int* indices = part->update_NA_indices; - int nchars = part->nNAtoupdate; - MPLstate* left = lset->downpass1; - MPLstate* right = rset->downpass1; - MPLstate* npre = nset->downpass1; - MPLstate* nifin = nset->uppass1; - MPLstate* anc = ancset->uppass1; - - for (i = 0; i < nchars; ++i) { - - j = indices[i]; - - if (npre[j] & NA) { - if (npre[j] & ISAPPLIC) { - if (anc[j] == NA) { - nifin[j] = NA; - } - else { - nifin[j] = npre[j] & ISAPPLIC; - } - } - else { - if (anc[j] == NA) { - nifin[j] = NA; - } - else { - if ((left[j] | right[j]) & ISAPPLIC) { - nifin[j] = ((left[j] | right[j]) & ISAPPLIC); - } - else { - nifin[j] = NA; - } - } - } - } - else { - nifin[j] = npre[j]; - } - -#ifdef DEBUG - assert(nifin[j]); -#endif - } - - return 0; -} - - -int mpl_NA_fitch_second_downpass - (MPLndsets* lset, MPLndsets* rset, MPLndsets* nset, MPLpartition* part) -{ - int i = 0; - int j = 0; - int steps = 0; - const int* indices = part->charindices; - int nchars = part->ncharsinpart; - MPLstate* left = lset->downpass2; - MPLstate* right = rset->downpass2; - MPLstate* nifin = nset->uppass1; - MPLstate* npre = nset->downpass2; - MPLstate* npret = nset->temp_downpass2; - MPLstate* stacts = nset->subtree_actives; - MPLstate* tstatcs = nset->temp_subtr_actives; - MPLstate* lacts = lset->subtree_actives; - MPLstate* racts = rset->subtree_actives; - MPLstate temp = 0; - unsigned long* weights = part->intwts; - - for (i = 0; i < nchars; ++i) { - - j = indices[i]; - - nset->changes[j] = false; - - if (nifin[j] & ISAPPLIC) { - if ((temp = (left[j] & right[j]))) { - if (temp & ISAPPLIC) { - npre[j] = temp & ISAPPLIC; - } else { - npre[j] = temp; - } - } - else { - npre[j] = (left[j] | right[j]) & ISAPPLIC; - - if (left[j] & ISAPPLIC && right[j] & ISAPPLIC) { - steps += weights[i]; - nset->changes[j] = true; - } else if (lacts[j] && racts[j]) { - steps += weights[i]; - nset->changes[j] = true; - } - } - } - else { - npre[j] = nifin[j]; - - if (lacts[j] && racts[j]) { - steps += weights[i]; - nset->changes[j] = true; - } - } - - /* Store the states active on this subtree */ - stacts[j] = (lacts[j] | racts[j]) & ISAPPLIC; - - npret[j] = npre[j]; - tstatcs[j] = stacts[j]; - - } - - return steps; -} - - -int mpl_NA_fitch_second_update_downpass - (MPLndsets* lset, MPLndsets* rset, MPLndsets* nset, MPLpartition* part) -{ - /*------------------------------------------------------------------------* - | This function is for doing a partial downpass when proposing a | - | subtree reinsertion during branchswapping. Its purpose is to | - | (partially) correct any character state sets that are affected by | - | the proposed reinsertion. It is nearly identical to its original- | - | pass counterpart except that it does not overwrite the temp state | - | storage. | - *------------------------------------------------------------------------*/ - int i = 0; - int j = 0; - int steps = 0; - const int* indices = part->update_NA_indices; - int nchars = part->nNAtoupdate; - MPLstate* left = lset->downpass2; - MPLstate* right = rset->downpass2; - MPLstate* nifin = nset->uppass1; - MPLstate* npre = nset->downpass2; - const MPLstate* npret = nset->temp_downpass2; - MPLstate* stacts = nset->subtree_actives; - MPLstate* lacts = lset->subtree_actives; - MPLstate* racts = rset->subtree_actives; - MPLstate temp = 0; - unsigned long* weights = part->intwts; - - for (i = 0; i < nchars; ++i) { - - j = indices[i]; - - if (nifin[j] & ISAPPLIC) { - if ((temp = (left[j] & right[j]))) { - if (temp & ISAPPLIC) { - npre[j] = temp & ISAPPLIC; - } else { - npre[j] = temp; - } - } - else { - npre[j] = (left[j] | right[j]) & ISAPPLIC; - - if (left[j] & ISAPPLIC && right[j] & ISAPPLIC) { - steps += weights[i]; - } else if (lacts[j] && racts[j]) { - steps += weights[i]; - } - } - } - else { - npre[j] = nifin[j]; - } - - stacts[j] = (lacts[j] | racts[j]) & ISAPPLIC; - - /* Flag as updated if current set is different from previous */ - if (npre[j] != npret[j]) { - nset->updated = true; - } - -#ifdef DEBUG - assert(npre[j]); -#endif - } - - return steps; -} - - -int mpl_NA_fitch_second_uppass - (MPLndsets* lset, MPLndsets* rset, MPLndsets* nset, MPLndsets* ancset, - MPLpartition* part) -{ - int i = 0; - int j = 0; - int steps = 0; - const int* indices = part->charindices; - int nchars = part->ncharsinpart; - MPLstate* left = lset->downpass2; - MPLstate* right = rset->downpass2; - MPLstate* npre = nset->downpass2; - MPLstate* nfin = nset->uppass2; - MPLstate* nfint = nset->temp_uppass2; - MPLstate* anc = ancset->uppass2; - - for (i = 0; i < nchars; ++i) { - - j = indices[i]; - - if (npre[j] & ISAPPLIC) { - if (anc[j] & ISAPPLIC) { - if ((anc[j] & npre[j]) == anc[j]) { - nfin[j] = anc[j] & npre[j]; - } else { - if (left[j] & right[j]) { - nfin[j] = (npre[j] | (anc[j] & (left[j] | right[j]))); - } - else { - if ((left[j] | right[j]) & NA) { - if ((left[j] | right[j]) & anc[j]) { - nfin[j] = anc[j]; - } else { - nfin[j] = (left[j] | right[j] | anc[j]) & ISAPPLIC; - } - } else { - nfin[j] = npre[j] | anc[j]; - } - } - } - } - else { - nfin[j] = npre[j]; - } - } - else { - nfin[j] = npre[j]; - } - - nfint[j] = nfin[j]; -#ifdef DEBUG - assert(nfin[j]); -#endif -} - - return steps; -} - - -int mpl_NA_fitch_second_update_uppass - (MPLndsets* lset, MPLndsets* rset, MPLndsets* nset, MPLndsets* ancset, - MPLpartition* part) -{ - /*------------------------------------------------------------------------* - | This function is for doing a partial uppsass when proposing a subtree | - | reinsertion during branchswapping. Its purpose is to (partially) | - | correct any character state sets that are affected by the proposed | - | reinsertion. | - *------------------------------------------------------------------------*/ - int i = 0; - int j = 0; - int steps = 0; - int step_recall = 0; - const int* indices = part->update_NA_indices; - int nchars = part->nNAtoupdate; - MPLstate* left = lset->downpass2; - MPLstate* right = rset->downpass2; - MPLstate* npre = nset->downpass2; - MPLstate* nfin = nset->uppass2; - MPLstate* nfint = nset->temp_uppass2; - MPLstate* anc = ancset->uppass2; - MPLstate* lacts = lset->subtree_actives; - MPLstate* racts = rset->subtree_actives; - unsigned long* weights = part->intwts; - - for (i = 0; i < nchars; ++i) { - - j = indices[i]; - - if (npre[j] & ISAPPLIC) { - if (anc[j] & ISAPPLIC) { - if ((anc[j] & npre[j]) == anc[j]) { - nfin[j] = anc[j] & npre[j]; - } else { - if (left[j] & right[j]) { - nfin[j] = (npre[j] | (anc[j] & (left[j] | right[j]))); - } - else { - if ((left[j] | right[j]) & NA) { - if ((left[j] | right[j]) & anc[j]) { - nfin[j] = anc[j]; - } else { - nfin[j] = (left[j] | right[j] | anc[j]) & ISAPPLIC; - } - } else { - nfin[j] = npre[j] | anc[j]; - } - } - } - } - else { - nfin[j] = npre[j]; - } - } - else { - nfin[j] = npre[j]; - - if (lacts[j] && racts[j]) { - steps += weights[i]; - } - } - - if (nfint[j] != nfin[j]) { - nset->updated = true; - } - - if (nset->changes[j] == true) { - step_recall += weights[i]; - } - - -#ifdef DEBUG - assert(nfin[j]); -#endif - } - - nset->steps_to_recall += step_recall; - - return steps; -} - - -int mpl_fitch_NA_local_reopt - (MPLndsets* srcset, MPLndsets* tgt1set, MPLndsets* tgt2set, MPLpartition* part, - int maxlen, bool domaxlen) -{ - - part->ntoupdate = 0; - - int i = 0; - int j = 0; - int need_update = 0; - int steps = 0; - const int* indices = part->charindices; - int nchars = part->ncharsinpart; - for (i = 0; i < nchars; ++i) { - - j = indices[i]; - - part->update_NA_indices[need_update] = j; - ++need_update; - - } - - part->nNAtoupdate = need_update; - - return steps; -} - - -int mpl_fitch_tip_update(MPLndsets* tset, MPLndsets* ancset, MPLpartition* part) -{ - int i = 0; - int j = 0; - int* indices = part->charindices; - int nchars = part->ncharsinpart; - - MPLstate* tprelim = tset->downpass1; - MPLstate* tfinal = tset->uppass1; - MPLstate* ttfinal = tset->temp_uppass1; - MPLstate* astates = ancset->uppass1; - - for (i = 0; i < nchars; ++i) { - j = indices[i]; - if (tprelim[j] & astates[j]) { - tfinal[j] = tprelim[j] & astates[j]; - } - else { - tfinal[j] = tprelim[j]; - } - ttfinal[j] = tfinal[j]; - } - return 0; -} - -int mpl_fitch_one_branch - (MPLndsets* tipanc, MPLndsets* node, MPLpartition* part) -{ - int i = 0; - int j = 0; - int* indices = part->charindices; - int nchars = part->ncharsinpart; - MPLstate* tipset = tipanc->downpass1; - MPLstate* tipfin = tipanc->uppass1; - MPLstate* ndset = node->downpass1; - MPLstate temp = 0; - unsigned long* weights = part->intwts; - int length = 0; - - for (i = 0; i < nchars; ++i) { - j = indices[i]; - - temp = tipset[j] & ndset[j]; - - if (temp == 0) { - tipfin[j] = tipset[j]; - length += weights[i]; - node->uppass1[j] = ndset[j]; - } - else { - tipfin[j] = temp; - node->uppass1[j] = temp; - } - } - - return length; -} - - -int mpl_fitch_NA_first_one_branch - (MPLndsets* tipanc, MPLndsets* node, MPLpartition* part) -{ - int i = 0; - int j = 0; - int* indices = part->charindices; - int nchars = part->ncharsinpart; - MPLstate* tipset = tipanc->downpass1; - MPLstate* tipifin = tipanc->uppass1; - MPLstate* ndset = node->downpass1; - MPLstate temp = 0; - - for (i = 0; i < nchars; ++i) { - - j = indices[i]; - - tipanc->changes[j] = false; - temp = tipset[j] & ndset[j]; - - if (temp != 0) { - tipifin[j] = temp; - node->uppass1[j] = temp; - } - } - - return 0; -} - -int mpl_fitch_NA_second_one_branch - (MPLndsets* tipanc, MPLndsets* node, MPLpartition* part) -{ - int i = 0; - int j = 0; - int* indices = part->charindices; - int nchars = part->ncharsinpart; - MPLstate* tipset = tipanc->downpass1; - MPLstate* tipifin = tipanc->uppass1; - MPLstate* ndset = node->downpass2; - MPLstate* ndacts = node->subtree_actives; - MPLstate temp = 0; - unsigned long* weights = part->intwts; - int length = 0; - - for (i = 0; i < nchars; ++i) { - - j = indices[i]; - - temp = tipset[j] & ndset[j]; - - if (temp == 0) { - if (tipset[j] & ISAPPLIC) { - if (ndset[j] & ISAPPLIC) { - length += weights[i]; - tipanc->changes[j] = true; - } - else { - if (ndacts[j]) { - length += weights[i]; - tipanc->changes[j] = true; - } - } - } - - tipifin[j] = tipset[j]; - } - else { - tipifin[j] = temp; - } - - tipanc->temp_downpass1[j] = tipanc->downpass1[j]; - tipanc->temp_uppass1[j] = tipanc->uppass1[j]; - tipanc->temp_downpass2[j] = tipanc->downpass2[j]; - tipanc->temp_uppass2[j] = tipanc->uppass2[j]; - } - - return length; -} - -int mpl_fitch_NA_second_one_branch_recalc - (MPLndsets* tipanc, MPLndsets* node, MPLpartition* part) -{ - int i = 0; - int j = 0; - int* indices = part->charindices; - int nchars = part->ncharsinpart; - MPLstate* tipset = tipanc->downpass1; - MPLstate* tipifin = tipanc->uppass1; - MPLstate* ndset = node->downpass2; - MPLstate* ndacts = node->subtree_actives; - MPLstate temp = 0; - unsigned long* weights = part->intwts; - unsigned long step_recall = 0; - int length = 0; - - for (i = 0; i < nchars; ++i) { - - j = indices[i]; - - temp = tipset[j] & ndset[j]; - - if (temp == 0) { - if (tipset[j] & ISAPPLIC) { - if (ndset[j] & ISAPPLIC) { - length += weights[i]; - } - else { - if (ndacts[j]) { - length += weights[i]; - } - } - } - - tipifin[j] = tipset[j]; - } - else { - tipifin[j] = temp; - } - - if (tipanc->changes[j] == true) { - step_recall += weights[i]; - } - } - - tipanc->steps_to_recall += step_recall; - - return length; -} - - -int mpl_fitch_NA_tip_update - (MPLndsets* tset, MPLndsets* ancset, MPLpartition* part) -{ - int i = 0; - int j = 0; - int* indices = part->charindices; - int nchars = part->ncharsinpart; - - MPLstate* tpass1 = tset->downpass1; - MPLstate* tpass2 = tset->uppass1; - MPLstate* tpass3 = tset->downpass2; - MPLstate* ttpass1 = tset->temp_downpass1; - MPLstate* ttpass2 = tset->temp_uppass1; - MPLstate* ttpass3 = tset->temp_downpass2; - MPLstate* astates = ancset->uppass1; - MPLstate* stacts = tset->subtree_actives; - MPLstate* tstatcs = tset->temp_subtr_actives; - - for (i = 0; i < nchars; ++i) { - - j = indices[i]; - - if (tpass1[j] & astates[j]) { - stacts[j] = (tpass1[j] & astates[j] & ISAPPLIC); - } - else { - stacts[j] |= tpass1[j] & ISAPPLIC; - } - - tpass2[j] = tpass1[j]; - - if (tpass2[j] & astates[j]) { - if (astates[j] & ISAPPLIC) { - tpass2[j] &= ISAPPLIC; - } - } - - tpass3[j] = tpass2[j]; - - ttpass1[j] = tpass1[j]; - ttpass2[j] = tpass2[j]; - ttpass3[j] = tpass3[j]; - tstatcs[j] = stacts[j]; -#ifdef DEBUG - assert(tpass3[j]); - assert(tpass2[j]); -#endif - } - - return 0; -} - - -int mpl_fitch_NA_tip_recalc_update - (MPLndsets* tset, MPLndsets* ancset, MPLpartition* part) -{ - int i = 0; - int j = 0; - int* indices = part->charindices; - int nchars = part->ncharsinpart; - - MPLstate* tpass1 = tset->downpass1; - MPLstate* tpass2 = tset->uppass1; - MPLstate* tpass3 = tset->downpass2; - MPLstate* astates = ancset->uppass1; - MPLstate* stacts = tset->subtree_actives; - - for (i = 0; i < nchars; ++i) { - - j = indices[i]; - - if (tpass1[j] & astates[j]) { - stacts[j] = (tpass1[j] & astates[j] & ISAPPLIC); - } - else { - stacts[j] |= tpass1[j] & ISAPPLIC; - } - - tpass2[j] = tpass1[j]; - - if (tpass2[j] & astates[j]) { - if (astates[j] & ISAPPLIC) { - tpass2[j] &= ISAPPLIC; - } - } - - tpass3[j] = tpass2[j]; - -#ifdef DEBUG - assert(tpass3[j]); - assert(tpass2[j]); -#endif - } - - return 0; -} - - -int mpl_fitch_NA_tip_finalize - (MPLndsets* tset, MPLndsets* ancset, MPLpartition* part) -{ - int i = 0; - int j = 0; - int* indices = part->charindices; - int nchars = part->ncharsinpart; - MPLstate* tpass1 = tset->downpass1; - MPLstate* tfinal = tset->uppass2; - MPLstate* ttfinal = tset->temp_uppass2; - MPLstate* astates = ancset->uppass2; - MPLstate* stacts = tset->subtree_actives; - MPLstate* tstacts = tset->temp_subtr_actives; - - for (i = 0; i < nchars; ++i) { - - j = indices[i]; - - if (tpass1[j] & astates[j]) { - tfinal[j] = tpass1[j] & astates[j]; - } - else { - tfinal[j] = tpass1[j]; - } - ttfinal[j] = tfinal[j]; - tstacts[j] = stacts[j]; - } - - return 0; -} diff --git a/src/fitch.h b/src/fitch.h deleted file mode 100644 index 87d1dbc47..000000000 --- a/src/fitch.h +++ /dev/null @@ -1,51 +0,0 @@ -/* -// fitch.h -// MorPhy2 -// -// Created by mbrazeau on 02/05/2017. -// Copyright © 2017 brazeaulab. All rights reserved. -*/ - -#ifndef fitch_h -#define fitch_h - -int mpl_fitch_downpass(MPLndsets* lset, MPLndsets* rset, MPLndsets* nset, MPLpartition* part); - -int mpl_fitch_uppass(MPLndsets* lset, MPLndsets* rset, MPLndsets* nset, MPLndsets* ancset, MPLpartition* part); - -int mpl_fitch_local_reopt(MPLndsets* srcset, MPLndsets* tgt1set, MPLndsets* tgt2set, MPLpartition* part, int maxlen, bool domaxlen); - -int mpl_NA_fitch_first_downpass(MPLndsets* lset, MPLndsets* rset, MPLndsets* nset, MPLpartition* part); - -int mpl_NA_fitch_first_update_downpass(MPLndsets* lset, MPLndsets* rset, MPLndsets* nset, MPLpartition* part); - -int mpl_NA_fitch_first_uppass(MPLndsets* lset, MPLndsets* rset, MPLndsets* nset, MPLndsets* ancset, MPLpartition* part); - -int mpl_NA_fitch_first_update_uppass(MPLndsets* lset, MPLndsets* rset, MPLndsets* nset, MPLndsets* ancset, MPLpartition* part); - -int mpl_NA_fitch_second_downpass(MPLndsets* lset, MPLndsets* rset, MPLndsets* nset, MPLpartition* part); - -int mpl_NA_fitch_second_update_downpass(MPLndsets* lset, MPLndsets* rset, MPLndsets* nset, MPLpartition* part); - -int mpl_NA_fitch_second_uppass(MPLndsets* lset, MPLndsets* rset, MPLndsets* nset, MPLndsets* ancset, MPLpartition* part); - -int mpl_NA_fitch_second_update_uppass(MPLndsets* lset, MPLndsets* rset, MPLndsets* nset, MPLndsets* ancset, MPLpartition* part); - -int mpl_fitch_NA_local_reopt (MPLndsets* srcset, MPLndsets* tgt1set, MPLndsets* tgt2set, MPLpartition* part, int maxlen, bool domaxlen); - -int mpl_fitch_tip_update(MPLndsets* tset, MPLndsets* ancset, MPLpartition* part); - -int mpl_fitch_one_branch(MPLndsets* tipanc, MPLndsets* node, MPLpartition* part); - -int mpl_fitch_NA_first_one_branch(MPLndsets* tipanc, MPLndsets* node, MPLpartition* part); - -int mpl_fitch_NA_second_one_branch(MPLndsets* tipanc, MPLndsets* node, MPLpartition* part); - -int mpl_fitch_NA_second_one_branch_recalc(MPLndsets* tipanc, MPLndsets* node, MPLpartition* part); - -int mpl_fitch_NA_tip_update(MPLndsets* tset, MPLndsets* ancset, MPLpartition* part); - -int mpl_fitch_NA_tip_recalc_update(MPLndsets* tset, MPLndsets* ancset, MPLpartition* part); - -int mpl_fitch_NA_tip_finalize(MPLndsets* tset, MPLndsets* ancset, MPLpartition* part); -#endif /* fitch_h */ diff --git a/src/morphy.c b/src/morphy.c deleted file mode 100644 index ea70e3097..000000000 --- a/src/morphy.c +++ /dev/null @@ -1,1126 +0,0 @@ -/* -// morphy.c -// MorPhy2 -// -// Created by mbrazeau on 23/04/2017. -// Copyright © 2017 brazeaulab. All rights reserved. -*/ -#include "mpl.h" -#include "morphydefs.h" -#include "morphy.h" -#include "mplerror.h" -#include "statedata.h" -#include "fitch.h" -#include "wagner.h" - -void *mpl_alloc(size_t size, int setval) -{ - void *ret = malloc(size); - if (ret) { - memset(ret, setval, size); - } - return ret; -} - - -Morphyp mpl_new_Morphy_t(void) -{ - Morphyp new = (Morphyp)calloc(1, sizeof(Morphy_t)); - - mpl_set_gaphandl(GAP_INAPPLIC, (Morphy)new); - new->symbols.gap = DEFAULTGAP; - new->symbols.missing = DEFAULTMISSING; - new->nthreads = 1; - new->usrwtbase = 0; - new->wtbase = 1; - - return new; -} - - -/*void* mpl_get_from_matrix -(const int row, - const int col, - const int ncol, - const size_t size, - const void* data) -{ - return (void*)(data + (row * ncol * size + (size * col))); -}*/ - - -int mpl_get_gaphandl(Morphyp handl) -{ - assert(handl); - return handl->gaphandl; -} - - -int mpl_set_num_charac(const int nchar, Morphyp m) -{ - if (!m) { - return ERR_BAD_PARAM; - } - - m->numcharacters = nchar; - - return ERR_NO_ERROR; -} - - -int mpl_set_numtaxa(const int ntax, Morphyp m) -{ - if (!m) { - return ERR_BAD_PARAM; - } - - m->numtaxa = ntax; - - return ERR_NO_ERROR; -} - - -int mpl_check_data_loaded(Morphyp m) -{ - if (m->char_t_matrix) { - return 1; - } - - return 0; -} - - -char mpl_get_gap_symbol(Morphyp handl) -{ - return handl->symbols.gap; -} - -void mpl_flt_rational_approx -(unsigned long *a, unsigned long *b, const double fval) -{ - /* Using David Eppstein's method - http://www.ics.uci.edu/~eppstein/numth/frap.c*/ - - - long m[2][2]; - long ai; - long maxden = 100; - double x = fval; - - m[0][0] = m[1][1] = 1; - m[0][1] = m[1][0] = 0; - - while (m[1][0] * (ai = (long)x) + m[1][1] <= maxden) { - long t; - t = m[0][0] * ai + m[0][1]; - m[0][1] = m[0][0]; - m[0][0] = t; - t = m[1][0] * ai + m[1][1]; - m[1][1] = m[1][0]; - m[1][0] = t; - if (x == (double)ai) { - break; - } - x = 1 /(x - (double) ai); - if (x > (double)INT_MAX) { - break; - } - } - - *a = m[0][0]; - *b = m[1][0]; -} - - -bool mpl_almost_equal(double a, double b) -{ - double diff = fabs(a - b); - double largest = 0.0; - - a = fabs(a); - b = fabs(b); - - largest = (b > a) ? b : a; - - if (diff <= largest * MPL_EPSILON) { - return true; - } - - return false; -} - -/*! - @brief Checks whether or not a value corresponds to a real number or is whole - @discussion Should be used only to check values from external calling functions - that are not expected to be the product of a calculation (i.e. are a user- - supplied value, such as an input weight). - @param n The value to be tested. - @return A true/false value: true if value is fractional, false if value is - whole. - */ -bool mpl_isreal(const double n) -{ - assert(!(n > (double)LONG_MAX)); - long i = (long)n; - if (n == (double)i) { - return false; - } - return true; -} - - -int mpl_change_weight_base(const unsigned long wtbase, Morphyp handl) -{ - if (handl->usrwtbase) { - return 1; - } - - handl->wtbase = wtbase; - - return 0; -} - -static inline unsigned long mpl_greatest_common_denom -(unsigned long a, unsigned long b) -{ - unsigned long t = 0; - while (b) { - t = b; - b = a % b; - a = t; - } - - return a; -} - -unsigned long mpl_least_common_multiple(unsigned long a, unsigned long b) -{ - return (a * b) / mpl_greatest_common_denom(a, b); -} - -void mpl_set_new_weight_public -(const double wt, const int char_id, Morphyp handl) -{ - bool wtisreal = mpl_isreal(wt); - - - if (wtisreal) { - - if (!mpl_isreal(handl->charinfo[char_id].realweight) || - handl->charinfo[char_id].realweight == 0.0) - { - ++handl->numrealwts; - } - } - else { - - if (mpl_isreal(handl->charinfo[char_id].realweight)) { - --handl->numrealwts; - } - } - - handl->charinfo[char_id].realweight = wt; -} - -void mpl_scale_all_intweights(Morphyp handl) -{ - int i = 0; - int nchar = mpl_get_num_charac((Morphy)handl); - - - if (!handl->numrealwts) { - if (handl->usrwtbase != 0) { - handl->wtbase = handl->usrwtbase; - } else { - handl->wtbase = DEFAULTWTBASE; - } - } - - for (i = 0; i < nchar; ++i) { - mpl_flt_rational_approx(&handl->charinfo[i].intwt, - &handl->charinfo[i].basewt, - handl->charinfo[i].realweight); - } - - for (i = 0; i < nchar; ++i) { - handl->wtbase = mpl_least_common_multiple(handl->wtbase, - handl->charinfo[i].basewt); - } - - for (i = 0; i < nchar; ++i) { - handl->charinfo[i].intwt *= (handl->wtbase / handl->charinfo[i].basewt); - handl->charinfo[i].basewt = handl->wtbase; - } - -} - -void mpl_assign_fitch_fxns(MPLpartition* part) -{ - assert(part); - - if (part->isNAtype) { - part->inappdownfxn = mpl_NA_fitch_second_downpass; - part->inappupfxn = mpl_NA_fitch_second_uppass; - part->prelimfxn = mpl_NA_fitch_first_downpass; - part->finalfxn = mpl_NA_fitch_first_uppass; - part->tipupdate = mpl_fitch_NA_tip_update; - part->tipfinalize = mpl_fitch_NA_tip_finalize; - part->tiproot = mpl_fitch_NA_first_one_branch; - part->tiprootfinal = mpl_fitch_NA_second_one_branch; - part->loclfxn = mpl_fitch_NA_local_reopt; - part->downrecalc1 = mpl_NA_fitch_first_update_downpass; - part->uprecalc1 = mpl_NA_fitch_first_update_uppass; - part->inappdownrecalc2 = mpl_NA_fitch_second_update_downpass; - part->inapuprecalc2 = mpl_NA_fitch_second_update_uppass; - part->tipupdaterecalc = mpl_fitch_NA_tip_recalc_update; - part->tiprootrecalc = mpl_fitch_NA_first_one_branch; - part->tiprootupdaterecalc = mpl_fitch_NA_second_one_branch_recalc; - } - else { - part->prelimfxn = mpl_fitch_downpass; - part->finalfxn = mpl_fitch_uppass; - part->tipupdate = mpl_fitch_tip_update; - part->tiproot = mpl_fitch_one_branch; - part->tipfinalize = NULL; - part->inappdownfxn = NULL; - part->inappupfxn = NULL; - part->loclfxn = mpl_fitch_local_reopt; - part->downrecalc1 = NULL; - part->uprecalc1 = NULL; - part->inappdownrecalc2 = NULL; - part->inapuprecalc2 = NULL; - } -} - -void mpl_assign_wagner_fxns(MPLpartition* part) -{ - assert(part); - - part->prelimfxn = mpl_wagner_downpass; - part->finalfxn = mpl_wagner_uppass; - part->tipupdate = mpl_wagner_tip_update; - part->tipfinalize = NULL; - part->inappdownfxn = NULL; - part->inappupfxn = NULL; - part->loclfxn = NULL; - -} - - - -int mpl_fetch_parsim_fxn_setter -(void(**pars_assign)(MPLpartition*), MPLchtype chtype) -{ - int err = ERR_NO_ERROR; - - switch (chtype) { - case FITCH_T: - if (pars_assign) { - *pars_assign = mpl_assign_fitch_fxns; - } - break; - case WAGNER_T: - if (pars_assign) { - *pars_assign = mpl_assign_wagner_fxns; - } - break; - - - default: - err = ERR_CASE_NOT_IMPL; - break; - } - - return err; -} - - -int mpl_assign_partition_fxns(MPLpartition* part) -{ - assert(part); - int err = ERR_NO_ERROR; - - void (*pars_assign)(MPLpartition*) = NULL; - - err = mpl_fetch_parsim_fxn_setter(&pars_assign, part->chtype); - - if (!err && pars_assign) { - pars_assign(part); - } - - return err; -} - - -int mpl_extend_intarray(int** array, size_t size) -{ - int* temp = (int*)realloc(*array, size); - if (!temp) { - return ERR_BAD_MALLOC; - } - - *array = temp; - - return ERR_NO_ERROR; -} - - -int mpl_part_push_index(int newint, MPLpartition* part) -{ - int err = ERR_NO_ERROR; - - if (part->ncharsinpart < part->maxnchars) { - part->charindices[part->ncharsinpart] = newint; - ++part->ncharsinpart; - } - else { - err = mpl_extend_intarray(&part->charindices, - (part->maxnchars + 1) * sizeof(int)); - if (!err) { - part->charindices[part->ncharsinpart] = newint; - ++part->ncharsinpart; - ++part->maxnchars; - } - } - - return err; -} - - -int mpl_part_remove_index(int index, MPLpartition* part) -{ - if (!part->ncharsinpart) { - return 1; - } - - --part->ncharsinpart; - assert(part->ncharsinpart >= 0); - - int i = 0; - for (i = 0; i < part->ncharsinpart; ++i) { - part->charindices[i] = part->charindices[i + 1]; - } - part->charindices[i] = MPLCHARMAX; - - return 0; -} - - -int mpl_delete_partition(MPLpartition* part) -{ - int err = ERR_UNEXP_NULLPTR; - - if (part) { - - if (part->charindices) { - free(part->charindices); - part->charindices = NULL; - } - if (part->intwts) { - free(part->intwts); - part->intwts = NULL; - } - part->maxnchars = 0; - part->ncharsinpart = 0; - part->chtype = NONE_T; - part->tipupdate = NULL; - part->tipfinalize = NULL; - part->inappdownfxn = NULL; - part->inappupfxn = NULL; - part->prelimfxn = NULL; - part->finalfxn = NULL; - part->next = NULL; - free(part); - err = ERR_NO_ERROR; - } - - return err; -} - -int mpl_delete_all_partitions(Morphyp handl) -{ - assert(handl); - - int i = 0; - - if (handl->numparts) { - - mpl_delete_all_update_buffers(handl); /* MS addition, 2021-02-01 */ - MPLpartition* p = handl->partstack; - MPLpartition* q = NULL; - while (p) { - q = p->next; - mpl_delete_partition(p); - p = q; - } - - for (i = 0; i < handl->numparts; ++i) { - handl->partitions[i] = NULL; - } - free(handl->partitions); - handl->partitions = NULL; - - return ERR_NO_ERROR; - } - return ERR_UNEXP_NULLPTR; -} - - -MPLpartition* mpl_new_partition(const MPLchtype chtype, const bool hasNA) -{ - assert(chtype); - - MPLpartition *new = (MPLpartition*)calloc(1, sizeof(MPLpartition)); - - if (!new) { - return NULL; - } - - new->chtype = chtype; - new->isNAtype = hasNA; - - new->charindices = (int*)calloc(1, sizeof(int)); - if (!new->charindices) { - free(new); - return NULL; - } - - new->maxnchars = 1; - new->ncharsinpart = 0; - - mpl_assign_partition_fxns(new); - - return new; -} - - -int mpl_count_gaps_in_columns(Morphyp handl) -{ - int i = 0; - int j = 0; - char gap = mpl_get_gap_symbol(handl); - int numchar = mpl_get_num_charac((Morphy)handl); - int numtax = mpl_get_numtaxa((Morphy)handl); - MPLmatrix* matrix = mpl_get_mpl_matrix(handl); - MPLcharinfo* chinfo = handl->charinfo; - int numna = 0; - - for (i = 0; i < numchar; ++i) { - chinfo[i].ninapplics = 0; - for (j = 0; j < numtax; ++j) { - - MPLcell* cell = &matrix->cells[j * numchar + i]; - - if (strchr(cell->asstr, gap)) { - ++chinfo[i].ninapplics; - } - - if (chinfo[i].ninapplics > NACUTOFF) { - ++numna; - break; - } - } - } - - return numna; -} - - -int mpl_compare_partition_with_char_info -(const MPLcharinfo *chinfo, const MPLpartition* part, const MPLgap_t gaphandl) -{ - int ret = 0; - - if (chinfo->chtype != part->chtype) { - ++ret; - } - - if (gaphandl == GAP_INAPPLIC) { - if (chinfo->ninapplics <= NACUTOFF) { - if (part->isNAtype) { - ++ret; - } - } - else { - if (!part->isNAtype) { - ++ret; - } - } - } - - return ret; -} - - -/*! - @brief Searches the partition list for a partition matching the supplied info - @discussion Traverses a linked list of partitions, looking for a partition - matching the supplied information. If this function returns NULL, then the - supplied info does not match a character in the list. A new partition will - need to be created. - @param chinfo MPLchtype providing data on a character in the matrix. - @param part A data partition; should be the first partition in the list. - @return A pointer to the partition corresponding to the supplied character - information. - */ -MPLpartition* mpl_search_partitions -(MPLcharinfo *chinfo, MPLpartition* part, MPLgap_t gaphandl) -{ - assert(chinfo); - MPLpartition* p = part; - - while (p) { - if (!mpl_compare_partition_with_char_info(chinfo, p, gaphandl)) { - return p; - } - p = p->next; - } - - return p; -} - - -int mpl_compare_partitions(const void* ptr1, const void* ptr2) -{ - MPLpartition* part1 = *(MPLpartition**)ptr1; - MPLpartition* part2 = *(MPLpartition**)ptr2; - - int ret; - MPLchtype cdiff = NONE_T; - - cdiff = part1->chtype - part2->chtype; - ret = (int)cdiff; - - if (!cdiff) { - if (part2->isNAtype) { - ret = 1; - } - else { - ret = 0; - } - } - - return ret; -} - - -int mpl_put_partitions_in_handle(MPLpartition* first, Morphyp handl) -{ - assert(handl); - if (!handl->numparts) { - return ERR_NO_DATA; - } - handl->partitions = (MPLpartition**)calloc(handl->numparts, - sizeof(MPLpartition*)); - if (!handl->partitions) { - return ERR_BAD_MALLOC; - } - - int i = 0; - MPLpartition* p = first; - while (p) { - handl->partitions[i] = p; - ++i; - p = p->next; - } - assert(i == handl->numparts); - - qsort(handl->partitions, handl->numparts, sizeof(MPLpartition*), mpl_compare_partitions); - handl->partstack = first; - - return ERR_NO_ERROR; -} - - -void mpl_delete_all_update_buffers(Morphyp handl) -{ - /* Erases all the update buffers */ - int i = 0; - for (i = 0; i < handl->numparts; ++i) { - MPLpartition* p = handl->partitions[i]; - if (p->update_indices) { - free(p->update_indices); - p->update_indices = NULL; - } - if (p->update_NA_indices) { - free(p->update_NA_indices); - p->update_NA_indices = NULL; - } - } -} - - -int mpl_allocate_update_buffers(Morphyp handl) -{ - /* Allocates memory for an array of indices needed update on the tree */ - int i = 0; - for (i = 0; i < handl->numparts; ++i) { - MPLpartition* p = handl->partitions[i]; - p->update_indices = (int*)calloc(p->ncharsinpart, sizeof(int)); - if (!p->update_indices) { - mpl_delete_all_update_buffers(handl); - return ERR_BAD_MALLOC; - } - p->update_NA_indices = (int*)calloc(p->ncharsinpart, sizeof(int)); - if (!p->update_NA_indices) { - mpl_delete_all_update_buffers(handl); - return ERR_BAD_MALLOC; - } - - p->ntoupdate = 0; - p->nNAtoupdate = 0; - } - - return ERR_NO_ERROR; -} - -int mpl_setup_partitions(Morphyp handl) -{ - assert(handl); - - int err = ERR_NO_ERROR; - - int i = 0; - int nchar = mpl_get_num_charac((Morphyp)handl); - - MPLcharinfo* chinfo = NULL; - MPLpartition* first = NULL; - MPLpartition* last = NULL; - MPLpartition* p = NULL; - int numparts = 0; - - if (handl->partitions) { - mpl_delete_all_partitions(handl); - } - - for (i = 0; i < nchar; ++i) { - chinfo = &handl->charinfo[i]; - - p = mpl_search_partitions(chinfo, first, mpl_get_gaphandl(handl)); - - if (p) { - mpl_part_push_index(i, p); - } - else { - bool hasNA = false; - if (handl->gaphandl == GAP_INAPPLIC) { - if (chinfo->ninapplics > NACUTOFF) { - hasNA = true; - } - } - p = mpl_new_partition(chinfo->chtype, hasNA); - mpl_part_push_index(i, p); - if (!first) { - first = p; - last = p; - } - else { - last->next = p; - last = p; - } - - ++numparts; - } - } - - handl->numparts = numparts; - err = mpl_put_partitions_in_handle(first, handl); - mpl_allocate_update_buffers(handl); - - return err; -} - - -int mpl_get_numparts(Morphyp handl) -{ - return handl->numparts; -} - - -void mpl_delete_nodal_strings(const int nchars, MPLndsets* set) -{ - int i = 0; - - for (i = 0; i < nchars; ++i) { - if (set->downp1str) { - free(set->downp1str[i]); - set->downp1str[i] = NULL; - } - if (set->upp1str) { - free(set->upp1str[i]); - set->upp1str[i] = NULL; - } - if (set->downp2str) { - free(set->downp2str[i]); - set->downp2str[i] = NULL; - } - if (set->upp2str) { - free(set->upp2str[i]); - set->upp2str[i] = NULL; - } - } -} - - -int mpl_allocate_stset_stringptrs(const int nchars, MPLndsets* set) -{ - if (!set->downp1str) { - set->downp1str = (char**)calloc(nchars, sizeof(char*)); - if (!set->downp1str) { - mpl_delete_nodal_strings(nchars, set); - return ERR_BAD_MALLOC; - } - } - - if (!set->upp1str) { - set->upp1str = (char**)calloc(nchars, sizeof(char*)); - if (!set->upp1str) { - mpl_delete_nodal_strings(nchars, set); - return ERR_BAD_MALLOC; - } - } - - if (!set->downp2str) { - set->downp2str = (char**)calloc(nchars, sizeof(char*)); - if (!set->downp2str) { - mpl_delete_nodal_strings(nchars, set); - return ERR_BAD_MALLOC; - } - } - - if (!set->upp2str) { - set->upp2str = (char**)calloc(nchars, sizeof(char*)); - if (!set->upp2str) { - mpl_delete_nodal_strings(nchars, set); - return ERR_BAD_MALLOC; - } - } - - - return ERR_NO_ERROR; -} - - -MPLndsets* mpl_alloc_stateset(int numchars) -{ - MPLndsets* new = (MPLndsets*)calloc(1, sizeof(MPLndsets)); - if (!new) { - return NULL; - } - - new->downpass1 = (MPLstate*)calloc(numchars, sizeof(MPLstate)); - if (!new->downpass1) { - mpl_free_stateset(numchars, new); - return NULL; - } - - new->uppass1 = (MPLstate*)calloc(numchars, sizeof(MPLstate)); - if (!new->uppass1) { - mpl_free_stateset(numchars, new); - return NULL; - } - - new->downpass2 = (MPLstate*)calloc(numchars, sizeof(MPLstate)); - if (!new->downpass1) { - mpl_free_stateset(numchars, new); - return NULL; - } - - new->uppass2 = (MPLstate*)calloc(numchars, sizeof(MPLstate)); - if (!new->uppass2) { - mpl_free_stateset(numchars, new); - return NULL; - } - - new->subtree_actives = (MPLstate*)calloc(numchars, sizeof(MPLstate)); - if (!new->subtree_actives) { - mpl_free_stateset(numchars, new); - return NULL; - } - - new->temp_subtr_actives = (MPLstate*)calloc(numchars, sizeof(MPLstate)); - if (!new->temp_subtr_actives) { - mpl_free_stateset(numchars, new); - return NULL; - } - - new->temp_downpass1 = (MPLstate*)calloc(numchars, sizeof(MPLstate)); - if (!new->temp_downpass1) { - mpl_free_stateset(numchars, new); - return NULL; - } - - new->temp_uppass1 = (MPLstate*)calloc(numchars, sizeof(MPLstate)); - if (!new->temp_uppass1) { - mpl_free_stateset(numchars, new); - return NULL; - } - - new->temp_downpass2 = (MPLstate*)calloc(numchars, sizeof(MPLstate)); - if (!new->temp_downpass1) { - mpl_free_stateset(numchars, new); - return NULL; - } - - new->temp_uppass2 = (MPLstate*)calloc(numchars, sizeof(MPLstate)); - if (!new->temp_uppass2) { - mpl_free_stateset(numchars, new); - return NULL; - } - new->changes = (bool*)calloc(numchars, sizeof(bool)); - if (!new->changes) { - mpl_free_stateset(numchars, new); - return NULL; - } - mpl_allocate_stset_stringptrs(numchars, new); - - return new; -} - - -void mpl_free_stateset(const int nchars, MPLndsets* statesets) -{ - if (!statesets) { - return; - } - if (statesets->downpass1) { - free(statesets->downpass1); - statesets->downpass1 = NULL; - } - if (statesets->uppass1) { - free(statesets->uppass1); - statesets->uppass1 = NULL; - } - if (statesets->downpass2) { - free(statesets->downpass2); - statesets->downpass2 = NULL; - } - if (statesets->uppass2) { - free(statesets->uppass2); - statesets->uppass2 = NULL; - } - if (statesets->subtree_actives) { - free(statesets->subtree_actives); - statesets->subtree_actives = NULL; - } - if (statesets->temp_subtr_actives) { - free(statesets->temp_subtr_actives); - statesets->temp_subtr_actives = NULL; - } - if (statesets->temp_downpass1) { - free(statesets->temp_downpass1); - statesets->temp_downpass1 = NULL; - } - if (statesets->temp_uppass1) { - free(statesets->temp_uppass1); - statesets->temp_uppass1 = NULL; - } - if (statesets->temp_downpass2) { - free(statesets->temp_downpass2); - statesets->temp_downpass2 = NULL; - } - if (statesets->temp_uppass2) { - free(statesets->temp_uppass2); - statesets->temp_uppass2 = NULL; - } - if (statesets->changes) { - free(statesets->changes); - statesets->changes = NULL; - } - - mpl_delete_nodal_strings(nchars, statesets); - - if (statesets->downp1str) { - free(statesets->downp1str); - statesets->downp1str = NULL; - } - if (statesets->upp1str) { - free(statesets->upp1str); - statesets->upp1str = NULL; - } - if (statesets->downp2str) { - free(statesets->downp2str); - statesets->downp2str = NULL; - } - if (statesets->upp2str) { - free(statesets->upp2str); - statesets->upp2str = NULL; - } - - free(statesets); -} - - -int mpl_setup_statesets(Morphyp handl) -{ - MPL_ERR_T err = ERR_NO_ERROR; - - int numnodes = handl->numnodes; - - if (handl->statesets) { - return 1; - } - - handl->statesets = (MPLndsets**)calloc(numnodes, sizeof(MPLndsets*)); - - if (!handl->statesets) { - return ERR_BAD_MALLOC; - } - - int i = 0; - int nchars = mpl_get_num_charac((Morphyp)handl); - - for (i = 0; i < numnodes; ++i) { - if (!(handl->statesets[i] = mpl_alloc_stateset(nchars))) { - err = ERR_BAD_MALLOC; - mpl_destroy_statesets(handl); - break; - } - } - - return err; -} - - -int mpl_destroy_statesets(Morphyp handl) -{ - int i = 0; - int numnodes = handl->numnodes; - - if (handl->statesets) { - - for (i = 0; i < numnodes; ++i) { - mpl_free_stateset(mpl_get_num_charac((Morphy)handl), handl->statesets[i]); - } - - free(handl->statesets); - handl->statesets = NULL; - } - - return ERR_NO_ERROR; -} - - -int mpl_copy_data_into_tips(Morphyp handl) -{ - int i = 0; - int j = 0; - int ntax = mpl_get_numtaxa((Morphy)handl); - int nchar = mpl_get_num_charac((Morphy)handl); - MPLndsets** nsets = handl->statesets; - - for (i = 0; i < ntax; ++i) { - for (j = 0; j < nchar; ++j) { - nsets[i]->downpass1[j] = - handl->inmatrix.cells[i * nchar + j].asint; - nsets[i]->uppass1[j] = nsets[i]->downpass1[j]; - nsets[i]->uppass2[j] = nsets[i]->downpass1[j]; - nsets[i]->downpass2[j] = nsets[i]->downpass1[j]; - } - } - - return ERR_NO_ERROR; -} - -int mpl_assign_intwts_to_partitions(Morphyp handl) -{ - int i = 0; - int j = 0; - int numparts = mpl_get_numparts(handl); - - if (!numparts) { - return ERR_NO_DATA; - } - - for (i = 0; i < numparts; ++i) { - - if (handl->partitions[i]->intwts) { - free(handl->partitions[i]->intwts); - handl->partitions[i]->intwts = NULL; - } - - handl->partitions[i]->intwts = (unsigned long*)calloc - (handl->partitions[i]->ncharsinpart, - sizeof(unsigned long)); - - for (j = 0; j < handl->partitions[i]->ncharsinpart; ++j) { - int charindex = handl->partitions[i]->charindices[j]; - handl->partitions[i]->intwts[j] = handl->charinfo[charindex].intwt; - } - } - - return 0; -} - -int mpl_update_root(MPLndsets* lower, MPLndsets* upper, MPLpartition* part) -{ - int i = 0; - int j = 0; - int nchar = part->ncharsinpart; - int *indices = part->charindices; - - - for (i = 0; i < nchar; ++i) { - j = indices[i]; - lower->downpass1[j] = upper->downpass1[j]; - lower->uppass1[j] = upper->downpass1[j]; - } - - return 0; -} - - -int mpl_update_NA_root(MPLndsets* lower, MPLndsets* upper, MPLpartition* part) -{ - int i = 0; - int j = 0; - int nchar = part->ncharsinpart; - int *indices = part->charindices; - - for (i = 0; i < nchar; ++i) { - j = indices[i]; - - if (upper->downpass1[j] & ISAPPLIC) { - lower->downpass1[j] = upper->downpass1[j] & ISAPPLIC; - } - else { - lower->downpass1[j] = NA; - } - - lower->uppass2[j] = upper->downpass2[j]; - lower->downpass1[j] = lower->downpass1[j]; - lower->uppass1[j] = lower->downpass1[j]; - - lower->temp_downpass1[j] = lower->downpass1[j]; - lower->temp_uppass1[j] = lower->uppass1[j]; - lower->temp_downpass2[j] = lower->downpass2[j]; - lower->temp_uppass2[j] = lower->uppass2[j]; - } - - return 0; -} - -int mpl_update_NA_root_recalculation(MPLndsets* lower, MPLndsets* upper, MPLpartition* part) -{ - int i = 0; - int j = 0; - int nchar = part->nNAtoupdate; - int *indices = part->update_NA_indices; - - for (i = 0; i < nchar; ++i) { - j = indices[i]; - - if (upper->downpass1[j] & ISAPPLIC) { - lower->downpass1[j] = upper->downpass1[j] & ISAPPLIC; - } - else { - lower->downpass1[j] = NA; - } - - lower->uppass2[j] = upper->downpass2[j]; - lower->downpass1[j] = lower->downpass1[j]; - lower->uppass1[j] = lower->downpass1[j]; - } - - return 0; -} diff --git a/src/morphy.h b/src/morphy.h deleted file mode 100644 index 0eb19d775..000000000 --- a/src/morphy.h +++ /dev/null @@ -1,63 +0,0 @@ -/* - * morphy.h - * MorPhy2 - * - * Created by mbrazeau on 23/04/2017. - * Copyright © 2017 brazeaulab. All rights reserved. - */ - -#ifndef morphy_h -#define morphy_h - -#ifdef DEBUG -#include -#define dbg_printf(...) printf(__VA_ARGS__) -#else -#define dbg_printf(...) -#endif - -#include -#include -#include -#include -#include - -/* Function prototypes */ - -Morphyp mpl_new_Morphy_t(void); -int mpl_set_numtaxa(const int ntax, Morphyp m); -int mpl_set_num_charac(const int ncharac, Morphyp m); -int mpl_get_gaphandl(Morphyp handl); -int mpl_check_data_loaded(Morphyp m); -char mpl_get_gap_symbol(Morphyp handl); -bool mpl_almost_equal(double a, double b); -bool mpl_isreal(const double n); -void mpl_set_new_weight_public(const double wt, const int char_id, Morphyp handl); -void mpl_scale_all_intweights(Morphyp handl); -MPLchtype* mpl_get_charac_types(Morphyp handl); -int mpl_assign_partition_fxns(MPLpartition* part); -int mpl_fetch_parsim_fxn_setter (void(**pars_assign)(MPLpartition*), MPLchtype chtype); -int mpl_extend_intarray(int** array, size_t size); -int mpl_part_push_index(int newint, MPLpartition* part); -int mpl_part_remove_index(int index, MPLpartition* part); -int mpl_delete_partition(MPLpartition* part); -MPLpartition* mpl_new_partition(const MPLchtype chtype, const bool hasNA); -int mpl_count_gaps_in_columns(Morphyp handl); -int mpl_put_partitions_in_handle(MPLpartition* first, Morphyp handl); -void mpl_delete_all_update_buffers(Morphyp handl); -int mpl_allocate_update_buffers(Morphyp handl); -int mpl_setup_partitions(Morphyp handle); -int mpl_get_numparts(Morphyp handl); -MPLndsets* mpl_alloc_stateset(int numchars); -void mpl_free_stateset(const int nchars, MPLndsets* statesets); -int mpl_delete_all_partitions(Morphyp handl); -int mpl_allocate_stset_stringptrs(const int nchars, MPLndsets* set); -int mpl_setup_statesets(Morphyp handl); -int mpl_destroy_statesets(Morphyp handl); -int mpl_copy_data_into_tips(Morphyp handl); -int mpl_assign_intwts_to_partitions(Morphyp handl); -int mpl_update_root(MPLndsets* lower, MPLndsets* upper, MPLpartition* part); -int mpl_update_NA_root(MPLndsets* lower, MPLndsets* upper, MPLpartition* part); -int mpl_update_NA_root_recalculation(MPLndsets* lower, MPLndsets* upper, MPLpartition* part); - -#endif /* morphy_h */ diff --git a/src/morphy_score.cpp b/src/morphy_score.cpp deleted file mode 100644 index ce43571b5..000000000 --- a/src/morphy_score.cpp +++ /dev/null @@ -1,219 +0,0 @@ -#include -#include // for assert - -extern "C" { -#include "mpl.h" -#include "RMorphy.h" -} - -using namespace Rcpp; - -// [[Rcpp::export]] -int preorder_morphy(IntegerMatrix edge, SEXP MorphyHandl) { - Morphy handl = R_ExternalPtrAddr(MorphyHandl); - const int - n_tip = mpl_get_numtaxa(handl), - n_internal = mpl_get_num_internal_nodes(handl), - n_vertex = n_tip + n_internal, - root_node = n_tip - ; - - IntegerVector parent_of(n_vertex); - IntegerVector left_child(n_internal); - IntegerVector right_child(n_internal); - - for (int i = edge.nrow(); i--; ) { - const int - parent = edge(i, 0) - 1, - child = edge(i, 1) - 1 - ; - parent_of[child] = parent; - if (right_child[parent - n_tip]) { - left_child[parent - n_tip] = child; - } else { - right_child[parent - n_tip] = child; - } - } - parent_of[root_node] = root_node; - - const int - /* INTEGER gives pointer to first element of an R vector */ - *ancestor = parent_of.begin(), - *left = left_child.begin(), - *right = right_child.begin() - ; - - /* Initialize return variables */ - int score = 0; - morphy_length(ancestor, left, right, handl, &score); /* Updates score */ - return score; -} - -// [[Rcpp::export]] -IntegerVector preorder_morphy_by_char(IntegerMatrix edge, List MorphyHandls) { - Morphy handl = R_ExternalPtrAddr(MorphyHandls[0]); - const int - n_tip = mpl_get_numtaxa(handl), - n_internal = mpl_get_num_internal_nodes(handl), - n_vertex = n_tip + n_internal, - root_node = n_tip - ; - - IntegerVector parent_of(n_vertex); - IntegerVector left_child(n_internal); - IntegerVector right_child(n_internal); - - for (int i = edge.nrow(); i--; ) { - const int - parent = edge(i, 0) - 1, - child = edge(i, 1) - 1 - ; - parent_of[child] = parent; - if (right_child[parent - n_tip]) { - left_child[parent - n_tip] = child; - } else { - right_child[parent - n_tip] = child; - } - } - parent_of[root_node] = root_node; - - const int - /* INTEGER gives pointer to first element of an R vector */ - *ancestor = parent_of.begin(), - *left = left_child.begin(), - *right = right_child.begin() - ; - - - /* Initialize return variables */ - IntegerVector ret (MorphyHandls.length()); - for (int i = MorphyHandls.length(); i--; ) { - int score = 0; - Morphy handl = R_ExternalPtrAddr(MorphyHandls[i]); - morphy_length(ancestor, left, right, handl, &score); /* Updates score */ - ret[i] = score; - } - return ret; -} - -// ~20x faster to pass list of morphyObjs than to use a single object and -// set weights / apply tipdata one character at a time. -// [[Rcpp::export]] -double morphy_iw( - IntegerMatrix edge, - List MorphyHandls, - NumericVector weight, - IntegerVector minScore, - IntegerVector sequence, - NumericVector concavity, - NumericVector target -) { - const double k = concavity[0]; - const double target_score = target[0]; - Morphy handl = R_ExternalPtrAddr(MorphyHandls[0]); - const int n_tip = mpl_get_numtaxa(handl); - const int n_internal = mpl_get_num_internal_nodes(handl); - const int n_vertex = n_tip + n_internal; - const int root_node = n_tip; - - IntegerVector parent_of(n_vertex); - IntegerVector left_child(n_internal); - IntegerVector right_child(n_internal); - - for (int i = edge.nrow(); i--; ) { - const int - parent = edge(i, 0) - 1, - child = edge(i, 1) - 1 - ; - parent_of[child] = parent; - if (right_child[parent - n_tip]) { - left_child[parent - n_tip] = child; - } else { - right_child[parent - n_tip] = child; - } - } - parent_of[root_node] = root_node; - - const int *ancestor = parent_of.begin(); - const int *left = left_child.begin(); - const int *right = right_child.begin(); - - double ret = 0; - for (int index = sequence.length(); index--; ) { - const int i = sequence[index]; - const int weight_i = weight[i]; - if (weight_i) { - Morphy handl = R_ExternalPtrAddr(MorphyHandls[i]); - int e = -minScore[i]; - morphy_length(ancestor, left, right, handl, &e); /* Updates e */ - ret += weight_i * e / (k + e); - if (ret > target_score) return R_PosInf; - } - } - return ret; -} - -// NOTE: All characters must be informative. -// [[Rcpp::export]] -double morphy_profile(IntegerMatrix edge, - List MorphyHandls, - NumericVector weight, - IntegerVector sequence, - NumericMatrix profiles, - NumericVector target) { - Morphy handl = R_ExternalPtrAddr(MorphyHandls[0]); - const int n_tip = mpl_get_numtaxa(handl); - const int n_internal = mpl_get_num_internal_nodes(handl); - const int n_vertex = n_tip + n_internal; - const int root_node = n_tip; - const double target_score = target[0]; - - // Basic dimensions check - protect against segfaults - if (edge.nrow() != n_tip + n_internal - 1) { - Rcpp::Rcout << n_tip << " + " << n_internal << " != " << edge.nrow() << "\n"; - Rcpp::stop("Number of edges does not match Morphy object dimensions."); - } - - IntegerVector parent_of(n_vertex); - IntegerVector left_child(n_internal); - IntegerVector right_child(n_internal); - - for (int i = edge.nrow(); i--; ) { - const int - parent = edge(i, 0) - 1, - child = edge(i, 1) - 1 - ; - parent_of[child] = parent; - if (right_child[parent - n_tip]) { - left_child[parent - n_tip] = child; - } else { - right_child[parent - n_tip] = child; - } - } - parent_of[root_node] = root_node; - - const int - /* INTEGER gives pointer to first element of an R vector */ - *ancestor = parent_of.begin(), - *left = left_child.begin(), - *right = right_child.begin() - ; - - - double ret = 0; - for (int index = sequence.length(); index--; ) { - const int i = sequence[index]; - const int weight_i = weight[i]; - if (weight_i) { - Morphy handl = R_ExternalPtrAddr(MorphyHandls[i]); - int e = -1; - morphy_length(ancestor, left, right, handl, &e); /* Updates e */ - if (e > -1) { // In case invariant sites have not been zero-weighted - assert(e < profiles.nrow()); - ret += weight_i * profiles(e, i); - } - if (ret > target_score) return R_PosInf; - } - } - return ret; -} diff --git a/src/morphydefs.h b/src/morphydefs.h deleted file mode 100644 index 61446b3b3..000000000 --- a/src/morphydefs.h +++ /dev/null @@ -1,213 +0,0 @@ -/* -// morphydefs.h -// MorPhy2 -// -// Created by mbrazeau on 07/05/2017. -// Copyright © 2017 brazeaulab. All rights reserved. -*/ - -#ifndef morphydefs_h -#define morphydefs_h - -#ifdef __cplusplus -extern "C" { -#endif - -#include -#include - - - typedef double Mflt; -#define MPL_EPSILON DBL_EPSILON - - typedef unsigned int MPLstate; - -#define NA ((MPLstate)1) -#define MISSING ((MPLstate)~0) -#define ISAPPLIC (((MPLstate)~0)^NA) -#define UNKNOWN ISAPPLIC -#define MAXSTATES (CHAR_BIT * sizeof(MPLstate)) -#define DEFAULTGAP '-' -#define DEFAULTMISSING '?' -#define DEFAULTUNKNOWN '+' -#define DEFAULCHARTYPE FITCH_T -#define DEFAULTWTBASE 1 -#define NACUTOFF 2 -#define MPLCHARMAX INT_MAX -#define USRWTMIN 0.00001 /*! Minimum fractional weight a caller can ask - for when setting weights. Anything less than -this will be considered 0. */ -#define MPLWTMIN (MPL_EPSILON * 10) /*! Safest (for me!) if calculations -steer pretty clear of epsilon */ - -typedef struct MPLndsets MPLndsets; -typedef struct MPLpartition MPLpartition; - -typedef int (*MPLdownfxn) - (MPLndsets* lset, - MPLndsets* rset, - MPLndsets* nset, - MPLpartition* part); - -typedef int (*MPLupfxn) - (MPLndsets* lset, - MPLndsets* rset, - MPLndsets* nset, - MPLndsets* ancset, - MPLpartition* part); - -typedef int (*MPLtipfxn) - (MPLndsets* tset, - MPLndsets* ancset, - MPLpartition* part); - -typedef int (*MPLloclfxn) - (MPLndsets* srcset, - MPLndsets* topnod, - MPLndsets* botnod, - MPLpartition* part, - int cutoff, - bool usemax); - - -typedef struct { - MPLstate asint; - char* asstr; -} MPLcell; - - -typedef struct MPLcharinfo MPLcharinfo; -struct MPLcharinfo { - - int charindex; - int ninapplics; - - MPLchtype chtype; - double realweight; - unsigned long basewt; - unsigned long intwt; - Mflt fltwt; - Mflt CIndex; - Mflt RCIndex; - Mflt HIndex; - Mflt RetIndex; - -}; - - -typedef struct { - int maxchars; - int nupdate; - int* indices; -} MPLcupdate; - - -struct MPLpartition { - - MPLchtype chtype; /*!< The optimality type used for this partition. */ - bool isNAtype; /*!< This character should be treated as having inapplicable data. */ - int maxnchars; - int ncharsinpart; - int* charindices; - unsigned long nchanges; /*!< Number of state changes in this partition. */ - int ntoupdate; - int* update_indices; - int nNAtoupdate; - int* update_NA_indices; - bool usingfltwt; - unsigned long* intwts; - Mflt* fltwts; - MPLtipfxn tipupdate; - MPLtipfxn tipfinalize; - MPLtipfxn tiproot; /*!< For the function that adds length at the base of an unrooted tree. */ - MPLtipfxn tiprootfinal; - MPLtipfxn tipupdaterecalc; - MPLtipfxn tipfinalrecalc; - MPLtipfxn tiprootrecalc; - MPLtipfxn tiprootupdaterecalc; - MPLdownfxn inappdownfxn; - MPLdownfxn inappdownrecalc2; - MPLupfxn inappupfxn; - MPLupfxn inapuprecalc2; - MPLdownfxn prelimfxn; - MPLdownfxn downrecalc1; - MPLupfxn finalfxn; - MPLupfxn uprecalc1; - MPLloclfxn loclfxn; - MPLpartition* next; - -}; - - -struct MPLndsets { - - bool updated; - int steps_to_recall; - MPLstate* downpass1; - MPLstate* uppass1; - MPLstate* downpass2; - MPLstate* uppass2; - MPLstate* subtree_actives; - MPLstate* temp_subtr_actives; - MPLstate* temp_downpass1; - MPLstate* temp_uppass1; - MPLstate* temp_downpass2; - MPLstate* temp_uppass2; - bool* changes; - char** downp1str; - char** downp2str; - char** upp1str; - char** upp2str; - -}; - - -typedef struct mpl_matrix_s { - int ncells; - MPLcell* cells; -} MPLmatrix; - - -typedef struct symbols_s { - int numstates; - char* statesymbols; - char* symbolsinmatrix; - MPLstate* packed; - char gap; - char missing; -} MPLsymbols; - - -/*! \struct*/ -typedef struct Morphy_t { - - int numtaxa; - int numcharacters; - int numrealwts; - MPLcharinfo* charinfo; - unsigned long usrwtbase; - unsigned long wtbase; - int numparts; - MPLpartition* partstack; - MPLpartition** partitions; - MPLsymbols symbols; - MPLgap_t gaphandl; - union { - int asint; - Mflt asfloat; - } score; - MPLmatrix inmatrix; - char* char_t_matrix; - int numnodes; - int* nodesequence; - int nthreads; - MPLndsets** statesets; - -} Morphy_t, *Morphyp; - - -#ifdef __cplusplus -} -#endif - -#endif /* morphydefs_h */ diff --git a/src/mpl.c b/src/mpl.c deleted file mode 100644 index af0a16423..000000000 --- a/src/mpl.c +++ /dev/null @@ -1,1038 +0,0 @@ -/* -* mpl.c -* MorPhy2 -* -* Created by mbrazeau on 04/05/2017. -* Copyright © 2017 brazeaulab. All rights reserved. -*/ - -#include "mpl.h" -#include "morphydefs.h" -#include "morphy.h" -#include "mplerror.h" -#include "statedata.h" - -/* TODO: This is temporary */ -#include "fitch.h" - -Morphy mpl_new_Morphy(void) -{ - Morphyp new = mpl_new_Morphy_t(); - - return (Morphy)new; -} - - -int mpl_delete_Morphy(Morphy m) -{ - if (!m) { - return ERR_UNEXP_NULLPTR; - } - Morphyp m1 = (Morphyp)m; - - free(m1->char_t_matrix); - m1->char_t_matrix = NULL; - mpl_delete_mpl_matrix(&m1->inmatrix); - mpl_destroy_symbolset(m1); - mpl_delete_charac_info(m1); - mpl_delete_all_update_buffers(m1); /* MS addition, 2021-01-30 */ - mpl_delete_all_partitions(m1); - mpl_destroy_statesets(m1); - free(m1); - - return ERR_NO_ERROR; -} - - -int mpl_init_Morphy(const int ntax, const int nchar, Morphy m) -{ - if (!m) { - return ERR_UNEXP_NULLPTR; - } - - if (!ntax || !nchar) { - return ERR_NO_DIMENSIONS; - } - - int ret = ERR_NO_ERROR; - Morphyp mi = (Morphyp)m; - - if (ntax != mpl_get_numtaxa(m)) { - if (mpl_check_data_loaded(mi)) { - return ERR_EX_DATA_CONF; - } - } - - if (nchar != mpl_get_num_charac(m)) { - if (mpl_check_data_loaded(mi)) { - return ERR_EX_DATA_CONF; - } - } - - ret = mpl_set_numtaxa(ntax, mi); - if (ret) { - return ret; - } - - ret = mpl_set_num_internal_nodes(ntax, mi); - if (ret) { - return ret; - } - - ret = mpl_set_num_charac(nchar, mi); - if (ret) { - return ret; - } - - /* TODO: Revise this? */ - mpl_init_charac_info(mi); - - return ret; -} - - -int mpl_get_numtaxa(Morphy m) -{ - if (!m) { - return ERR_UNEXP_NULLPTR; - } - - return ((Morphyp)m)->numtaxa; -} - - -int mpl_get_num_charac(Morphy m) -{ - if (!m) { - return ERR_UNEXP_NULLPTR; - } - - return ((Morphyp)m)->numcharacters; -} - - -int mpl_set_num_internal_nodes(const int nnodes, Morphy m) -{ - if (!m) { - return ERR_UNEXP_NULLPTR; - } - - int ntax = 0; - if (!(ntax = mpl_get_numtaxa(m))) { - return ERR_NO_DIMENSIONS; - } - - ((Morphyp)m)->numnodes = nnodes + ntax; - - return ERR_NO_ERROR; -} - - -int mpl_get_num_internal_nodes(Morphy m) -{ - if (!m) { - return ERR_UNEXP_NULLPTR; - } - - return (((Morphyp)m)->numnodes - mpl_get_numtaxa(m)); -} - -int mpl_attach_symbols(const char *symbols, Morphy m) -{ - if (!symbols || !m) { - return ERR_BAD_PARAM; - } - - int isdataloaded = mpl_check_data_loaded((Morphyp)m); - - int i = 0; - int len = 0; - - while(isalnum(symbols[i])) { - ++len; - ++i; - }; - ++len; - - char* symbsnospaces = (char*)calloc(len, sizeof(char)); - - int j = 0; - for (i = 0; symbols[i]; ++i) { - if (isalnum(symbols[i])) { - symbsnospaces[j] = symbols[i]; - ++j; - } - } - symbsnospaces[j] = '\0'; - - if (isdataloaded) { - char* matrixsymbs = mpl_query_symbols_from_matrix((Morphyp)m); - assert(matrixsymbs); - - if (mpl_compare_symbol_lists(symbsnospaces, matrixsymbs)) { - free(symbsnospaces); - return ERR_SYMBOL_MISMATCH; - } - } - - ((Morphyp)m)->symbols.statesymbols = symbsnospaces; - - return ERR_NO_ERROR; -} - - -char* mpl_get_symbols(Morphy m) -{ - - Morphyp mi = (Morphyp)m; - - return mi->symbols.statesymbols; -} - - -int mpl_attach_rawdata(const char* rawmatrix, Morphy m) -{ - if (!rawmatrix || !m) { - return ERR_BAD_PARAM; - } - - if (!mpl_get_numtaxa(m) || !mpl_get_num_charac(m)) { - return ERR_NO_DIMENSIONS; - } - - Morphyp m1 = (Morphyp)m; - if (mpl_check_data_loaded(m1)) { - return ERR_EX_DATA_CONF; - } - mpl_copy_raw_matrix(rawmatrix, m1); - - /* Check validity of preprocessed matrix */ - MPL_ERR_T err = ERR_NO_ERROR; - err = mpl_check_nexus_matrix_dimensions(mpl_get_preprocessed_matrix(m1), - mpl_get_numtaxa(m1), - mpl_get_num_charac(m1)); - - if (err) { - mpl_delete_rawdata(m1); - return err; - } - - err = mpl_preproc_rawdata((Morphyp)m); - - return err; -} - - -int mpl_delete_rawdata(Morphy m) -{ - if (!m) { - return ERR_UNEXP_NULLPTR; - } - Morphyp mp = (Morphyp)m; - - /* TODO: This must reset all matrix dependencies */ - if (mp->char_t_matrix) { - free(mp->char_t_matrix); - mp->char_t_matrix = NULL; - mpl_delete_mpl_matrix(mpl_get_mpl_matrix((Morphyp)m)); - mpl_delete_all_partitions((Morphyp)m); - - } - return ERR_NO_ERROR; -} - - -int mpl_apply_tipdata(Morphy m) -{ - if (!m) { - return ERR_UNEXP_NULLPTR; - } - - Morphyp mi = (Morphyp)m; - - /* Create dictionary and convert */ - mpl_create_state_dictionary(mi); - mpl_convert_cells(mi); - - /* TODO: Check for existing partitions; */ - /* Call here */ - - /* Setup the partitions */ - mpl_setup_partitions(mi); - mpl_scale_all_intweights(mi); - mpl_assign_intwts_to_partitions(mi); - - /* Create all the internal data memory */ - mpl_setup_statesets(mi); - - /* Apply the data to the tips */ - mpl_copy_data_into_tips(mi); - - return ERR_NO_ERROR; -} - - -int mpl_set_charac_weight(const int charID, const double weight, Morphy m) -{ - if (!m) { - return ERR_UNEXP_NULLPTR; - } - - if (!mpl_get_num_charac(m)) { - return ERR_NO_DIMENSIONS; - } - - if (charID >= mpl_get_num_charac(m)) { - return ERR_OUT_OF_BOUNDS; - } - - Morphyp mi = (Morphyp)m; - mpl_set_new_weight_public(weight, charID, mi); - - return ERR_NO_ERROR; -} - - -unsigned long mpl_get_charac_weight -(double* weight, const int char_id, const Morphy m) -{ - if (!m) { - return ERR_UNEXP_NULLPTR; - } - - if (char_id >= mpl_get_num_charac(m)) { - return ERR_OUT_OF_BOUNDS; - } - - Morphyp mi = (Morphyp)m; - - *weight = (double) mi->charinfo[char_id].intwt/mi->charinfo[char_id].basewt; - - return mi->charinfo[char_id].intwt; -} - - -int mpl_set_parsim_t(const int charID, const MPLchtype chtype, Morphy m) -{ - if (!m) { - return ERR_BAD_PARAM; - } - - MPL_ERR_T err = ERR_NO_ERROR; - - if (chtype >= MAX_CTYPE) { - return ERR_UNKNOWN_CHTYPE; - } - - if (charID >= mpl_get_num_charac(m)) { - return ERR_OUT_OF_BOUNDS; - } - - if ((err = mpl_fetch_parsim_fxn_setter(NULL, chtype))) { - return err; - } - - Morphyp handl = (Morphyp)m; - handl->charinfo[charID].chtype = chtype; - - if (chtype == NONE_T) { - handl->charinfo[charID].realweight = 0.0; - } - else { - handl->charinfo[charID].realweight = handl->wtbase; - } - - return ERR_NO_ERROR; -} - - -int mpl_set_gaphandl(const MPLgap_t gaptype, Morphy m) -{ - if (!m) { - return ERR_BAD_PARAM; - } - - Morphyp mp = (Morphyp)m; - mp->gaphandl = gaptype; - return ERR_NO_ERROR; -} - - -int mpl_query_gaphandl(Morphy m) -{ - if (!m) { - return ERR_BAD_PARAM; - } - - return mpl_get_gaphandl((Morphyp)m); -} - - -int mpl_first_down_recon -(const int node_id, const int left_id, const int right_id, Morphy m) -{ - if (!m) { - return ERR_UNEXP_NULLPTR; - } - - Morphyp handl = (Morphyp)m; - MPLndsets* nstates = handl->statesets[node_id]; - MPLndsets* lstates = handl->statesets[left_id]; - MPLndsets* rstates = handl->statesets[right_id]; - - int i = 0; - int res = 0; - int numparts = mpl_get_numparts(handl); - MPLdownfxn downfxn = NULL; - - nstates->updated = false; - - for (i = 0; i < numparts; ++i) { - downfxn = handl->partitions[i]->prelimfxn; - res += downfxn(lstates, rstates, nstates, handl->partitions[i]); - } - - return res; -} - - -int mpl_first_up_recon -(const int node_id, const int left_id, const int right_id, const int anc_id, - Morphy m) -{ - if (!m) { - return ERR_UNEXP_NULLPTR; - } - - Morphyp handl = (Morphyp)m; - MPLndsets* nstates = handl->statesets[node_id]; - MPLndsets* lstates = handl->statesets[left_id]; - MPLndsets* rstates = handl->statesets[right_id]; - MPLndsets* astates = handl->statesets[anc_id]; - - int i = 0; - int res = 0; - int numparts = mpl_get_numparts(handl); - MPLupfxn upfxn = NULL; - - nstates->updated = false; - - for (i = 0; i < numparts; ++i) { - upfxn = handl->partitions[i]->finalfxn; - res += upfxn(lstates, rstates, nstates, astates, handl->partitions[i]); - } - - return res; -} - - -int mpl_second_down_recon -(const int node_id, const int left_id, const int right_id, Morphy m) -{ - if (!m) { - return ERR_UNEXP_NULLPTR; - } - - Morphyp handl = (Morphyp)m; - MPLndsets* nstates = handl->statesets[node_id]; - MPLndsets* lstates = handl->statesets[left_id]; - MPLndsets* rstates = handl->statesets[right_id]; - - int i = 0; - int res = 0; - int numparts = mpl_get_numparts(handl); - MPLdownfxn downfxn = NULL; - - nstates->updated = false; - - for (i = 0; i < numparts; ++i) { - downfxn = handl->partitions[i]->inappdownfxn; - if (downfxn) { - res += downfxn(lstates, rstates, nstates, handl->partitions[i]); - } - downfxn = NULL; - } - - return res; -} - - -int mpl_second_up_recon -(const int node_id, const int left_id, const int right_id, const int anc_id, - Morphy m) -{ - if (!m) { - return ERR_UNEXP_NULLPTR; - } - - Morphyp handl = (Morphyp)m; - MPLndsets* nstates = handl->statesets[node_id]; - MPLndsets* lstates = handl->statesets[left_id]; - MPLndsets* rstates = handl->statesets[right_id]; - MPLndsets* astates = handl->statesets[anc_id]; - - int i = 0; - int res = 0; - int numparts = mpl_get_numparts(handl); - MPLupfxn upfxn = NULL; - - nstates->updated = false; - - for (i = 0; i < numparts; ++i) { - upfxn = handl->partitions[i]->inappupfxn; - if (upfxn) { - res += upfxn(lstates, rstates, nstates, astates, - handl->partitions[i]); - } - } - - return res; -} - -int mpl_update_tip(const int tip_id, const int anc_id, Morphy m) -{ - if (!m) { - return ERR_UNEXP_NULLPTR; - } - - Morphyp handl = (Morphyp)m; - MPLndsets* tipset = handl->statesets[tip_id]; - MPLndsets* ancset = handl->statesets[anc_id]; - - int i = 0; - int numparts = mpl_get_numparts(handl); - MPLtipfxn tipfxn = NULL; - - tipset->updated = false; - - for (i = 0; i < numparts; ++i) { - tipfxn = handl->partitions[i]->tipupdate; - tipfxn(tipset, ancset, handl->partitions[i]); - } - - - return ERR_NO_ERROR; -} - - -int mpl_finalize_tip(const int tip_id, const int anc_id, Morphy m) -{ - if (!m) { - return ERR_UNEXP_NULLPTR; - } - - Morphyp handl = (Morphyp)m; - MPLndsets* tipset = handl->statesets[tip_id]; - MPLndsets* ancset = handl->statesets[anc_id]; - - int i = 0; - int numparts = mpl_get_numparts(handl); - MPLtipfxn tipfxn = NULL; - - tipset->updated = false; - - for (i = 0; i < numparts; ++i) { - tipfxn = handl->partitions[i]->tipfinalize; - if (tipfxn) { - tipfxn(tipset, ancset, handl->partitions[i]); - } - } - - - return ERR_NO_ERROR; -} - - -int mpl_update_lower_root(const int l_root_id, const int root_id, Morphy m) -{ - if (!m) { - return ERR_UNEXP_NULLPTR; - } - - Morphyp handl = (Morphyp)m; - MPLndsets* lower = handl->statesets[l_root_id]; - MPLndsets* upper = handl->statesets[root_id]; - MPLpartition** parts = handl->partitions; - - int i = 0; - int numparts = mpl_get_numparts(handl); - - for (i = 0; i < numparts; ++i) { - if (!parts[i]->isNAtype) { - mpl_update_root(lower, upper, parts[i]); - } else { - mpl_update_NA_root(lower, upper, parts[i]); - } - } - - return ERR_NO_ERROR; -} - -int mpl_do_tiproot(const int tip_id, const int node_id, Morphy m) -{ - if (!m) { - return ERR_UNEXP_NULLPTR; - } - - Morphyp handl = (Morphyp)m; - MPLndsets* lower = handl->statesets[tip_id]; - MPLndsets* upper = handl->statesets[node_id]; - MPLpartition** parts = handl->partitions; - - MPLtipfxn tiprootfxn = NULL; - int i = 0; - int numparts = mpl_get_numparts(handl); - int res = 0; - - lower->updated = false; - - for (i = 0; i < numparts; ++i) { - - tiprootfxn = parts[i]->tiproot; - res += tiprootfxn(lower, upper, parts[i]); - } - - return res; -} - - -int mpl_finalize_tiproot(const int tip_id, const int node_id, Morphy m) -{ - if (!m) { - return ERR_UNEXP_NULLPTR; - } - - Morphyp handl = (Morphyp)m; - MPLndsets* lower = handl->statesets[tip_id]; - MPLndsets* upper = handl->statesets[node_id]; - MPLpartition** parts = handl->partitions; - - MPLtipfxn tiprootfxn = NULL; - int i = 0; - int numparts = mpl_get_numparts(handl); - int res = 0; - - lower->updated = false; - - for (i = 0; i < numparts; ++i) { - if (handl->partitions[i]->isNAtype == true) { - tiprootfxn = parts[i]->tiprootfinal; - res += tiprootfxn(lower, upper, parts[i]); - } - } - - return res; -} - -int mpl_na_tiproot_recalculation(const int tip_id, const int node_id, Morphy m) -{ - if (!m) { - return ERR_UNEXP_NULLPTR; - } - - Morphyp handl = (Morphyp)m; - MPLndsets* lower = handl->statesets[tip_id]; - MPLndsets* upper = handl->statesets[node_id]; - MPLpartition** parts = handl->partitions; - - MPLtipfxn tiprootfxn = NULL; - int i = 0; - int numparts = mpl_get_numparts(handl); - int res = 0; - - lower->updated = false; - - for (i = 0; i < numparts; ++i) { - if (handl->partitions[i]->isNAtype == true) { - tiprootfxn = parts[i]->tiprootrecalc; - res += tiprootfxn(lower, upper, parts[i]); - } - } - - return res; -} - -int mpl_na_tiproot_final_recalculation -(const int tip_id, const int node_id, Morphy m) -{ - if (!m) { - return ERR_UNEXP_NULLPTR; - } - - Morphyp handl = (Morphyp)m; - MPLndsets* lower = handl->statesets[tip_id]; - MPLndsets* upper = handl->statesets[node_id]; - MPLpartition** parts = handl->partitions; - - MPLtipfxn tiprootfxn = NULL; - int i = 0; - int numparts = mpl_get_numparts(handl); - int res = 0; - - lower->updated = false; - - lower->steps_to_recall = 0; - - for (i = 0; i < numparts; ++i) { - if (handl->partitions[i]->isNAtype == true) { - tiprootfxn = parts[i]->tiprootupdaterecalc; - res += tiprootfxn(lower, upper, parts[i]); - } - } - - return res; -} - -int mpl_na_first_down_recalculation -(const int node_id, const int left_id, const int right_id, Morphy m) -{ - if (!m) { - return ERR_UNEXP_NULLPTR; - } - - Morphyp handl = (Morphyp)m; - MPLndsets* nstates = handl->statesets[node_id]; - MPLndsets* lstates = handl->statesets[left_id]; - MPLndsets* rstates = handl->statesets[right_id]; - - int i = 0; - int numparts = mpl_get_numparts(handl); - MPLdownfxn downfxn = NULL; - - nstates->updated = false; - - for (i = 0; i < numparts; ++i) { - if (handl->partitions[i]->isNAtype == true) { - downfxn = handl->partitions[i]->downrecalc1; - downfxn(lstates, rstates, nstates, handl->partitions[i]); - } - } - - return ERR_NO_ERROR; -} - - -int mpl_na_first_up_recalculation -(const int node_id, const int left_id, const int right_id, const int anc_id, - Morphy m) -{ - if (!m) { - return ERR_UNEXP_NULLPTR; - } - - Morphyp handl = (Morphyp)m; - MPLndsets* nstates = handl->statesets[node_id]; - MPLndsets* lstates = handl->statesets[left_id]; - MPLndsets* rstates = handl->statesets[right_id]; - MPLndsets* astates = handl->statesets[anc_id]; - - int i = 0; - int res = 0; - int numparts = mpl_get_numparts(handl); - MPLupfxn upfxn = NULL; - - nstates->updated = false; - - for (i = 0; i < numparts; ++i) { - if (handl->partitions[i]->isNAtype == true) { - upfxn = handl->partitions[i]->uprecalc1; - upfxn(lstates, rstates, nstates, astates, handl->partitions[i]); - } - } - - return res; -} - - -int mpl_na_second_down_recalculation -(const int node_id, const int left_id, const int right_id, Morphy m) -{ - if (!m) { - return ERR_UNEXP_NULLPTR; - } - - Morphyp handl = (Morphyp)m; - MPLndsets* nstates = handl->statesets[node_id]; - MPLndsets* lstates = handl->statesets[left_id]; - MPLndsets* rstates = handl->statesets[right_id]; - - int i = 0; - int res = 0; - int numparts = mpl_get_numparts(handl); - MPLdownfxn downfxn = NULL; - - nstates->updated = false; - nstates->steps_to_recall = 0; - - for (i = 0; i < numparts; ++i) { - if (handl->partitions[i]->isNAtype == true) { - downfxn = handl->partitions[i]->inappdownrecalc2; - res += downfxn(lstates, rstates, nstates, handl->partitions[i]); - } - } - - return res; -} - - -int mpl_na_second_up_recalculation -(const int node_id, const int left_id, const int right_id, const int anc_id, - Morphy m) -{ - if (!m) { - return ERR_UNEXP_NULLPTR; - } - - Morphyp handl = (Morphyp)m; - MPLndsets* nstates = handl->statesets[node_id]; - MPLndsets* lstates = handl->statesets[left_id]; - MPLndsets* rstates = handl->statesets[right_id]; - MPLndsets* astates = handl->statesets[anc_id]; - - int i = 0; - int res = 0; - int numparts = mpl_get_numparts(handl); - MPLupfxn upfxn = NULL; - - nstates->updated = false; - nstates->steps_to_recall = 0; - - for (i = 0; i < numparts; ++i) { - if (handl->partitions[i]->isNAtype == true) { - upfxn = handl->partitions[i]->inapuprecalc2; - res += upfxn(lstates, rstates, nstates, astates, handl->partitions[i]); - } - } - - return res; -} - - -int mpl_lower_root_recalculation(const int l_root_id, const int root_id, Morphy m) -{ - if (!m) { - return ERR_UNEXP_NULLPTR; - } - - Morphyp handl = (Morphyp)m; - MPLndsets* lower = handl->statesets[l_root_id]; - MPLndsets* upper = handl->statesets[root_id]; - MPLpartition** parts = handl->partitions; - - int i = 0; - int numparts = mpl_get_numparts(handl); - - for (i = 0; i < numparts; ++i) { - if (parts[i]->isNAtype) { - mpl_update_NA_root_recalculation(lower, upper, parts[i]); - } - } - - return ERR_NO_ERROR; -} - - -int mpl_na_update_tip(const int tip_id, const int anc_id, Morphy m) -{ - if (!m) { - return ERR_UNEXP_NULLPTR; - } - - Morphyp handl = (Morphyp)m; - MPLndsets* tipset = handl->statesets[tip_id]; - MPLndsets* ancset = handl->statesets[anc_id]; - - int i = 0; - int numparts = mpl_get_numparts(handl); - MPLtipfxn tipfxn = NULL; - - tipset->updated = false; - - for (i = 0; i < numparts; ++i) { - if (handl->partitions[i]->isNAtype == true) { - tipfxn = handl->partitions[i]->tipupdaterecalc; - tipfxn(tipset, ancset, handl->partitions[i]); - } - } - - - return ERR_NO_ERROR; -} - -int mpl_get_step_recall(const int node_id, Morphy m) -{ - if (!m) { - return ERR_UNEXP_NULLPTR; - } - - Morphyp handl = (Morphyp)m; - - int ret = handl->statesets[node_id]->steps_to_recall; - handl->statesets[node_id]->steps_to_recall = 0; - - return ret; - -} - -int mpl_get_insertcost -(const int srcID, const int tgt1ID, const int tgt2ID, const bool max, - const int cutoff, Morphy m) -{ - if (!m) { - return ERR_UNEXP_NULLPTR; - } - - Morphyp handl = (Morphyp)m; - MPLndsets* srcset = handl->statesets[srcID]; - MPLndsets* tgt1set = handl->statesets[tgt1ID]; - MPLndsets* tgt2set = handl->statesets[tgt2ID]; - - int i = 0; - int res = 0; - int numparts = mpl_get_numparts(handl); - MPLloclfxn loclfxn = NULL; - - for (i = 0; i < numparts; ++i) { - handl->partitions[i]->nNAtoupdate = 0; - loclfxn = handl->partitions[i]->loclfxn; - res += loclfxn(srcset, tgt1set, tgt2set, handl->partitions[i], cutoff, max); - loclfxn = NULL; - } - - return res; -} - - -int mpl_check_reopt_inapplics(Morphy m) -{ - if (!m) { - return ERR_UNEXP_NULLPTR; - } - - Morphyp mi = (Morphyp)m; - int n = 0; - int i = 0; - for (i = 0; i < mi->numparts; ++i) { - if (mi->partitions[i]->isNAtype == true) { - n += mi->partitions[i]->nNAtoupdate; - } - } - - return n; -} - -bool mpl_check_updated(const int node_id, Morphy m) -{ - if (!m) { - return ERR_UNEXP_NULLPTR; - } - - Morphyp mi = (Morphyp)m; - - return mi->statesets[node_id]->updated; -} - -int mpl_restore_original_sets(const int node_id, Morphy m) -{ - if (m == NULL) { - return ERR_UNEXP_NULLPTR; - } - - Morphyp mi = (Morphyp)m; - int i = 0; - int k = 0; - - for (i = 0; i < mi->numparts; ++i) { - if (mi->partitions[i]->isNAtype) { - - /* Set any flags or temp variables back to defaults */ - mi->statesets[node_id]->updated = false; - mi->statesets[node_id]->steps_to_recall = 0; - - /* Restore the original sets */ - for (k = 0; k < mi->partitions[i]->ncharsinpart; ++k) { - - int j = 0; - j = mi->partitions[i]->charindices[k]; - - mi->statesets[node_id]->downpass1[j] - = mi->statesets[node_id]->temp_downpass1[j]; - mi->statesets[node_id]->uppass1[j] - = mi->statesets[node_id]->temp_uppass1[j]; - mi->statesets[node_id]->downpass2[j] - = mi->statesets[node_id]->temp_downpass2[j]; - mi->statesets[node_id]->uppass2[j] - = mi->statesets[node_id]->temp_uppass2[j]; - mi->statesets[node_id]->subtree_actives[j] - = mi->statesets[node_id]->temp_subtr_actives[j]; - } - } - } - - return ERR_NO_ERROR; -} - - -unsigned int mpl_get_packed_states -(const int nodeID, const int character, const int passnum, const Morphy m) -{ - if (!m) { - return ERR_UNEXP_NULLPTR; - } - - Morphyp mi = (Morphyp)m; - - if (passnum == 1) { - return (int)mi->statesets[nodeID]->downpass1[character]; - } - else if (passnum == 2) { - return (int)mi->statesets[nodeID]->uppass1[character]; - } - else if (passnum == 3) { - return (int)mi->statesets[nodeID]->downpass2[character]; - } - else if (passnum == 4) { - return (int)mi->statesets[nodeID]->uppass2[character]; - } - - return ERR_BAD_PARAM; -} - -const char* mpl_get_stateset -(const int nodeID, const int character, const int passnum, Morphy m) -{ - MPLstate result = mpl_get_packed_states(nodeID, character, passnum, m); - char* ret = mpl_translate_state2char(result, (Morphyp)m); - - Morphyp mi = (Morphyp)m; - - - mpl_allocate_stset_stringptrs(mpl_get_num_charac(m), mi->statesets[nodeID]); - - if (passnum == 1) { - if (mi->statesets[nodeID]->downp1str[character]) { - free(mi->statesets[nodeID]->downp1str[character]); - } - mi->statesets[nodeID]->downp1str[character] = ret; - } - else if (passnum == 2) { - if (mi->statesets[nodeID]->upp1str[character]) { - free(mi->statesets[nodeID]->upp1str[character]); - } - mi->statesets[nodeID]->upp1str[character] = ret; - } - else if (passnum == 3) { - if (mi->statesets[nodeID]->downp2str[character]) { - free(mi->statesets[nodeID]->downp2str[character]); - } - mi->statesets[nodeID]->downp2str[character] = ret; - } - else if (passnum == 4) { - if (mi->statesets[nodeID]->upp2str[character]) { - free(mi->statesets[nodeID]->upp2str[character]); - } - mi->statesets[nodeID]->upp2str[character] = ret; - } - - return ret; -} diff --git a/src/mpl.h b/src/mpl.h deleted file mode 100644 index dac0d153d..000000000 --- a/src/mpl.h +++ /dev/null @@ -1,827 +0,0 @@ - /*! - @file mpl.h - - @brief Defines the Morphy Phylogenetic Library API: a library for phylogenetic - computation accommodating morphological character hierarchies. - - Copyright (C) 2017 Martin D. Brazeau - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - - @discussion This header includes all the externally exported definitions and - function prototypes. A calling program creates an instance of a Morphy object - and interacts with its elements through the functions described in this - interface. The Morphy object contains no tree objects, but requires a - pre-specified list of indices (integers) corresponding to the node indices in - the calling program. Morphy will not keep track of the relationships between - the nodes, and it is up to the caller to keep track of these. Each character - *must* be assigned a type, and Morphy will make no default assumptions. Once - one or more characters are assigned a function type (which creates internal - partitions), and a postorder list of nodes is known, then the library functions - can be called to reconstruct state sets and deliver length estimates for each - node. - - Morphy will provide functions for local reoptimisation, partial reoptimisation - and optimisation of subtrees. - - */ - -#ifndef mpl_h -#define mpl_h - - -#ifdef __cplusplus - extern "C" { -#endif /*__cplusplus */ - -#include -#include "mplerror.h" - -typedef void* Morphy; - -typedef enum { - - NONE_T = 0, - FITCH_T = 1, - WAGNER_T = 2, - DOLLO_T = 3, - IRREVERSIBLE_T = 4, - USERTYPE_T = 5, - - MAX_CTYPE - -} MPLchtype; - -typedef enum { - - GAP_INAPPLIC, - GAP_MISSING, - GAP_NEWSTATE, - - GAP_MAX - -} MPLgap_t; - - /* Public functions */ - - /*! - - @brief Creates a new instance of a Morphy object - - @discussion Creates a new empty Morphy object. All fields are unpopulated and - uninitialised. - - @return A void pointer to the Morphy instance. NULL if unsuccessful. - - */ -Morphy mpl_new_Morphy - - (void); - - - /*! - - @brief Destroys an instance of a Morphy object. - - @discussion Destroys an instance of the Morphy object, calling all destructors - for internal object completely returning the memory to the system. - - @param m A Morphy object to be destroyed. - - @return A Morphy error code. - - */ -int mpl_delete_Morphy - - (Morphy m); - - -/*! - - @brief Sets up the dimensions of the dataset. - - @discussion Provides initial dimensions for the dataset, which will constrain - any input matrix supplied to Morphy. - - @param ntax The number of taxa (or tips/terminals). - - @param nchar The number of characters (i.e. transformation series) in the - data set. - - @param m An instance of the Morphy object. - - @return Morphy error code. - - */ -int mpl_init_Morphy - - (const int ntax, - const int nchar, - Morphy m); - - -/*! - - @brief Retrieve the number of taxa (rows) in the dataset. - - @discussion Retrieves the number of taxa (rows) in the dataset. - - @param m An instance of the Morphy object. - - @return The number of taxa if success, otherwise an error code. - - */ -int mpl_get_numtaxa - - (Morphy m); - - -/*! - - @brief Retrieve the number of taxa (rows) in the dataset. - - @discussion Retrieves the number of taxa (rows) in the dataset. - - @param m An instance of the Morphy object. - - @return The number of taxa if success, otherwise an error code. - - */ -int mpl_get_num_charac - - (Morphy m); - - -/*! - - @brief Sets the number of internal nodes in the dataset - - @discussion This specifies the number of internal nodes over which - reconstruction sets need to be made. It is up to the caller to ensure the - correct number of nodes and the relationships between them. - - @param nnodes The desired number of internal nodes. - - @param m An instance of the Morphy object - - @return A Morphy error code. - -*/ -int mpl_set_num_internal_nodes - - (const int nnodes, - Morphy m); - -/*! - - @brief Gets the number of internal nodal reconstruction sets being used by - MorphyLib. - - @discussion Gets the number of internal nodal reconstruction sets being used by - MorphyLib. - - @param m An instance of the Morphy object. - - @return The number of internal nodes. - -*/ -int mpl_get_num_internal_nodes - - (Morphy m); - -/*! - - @brief Attach a caller-specified list of symbols. - - @discussion Allows the caller to specify a list of symbols in the data matrix, - otherwise, the symbols list used by Morphy will be extracted from the matrix. - The symbols list must match the symbols provided in the matrix. When Morphy - extracts symbols from the matrix, their ordering is alphanumeric, according to - their ASCII codes (i.e. "+0123...ABCD...abcd..."). Loading a user-specified - symbols list will override this ordering. Symbols loaded in either the list or - the matrix must be valid Morphy character state symbols as defined in the - statedata.h header file. - - @param symbols A C-style (i.e. NULL-terminated) string of valid state symbols. - - @param m An instance of the Morphy object. - - @return Morphy error code. - - */ -int mpl_attach_symbols - - (const char* symbols, - Morphy m); - - -/*! - - @brief Retrieves the current list of symbols. - - @discussion Returns a pointer to the string of character state symbols - currently being used by Morphy (i.e. either the list of symbols extracted - from the matrix, or the caller-specified values). - - @param m An instance of the Morphy object. - - @return A C-style (null-terminated) string of the character state symbols being - used. NULL if failure. - - */ -char* mpl_get_symbols - - (const Morphy m); - - -/*! - - @brief Attach raw character state data (i.e. tip data). - - - @discussion Attaches a raw data character state matrix in the form of a C-style - (i.e. NULL-terminated string). This can be the matrix block extracted from a - Nexus file or an xread table format. The matrix should contain no terminal or - tip labels. - - @param rawmatrix C-style string corresponding to the tip data. - - @param m An instance of the Morphy object. - - @return Morphy error code. - - */ -int mpl_attach_rawdata - - (const char* rawmatrix, - Morphy m); - - -/*! - - @brief Deletes the caller-input data - - @discussion Deletes all of the user-input data and restores all parameters to - their original values, except for the dimensions of the matrix. - - @param m An instance of the Morphy object. - - @return Morphy error code. -*/ -int mpl_delete_rawdata - - (Morphy m); - - -int mpl_set_gap_symbol - - (const char gapsymb, - Morphy m); - - -int mpl_set_missing_symbol - - (const char missymb, - Morphy m); - - -/*! - - @brief Commits parameters prior to nodal set calculations. - - @discussion Once the caller is satisfied with the setup of types, weights, and - partitioning, this function must be called, thereby committing the parameters - until any changes are made. If no character types have been assigned, the - function will fail with an error code. - - @param m An instance of the Morphy object. - - @return A Morphy error code. -*/ -int mpl_apply_tipdata - - (Morphy m); - - -int mpl_incl_charac - - (const int charID, - Morphy m); - - -int mpl_excl_charac - - (const int charID, - Morphy m); - - -/*! - - @brief Sets the weight for a specified character. - - @discussion Sets a weight for a specified character. The function takes a - floating point value. However, in the current implementation, fractional values - will be interpreted and estimated using an approximation of the rational - factors. In the current version, MorphyLib uses this method to circumvent any - floating point calculations that aren't absolutely necessary. - - @param charID The index of the character to be weighted. - - @param weight The weight requested for the character. - - @param m An instance of the Morphy object. - - @return A Morphy error code. - - */ -int mpl_set_charac_weight - - (const int charID, - const double weight, - Morphy m); - -/* TODO: Document */ -unsigned long mpl_get_charac_weight - - (double* weight, - const int char_id, - const Morphy m); - -/*! - - @brief Sets a character's parsimony function type - - @discussion Set the parsimony function type to one defined in the morphydefs.h - header file. Setting the character to type NONE_T will also cause it to be - excluded from any further calculations. - - @param charID The index of the character (transformation series) as defined in - the input matrix. - - @param chtype The parsimony function type as defined in morphydefs.h - - @param m An instance of the Morphy object. - - @return A Morphy error code. - - */ -int mpl_set_parsim_t - - (const int charID, - const MPLchtype chtype, - Morphy m); - - -/*! - - @brief Tells MorphyLib how to treat the gap symbol. - - @discussion The caller can specify the type of gap handling to use before the - tipdata are applied. The options are documented in the morphydefs.h header file - but include at least GAP_INAPPLIC, GAP_MISSING, and GAP_NEWSTATE to specify - inapplicable, missing, or new state values respectively. These values are - applied to all characters for which they are appropriate. - - @param gaptype The type of gap treatment to be applied (documented in - morphydefs.h). - - @param m An instance of the Morphy object. - - @return A Morphy error code. - -*/ -int mpl_set_gaphandl - - (const MPLgap_t gaptype, - Morphy m); - -/*! - - @brief Returns the type of gap handling method currently in effect. - - @discussion Returns the type of gap handling method currently in effect. The - methods are defined in the morphydefs.h file. - - @param m An instance of the Morphy object. - - @return A Morphy error code. - -*/ -int mpl_query_gaphandl - - (Morphy m); - - -/*! - - @brief Reconstructs the first (downpass) nodal reconstructions - - @discussion Reconstructs the preliminary nodal set for all characters for a - particular node. This function is called over a postorder sequence of internal - nodes where left and right descendants are known. - - Because this function needs to be fairly high-performance, it does not do much - checking for parameter validity, thus unsafe usage of this function might not - be caught. It is up to calling functions to ensure that the appropriate - parameters have been set before use. - - @param node_id The index of the node being reconstructed. - - @param left_id The index of the left descendant. - - @param right_id The index of the right descendant. - - @param m An instance of the Morphy object. - - @return The integral parsimony length (right now) - - */ -int mpl_first_down_recon - - (const int node_id, - const int left_id, - const int right_id, - Morphy m); - - -/*! - - @brief Reconstructs the second (uppass) nodal reconstructions. - - @discussion Reconstructs second-pass nodal sets. For normal (all-applicable) - characters, this is the final pass. This function is called over a preorder - sequence of nodes where left, right, and ancestral nodes are known. - - Because this function needs to be fairly high-performance, it does not do much - checking for parameter validity, thus unsafe usage of this function might not - be caught. It is up to calling functions to ensure that the appropriate - parameters have been set before use. - - @param node_id The index of the node being reconstructed. - - @param left_id The index of the left descendant. - - @param right_id The index of the right descendant. - - @param anc_id The index of the immediate ancestor of the node. - - @param m An instance of the Morphy object. - - @return A null value (for now). - */ -int mpl_first_up_recon - (const int node_id, - const int left_id, - const int right_id, - const int anc_id, - Morphy m); - - -/*! - - @brief Performs the second nodal reconstructions for characters with - inapplicability. - - @discussion Updates the nodal sets that had ambiguous unions with the - inapplicable state and calculates steps involving applicable states after - the update. - - Because this function needs to be fairly high-performance, it does not do much - checking for parameter validity, thus unsafe usage of this function might not - be caught. It is up to calling functions to ensure that the appropriate - parameters have been set before use. - - @param node_id The index of the node being reconstructed. - - @param left_id The index of the left descendant. - - @param right_id The index of the right descendant. - - @param m An instance of the Morphy object. - - @return The integral parsimony length (right now) - */ -int mpl_second_down_recon - - (const int node_id, - const int left_id, - const int right_id, - Morphy m); - - -/*! - - @brief Finalises the ancestral state reconstructions for characters with - inapplicable values. - - @discussion Finalises the nodal sets for any characters that may have involved - the inapplicable token and counts excess regions of applicability at nodes - having at least two descendant subtrees that possess any applicable characters. - - Because this function needs to be fairly high-performance, it does not do much - checking for parameter validity, thus unsafe usage of this function might not - be caught. It is up to calling functions to ensure that the appropriate - parameters have been set before use. - - @param node_id The index of the node being reconstructed. - - @param left_id The index of the left descendant. - - @param right_id The index of the right descendant. - - @param anc_id The index of the immediate ancestor of the node. - - @param m An instance of the Morphy object. - - @return The integral parsimony length (for now) - */ -int mpl_second_up_recon - - (const int node_id, - const int left_id, - const int right_id, - const int anc_id, - Morphy m); - - -/*! - - @brief Initial update of tip values following uppass reconstruction - - @discussion Polymorphic terminal state sets need to be resolved after the - uppass based on descendant state values in order for local reoptimisation - procedures to be accurate and for inapplicable step counting to proceed - accurately. This function calls updaters for the records of states active on - the subtrees, thereby allowing the second downpass to accurately reconstruct - subtree state activity. Missing values are left as-is in characters with - inapplicability, otherwise, final ancestral state reconstructions may be - inaccurate. - - Because this function needs to be fairly high-performance, it does not do much - checking for parameter validity, thus unsafe usage of this function might not - be caught. It is up to calling functions to ensure that the appropriate - parameters have been set before use. - - @param tip_id The index of the tip being updated. - - @param anc_id The index of the tip's immediate ancestor. - - @param m An instance of the Morphy object. - - @return A null value (for now). - */ -int mpl_update_tip - - (const int tip_id, - const int anc_id, - Morphy m); - -/*! - - @brief Finalizes ambiguous or missing values in the tips. - - @discussion Ambiguous terminal state sets need to be resolved after the uppass - based on descendant state values in order for local reoptimisation procedures - to be accurate and for inapplicable step counting to proceed accurately. This - function calls updaters for the records of states active on the subtrees, - thereby allowing local reoptimization functions to accurately predict length - increases when a subtree is added near a tip. - - Because this function needs to be fairly high-performance, it does not do much - checking for parameter validity, thus unsafe usage of this function might not - be caught. It is up to calling functions to ensure that the appropriate - parameters have been set before use. - - @param tip_id The index of the tip being updated. - - @param anc_id The index of the tip's immediate ancestor. - - @param m An instance of the Morphy object. - - @return A null value (for now). - */ -int mpl_finalize_tip - - (const int tip_id, - const int anc_id, - Morphy m); - -/*! - @brief Used to update a root-like tip in an unrooted tree and length added. - - @discussion If using an unrooted tree structure, a tip is commonly used as an - entry point for traversals on the tree. This tip is jointed either as an extra - descendant or the ancestor of the calculation root node in the tree. In these - circumstances, a binary traversal on the tree will not give complete - reconstructions or length counts for the tree. This function is called at the - end of the optimization process and is required for the complete tree length of - an unrooted tree. This function will update the state sets of both nodes - reciprocally. - - @param tip_id An index corresponding to the tip number being updated. - - @param node_id An index of the tip's neighboring internal node. - - @param m An instance of the Morphylib object. - - @return The weighted number of steps (positive) or a negative number - corresponding to a morphylib error code. - */ - -int mpl_do_tiproot - - (const int tip_id, - const int node_id, - Morphy m); - -int mpl_finalize_tiproot - - (const int tip_id, - const int node_id, - Morphy m); -/*! - - @brief Updates the nodal sets for a lower ('dummy') root node - - @discussion If trees are rooted, then Morphy uppass functions - require a lower or 'dummy' root in order to function properly. This - function should be called to set the nodal state sets to the dummy - root. The nodal set will be equal to the set of the root node, unless - there is an ambiguous union of applicable and gap tokens when gaps are - treated as in applicable. In which case, the set union is resolved in - favour of any applicable tokens in the set. - - @param l_root_id The index of the lower root. - - @param root_id The index of the upper root node. - - @return A Morphy error code. - - */ -int mpl_update_lower_root - - (const int l_root_id, - const int root_id, - Morphy m); - - -int mpl_na_first_down_recalculation - - (const int node_id, - const int left_id, - const int right_id, - Morphy m); - - -int mpl_na_first_up_recalculation - - (const int node_id, - const int left_id, - const int right_id, - const int anc_id, - Morphy m); - - -/* Returns number of steps to add */ -int mpl_na_second_down_recalculation - - (const int node_id, - const int left_id, - const int right_id, - Morphy m); - -/* Returns number of steps to add */ -int mpl_na_second_up_recalculation - - (const int node_id, - const int left_id, - const int right_id, - const int anc_id, - Morphy m); - -int mpl_lower_root_recalculation - - (const int l_root_id, - const int root_id, - Morphy m); - -int mpl_na_tiproot_recalculation - - (const int tip_id, - const int node_id, - Morphy m); - -int mpl_na_tiproot_final_recalculation - - (const int tip_id, - const int node_id, - Morphy m); - -int mpl_get_insertcost - - (const int srcID, - const int tgt1ID, - const int tgt2ID, - const bool max, - const int cutoff, - Morphy m); - -int mpl_na_update_tip - - (const int tip_id, - const int anc_id, - Morphy m); - - -int mpl_get_step_recall - - (const int node_id, - Morphy m); - - -/* Indicates whether or not partitions with inapplicable characters need partial - reoptimisation on the target subtree. SHOULD RETURN: Number of characters - needing partial reoptimisation on the subtree. */ -int mpl_check_reopt_inapplics - - (Morphy m); - -bool mpl_check_updated - - (const int node_id, - Morphy m); - -/*! - - @brief Restores original state sets at a node. - - @discussion This function restores the state sets in the tree to the ones - calculated using the initial fullpass optimizations (first, and second down and - up functions). It is used after partial reoptimization of a tree and if the - client program needs to restore the state sets to their original values before - continuing to evaluate proposed insertions. - @param node_id The index value of the node having its state sets restored. - - @param m An instance of the morphylib object. - - @return 0 if success, a morphylib error code if there has been an error. - - */ -int mpl_restore_original_sets - - (const int node_id, - Morphy m); -/*! - - @brief Returns the state set for a character at a given node as set bits in an - unsigned integer. - - @discussion If the caller requires the internal state representation of a nodal - set used by MorphyLib, this function can be called to retrieve it. The caller - needs to specify the node index, the character number, and the pass number - (1-based, because these are not indices in a C array). - - @param nodeID The index of the node set required. - - @param character The character number to be queried. - - @param passnum The traversal iteration corresponding to the set required. These - range from 1 to 4 and represent first downpass, first uppass, second downpass - and second uppass respectively. - - @return An unsigned integer with bits set corresponding to values used by - MorphyLib. - - */ -unsigned -int mpl_get_packed_states - - (const int nodeID, - const int character, - const int passnum, - Morphy m); - - -const char* mpl_get_stateset - - (const int nodeID, - const int character, - const int passnum, - Morphy m); - -#ifdef __cplusplus -} -#endif /*__cplusplus */ - -#endif /* mpl_h */ diff --git a/src/mplerror.h b/src/mplerror.h deleted file mode 100644 index fa28d3315..000000000 --- a/src/mplerror.h +++ /dev/null @@ -1,54 +0,0 @@ -/*! - @file mplerror.h - @brief Error codes and descriptions for MorphyLib. - */ - -#ifndef mplerror_h -#define mplerror_h - -/*! - @typedef MPL_ERR_T - @brief List of error codes. Each error is a negative value. - @discussion These error codes are returned by library interface functions (and - used by some internal functions) to report errors back to the caller. - */ -typedef enum { - - ERR_EX_DATA_CONF = -15, /*! Input conflicts with existing dataset */ - ERR_OUT_OF_BOUNDS = -14, /*! Attempt to index out of bounds of an - array */ - - ERR_CASE_NOT_IMPL = -13, /*! Case not implemented. */ - - ERR_UNKNOWN_CHTYPE = -12, /*! Character type is unknown. It either - exceeds the list of character types or - a user type matrix has not yet been - supplied. */ - - ERR_SYMBOL_MISMATCH = -11, /*! Symbols list and matrix have a mismatch - (i.e. symbol not found).*/ - ERR_MATCHING_PARENTHS = -10, /*! Data input has unexpected non-matching - parentheses.*/ - ERR_ATTEMPT_OVERWRITE = -9, /*! Caller attempted to overwrite a loaded - dataset.*/ - ERR_NO_DIMENSIONS = -8, /*! Function requires pre-specified - dimensions to function properly.*/ - ERR_DIMENS_UNDER = -7, /*! Supplied dimensions underestimate size - of dataset.*/ - ERR_DIMENS_OVER = -6, /*! Supplied dimensions overestimate size of - dataset.*/ - ERR_NO_DATA = -5, /*! No dataset supplied.*/ - - ERR_BAD_MALLOC = -4, /*! Memory allocation failure.*/ - - ERR_BAD_PARAM = -3, /*! Unexpected parameter value passed to - function.*/ - ERR_UNEXP_NULLPTR = -2, /*! Unexpected NULL pointer passed to - function.*/ - ERR_INVALID_SYMBOL = -1, /*! Symbol in dataset or symbol list is not - allowed by Morphy.*/ - ERR_NO_ERROR = 0 /*! No error. Everything went OK.*/ - -} MPL_ERR_T; - -#endif /* mplerror_h */ diff --git a/src/statedata.c b/src/statedata.c deleted file mode 100644 index 85f8652a9..000000000 --- a/src/statedata.c +++ /dev/null @@ -1,738 +0,0 @@ -/* -// statedata.c -// MorPhy2 -// -// Created by mbrazeau on 26/04/2017. -// Copyright © 2017 brazeaulab. All rights reserved. -*/ -#include "mpl.h" -#include "morphydefs.h" -#include "morphy.h" -#include "mplerror.h" -#include "statedata.h" - -char* mpl_skip_closure(const char *closure, const char openc, const char closec) -{ - if (*closure != openc) { - return (char*)ERR_BAD_PARAM; - } - char *ret = (char*)closure; - - do { - ++ret; - if (*ret == closec) { - return ret; - } - } while (*ret); - - return NULL; -} - - -int compare_char_t_states(const void *ptr1, const void *ptr2) -{ - return *(char*)ptr1 - *(char*)ptr2; -} - - -int mpl_compare_symbol_lists(const char* sym1, const char* sym2) -{ - int i = 0; - - for (i = 0; sym1[i]; ++i) { - if (!strchr(sym2, sym1[i])) { - if (!isspace(sym1[i])) { - return 1; - } - } - } - - for (i = 0; sym2[i]; ++i) { - if (!strchr(sym1, sym2[i])) { - if (!isspace(sym2[i])) { - return 1; - } - } - } - - return 0; -} - - -int mpl_assign_symbol_list_from_matrix -(const char *symbs, MPLsymbols* symlist) -{ - assert(symbs && symlist); - - int nsymbs = (int)strlen(symbs); - - ++nsymbs; - symlist->symbolsinmatrix = (char*)calloc(nsymbs, sizeof(char)); - - if (!symlist->symbolsinmatrix) { - return ERR_BAD_MALLOC; - } - - strcpy(symlist->symbolsinmatrix, symbs); - - return ERR_NO_ERROR; -} - - -char *mpl_query_symbols_from_matrix(Morphyp m) -{ - return m->symbols.symbolsinmatrix; -} - - -int mpl_get_states_from_rawdata(Morphyp handl) -{ - - assert(handl); - - int count = 0; - char *rawmatrix = handl->char_t_matrix; - char *current = NULL; - int listmax = MAXSTATES + 1; // +1 for terminal null. - char* statesymbols = (char*)calloc(listmax, sizeof(char));//[listmax]; -// int dbg_loopcount = 0; - - statesymbols[0] = '\0'; - current = rawmatrix; - - do { - if (strchr(VALIDSYMB, *current)) { - - if (strchr(VALID_NEXMAT_PUNC, *current)) { - ++current; - } - if (!strchr(statesymbols, *current) && - strchr(VALID_STATESYMB, *current)) { - // Put in list - statesymbols[count] = *current; - ++count; - statesymbols[count] = '\0'; - } - } - else { - return ERR_INVALID_SYMBOL; - } - - ++current; - - } while (*current); - - // Sort alphanumerically - qsort(statesymbols, strlen(statesymbols), sizeof(char), - compare_char_t_states); - - int numstates = (int)strlen(statesymbols); - mpl_set_numsymbols(numstates, handl); - mpl_assign_symbol_list_from_matrix(statesymbols, &handl->symbols); - free(statesymbols); - return count-1; -} - - -int mpl_set_numsymbols(int numsymb, Morphyp handl) -{ - assert(handl); - handl->symbols.numstates = numsymb; - return ERR_NO_ERROR; -} - - -int mpl_get_numsymbols(Morphyp handl) -{ - assert(handl); - return handl->symbols.numstates; -} - - -int mpl_create_state_dictionary(Morphyp handl) -{ - int i = 0; - int gappush = 0; - int numsymbs = handl->symbols.numstates; - mpl_get_symbols((Morphy)handl); - - if (!handl->symbols.packed) { - - handl->symbols.packed = (MPLstate*)calloc(handl->symbols.numstates, - sizeof(MPLstate)); - if (!handl->symbols.packed) { - return ERR_BAD_MALLOC; - } - } - - if (handl->gaphandl == GAP_INAPPLIC || handl->gaphandl == GAP_NEWSTATE) { - gappush = 1; - } - - for (i = 0; i < numsymbs; ++i) { - handl->symbols.packed[i] = 1 << (i + gappush); - } - - return ERR_NO_ERROR; -} - - -MPLstate mpl_convert_gap_symbol(Morphyp handl, bool over_cutoff) -{ - if (handl->gaphandl == GAP_INAPPLIC) { - if (over_cutoff) { - return NA; - } - else { - return MISSING; - } - } - else if (handl->gaphandl == GAP_NEWSTATE) { - return (MPLstate)1; - } - else if (handl->gaphandl == GAP_MISSING) { - return MISSING; - } - - return ERR_NO_DATA; -} - - -MPLstate mpl_convert_char_to_MPLstate(const char* celldata, Morphyp handl) -{ - int i = 0; - MPLstate result = 0; - - do { - i = 0; - do { - if (*celldata == handl->symbols.statesymbols[i]) { - result |= handl->symbols.packed[i]; - } - ++i; - } while (handl->symbols.statesymbols[i]); - ++celldata; - } while (*celldata); - - return result; -} - -// TODO: Call this function during the 'apply data' routine. -int mpl_convert_cells(Morphyp handl) -{ - - int i = 0; - int j = 0; - int ncols = mpl_get_num_charac((Morphy)handl); - int nrows = mpl_get_numtaxa((Morphy)handl); - MPLmatrix *inmatrix = &handl->inmatrix; - MPLcharinfo* chinfo = handl->charinfo; - MPLcell *cell; - - if (handl->gaphandl == GAP_INAPPLIC) { - mpl_count_gaps_in_columns(handl); - } - - char *celldata = NULL; - - for (i = 0; i < ncols; ++i) { - - for (j = 0; j < nrows; ++j) { - - cell = &inmatrix->cells[j * ncols + i]; - celldata = cell->asstr; - - if (*celldata == handl->symbols.gap) { - - bool over_cutoff = false; - - if (chinfo[i].ninapplics > NACUTOFF) { - over_cutoff = true; - } - - cell->asint = mpl_convert_gap_symbol(handl, over_cutoff); - } - else if (*celldata == handl->symbols.missing) { - cell->asint = MISSING; - } - else { - cell->asint = mpl_convert_char_to_MPLstate(celldata, handl); - } - - } - - } - - return ERR_NO_ERROR; -} - - -void mpl_destroy_symbolset(Morphyp m) -{ - assert(m); - if (m->symbols.statesymbols) { - if (m->symbols.statesymbols == m->symbols.symbolsinmatrix) { - free(m->symbols.statesymbols); - m->symbols.statesymbols = NULL; - m->symbols.symbolsinmatrix = NULL; - } - else { - free(m->symbols.statesymbols); - m->symbols.statesymbols = NULL; - if (m->symbols.symbolsinmatrix) { - free(m->symbols.symbolsinmatrix); - m->symbols.symbolsinmatrix = NULL; - } - } - } - if (m->symbols.packed) { - free(m->symbols.packed); - m->symbols.packed = NULL; - } -} - - -bool mpl_is_valid_matrix_symbol(const char c) -{ - if (strchr(VALID_STATESYMB, c)) { - return true; - } - else if (strchr(VALID_WILDCAR, c)) { - return true; - } - else if (strchr(VALID_NEXMAT_PUNC, c)) { - return true; - } - - return false; -} - - -unsigned long mpl_get_valid_matrix_length(const char* rawmatrix) -{ - unsigned long len = 0; - char* matptr = (char*)rawmatrix; - - do { - if (mpl_is_valid_matrix_symbol(*matptr)) { - ++len; - } - else if (*matptr == '[') { - matptr = mpl_skip_closure(matptr, '[', ']'); - assert(matptr != NULL); - } - ++matptr; - } while (*matptr); - - return len; -} - - -void mpl_copy_valid_matrix_data(char *copy, const char* rawmatrix) -{ - int i = 0; - char* matptr = (char*)rawmatrix; - - do { - if (mpl_is_valid_matrix_symbol(*matptr)) { - copy[i] = *matptr; - ++i; - } - else if (*matptr == '[') { - matptr = mpl_skip_closure(matptr, '[', ']'); - assert(matptr != NULL); - } - ++matptr; - } while (*matptr); - - copy[i-1] = '\0'; -} - - -// Copy the raw matrix, take out whitespace and comments -int mpl_copy_raw_matrix(const char* rawmatrix, Morphyp handl) -{ - unsigned long len = mpl_get_valid_matrix_length(rawmatrix); - - char *matcpy = (char*)calloc(len + 1, sizeof(char)); - - if (!matcpy) { - return ERR_BAD_MALLOC; - } - mpl_copy_valid_matrix_data(matcpy, rawmatrix); - handl->char_t_matrix = matcpy; - return ERR_NO_ERROR; -} - - -int mpl_check_nexus_matrix_dimensions -(char *preproc_matrix, int input_num_taxa, int input_num_chars) -{ - /* An input matrix should not have inline taxon names. This function - * scans each row of the input matrix to determine whether or not the - * number of places in the row corresponds to input number of - * of characters. If the number exceeds the expected number of data - * columns (num_input_chars), then it is inferred that taxon names or - * other extraneous info are included in the matrix. */ - - char* current = NULL; - int matrix_size = 0; - int expected_size = 0; - - expected_size = input_num_chars * input_num_taxa; - - current = preproc_matrix; - assert(current); - - do { - if (strchr(VALID_STATESYMB, *current) - || strchr(VALID_WILDCAR, *current)) { - ++matrix_size; - } - else if (*current == '(' || *current == '{') { - - char* err = 0; - - if (*current == '(') { - err = mpl_skip_closure(current, '(', ')'); - } - else { - err = mpl_skip_closure(current, '{', '}'); - } - if (*err <= 0) { - return ERR_MATCHING_PARENTHS; - } - - current = err; - assert(current != NULL); - ++matrix_size; - } - - ++current; - } while (*current); - - if (matrix_size > expected_size) { - return ERR_DIMENS_UNDER; - } - else if (matrix_size < expected_size) { - return ERR_DIMENS_OVER; - } - - return ERR_NO_ERROR; -} - - -char* mpl_get_preprocessed_matrix(Morphyp handl) -{ - assert(handl); - return handl->char_t_matrix; -} - - -MPLstate mpl_gap_value(Morphyp handl) -{ - switch (mpl_get_gaphandl(handl)) { - case GAP_INAPPLIC: - return NA; - case GAP_MISSING: - return MISSING; - case GAP_NEWSTATE: - return (MPLstate)1; - case GAP_MAX: - return -1; - default: - break; - } - - return -2; -} - -int mpl_init_inmatrix(Morphyp handl) -{ - assert(handl); - MPLmatrix* mat = &handl->inmatrix; - int ntaxa = mpl_get_numtaxa((Morphyp)handl); - int nchar = mpl_get_num_charac((Morphyp)handl); - int nstates = mpl_get_numsymbols(handl); - -// mat->chtypes = (MPLchtype*)calloc(nchar, sizeof(MPLchtype)); -// if (!mat->chtypes) { -// return ERR_BAD_MALLOC; -// } -// -// mat->intweights = (int*)calloc(nchar, sizeof(int)); -// if (!mat->intweights) { -// mpl_delete_mpl_matrix(mat); -// return ERR_BAD_MALLOC; -// } -// -// mat->fltweights = (Mflt*)calloc(nchar, sizeof(Mflt)); -// if (!mat->fltweights) { -// mpl_delete_mpl_matrix(mat); -// return ERR_BAD_MALLOC; -// } - - mat->cells = (MPLcell*)calloc(ntaxa * nchar, sizeof(MPLcell)); - if (!mat->cells) { - mpl_delete_mpl_matrix(mat); - return ERR_BAD_MALLOC; - } - - mat->ncells = ntaxa * nchar; - int i = 0; - - for (i = 0; i < mat->ncells; ++i) { - // MS: Consider case where nstates = 0 and we place a null in asstr[1]. - mat->cells[i].asstr = (char*)calloc((nstates ? nstates + 1 : 2), sizeof(char)); - if (!mat->cells[i].asstr) { - int j = 0; - for (j = 0; j < i; ++j) { - free(mat->cells[i].asstr); - mat->cells[i].asstr = NULL; - } - mpl_delete_mpl_matrix(mat); - return ERR_BAD_MALLOC; - } - } - - return ERR_NO_ERROR; -} - - -int mpl_delete_mpl_matrix(MPLmatrix* m) -{ - if (!m) { - return ERR_BAD_PARAM; - } - - int i = 0; - - if (m->cells) { - for (i = 0; i < m->ncells; ++i) { - if (m->cells[i].asstr) { - free(m->cells[i].asstr); - m->cells[i].asstr = NULL; - } - } - free(m->cells); - m->cells = NULL; - } - -// if (m->chtypes) { -// free(m->chtypes); -// m->chtypes = NULL; -// } -// -// if (m->fltweights) { -// free(m->fltweights); -// m->fltweights = NULL; -// } -// -// if (m->intweights) { -// free(m->intweights); -// m->intweights = NULL; -// } - - return ERR_NO_ERROR; -} - - -MPLmatrix* mpl_get_mpl_matrix(Morphyp m) -{ - return &m->inmatrix; -} - - -int mpl_set_gap_push(Morphyp handl) -{ - MPLgap_t gt = mpl_get_gaphandl(handl); - - if (gt == GAP_INAPPLIC || gt == GAP_NEWSTATE) { - return 1; - } - else if (gt == GAP_MISSING) { - return 0; - } - - return -1; -} - - -int mpl_get_uncorrected_shift_value(char symb, Morphyp handl) -{ - // Gets the raw shift value as determined by the order in the symbols list - assert(symb != DEFAULTGAP && symb != DEFAULTMISSING); - int shift = 0; - char* symbols = mpl_get_symbols((Morphy)handl); - - while (*symbols != symb && *symbols) { - ++symbols; - ++shift; - } - - return shift; -} - - -void mpl_use_symbols_from_matrix(Morphyp handl) -{ - handl->symbols.statesymbols = handl->symbols.symbolsinmatrix; -} - - -int mpl_write_input_rawchars_to_cells(Morphyp handl) -{ - assert(handl); - int i = 0; - int j = 0; -// int rows = mpl_get_numtaxa((Morphyp)handl); -// int cols = mpl_get_num_charac((Morphyp)handl); -// int length = rows * cols; - - char* prpdata = mpl_get_preprocessed_matrix(handl); - - while (*prpdata) { - - if (!strchr(VALID_NEXMAT_PUNC, *prpdata)) { - handl->inmatrix.cells[i].asstr[0] = *prpdata; - handl->inmatrix.cells[i].asstr[1] = '\0'; - } - else { - if (*prpdata == '(') { - j = 0; - ++prpdata; - do { - - handl->inmatrix.cells[i].asstr[j] = *prpdata; - ++j; - ++prpdata; - } while (*prpdata != ')'); - handl->inmatrix.cells[i].asstr[j] = '\0'; - } - - if (*prpdata == '{') { - j = 0; - ++prpdata; - do { - handl->inmatrix.cells[i].asstr[j] = *prpdata; - ++j; - ++prpdata; - } while (*prpdata != '}'); - handl->inmatrix.cells[i].asstr[j] = '\0'; - } - if (*prpdata == ';') { - break; - } - } - - ++i; - ++prpdata; - }; - - //prpdata = mpl_get_preprocessed_matrix(handl); - - return ERR_NO_ERROR; -} - -// TODO: Rename this. -int mpl_preproc_rawdata(Morphyp handl) -{ - int ret = ERR_NO_ERROR; - - mpl_get_states_from_rawdata(handl); - - // If no symbols supplied by the user - if (!mpl_get_symbols((Morphy)handl)) { - // Assign internal symbols to list - mpl_use_symbols_from_matrix(handl); - } - else { - - char *frommatrix = mpl_query_symbols_from_matrix(handl); - char *user = mpl_get_symbols((Morphyp)handl); - - if (mpl_compare_symbol_lists(frommatrix, user)) { - return ERR_SYMBOL_MISMATCH; - } - } - - mpl_init_inmatrix(handl); - - // Now safe to write characters into cells. - mpl_write_input_rawchars_to_cells(handl); - - return ret; -} - -// TODO: This probably needs to be more memory-safe -char *mpl_translate_state2char(MPLstate cstates, Morphyp handl) -{ - int i = 0; - int shift = 0; - int gapshift = 0; - - MPLgap_t gaphandl = mpl_query_gaphandl((Morphyp)handl); - if (gaphandl == GAP_INAPPLIC || gaphandl == GAP_NEWSTATE) { - gapshift = 1; - } - char *res = calloc(MAXSTATES+1, sizeof(char)); - if (!res) { - return NULL; - } - char* symbols = mpl_get_symbols((Morphy)handl); - - if (cstates < (MISSING-NA)) { - while (cstates) { - if (1 & cstates) { - if (shift == 0 && gapshift) { - res[i] = mpl_get_gap_symbol(handl); - } - else { - res[i] = symbols[shift - gapshift]; - } - ++i; - } - cstates = cstates >> 1; - ++shift; - } - } - else { - res[0] = '?'; - } - - return res; -} - -int mpl_init_charac_info(Morphyp handl) -{ - int nchar = mpl_get_num_charac((Morphy)handl); - - if (handl->charinfo) { - free(handl->charinfo); - } - - handl->charinfo = (MPLcharinfo*)calloc(nchar, sizeof(MPLcharinfo)); - if (!handl->charinfo) { - return ERR_BAD_MALLOC; - } - - int i = 0; - for (i = 0; i < nchar; ++i) { - handl->charinfo[i].charindex = i; - handl->charinfo[i].chtype = DEFAULCHARTYPE; - handl->charinfo[i].realweight = 1.0; - handl->charinfo[i].basewt = 1; - handl->charinfo[i].intwt = 1; - } - - return ERR_NO_ERROR; -} - -void mpl_delete_charac_info(Morphyp handl) -{ - assert(handl); - if (!handl->charinfo) { - return; - } - free(handl->charinfo); -} diff --git a/src/statedata.h b/src/statedata.h deleted file mode 100644 index e274f16af..000000000 --- a/src/statedata.h +++ /dev/null @@ -1,51 +0,0 @@ -/* -// statedata.h -// MorPhy2 -// -// Created by mbrazeau on 26/04/2017. -// Copyright © 2017 brazeaulab. All rights reserved. -*/ - -#ifndef statedata_h -#define statedata_h - -#include -#include -#include -#include - - -#define VALID_NEXMAT_PUNC "{}();" -#define VALID_XREAD_MATPUNC "[];" -#define VALID_WILDCAR "-?" -#define VALID_STATESYMB "+0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" -#define VALID_WS "\n\t " -#define VALIDSYMB VALID_NEXMAT_PUNC VALID_XREAD_MATPUNC VALID_WILDCAR \ - VALID_STATESYMB VALID_WS - - -/* Function prototypes */ -int mpl_init_symbolset(Morphyp m); -int mpl_set_numsymbols(int numsymb, Morphyp handl); -int mpl_get_numsymbols(Morphyp handl); -void mpl_destroy_symbolset(Morphyp m); -char* mpl_skip_closure(const char *closure, const char openc, const char closec); -int mpl_compare_symbol_lists(const char* sym1, const char* sym2); -int mpl_assign_symbol_list_from_matrix(const char *symbs, MPLsymbols* symlist); -char* mpl_query_symbols_from_matrix(Morphyp m); -int mpl_get_states_from_rawdata(Morphyp handl); -int mpl_copy_raw_matrix(const char* rawmatrix, Morphyp handl); -int mpl_check_nexus_matrix_dimensions(char *input_matrix, int input_num_taxa, int input_num_chars); -char* mpl_get_preprocessed_matrix(Morphyp handl); -int mpl_write_input_rawchars_to_cells(Morphyp handl); -int mpl_create_state_dictionary(Morphyp handl); -int mpl_convert_cells(Morphyp handl); -int mpl_preproc_rawdata(Morphyp handl); -MPLmatrix* mpl_new_mpl_matrix(const int ntaxa, const int nchar, const int nstates); -int mpl_delete_mpl_matrix(MPLmatrix* m); -MPLmatrix* mpl_get_mpl_matrix(Morphyp m); -char* mpl_translate_state2char(MPLstate cstates, Morphyp handl); -int mpl_init_charac_info(Morphyp handl); -void mpl_delete_charac_info(Morphyp handl); - -#endif /* statedata_h */ diff --git a/src/wagner.c b/src/wagner.c deleted file mode 100644 index 415c672a6..000000000 --- a/src/wagner.c +++ /dev/null @@ -1,121 +0,0 @@ -/* -// wagner.c -// morphylib -// -// Created by mbrazeau on 21/05/2017. -// Copyright © 2017 brazeaulab. All rights reserved. -*/ -#include "mpl.h" -#include "morphydefs.h" -#include "morphy.h" -#include "wagner.h" - -static inline unsigned mpl_closed_interval(MPLstate* res, MPLstate a, MPLstate b) -{ - unsigned steps = 0; - MPLstate c = 0; - - if (b > a) { - c = b; - b = a; - a = c; - } - - *res = a & (-a); - - while(!(*res & b)) { - ++steps; - *res |= a >> steps; - } - - return steps; -} - -int mpl_wagner_downpass -(MPLndsets* lset, MPLndsets* rset, MPLndsets* nset, MPLpartition* part) -{ - int i = 0; - int j = 0; - int steps = 0; - int* indices = part->charindices; - int nchars = part->ncharsinpart; - MPLstate* left = lset->downpass1; - MPLstate* right = rset->downpass1; - MPLstate* n = nset->downpass1; - - unsigned long* weights = part->intwts; - - for (i = 0; i < nchars; ++i) { - - j = indices[i]; - - if (left[j] & right[j]) { - n[j] = left[j] & right[j]; - } - else { - - n[j] = 0; - steps += weights[i] * mpl_closed_interval(&n[j], left[j], right[j]); - } - } - - return steps; -} - -int mpl_wagner_uppass -(MPLndsets* lset, MPLndsets* rset, MPLndsets* nset, MPLndsets* ancset, - MPLpartition* part) -{ - int i = 0; - int j = 0; - int* indices = part->charindices; - int nchars = part->ncharsinpart; - MPLstate* left = lset->downpass1; - MPLstate* right = rset->downpass1; - MPLstate* npre = nset->downpass1; - MPLstate* nfin = nset->uppass1; - MPLstate* anc = ancset->uppass1; - - for (i = 0; i < nchars; ++i) { - - j = indices[i]; - - if ((anc[j] & npre[j]) == anc[j]) { - nfin[j] = anc[j] & npre[j]; - } - else { - MPLstate res = 0; - mpl_closed_interval(&res, left[j], right[j]); - nfin[j] = (res & anc[j]) | npre[j]; - } - - assert(nfin[j]); - } - - return 0; -} - -int mpl_wagner_tip_update -(MPLndsets* tset, MPLndsets* ancset, MPLpartition* part) -{ - int i = 0; - int j = 0; - int* indices = part->charindices; - int nchars = part->ncharsinpart; - - MPLstate* tprelim = tset->downpass1; - MPLstate* tfinal = tset->uppass1; - MPLstate* astates = ancset->uppass1; - - for (i = 0; i < nchars; ++i) { - j = indices[i]; - if (tprelim[j] & astates[j]) { - tfinal[j] = tprelim[j] & astates[j]; - } - else { - tfinal[j] = tprelim[j]; - } - assert(tfinal[j]); - } - return 0; -} diff --git a/src/wagner.h b/src/wagner.h deleted file mode 100644 index 9d6984096..000000000 --- a/src/wagner.h +++ /dev/null @@ -1,19 +0,0 @@ -/* -// wagner.h -// morphylib -// -// Created by mbrazeau on 21/05/2017. -// Copyright © 2017 brazeaulab. All rights reserved. -*/ - -#ifndef wagner_h -#define wagner_h - -int mpl_wagner_downpass -(MPLndsets* lset, MPLndsets* rset, MPLndsets* nset, MPLpartition* part); -int mpl_wagner_uppass -(MPLndsets* lset, MPLndsets* rset, MPLndsets* nset, MPLndsets* ancset, - MPLpartition* part); -int mpl_wagner_tip_update -(MPLndsets* tset, MPLndsets* ancset, MPLpartition* part); -#endif /* wagner_h */ diff --git a/tests/testthat/_problems/test-Morphy-50.R b/tests/testthat/_problems/test-Morphy-50.R deleted file mode 100644 index 565ea24cb..000000000 --- a/tests/testthat/_problems/test-Morphy-50.R +++ /dev/null @@ -1,41 +0,0 @@ -# Extracted from test-Morphy.R:50 - -# prequel ---------------------------------------------------------------------- -library("TreeTools", quietly = TRUE) - -# test ------------------------------------------------------------------------- -constraint <- MatrixToPhyDat(c(a = 1, b = 1, c = 0, d = 0, e = 0, f = 0)) -characters <- MatrixToPhyDat(matrix( - c(0, 1, 1, 1, 0, 0, - 1, 1, 1, 0, 0, 0), ncol = 2, - dimnames = list(letters[1:6], NULL))) -set.seed(0) -ewResults <- Morphy(characters, - PectinateTree(c("a", "b", "f", "d", "e", "c")), - ratchIter = 0, constraint = constraint) -expect_equal(PectinateTree(letters[1:6]), ewResults[[1]]) -expect_equal(c(seed = 0, start = 1, final = 0), - attr(ewResults, "firstHit")) -expect_equal(names(ewResults), "start_1") -expect_equal(PectinateTree(letters[1:6]), - Morphy(characters, concavity = "p", - PectinateTree(c("a", "b", "f", "d", "e", "c")), - ratchIter = 0, constraint = constraint)[[1]]) -expect_equal(PectinateTree(letters[1:6]), - Morphy(characters, concavity = 10, - PectinateTree(c("a", "b", "f", "d", "e", "c")), - ratchIter = 0, constraint = constraint)[[1]]) -dataset <- characters -tree <- PectinateTree(c("a", "c", "f", "d", "e", "b")) -expect_equal(PectinateTree(letters[1:6]), - Morphy(characters, - PectinateTree(c("a", "c", "f", "d", "e", "b")), - ratchIter = 0, constraint = constraint)[[1]]) -dataset <- MatrixToPhyDat(matrix(c(0, 0, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 0, 0, 0), ncol = 2, - dimnames = list(letters[1:7], NULL))) -constraint <- MatrixToPhyDat(matrix(c(0, 0, 1, "?", 1, 1, - 1, 1, 1, 1, 0, 0), ncol = 2, - dimnames = list(letters[1:6], NULL))) -cons <- consensus(Morphy(dataset, constraint = constraint), - rooted = TRUE) diff --git a/tests/testthat/_problems/test-Morphy-53.R b/tests/testthat/_problems/test-Morphy-53.R deleted file mode 100644 index 9a977a663..000000000 --- a/tests/testthat/_problems/test-Morphy-53.R +++ /dev/null @@ -1,48 +0,0 @@ -# Extracted from test-Morphy.R:53 - -# setup ------------------------------------------------------------------------ -library(testthat) -test_env <- simulate_test_env(package = "TreeSearch", path = "..") -attach(test_env, warn.conflicts = FALSE) - -# prequel ---------------------------------------------------------------------- -library("TreeTools", quietly = TRUE) - -# test ------------------------------------------------------------------------- -constraint <- MatrixToPhyDat(c(a = 1, b = 1, c = 0, d = 0, e = 0, f = 0)) -characters <- MatrixToPhyDat(matrix( - c(0, 1, 1, 1, 0, 0, - 1, 1, 1, 0, 0, 0), ncol = 2, - dimnames = list(letters[1:6], NULL))) -set.seed(0) -ewResults <- Morphy(characters, - PectinateTree(c("a", "b", "f", "d", "e", "c")), - ratchIter = 0, constraint = constraint) -expect_equal(PectinateTree(letters[1:6]), ewResults[[1]]) -expect_equal(c(seed = 0, start = 1, final = 0), - attr(ewResults, "firstHit")) -expect_equal(names(ewResults), "start_1") -expect_equal(PectinateTree(letters[1:6]), - Morphy(characters, concavity = "p", - PectinateTree(c("a", "b", "f", "d", "e", "c")), - ratchIter = 0, constraint = constraint)[[1]]) -expect_equal(PectinateTree(letters[1:6]), - Morphy(characters, concavity = 10, - PectinateTree(c("a", "b", "f", "d", "e", "c")), - ratchIter = 0, constraint = constraint)[[1]]) -dataset <- characters -tree <- PectinateTree(c("a", "c", "f", "d", "e", "b")) -expect_equal(PectinateTree(letters[1:6]), - Morphy(characters, - PectinateTree(c("a", "c", "f", "d", "e", "b")), - ratchIter = 0, constraint = constraint)[[1]]) -dataset <- MatrixToPhyDat(matrix(c(0, 0, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 0, 0, 0), ncol = 2, - dimnames = list(letters[1:7], NULL))) -constraint <- MatrixToPhyDat(matrix(c(0, 0, 1, "?", 1, 1, - 1, 1, 1, 1, 0, 0), ncol = 2, - dimnames = list(letters[1:6], NULL))) -cons <- consensus(Morphy(dataset, constraint = constraint), - rooted = TRUE) -expect_true(as.Splits(as.logical(c(0, 0, 1, 1, 1)), letters[c(1:3, 5:6)]) %in% - as.Splits(DropTip(cons, c("d", "g")))) diff --git a/tests/testthat/_problems/test-Morphy-9.R b/tests/testthat/_problems/test-Morphy-9.R deleted file mode 100644 index 623ed9e86..000000000 --- a/tests/testthat/_problems/test-Morphy-9.R +++ /dev/null @@ -1,12 +0,0 @@ -# Extracted from test-Morphy.R:9 - -# prequel ---------------------------------------------------------------------- -library("TreeTools", quietly = TRUE) - -# test ------------------------------------------------------------------------- -skip_if(interactive()) -dataset <- MatrixToPhyDat(c(a = 1, b = 1, c = 0, d = 0, e = 3, f = 3)) -expect_warning(PrepareDataProfile(dataset), - "Can handle max. 2 informative tokens") -expect_warning(Morphy(dataset, concavity = "pr"), - "Can handle max. 2 informative tokens") diff --git a/tests/testthat/_problems/test-iw-scoring-9.R b/tests/testthat/_problems/test-iw-scoring-9.R deleted file mode 100644 index f76aecff6..000000000 --- a/tests/testthat/_problems/test-iw-scoring-9.R +++ /dev/null @@ -1,13 +0,0 @@ -# Extracted from test-iw-scoring.R:9 - -# test ------------------------------------------------------------------------- -library("TreeTools", quietly = TRUE) -data("Lobo", package = "TreeTools") -dataset <- Lobo.phy -tree <- NJTree(dataset) -.IWScore <- function (edge, morphyObjs, weight, minLength, concavity) { - steps <- preorder_morphy_by_char(edge, morphyObjs) - homoplasies <- steps - minLength - fit <- homoplasies / (homoplasies + concavity) - sum(fit * weight) - } diff --git a/tests/testthat/_problems/test-mpl_morphy_objects-44.R b/tests/testthat/_problems/test-mpl_morphy_objects-44.R deleted file mode 100644 index 5e4d9175e..000000000 --- a/tests/testthat/_problems/test-mpl_morphy_objects-44.R +++ /dev/null @@ -1,8 +0,0 @@ -# Extracted from test-mpl_morphy_objects.R:44 - -# test ------------------------------------------------------------------------- -morphyObj <- SingleCharMorphy("1") -on.exit(UnloadMorphy(morphyObj)) -expect_error(morphy_profile(matrix(NA, 10, 2), list(morphyObj), - 1, 1L, matrix(1), 1), - "Number of edges does not match Morphy object dimensions") diff --git a/tests/testthat/test-CustomSearch.R b/tests/testthat/test-CustomSearch.R index 54ee814b5..e1a4cc892 100644 --- a/tests/testthat/test-CustomSearch.R +++ b/tests/testthat/test-CustomSearch.R @@ -27,31 +27,6 @@ test_that("Tree can be found", { expect_false(all.equal(comb11, TreeSearch(random11, dataset = phy11, maxIter = 1000, stopAtPlateau = 1, verbosity = 0))) - - # CollapseNode produces a polytomy; Morphy emits a cli alert about - # collapsing polytomies that we suppress (it is informational, not the - # subject of the test). - mp1 <- RootTree( - suppressMessages( - Morphy(phy11, tree = CollapseNode(random11, 13), - ratchIter = 1, verbosity = 0L) - )[[1]], - "a") - expect_true(all.equal(mp1, comb11)) - expect_true(all.equal( - Morphy(phy11, tree = random11, verbosity = 0L)[[1]], - comb11 - )) - expect_true(all.equal( - Morphy(phy11, random11, ratchIter = 0, verbosity = 0L)[[1]], - comb11 - )) - - # Interestingly, a good example of a case with multiple optima that require - # ratchet to move between - iw <- Morphy(phy11, random11, ratchIter = 1, tbrIter = 5, - concavity = 10, verbosity = 0L)[[1]] - expect_equal_tree(comb11, iw) # TODO: Sectorial Search not working yet! # expect_equal(SectorialSearch(RandomTree(phy11, "a"), phy11, verbosity = -1), comb11) }) @@ -64,8 +39,8 @@ test_that("Tree search finds shortest tree", { start_tree <- TreeTools::RenumberTips(ape::read.tree( text = "(((1, 6), 3), (2, (4, 5)));"), true_tree$tip.label) expect_equal(TreeLength(start_tree, dataset), 6) - morphyObj <- PhyDat2Morphy(dataset) - on.exit(morphyObj <- UnloadMorphy(morphyObj)) + preparedData <- PrepareData(dataset) + on.exit(preparedData <- ReleaseData(preparedData)) # NNI can reach a local optimum that SPR/TBR can escape. # Rooted swappers cannot move the root, so may stay at start-tree score. @@ -104,14 +79,6 @@ test_that("Profile parsimony works in tree search", { random11 <- as.phylo(17905853L, 11, letters[1:11]) # Rooted on "a" - # Use more iterations than necessary locally, as RNG may differ on other - # platforms. - expect_equal_tree(comb11, - Morphy(phy11, c(random11, random11), # multiPhylo - ratchIter = 1, tbrIter = 2, maxHits = 10, - concavity = "profile", verbosity = 0)[[1]]) - - sillyData <- lapply(1:22, function (i) c(rep(0, i - 1), rep(1, 22 - i), rep(1, 22 - i), rep(0, i - 1)))#, sample(2, 20, replace = TRUE)-1)) names(sillyData) <- as.character(1:22) @@ -124,11 +91,11 @@ test_that("Profile parsimony works in tree search", { rTree <- randomTree <- RandomTree(dataset, "1") expect_lte(TreeLength(rTree, readyData), TreeLength(rTree, dataset)) - quickTS <- TreeSearch(rTree, dataset, TreeScorer = MorphyLength, EdgeSwapper = RootedNNISwap, + quickTS <- TreeSearch(rTree, dataset, TreeScorer = EdgeListScore, EdgeSwapper = RootedNNISwap, maxIter = 1600, maxHits = 40, verbosity = 0) expect_equal(42L, attr(quickTS, "score")) - quickFitch <- Ratchet(rTree, dataset, TreeScorer = MorphyLength, suboptimal = 2, + quickFitch <- Ratchet(rTree, dataset, TreeScorer = EdgeListScore, suboptimal = 2, swappers = RootySwappers, ratchHits = 3, searchHits = 15, searchIter = 100, ratchIter = 500, verbosity = 0L) diff --git a/tests/testthat/test-Morphy.R b/tests/testthat/test-Morphy.R deleted file mode 100644 index 1170d774d..000000000 --- a/tests/testthat/test-Morphy.R +++ /dev/null @@ -1,258 +0,0 @@ -library("TreeTools", quietly = TRUE) - -test_that("Profile handles multi-state characters", { - # 3-state char with 6 tips: now natively supported by MaddisonSlatkin - # (feasible for k=3, n=6, threshold=15). No warning or binary reduction. - dataset <- MatrixToPhyDat(c(a = 1, b = 1, c = 0, d = 0, e = 3, f = 3)) - pd <- PrepareDataProfile(dataset) - expect_equal(3L, length(attr(pd, "levels"))) - expect_s3_class(pd, "phyDat") -}) - -test_that("Constraints work", { - # Morphy() emits informational cli messages via message() - # ("Initialized N distinct constraints", "Modifying tree to match - # constraint", ...) that are not under test here. Wrap the whole - # body in suppressMessages() to keep test output clean; warnings and - # errors are still raised normally. Verbose paths are exercised in - # separate tests below. - suppressMessages({ - constraint <- MatrixToPhyDat(c(a = 1, b = 1, c = 0, d = 0, e = 0, f = 0)) - characters <- MatrixToPhyDat(matrix( - c(0, 1, 1, 1, 0, 0, - 1, 1, 1, 0, 0, 0), ncol = 2, - dimnames = list(letters[1:6], NULL))) - set.seed(0) - # Morphy() defaults to verbosity = 3 and prints a banner / score lines to - # stdout. The verbose output is not under test here, so silence it with - # verbosity = 0L. (Verbose paths are exercised separately below.) - ewResults <- Morphy(characters, - PectinateTree(c("a", "b", "f", "d", "e", "c")), - ratchIter = 0, constraint = constraint, - verbosity = 0L) - expect_equal_tree(PectinateTree(letters[1:6]), ewResults[[1]]) - expect_equal(c(seed = 0, start = 1, final = 0), - attr(ewResults, "firstHit")) - expect_equal(names(ewResults), "start_1") - expect_equal_tree(PectinateTree(letters[1:6]), - Morphy(characters, concavity = "p", - PectinateTree(c("a", "b", "f", "d", "e", "c")), - ratchIter = 0, constraint = constraint, - verbosity = 0L)[[1]]) - expect_equal_tree(PectinateTree(letters[1:6]), - Morphy(characters, concavity = 10, - PectinateTree(c("a", "b", "f", "d", "e", "c")), - ratchIter = 0, constraint = constraint, - verbosity = 0L)[[1]]) - # Start tree not consistent with constraint - dataset <- characters - tree <- PectinateTree(c("a", "c", "f", "d", "e", "b")) - expect_equal_tree(PectinateTree(letters[1:6]), - Morphy(characters, - PectinateTree(c("a", "c", "f", "d", "e", "b")), - ratchIter = 0, constraint = constraint, - verbosity = 0L)[[1]]) - - - dataset <- MatrixToPhyDat(matrix(c(0, 0, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 0, 0, 0), ncol = 2, - dimnames = list(letters[1:7], NULL))) - constraint <- MatrixToPhyDat(matrix(c(0, 0, 1, "?", 1, 1, - 1, 1, 1, 1, 0, 0), ncol = 2, - dimnames = list(letters[1:6], NULL))) - # T-039 fixed: column-major indexing in build_constraint + Wagner guards - cons <- consensus(Morphy(dataset, constraint = constraint, - verbosity = 0L), - rooted = TRUE) - # Avoid %in%.Splits — S3 dispatch breaks in testthat's cloned namespace - # (test_check / R CMD check). Compare bipartitions as plain logical vectors. - split_in_splits <- function(sp, table) { - tips <- attr(table, "tip.label") - sp <- as.Splits(sp, tipLabels = tips) - s <- as.logical(as.logical(sp)) # flatten to plain vector - tab <- as.logical(table) - if (!is.matrix(tab)) tab <- matrix(tab, nrow = 1) - any(apply(tab, 1, function(r) all(s == r) || all(s == !r))) - } - expect_true(split_in_splits( - as.Splits(as.logical(c(0, 0, 1, 1, 1)), letters[c(1:3, 5:6)]), - as.Splits(DropTip(cons, c("d", "g"))))) - - expect_true(split_in_splits( - as.Splits(as.logical(c(0, 0, 0, 0, 1, 1)), letters[1:6]), - as.Splits(DropTip(cons, "g")))) - - }) # end suppressMessages -}) - -test_that("Inconsistent constraints fail", { - constraint <- MatrixToPhyDat(matrix( - c(0, 1, 1, 1, 0, 0, - 1, 1, 1, 0, 0, 0), ncol = 2, - dimnames = list(letters[1:6], NULL))) - # Morphy() may emit cli messages before the error fires; suppress so - # they do not leak into testthat output. - expect_error( - suppressMessages( - Morphy(constraint, - PectinateTree(c("a", "b", "f", "d", "e", "c")), - ratchIter = 0, constraint = constraint, - verbosity = 0L) - ) - ) -}) - -test_that("Morphy() times out", { - # Do not run on CRAN: Writing R Extensions discourages testing timings - skip_if(Sys.getenv("GITHUB_PAT") == "") # Run only on GH Actions - - data("congreveLamsdellMatrices", package = "TreeSearch") - dataset <- congreveLamsdellMatrices[[42]] - startTime <- Sys.time() - # Discard verbose progress output — the test is about wall-clock timing. - invisible(capture.output( - Morphy(dataset, ratchIter = 10000, tbrIter = 1, maxHits = 1, - maxTime = 0) - )) - expect_gt(as.difftime(5, units = "secs"), Sys.time() - startTime) -}) - -test_that("Seed trees retained", { - tree1 <- read.tree(text = "(a, (b, (c, (d, (e, f)))));") - tree2 <- read.tree(text = "(a, (b, (c, (f, (e, d)))));") - badTree <- read.tree(text = "(f, (b, (c, (a, (e, d)))));") - dat <- StringToPhyDat("110000 110000 111000 111000 111100 111001", - letters[1:6], byTaxon = FALSE) - # verbosity = 4 deliberately exercises the most verbose printing path, - # which mixes cli messages (stderr) and Rprintf output (stdout). - # Capture both streams so nothing leaks into testthat output, and - # assert that the verbose marker is present so a future change that - # silently breaks the print path would fail this test. - msg_lines <- character() - stdout_lines <- capture.output( - msg_lines <- capture.output( - results <- Morphy(dataset = dat, - tree = c(tree1, tree2, badTree), - ratchIter = 0, verbosity = 4), - type = "message" - ) - ) - all_lines <- c(stdout_lines, msg_lines) - expect_true(any(grepl("TREE SEARCH|Score|Initial score|Starting search", - all_lines))) - expect_equal(attr(results, "firstHit"), - c(seed = 2, start = 0, final = 0)) -}) - -test_that("Mismatched tree/dataset handled with warnings", { - treeAf <- read.tree(text = "(a, (b, (c, (d, (e, f)))));") - treeBg <- read.tree(text = "(g, (b, (c, (d, (e, f)))));") - datAf <- StringToPhyDat("110000 110000 111100 111000", - letters[1:6], byTaxon = FALSE) - datAe <- StringToPhyDat("11000 11000 11110 11100", - letters[1:5], byTaxon = FALSE) - datAg <- StringToPhyDat("1100000 1100000 1111000 1110000", - letters[1:7], byTaxon = FALSE) - - # QP emits cli messages ("Ignoring taxa...", "Initialized N distinct - # constraints") in addition to the R-level warning the tests check - # for. Wrap each call in suppressMessages() to silence the - # informational cli output while preserving warning capture. - QP <- function (...) suppressMessages( - Morphy(..., ratchIter = 0, maxHits = 1, verbosity = 0) - ) - - expect_warning(r1 <- QP(datAf, treeBg)); expect_equal(5, unname(NTip(r1))) - expect_warning(r2 <- QP(datAe, treeAf)); expect_equal(5, unname(NTip(r2))) - expect_warning(r3 <- QP(datAg, treeAf)); expect_equal(6, unname(NTip(r3))) - expect_warning(r4 <- QP(datAf, treeBg, constraint = datAe)); expect_equal(5, unname(NTip(r4))) - expect_equal(6, unname(NTip(QP(datAf, treeAf, constraint = datAe)))) - expect_warning(r5 <- QP(datAf, treeAf, constraint = datAg)); expect_equal(6, unname(NTip(r5))) -}) - -test_that("Root retained if not 1", { - tr <- RootTree(BalancedTree(8), "t5") - dataset <- StringToPhyDat("11000000 11100000 11110000 11111000", - paste0("t", 1:8), byTaxon = FALSE) - - mpt <- Morphy(dataset, tr, verbosity = 0L) - expect_equal(5, mpt[[1]]$edge[14, 2]) -}) - -test_that("Resample() fails and works", { - expect_error(Resample(0)) - dataset <- MatrixToPhyDat(rbind( - a = c(0, 0, 0, 0, 0, 0), - b = c(0, 0, 0, 0, 0, 0), - c = c(1, 1, 0, 0, 0, 1), - d = c(1, 1, 0, 0, 1, 0), - e = c(1, 1, 1, 1, 1, 1), - f = c(1, 1, 1, 1, 1, 1))) - - expect_error(Resample(dataset, method = "ERROR")) - expect_error(Resample(dataset, proportion = 0)) - expect_error(Resample(dataset, proportion = 6 / 7)) - - nRep <- 42L # Arbitrary number to balance runtime vs false +ves & -ves - bal <- as.Splits(BalancedTree(dataset)) - set.seed(6034) # Fix seed: stochastic test has ~13% failure rate without it - - jackTrees <- replicate(nRep, Resample(dataset, NJTree(dataset), verbosity = 0L), - simplify = FALSE) - jackSplits <- as.Splits(unlist(jackTrees, recursive = FALSE)) - jackSupport <- rowSums( - # TODO replace :::.in.Splits with exported %in% - # %in% works when testing file but not entire package - # See https://github.com/r-lib/testthat/issues/1661 - vapply(jackSplits, function(sp) TreeTools:::.in.Splits(bal, sp), logical(3)) - ) - - # Stochastic test — tolerance allows for sampling variability - expect_equal(jackSupport, tolerance = 0.3, - c("8" = 1/2, "9" = 1, "10" = 1/2, "11" = 0)[names(bal)] * - sum(vapply(jackTrees, length, 1L))) - - set.seed(4817) # Separate seed so jackknife changes don't shift bootstrap RNG - bootTrees <- replicate(nRep, Resample(dataset, method = "bootstrap", - verbosity = 0), - simplify = FALSE) - bootSupport <- rowSums(vapply( - unlist(bootTrees, recursive = FALSE), - # TODO replace :::.in.Splits with exported %in% - # %in% works when testing file but not entire package - # See https://github.com/r-lib/testthat/issues/1661 - function(tr) TreeTools:::.in.Splits(bal, as.Splits(tr)), - logical(3) - )) - expect_equal(bootSupport, tolerance = 0.3, - c("8" = 1/2, "9" = 1, "10" = 1/2, "11" = 0)[names(bal)] * - sum(vapply(bootTrees, length, 1L))) - -}) - -test_that("TreeSearch:::.CombineResults() handles duplicates", { - x <- structure( - array(c( - rep(1L, 8), - rep(2L, 8), - rep(3L, 8), - rep(2L, 8), - rep(1L, 8) - ), - dim = c(4, 2, 5)), - firstHit = c(start = 5, test = 0, end = 0) - ) - y <- array(c(rep(1L, 8), - rep(4L, 8), - rep(1L, 8), - rep(4L, 8), - rep(1L, 8)), - dim = c(4, 2, 5) - ) - expect_warning(TreeSearch:::.CombineResults(x, y, stage = "test")) - uX <- structure(unique(x, MARGIN = 3L), - firstHit = c(start = 3, test = 0, end = 0)) - expect_equal(attr(TreeSearch:::.CombineResults(uX, y, stage = "test"), "firstHit"), - c(start = 3, test = 1, end = 0)) - -}) diff --git a/tests/testthat/test-NativeSearch.R b/tests/testthat/test-NativeSearch.R new file mode 100644 index 000000000..e69af9859 --- /dev/null +++ b/tests/testthat/test-NativeSearch.R @@ -0,0 +1,41 @@ +# End-to-end checks of the native custom-search scoring path, including the +# `concavity` parameter (equal weights / implied weights / profile parsimony). + +test_that("TreeSearch() honours concavity (EW / IW / profile)", { + dataset <- TreeSearch::inapplicable.phyData[["Vinther2008"]] + start <- TreeTools::NJTree(dataset) + for (k in list(Inf, 10, "profile")) { + res <- TreeSearch(start, dataset, concavity = k, maxIter = 25L, + maxHits = 4L, verbosity = 0) + expect_s3_class(res, "phylo") + # The reported score is internally consistent with re-scoring under the + # same criterion. + expect_equal(attr(res, "score"), + TreeScore(res, PrepareData(dataset, concavity = k))) + } +}) + +test_that("Ratchet() honours concavity", { + dataset <- TreeSearch::inapplicable.phyData[["Vinther2008"]] + start <- TreeTools::NJTree(dataset) + res <- Ratchet(start, dataset, concavity = 10, + ratchIter = 2, searchIter = 25, searchHits = 4, + ratchHits = 2, verbosity = 0) + expect_s3_class(res, "phylo") + expect_equal(attr(res, "score"), + TreeScore(res, PrepareData(dataset, concavity = 10))) +}) + +test_that("Custom InitializeData ignores concavity", { + # A user-supplied InitializeData receives the dataset unchanged; concavity is + # not threaded into it. + dataset <- TreeSearch::inapplicable.phyData[["Vinther2008"]] + start <- TreeTools::NJTree(dataset) + res <- TreeSearch(start, dataset, concavity = 10, + InitializeData = function(d) PrepareData(d, concavity = Inf), + maxIter = 20L, maxHits = 3L, verbosity = 0) + # Scored under equal weights despite concavity = 10, because the custom + # InitializeData built an EW dataset. + expect_equal(attr(res, "score"), + TreeScore(res, PrepareData(dataset))) +}) diff --git a/tests/testthat/test-PrepareData.R b/tests/testthat/test-PrepareData.R new file mode 100644 index 000000000..c4786927f --- /dev/null +++ b/tests/testthat/test-PrepareData.R @@ -0,0 +1,80 @@ +test_that("PrepareData() validates input", { + expect_error(PrepareData(NA)) + expect_error(PrepareData(structure(list(), class = "phyDat"), concavity = -1)) +}) + +test_that("ReleaseData() / is.ParsimonyData()", { + pd <- TreeTools::MatrixToPhyDat(matrix( + c("-", "-", 0, 0), byrow = TRUE, nrow = 4L, + dimnames = list(letters[1:4], NULL))) + obj <- PrepareData(pd) + expect_true(is.ParsimonyData(obj)) + expect_false(is.ParsimonyData(pd)) + expect_identical(ReleaseData(obj), obj) +}) + +test_that("PrepareData() builds ParsimonyData objects", { + tokens <- matrix(c("-", "-", 0, 0), byrow = TRUE, nrow = 4L, + dimnames = list(letters[1:4], NULL)) + pd <- TreeTools::MatrixToPhyDat(tokens) + obj <- PrepareData(pd) + expect_true(is.ParsimonyData(obj)) + expect_equal(obj[["nTip"]], 4L) + expect_equal(0, RandomTreeScore(obj)) +}) + +test_that("SingleCharData() builds ParsimonyData objects", { + obj <- SingleCharData("-0-0") + expect_true(is.ParsimonyData(obj)) + expect_equal(obj[["nTip"]], 4L) + expect_error(SingleCharData(character(0))) +}) + +test_that("TreeScore() equals TreeLength() (EW, IW, profile)", { + dataset <- TreeSearch::inapplicable.phyData[["Vinther2008"]] + set.seed(1) + tree <- TreeTools::RandomTree(dataset, root = TRUE) + + # Equal weights + expect_equal(TreeScore(tree, PrepareData(dataset)), + TreeLength(tree, dataset)) + # Implied weights (k = 10), simple (non-extended) IW + expect_equal(TreeScore(tree, PrepareData(dataset, concavity = 10)), + TreeLength(tree, dataset, concavity = 10, extended_iw = FALSE)) + # Profile parsimony + expect_equal(TreeScore(tree, PrepareData(dataset, concavity = "profile")), + TreeLength(tree, dataset, concavity = "profile")) +}) + +test_that("Resampling weights change the score", { + # Regression guard: scoring uses the *current* weights, not weights frozen at + # construction. Doubling every weight doubles the score; zeroing one cannot + # increase it. + dataset <- TreeSearch::inapplicable.phyData[["Vinther2008"]] + set.seed(1) + tree <- TreeTools::RandomTree(dataset, root = TRUE) + obj <- PrepareData(dataset) + + full <- TreeScore(tree, obj) + expect_gt(full, 0) + + doubled <- obj + doubled[["weight"]] <- obj[["weight"]] * 2L + expect_equal(TreeScore(tree, doubled), full * 2) + + dropOne <- obj + dropOne[["weight"]] <- c(0L, obj[["weight"]][-1]) + expect_lte(TreeScore(tree, dropOne), full) +}) + +test_that("Deprecated Morphy aliases still work", { + pd <- TreeTools::MatrixToPhyDat(matrix( + c("-", "-", 0, 0), byrow = TRUE, nrow = 4L, + dimnames = list(letters[1:4], NULL))) + expect_warning(obj <- PhyDat2Morphy(pd), "PrepareData") + expect_true(is.ParsimonyData(obj)) + expect_warning(expect_true(is.morphyPtr(obj)), "is.ParsimonyData") + expect_warning(expect_equal(UnloadMorphy(obj), 0L), "ReleaseData") + expect_warning(SingleCharMorphy("-0-0"), "SingleCharData") + expect_error(suppressWarnings(PhyDat2Morphy(pd, "ambiguous"))) +}) diff --git a/tests/testthat/test-RMorphy.R b/tests/testthat/test-RMorphy.R deleted file mode 100644 index 8f4caf016..000000000 --- a/tests/testthat/test-RMorphy.R +++ /dev/null @@ -1,23 +0,0 @@ -test_that("NULL pointers don't cause crash", { - ptr <- mpl_new_Morphy() - expect_equal(0, mpl_delete_Morphy(ptr)) - expect_true(is.na(mpl_delete_Morphy(ptr))) -}) - -test_that("Pointers survive garbage collection", { - ptr <- mpl_new_Morphy() - gc() - expect_equal(0, mpl_delete_Morphy(ptr)) -}) - -test_that("preorder_morphy()", { - library('TreeTools', quietly = TRUE) - tree <- Preorder(RootTree(BalancedTree(6), 1)) - dat <- MatrixToPhyDat(matrix(c(0, 1, 0, 1, 0, 1, - 0, 0, 0, 1, 1, 1), byrow = FALSE, 6, - dimnames = list(TipLabels(6), NULL))) - morphyObj <- PhyDat2Morphy(dat) - on.exit(morphyObj <- UnloadMorphy(morphyObj)) - tree$edge - 1 - expect_equal(4L, TreeSearch:::preorder_morphy(tree$edge, morphyObj)) -}) diff --git a/tests/testthat/test-RandomTreeScore.R b/tests/testthat/test-RandomTreeScore.R index 4fcf880d9..be85d6c7e 100644 --- a/tests/testthat/test-RandomTreeScore.R +++ b/tests/testthat/test-RandomTreeScore.R @@ -1,11 +1,11 @@ -test_that("RandomMorphyTree() errors are handled", { - expect_error(RandomMorphyTree(-1)) - expect_error(RandomMorphyTree(0)) - expect_error(RandomMorphyTree(1)) +test_that("RandomPostorderTree() errors are handled", { + expect_error(RandomPostorderTree(-1)) + expect_error(RandomPostorderTree(0)) + expect_error(RandomPostorderTree(1)) }) test_that("Two tip 'random' tree", { - expect_equal(RandomMorphyTree(2), list(c(2, 2, 2), 0, 1)) + expect_equal(RandomPostorderTree(2), list(c(2, 2, 2), 0, 1)) }) test_that("RandomTreeScore() with phyDat dataset", { @@ -47,23 +47,21 @@ test_that("RandomTreeScore() with larger dataset", { expect_gt(expected, 0) }) -test_that("RandomTreeScore() backward compat with morphyObj", { +test_that("RandomTreeScore() with a ParsimonyData object", { tokens <- matrix(c( 0, "-", "-", 1, 1, 2, 0, "-", "-", 1, 1, 2, 0, "-", "-", 0, 0, 0), byrow = TRUE, nrow = 3L, dimnames = list(letters[1:3], NULL)) - + # One leaf pd <- TreeTools::MatrixToPhyDat(tokens[1, , drop = FALSE]) - morphyObj <- PhyDat2Morphy(pd) - expect_equal(mpl_get_numtaxa(morphyObj), 1L) - expect_equal(RandomTreeScore(morphyObj), 0) - morphyObj <- UnloadMorphy(morphyObj) - + obj <- PrepareData(pd) + expect_equal(obj[["nTip"]], 1L) + expect_equal(RandomTreeScore(obj), 0) + # Three leaves pd <- TreeTools::MatrixToPhyDat(tokens) - morphyObj <- PhyDat2Morphy(pd) - expect_equal(RandomTreeScore(morphyObj), 3L) - morphyObj <- UnloadMorphy(morphyObj) + obj <- PrepareData(pd) + expect_equal(RandomTreeScore(obj), 3L) }) diff --git a/tests/testthat/test-mpl_morphy_objects.R b/tests/testthat/test-mpl_morphy_objects.R deleted file mode 100644 index 3dd0fa809..000000000 --- a/tests/testthat/test-mpl_morphy_objects.R +++ /dev/null @@ -1,54 +0,0 @@ -test_that("PhyDat2Morphy() errors", { - expect_error(PhyDat2Morphy(NA)) -}) - -test_that("UnloadMorphy() errors", { - expect_error(UnloadMorphy(NA)) -}) - -test_that("GapHandler()", { - expect_error(GapHandler(0)) - tokens <- matrix(c("-", "-", 0, 0), byrow = TRUE, nrow = 4L, - dimnames = list(letters[1:4], NULL)) - pd <- TreeTools::MatrixToPhyDat(tokens) - - morphyObj <- PhyDat2Morphy(pd) - expect_equal(0, RandomTreeScore(morphyObj)) - expect_equal("Inapplicable", GapHandler(morphyObj)) - UnloadMorphy(morphyObj) - - morphyObj <- PhyDat2Morphy(pd, "ambigu") - expect_equal(0, RandomTreeScore(morphyObj)) - expect_equal("Missing data", GapHandler(morphyObj)) - UnloadMorphy(morphyObj) - - morphyObj <- PhyDat2Morphy(pd, "eXt") - expect_lt(0, RandomTreeScore(morphyObj)) - expect_equal("Extra state", GapHandler(morphyObj)) - UnloadMorphy(morphyObj) - - morphyObj <- SingleCharMorphy("-0-0", "eXt") - expect_lt(0, RandomTreeScore(morphyObj)) - expect_equal("Extra state", GapHandler(morphyObj)) - UnloadMorphy(morphyObj) - - expect_error(SingleCharMorphy("-0-0", "ERROR")) - expect_error(GapHandler(morphyObj)) -}) - -test_that("morphy_profile fails nicely", { - morphyObj <- SingleCharMorphy("1") - on.exit(UnloadMorphy(morphyObj)) - # The C++ function prints a diagnostic via Rprintf ("N + M != X") - # to stdout before signalling the R-level error. Capture so the - # diagnostic does not leak into testthat output, and assert that - # the diagnostic appeared so the C++ print path is exercised. - stdout_lines <- capture.output( - expect_error( - TreeSearch:::morphy_profile(matrix(NA, 10, 2), list(morphyObj), - 1, 1L, matrix(1), 1), - "Number of edges does not match Morphy object dimensions" - ) - ) - expect_true(any(grepl("!=", stdout_lines))) -}) diff --git a/tests/testthat/test-native-morphy-equivalence.R b/tests/testthat/test-native-morphy-equivalence.R new file mode 100644 index 000000000..96484e43b --- /dev/null +++ b/tests/testthat/test-native-morphy-equivalence.R @@ -0,0 +1,48 @@ +# The native scorer (PrepareData + TreeScore/EdgeListScore) computes the CORRECT +# Brazeau-Guillerme-Smith inapplicable scores -- NOT bit-equivalence with legacy +# MorphyLib, which mis-scored `{1-}` ambiguous-with-inapplicable tokens +# (Lobo pattern 93). + +test_that("PrepareData() builds a ParsimonyData handle", { + data("Lobo", package = "TreeTools") + obj <- PrepareData(Lobo.phy) + expect_true(is.ParsimonyData(obj)) + expect_equal(obj[["nTip"]], length(Lobo.phy)) +}) + +test_that("native TreeScore() equals native TreeLength()", { + data("Lobo", package = "TreeTools") + data("inapplicable.datasets") + datasets <- list(Lobo = Lobo.phy, + CL42 = congreveLamsdellMatrices[[42]], + CL10 = congreveLamsdellMatrices[[10]]) + for (ds in datasets) { + obj <- PrepareData(ds) + for (tr in list(TreeTools::PectinateTree(names(ds)), + TreeTools::BalancedTree(names(ds)))) { + expect_equal(TreeScore(tr, obj), TreeLength(tr, ds)) + } + } +}) + +test_that("native scorer fixes the MorphyLib {1-} bug (Lobo pattern 93)", { + data("Lobo", package = "TreeTools") + tr <- TreeTools::PectinateTree(names(Lobo.phy)) + obj <- PrepareData(Lobo.phy) + # Correct BGS length is 273; the legacy MorphyLib path returned 274. + expect_equal(TreeScore(tr, obj), 273) +}) + +test_that("SingleCharData() + EdgeListScore() score natively per character", { + data("Lobo", package = "TreeTools") + ds <- Lobo.phy + tr <- TreeTools::RenumberTips(TreeTools::PectinateTree(names(ds)), names(ds)) + tr <- TreeTools::Postorder(tr) + strs <- TreeTools::PhyToString(ds, byTaxon = FALSE, useIndex = FALSE, + concatenate = FALSE) + objs <- lapply(strs, SingleCharData) + e <- tr[["edge"]] + perChar <- vapply(objs, function(o) EdgeListScore(e[, 1], e[, 2], o), + double(1)) + expect_equal(sum(perChar * attr(ds, "weight")), TreeLength(tr, ds)) +}) diff --git a/tests/testthat/test-pp-random-tree.R b/tests/testthat/test-pp-random-tree.R index d140e0b94..e0de5547c 100644 --- a/tests/testthat/test-pp-random-tree.R +++ b/tests/testthat/test-pp-random-tree.R @@ -1,29 +1,23 @@ -# NB: RandomTreeScore uses C's MWC RNG (static global state in -# build_postorder.h), which is NOT seeded by set.seed(). The RNG state -# depends on what ran before this file. Use very wide binomial bounds -# (stringency <= 1e-6) to avoid false positives on CRAN/CI. -MorphyAction <- function (Action) expect_equal("ERR_NO_ERROR", mpl_translate_error(Action)) -MorphyWith <- function (char) { - nTip <- nchar(char) - 1L - morphyObj <- mpl_new_Morphy() - MorphyAction(mpl_init_Morphy(nTip, 1, morphyObj)) - MorphyAction(mpl_attach_rawdata(char, morphyObj)) - MorphyAction(mpl_set_num_internal_nodes(nTip - 1L, morphyObj)) - MorphyAction(mpl_set_parsim_t(1, "FITCH", morphyObj)) - MorphyAction(mpl_set_charac_weight(1, 1, morphyObj)) - MorphyAction(mpl_apply_tipdata(morphyObj)) - class(morphyObj) <- "morphyPtr" - morphyObj -} +# `RandomPostorderTree()` uses C's MWC RNG (static global state in +# build_postorder.h), which is NOT seeded by set.seed(). +# `RandomTreeScore()` builds a tree with TreeTools::RandomTree() (R's RNG) and +# scores it with the native Fitch kernel, so it IS reproducible via set.seed(). +# The heavy distribution-of-scores tests below are statistical and slow; they +# run only under TREESEARCH_EXTENDED_TESTS. Routine correctness of +# RandomTreeScore() is covered by test-RandomTreeScore.R. +ScoreObj <- function (char) { + # `char` is a Morphy token string without a trailing ";" + SingleCharData(char) +} test_that("four-tip trees are randomly distributed", { nTrees <- 36000 stringency <- 1e-6 nTip <- 4 expectedBounds <- qbinom(c(stringency, 1-stringency), nTrees, 1/(nTip - 1)) - rTrees <- vapply(logical(nTrees), function (XX) - unlist(RandomMorphyTree(nTip)), integer((nTip * 4) - 3)) + rTrees <- vapply(logical(nTrees), function (XX) + unlist(RandomPostorderTree(nTip)), integer((nTip * 4) - 3)) expect_true(all(rTrees[1 + (seq_len(nTip - 1)), ] %in% nTip + seq_len(nTip - 2))) expect_lt(expectedBounds[1], sum(rTrees[2, ] == 5)) expect_gt(expectedBounds[2], sum(rTrees[2, ] == 5)) @@ -40,30 +34,32 @@ test_that("four-tip trees are randomly distributed", { }) test_that("four-tip trees are randomly scored", { + skip_if_not(isTRUE(as.logical(Sys.getenv("TREESEARCH_EXTENDED_TESTS"))), + "Set TREESEARCH_EXTENDED_TESTS=true to run extended tests") set.seed(0) - + nTrees <- 12000 stringency <- 1e-6 nTip <- 4 - - morphyObj <- MorphyWith("0011;") - on.exit(morphyObj <- UnloadMorphy(morphyObj)) - + + morphyObj <- ScoreObj("0011") + expectedBounds <- qbinom(c(stringency, 1 - stringency), nTrees, NUnrooted(nTip - 1L) / NUnrooted(nTip)) - scores <- vapply(logical(nTrees), + scores <- vapply(logical(nTrees), function (XX) RandomTreeScore(morphyObj), integer(1)) expect_lt(expectedBounds[1], sum(scores==1)) expect_gt(expectedBounds[2], sum(scores==1)) }) test_that("five-tip trees are randomly scored", { + skip_if_not(isTRUE(as.logical(Sys.getenv("TREESEARCH_EXTENDED_TESTS"))), + "Set TREESEARCH_EXTENDED_TESTS=true to run extended tests") set.seed(0) nTrees <- 12000 stringency <- 1e-6 nTip <- 5 - morphyObj <- MorphyWith("00011;") - on.exit(morphyObj <- UnloadMorphy(morphyObj)) + morphyObj <- ScoreObj("00011") expectedBounds <- qbinom(c(stringency, 1-stringency), nTrees, NUnrooted(nTip - 1) / NUnrooted(nTip)) scores <- vapply(logical(nTrees), @@ -75,66 +71,65 @@ test_that("five-tip trees are randomly scored", { test_that("six-tip trees are randomly scored", { + skip_if_not(isTRUE(as.logical(Sys.getenv("TREESEARCH_EXTENDED_TESTS"))), + "Set TREESEARCH_EXTENDED_TESTS=true to run extended tests") set.seed(0) - + nTrees <- 12000 stringency <- 1e-6 nTip <- 6 - - morphyObj <- MorphyWith("000011;") - on.exit(morphyObj <- UnloadMorphy(morphyObj)) + + morphyObj <- ScoreObj("000011") expectedBounds <- qbinom(c(stringency, 1-stringency), nTrees, NUnrooted(5) / NUnrooted(6)) scores <- vapply(logical(nTrees), function (XX) RandomTreeScore(morphyObj), integer(1)) - morphyObj <- UnloadMorphy(morphyObj) - + expect_true(max(scores) == 2) expect_lt(expectedBounds[1], sum(scores==1)) expect_gt(expectedBounds[2], sum(scores==1)) - - morphyObj <- MorphyWith("001122;") + + morphyObj <- ScoreObj("001122") expectedBounds <- qbinom(c(stringency, 1 - stringency), nTrees, 7 / NUnrooted(nTip)) - scores <- vapply(logical(nTrees), + scores <- vapply(logical(nTrees), function (XX) RandomTreeScore(morphyObj), integer(1)) - morphyObj <- UnloadMorphy(morphyObj) - + expect_true(all(scores %in% 2:4)) expect_lt(expectedBounds[1], sum(scores == 2)) expect_gt(expectedBounds[2], sum(scores == 2)) - - morphyObj <- MorphyWith("000111;") + + morphyObj <- ScoreObj("000111") expectedBounds <- qbinom(c(stringency, 1-stringency), nTrees, 3 * 3 / NUnrooted(nTip)) scores <- vapply(logical(nTrees), function (XX) RandomTreeScore(morphyObj), integer(1)) - # unloaded on exit; don't unload twice || morphyObj <- UnloadMorphy(morphyObj) - + expect_true(max(scores) == 3) expect_lt(expectedBounds[1], sum(scores == 1)) expect_gt(expectedBounds[2], sum(scores == 1)) - + }) test_that("twelve-tip trees are randomly scored", { + skip_if_not(isTRUE(as.logical(Sys.getenv("TREESEARCH_EXTENDED_TESTS"))), + "Set TREESEARCH_EXTENDED_TESTS=true to run extended tests") + set.seed(0) nTrees <- 24000 stringency <- 1e-6 nTip <- 12 - morphyObj <- MorphyWith("000000011111;") - on.exit(morphyObj <- UnloadMorphy(morphyObj)) - expectedBounds <- qbinom(c(stringency, 1 - stringency), nTrees, + morphyObj <- ScoreObj("000000011111") + expectedBounds <- qbinom(c(stringency, 1 - stringency), nTrees, NUnrooted(7) * (2 * 7 - 3) * NUnrooted(5) * (2 * 5 - 3) / NUnrooted(nTip)) - - scores <- vapply(logical(nTrees), + + scores <- vapply(logical(nTrees), function (XX) RandomTreeScore(morphyObj), integer(1L)) - # table(scores) - + expect_equal(5L, max(scores)) nScoring1 <- sum(scores == 1) expect_lt(expectedBounds[1], nScoring1) - expect_gt(expectedBounds[2], nScoring1) + expect_gt(expectedBounds[2], nScoring1) }) diff --git a/vignettes/custom.Rmd b/vignettes/custom.Rmd index 8de28bec9..7b7b457b9 100644 --- a/vignettes/custom.Rmd +++ b/vignettes/custom.Rmd @@ -114,147 +114,41 @@ PlotTree(result) ## Searching using implied weights -> **Note:** If you simply want to run an implied weights search, use -> `MaximizeParsimony(dataset, concavity = k)`, which is much faster and -> easier. The example below demonstrates the _custom optimality criteria -> framework_ using implied weights as a familiar worked example. - -Now we consider a more complex case in which a scorer -must undergo a time-consuming initialization before tree search can begin, -and must be safely destroyed once tree search has completed. - -We start by defining an initialization function, which will create a new -Morphy object [@Brazeau2017] for each character in a phylogenetic dataset: - -```{r iw-setup} -IWInitMorphy <- function (dataset) { - attr(dataset, "morphyObjs") <- - lapply(PhyToString(dataset, byTaxon = FALSE, useIndex = FALSE, - concatenate = FALSE), - SingleCharMorphy) - - # Return: - dataset -} -``` - -To release memory back to the operating system, we must destroy each Morphy -object once we're finished with it: - -```{r iw-destroy} -IWDestroyMorphy <- function (dataset) { - vapply(attr(dataset, "morphyObjs"), UnloadMorphy, integer(1)) -} -``` - -Now we can write our tree scoring function, which will return the 'fit' -under implied weights [@Goloboff1993]. - -Note that we need to specify some extra parameters: `concavity` is the _k_ -value required by the implied weights formula (fit = _e / e + k_), -and `minLength` is the minimum number of steps required by each character -- -which we need in order to convert the total number of steps (returned by -`MorphyLength()` to a number of excess steps (_e_ in the implied weights formula) - -```{r iw-score} -IWScoreMorphy <- function (parent, child, dataset, concavity = 10L, - minLength = attr(dataset, "min.length"), ...) { - steps <- vapply(attr(dataset, "morphyObjs"), MorphyLength, - parent = parent, child = child, integer(1)) - homoplasies <- steps - minLength - fit <- homoplasies / (homoplasies + concavity) - # Return: - sum(fit * attr(dataset, "weight")) -} -``` - -Now we are ready to search: +> **Note:** For a standard implied weights analysis, use +> `MaximizeParsimony(dataset, concavity = k)`, which is faster and uses the +> full driven-search pipeline (see the +> [tree search vignette](tree-search.html#implied-weighting)). +> The example below shows that the custom-search functions `TreeSearch()` and +> `Ratchet()` support implied weights directly, through the `concavity` +> parameter. + +Implied weights [@Goloboff1993] penalize additional homoplasy according to a +concavity constant _k_. +`TreeSearch()`, `Ratchet()` and `Jackknife()` accept `concavity` directly -- +no custom scorer or data-initialization code is required: ```{r iw-search, message = FALSE} data("inapplicable.datasets") dataset <- congreveLamsdellMatrices[[42]] -# Populate `min.length` attribute -dataset <- PrepareDataIW(dataset) -iwTree <- TreeSearch(NJTree(dataset), dataset, - InitializeData = IWInitMorphy, - CleanUpData = IWDestroyMorphy, - TreeScorer = IWScoreMorphy, - concavity = 10, # Will be sent to TreeScorer - verbosity = 1) - +iwTree <- TreeSearch(NJTree(dataset), dataset, concavity = 10, + maxIter = 50L, maxHits = 10L, verbosity = 1) ``` -This quick search probably hasn't found the globally optimal tree. -Besides increasing the number of hits and rearrangements, -the parsimony ratchet [@Nixon1999] can help to escape local optima. -This introduces an additional complication: we need to bootstrap the characters -within `dataset`, and their accompanying Morphy objects. - -A `Bootstraper` function expects an `edgeList` (a list of the parent and child -of each edge in a tree, in turn) and a `dataset` argument, and conducts -a tree search, starting at `edgeList`, on a bootstrapped version of the dataset. -It is also sent the arguments `maxIter = bootstrapIter` and -`maxHits = bootstrapHits`, allowing ratchet search intensity to be controlled -from parameters sent to the `Ratchet()` function. - -```{r iw-bootstrap} -IWBootstrap <- function (edgeList, dataset, concavity = 10L, EdgeSwapper = NNISwap, - maxIter, maxHits, verbosity = 1L, ...) { - att <- attributes(dataset) - startWeights <- att[["weight"]] - - # Decompress phyDat object so each character is listed once - eachChar <- seq_along(startWeights) - deindexedChars <- rep.int(eachChar, startWeights) - - # Resample characters - resampling <- tabulate(sample(deindexedChars, replace = TRUE), length(startWeights)) - sampled <- resampling != 0 - sampledData <- lapply(dataset, function (x) x[sampled]) - sampledAtt <- att - sampledAtt[["index"]] <- rep.int(seq_len(sum(sampled)), resampling[sampled]) - sampledAtt[["weight"]] <- resampling[sampled] - sampledAtt[["nr"]] <- length(sampledAtt[["weight"]]) - sampledAtt[["min.length"]] <- minLength <- att[["min.length"]][sampled] - sampledAtt[["morphyObjs"]] <- att[["morphyObjs"]][sampled] - attributes(sampledData) <- sampledAtt - - # Search using resampled dataset - res <- EdgeListSearch(edgeList[1:2], sampledData, TreeScorer = IWScoreMorphy, - concavity = concavity, minLength = minLength, - EdgeSwapper = EdgeSwapper, - maxIter = maxIter, maxHits = maxHits, - verbosity = verbosity - 1L) - - res[1:2] -} - -``` - -Having defined the `Bootstrapper()` function we can now complete a Ratchet -search with: +The parsimony ratchet [@Nixon1999] can help to escape local optima; +bootstrap resampling of characters is handled for you: ```{r iw-ratchet, message = FALSE} -ratchetTree <- Ratchet(tree = iwTree, dataset = dataset, - concavity = 10, - InitializeData = IWInitMorphy, - CleanUpData = IWDestroyMorphy, - TreeScorer = IWScoreMorphy, - Bootstrapper = IWBootstrap, +ratchetTree <- Ratchet(iwTree, dataset, concavity = 10, ratchIter = 2, ratchHits = 2, searchIter = 20, searchHits = 10, verbosity = 2) - ``` - -It would be sensible to use much larger values of `ratchIter`, `ratchHits`, -`searchIter` and `searchHits` to be confident of locating an optimal tree. -Remember that for real implied weights analyses, -`MaximizeParsimony(dataset, concavity = k)` is faster, easier, and uses the -full driven search pipeline (see the -[tree search vignette](tree-search.html#implied-weighting)). +Use much larger values of `ratchIter`, `ratchHits`, `searchIter` and +`searchHits` for a thorough search. +Profile parsimony [@Faith2001] is available in the same way: set +`concavity = "profile"`. Hopefully these examples give a template from which you are able to construct your own optimality criteria. The maintainer is happy to answer questions via