superintervalsr

superintervalsr is an R wrapper for the SuperIntervals C++ library, designed for repeated overlap queries on an indexed collection of intervals. It is being prepared for Bioconductor submission and is not yet available there.

Installation

Install dependencies from CRAN and Bioconductor, then install the source package:

install.packages(c("Rcpp", "remotes"))
install.packages("BiocManager")
BiocManager::install(c("S4Vectors", "IRanges", "GenomicRanges"))
remotes::install_github("kcleal/superintervalsr")

A C++17 compiler is required. See BIOCONDUCTOR.md for development checks and submission steps.

Quick start

library(superintervalsr)
im <- IntervalMap(c(20, 1, 5), ends = c(30, 10, 15),
                  values = c("C", "A", "B"))
count.batch(im, c(7, 25), c(12, 35))
search_items(im, 7, 12)
search_point(im, 10)
coverage(im, 1, 15) # count = 2, total_coverage = 21 inclusive bases

# Incremental loading: build once after adding all intervals.
im <- IntervalMap()
reserve(im, 1000)
add(im, 1, 10, "A")
add(im, 5, 15, "B")
build(im)
search_values(im, 7, 12)

Intervals and queries are closed: both endpoints are included. Inputs must be finite whole numbers in the R integer range (excluding NA). Constructors validate coordinates and build automatically. Query functions retain a thin, low-overhead interface: callers must provide valid query ranges and call build() after every batch of additions. Index state is not checked per query.

build() sorts starts ascending and ends descending within tied starts. Search indices address this internal order, not original input rows. Hit order and the choice of metadata among identical coordinate ties are unspecified. For mapping back to source rows, store row IDs as values.

Genomic ranges

Use the S4 SuperIntervalMap adapter to index GRanges with multiple chromosomes, strand, sequence information and metadata. Build once and reuse the subject:

library(GenomicRanges)
gr <- GRanges(c("chr1", "chr1", "chr2"),
              IRanges(c(20, 1, 1), c(30, 10, 10)),
              strand = c("+", "*", "-"),
              gene_id = c("C", "A", "D"))
index <- SuperIntervalMap(gr)
query <- GRanges(c("chr1", "chr2"), IRanges(c(5, 3), c(25, 8)),
                 strand = c("+", "-"))
hits <- findOverlaps(query, index)
countOverlaps(query, index)
as_granges(index)[subjectHits(hits)]

Hits refer to original subject rows. Strand matching follows GenomicRanges, including wildcard "*"; use ignore.strand = TRUE to ignore it. Advanced overlap options and zero-width features use GenomicRanges directly. The genomic adapter uses one index per sequence, with strand filtering in C++. Reconstruct it after editing subject coordinates; save its original GRanges for serialization. The workflow vignette includes a real RNA-seq example using airway annotations.

The low-level IntervalMap(gr, seqname = "chr1") interface still indexes one sequence and ignores strand. Its search indices address sorted map positions; store row IDs as values when mapping low-level hits to original input rows.

GRanges interface benchmarks

On macOS ARM64 with R 4.6.1/Bioconductor 3.24 (14 October 2026), the chromosome- and strand-aware interface produced the same counts and hit pairs as GenomicRanges. The benchmark uses real airway gene spans and two synthetic subjects across 22 chromosomes, with 100, 1,000, 10,000, 100,000 and 1,000,000 promoter queries. Both strand-aware and strand-ignored queries are tested. Timings below are medians of five repetitions, with ten calls per repetition through 10,000 queries and one call per repetition at 100,000 and 1,000,000 queries. Subject indexes are built once and construction time is recorded separately. Units are milliseconds per batch.

Subject Operation Queries SuperIntervals Prebuilt GNCList GRanges
airway countOverlaps 10,000 2.2 10.8 16.8
airway findOverlaps 10,000 3.0 10.6 17.0
synthetic_10000 countOverlaps 10,000 1.4 6.8 7.3
synthetic_10000 findOverlaps 10,000 2.0 7.0 8.0
synthetic_100000 countOverlaps 10,000 1.9 12.6 16.4
synthetic_100000 findOverlaps 10,000 2.9 13.0 17.0

GNCList(subject) is GenomicRanges' prebuilt Nested Containment List index. It provides the repeated-query baseline; the GRanges column passes the original subject directly to GenomicRanges, which performs preprocessing during the call.

Index construction

These are median construction times over five repetitions, in milliseconds. Both constructors receive an existing GRanges; creating that input is excluded.

Subject Features SuperIntervalMap GNCList
airway 63,677 8 17
synthetic_10000 10,000 1 6
synthetic_100000 100,000 13 19

The SuperIntervalMap timings include the complete R adapter: splitting subjects by chromosome and building one native index per chromosome.

GRanges query benchmark

The complete results, construction timings, and session information are included. To reproduce from the repository with the required vignette dependencies:

Rscript inst/scripts/benchmark-genomic.R genomic-benchmark

Set operations

merge_overlaps(), union_with(), intersection(), difference(), symmetric_difference(), gaps(), expand(), flank() and unique_intervals() return independent, already indexed maps. span() returns the enclosing start/end pair or NULL for an empty map.

Merge and union coalesce overlaps, but keep adjacent non-overlapping intervals separate. Intersection returns one piece per overlapping pair, retaining the left input's value; use merge_overlaps() for disjoint output. Difference retains the left input's metadata, while expansion and flanks inherit each source interval's value. These operations do not reconcile all metadata from both inputs. Consult the help pages for exact value semantics.

coverage() returns the number of hits and the sum of inclusive intersection widths. Shared bases are counted once per stored interval, so this is not union width or the per-base coverage returned by IRanges::coverage().

Maps mutate by reference: other <- im aliases the same map. External-pointer maps cannot be restored with readRDS(); save coordinates and values and reconstruct them. Qualify names such as superintervalsr::coverage() and superintervalsr::flank() when working alongside Bioconductor packages.