Skip to content

Commit 2e3bf2c

Browse files
committed
Add simplify() for table collection
1 parent 67f3173 commit 2e3bf2c

9 files changed

Lines changed: 480 additions & 23 deletions

File tree

‎RcppTskit/.Rbuildignore‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@
55
^[.]?air[.]toml$
66
^[.]?jarl[.]toml$
77
^\.Rproj\.user$
8+
^\.idea$
9+
^src/\.idea$
10+
^src/tskit/\.idea$
811
^\.\.$
912
^\.clang-format$
1013
^\.covrignore$

‎RcppTskit/NEWS.md‎

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,9 @@ and releases adhere to [Semantic Versioning](https://semver.org/spec/v2.0.0.html
5353
to retrieve node-table rows by 0-based row index.
5454
- Added `rtsk_table_collection_sort()` and `TableCollection$sort()` to sort
5555
table collections.
56+
- Added `rtsk_table_collection_simplify()` and
57+
`TableCollection$simplify()` to simplify table collections, with C-level
58+
options at low level and Python-style arguments at the R6 level.
5659
- Added low-level variant iterators
5760
(`rtsk_variant_iterator_init()`/`rtsk_variant_iterator_next()`) and a
5861
user-facing `TreeSequence$variants()` method to iterate over decoded
@@ -74,7 +77,7 @@ and releases adhere to [Semantic Versioning](https://semver.org/spec/v2.0.0.html
7477
`pointer` to `xptr`.
7578
- Ensured `TableCollection$tree_sequence()` matches `tskit Python` API:
7679
it now builds indexes on the `TableCollection`, if indexes are not present.
77-
- Refined integer validation behavior across scalar and optional vector inputs.
80+
- Refined integer validation behaviour across scalar and optional vector inputs.
7881
- We now use `bit64::integer64` (signed 64 bit integer) instead of `int` aiming
7982
to approach `tsk_size_t` in `tskit C` (unsigned 64 bit integer); in low-level
8083
`rtsk_treeseq_get_num_*()` wrappers and count/metadata-length fields.

‎RcppTskit/R/Class-TableCollection.R‎

Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,165 @@ TableCollection <- R6Class(
131131
)
132132
},
133133

134+
#' @description Simplify this table collection in place.
135+
#' @param samples optional integer vector of node IDs to retain as samples.
136+
#' If \code{NULL}, use nodes currently marked with sample flags.
137+
#' @param reduce_to_site_topology logical; if \code{TRUE}, keep only
138+
#' topology needed for trees containing sites.
139+
#' @param filter_populations optional logical; if \code{NULL}, treated as
140+
#' \code{TRUE}.
141+
#' @param filter_individuals optional logical; if \code{NULL}, treated as
142+
#' \code{TRUE}.
143+
#' @param filter_sites optional logical; if \code{NULL}, treated as
144+
#' \code{TRUE}.
145+
#' @param filter_nodes optional logical; if \code{NULL}, treated as
146+
#' \code{TRUE}.
147+
#' @param update_sample_flags optional logical; if \code{NULL}, treated as
148+
#' \code{TRUE}.
149+
#' @param keep_unary logical; if \code{TRUE}, keep unary nodes.
150+
#' @param keep_unary_in_individuals optional logical; if \code{NULL},
151+
#' treated as \code{FALSE}.
152+
#' @param keep_input_roots logical; if \code{TRUE}, keep input roots.
153+
#' @param record_provenance logical; if \code{TRUE}, append a provenance row
154+
#' describing the simplify command.
155+
#' @param filter_zero_mutation_sites deprecated alias for
156+
#' \code{filter_sites}.
157+
#' @details See the \code{tskit Python} equivalent at
158+
#' \url{https://tskit.dev/tskit/docs/stable/python-api.html#tskit.TableCollection.simplify}.
159+
#' @return Integer vector mapping input node IDs to simplified node IDs.
160+
#' Dropped nodes map to \code{-1}.
161+
#' @examples
162+
#' ts_file <- system.file("examples/test.trees", package = "RcppTskit")
163+
#' tc <- tc_load(ts_file)
164+
#' node_map <- tc$simplify(samples = c(0L, 1L, 2L, 3L))
165+
#' is.integer(node_map)
166+
simplify = function(
167+
samples = NULL,
168+
reduce_to_site_topology = FALSE,
169+
filter_populations = NULL,
170+
filter_individuals = NULL,
171+
filter_sites = NULL,
172+
filter_nodes = NULL,
173+
update_sample_flags = NULL,
174+
keep_unary = FALSE,
175+
keep_unary_in_individuals = NULL,
176+
keep_input_roots = FALSE,
177+
record_provenance = TRUE,
178+
filter_zero_mutation_sites = NULL
179+
) {
180+
if (!is.null(samples)) {
181+
validate_optional_integer_vector_arg(samples, "samples")
182+
samples <- as.integer(samples)
183+
}
184+
validate_logical_arg(reduce_to_site_topology, "reduce_to_site_topology")
185+
validate_logical_arg(keep_unary, "keep_unary")
186+
validate_logical_arg(keep_input_roots, "keep_input_roots")
187+
validate_logical_arg(record_provenance, "record_provenance")
188+
189+
if (!is.null(filter_zero_mutation_sites)) {
190+
validate_logical_arg(
191+
filter_zero_mutation_sites,
192+
"filter_zero_mutation_sites"
193+
)
194+
if (
195+
!is.null(filter_sites) &&
196+
!identical(filter_sites, filter_zero_mutation_sites)
197+
) {
198+
stop("filter_sites and filter_zero_mutation_sites are inconsistent!")
199+
}
200+
warning(
201+
"filter_zero_mutation_sites is deprecated; use filter_sites",
202+
call. = FALSE
203+
)
204+
filter_sites <- filter_zero_mutation_sites
205+
}
206+
207+
resolve_optional_logical <- function(value, name, default) {
208+
if (is.null(value)) {
209+
return(default)
210+
}
211+
validate_logical_arg(value, name)
212+
return(value)
213+
}
214+
215+
filter_populations <- resolve_optional_logical(
216+
filter_populations,
217+
"filter_populations",
218+
TRUE
219+
)
220+
filter_individuals <- resolve_optional_logical(
221+
filter_individuals,
222+
"filter_individuals",
223+
TRUE
224+
)
225+
filter_sites <- resolve_optional_logical(
226+
filter_sites,
227+
"filter_sites",
228+
TRUE
229+
)
230+
filter_nodes <- resolve_optional_logical(
231+
filter_nodes,
232+
"filter_nodes",
233+
TRUE
234+
)
235+
update_sample_flags <- resolve_optional_logical(
236+
update_sample_flags,
237+
"update_sample_flags",
238+
TRUE
239+
)
240+
keep_unary_in_individuals <- resolve_optional_logical(
241+
keep_unary_in_individuals,
242+
"keep_unary_in_individuals",
243+
FALSE
244+
)
245+
246+
if (keep_unary && keep_unary_in_individuals) {
247+
stop("keep_unary and keep_unary_in_individuals cannot both be TRUE!")
248+
}
249+
250+
options <- 0L
251+
if (filter_sites) {
252+
options <- bitwOr(options, bitwShiftL(1L, 0))
253+
}
254+
if (filter_populations) {
255+
options <- bitwOr(options, bitwShiftL(1L, 1))
256+
}
257+
if (filter_individuals) {
258+
options <- bitwOr(options, bitwShiftL(1L, 2))
259+
}
260+
if (reduce_to_site_topology) {
261+
options <- bitwOr(options, bitwShiftL(1L, 3))
262+
}
263+
if (keep_unary) {
264+
options <- bitwOr(options, bitwShiftL(1L, 4))
265+
}
266+
if (keep_input_roots) {
267+
options <- bitwOr(options, bitwShiftL(1L, 5))
268+
}
269+
if (keep_unary_in_individuals) {
270+
options <- bitwOr(options, bitwShiftL(1L, 6))
271+
}
272+
if (!filter_nodes) {
273+
options <- bitwOr(options, bitwShiftL(1L, 7))
274+
}
275+
if (!update_sample_flags) {
276+
options <- bitwOr(options, bitwShiftL(1L, 8))
277+
}
278+
279+
node_map <- rtsk_table_collection_simplify(
280+
tc = self$xptr,
281+
samples = samples,
282+
options = options
283+
)
284+
285+
if (record_provenance) {
286+
self$provenance_table_add_row(
287+
record = "{\"command\":\"simplify\",\"TODO\":\"add simplify parameters\"}"
288+
)
289+
}
290+
return(node_map)
291+
},
292+
134293
#' @description Get the number of provenances in a table collection.
135294
#' @return A signed 64 bit integer \code{bit64::integer64}.
136295
#' @examples

‎RcppTskit/R/RcppExports.R‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,10 @@ rtsk_table_collection_sort <- function(tc, edge_start = 0L, site_start = 0L, mut
223223
invisible(.Call(`_RcppTskit_rtsk_table_collection_sort`, tc, edge_start, site_start, mutation_start, options))
224224
}
225225

226+
rtsk_table_collection_simplify <- function(tc, samples = NULL, options = 0L) {
227+
.Call(`_RcppTskit_rtsk_table_collection_simplify`, tc, samples, options)
228+
}
229+
226230
rtsk_table_collection_summary <- function(tc) {
227231
.Call(`_RcppTskit_rtsk_table_collection_summary`, tc)
228232
}

‎RcppTskit/inst/include/RcppTskit_public.hpp‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,9 @@ void rtsk_table_collection_build_index(SEXP tc, int options = 0);
6464
void rtsk_table_collection_drop_index(SEXP tc, int options = 0);
6565
void rtsk_table_collection_sort(SEXP tc, int edge_start = 0, int site_start = 0,
6666
int mutation_start = 0, int options = 0);
67+
Rcpp::IntegerVector rtsk_table_collection_simplify(
68+
SEXP tc, Rcpp::Nullable<Rcpp::IntegerVector> samples = R_NilValue,
69+
int options = 0);
6770
Rcpp::List rtsk_table_collection_summary(SEXP tc);
6871
Rcpp::List rtsk_table_collection_metadata_length(SEXP tc);
6972
int rtsk_individual_table_add_row(

0 commit comments

Comments
 (0)