Skill Tracer
Skills › Scientific Agent Skills › gtars › overlap.md

overlap.md

225 lines · skills/gtars/references/overlap.md at 5f2bc03

Open on GitHub

Most marks come from matching words in the file, so treat them as pointers.

1# Overlap, counts, set algebra, and consensus
2
3Locally tested with Python 0.10.0; Rust/CLI 0.10.0 source reviewed on **2026-10-01**.
4

Overlap, counts, set algebra, and consensus

Locally tested with Python 0.10.0; Rust/CLI 0.10.0 source reviewed on 2026-10-01.

Raw lines 1 to 4
5## Interval meaning
6
7Use 0-based, half-open intervals. Two valid intervals overlap when:
8
9```text
10a.start < b.end and b.start < a.end
11```
13Thus `[0,10)` overlaps `[9,20)` but not adjacent `[10,20)`. Validate assembly,
14exact contig names, `start < end`, chromosome bounds, and Gtars' `u32` coordinate
15limit before indexing.
17Overlap and reduction answer different questions:
19- overlap/query methods use ordinary half-open overlap;
20- `reduce()` merges overlapping **and adjacent** intervals;
21- `union()` reduces the concatenated sets;
22- consensus first reduces the union, so adjacency can combine support domains.

Interval meaning

Use 0-based, half-open intervals. Two valid intervals overlap when:

a.start < b.end and b.start < a.end

Thus [0,10) overlaps [9,20) but not adjacent [10,20). Validate assembly, exact contig names, start < end, chromosome bounds, and Gtars' u32 coordinate limit before indexing.

Overlap and reduction answer different questions:

  • overlap/query methods use ordinary half-open overlap;
  • reduce() merges overlapping and adjacent intervals;
  • union() reduces the concatenated sets;
  • consensus first reduces the union, so adjacency can combine support domains.
Raw lines 5 to 23
24## Python directional overlap queries
26```python
27from gtars.models import RegionSet
29query = RegionSet("query.bed")
30universe = RegionSet("universe.bed")
32counts = query.count_overlaps(universe)
33any_hit = query.any_overlaps(universe)
34hit_indices = query.find_overlaps(universe)
35query_with_hits = query.subset_by_overlaps(universe)
36```
38Interpretation is directional:
40- `counts[i]` is the number of universe intervals overlapping query interval `i`;
41- `any_hit[i]` is a boolean for query interval `i`;
42- `hit_indices[i]` contains 0-based indices into the in-memory `universe`;
43- `subset_by_overlaps` preserves only query intervals with one or more hits.
45Both file-backed sets are sorted by the constructor. Do not join these arrays to
46the original unsorted row number without carrying a separate stable identifier.
48For actual intersection coordinates:
50```python
51pieces = query.intersect_all(universe)
52```
54`intersect_all` computes `[max(starts), min(ends))` for every overlapping pair.
55It differs from `pintersect`, which pairs two sets by index position, truncates
56to the shorter length, and emits zero-width placeholders for nonoverlaps.
57Validate equal length and pairing before using it.

Python directional overlap queries

from gtars.models import RegionSet

query = RegionSet("query.bed")
universe = RegionSet("universe.bed")

counts = query.count_overlaps(universe)
any_hit = query.any_overlaps(universe)
hit_indices = query.find_overlaps(universe)
query_with_hits = query.subset_by_overlaps(universe)

Interpretation is directional:

  • counts[i] is the number of universe intervals overlapping query interval i;
  • any_hit[i] is a boolean for query interval i;
  • hit_indices[i] contains 0-based indices into the in-memory universe;
  • subset_by_overlaps preserves only query intervals with one or more hits.

Both file-backed sets are sorted by the constructor. Do not join these arrays to the original unsorted row number without carrying a separate stable identifier.

For actual intersection coordinates:

pieces = query.intersect_all(universe)

intersect_all computes [max(starts), min(ends)) for every overlapping pair. It differs from pintersect, which pairs two sets by index position, truncates to the shorter length, and emits zero-width placeholders for nonoverlaps. Validate equal length and pairing before using it.

Raw lines 24 to 58
59## Base-pair set metrics
61```python
62reduced = query.reduce()
63difference = query.setdiff(universe)
64combined = query.concat(universe)
65union = query.union(universe)
66pairwise = query.pintersect(universe)
68jaccard = query.jaccard(universe)
69covered_fraction = query.coverage(universe)
70overlap_coefficient = query.overlap_coefficient(universe)
71```
73- Jaccard: `intersection_bp / union_bp`.
74- Coverage: fraction of query base pairs covered by universe after overlap
75 normalization.
76- Overlap coefficient: `intersection_bp / min(query_bp, universe_bp)`.
77- `concat` does not merge; `union` does.
78- `setdiff` can split query intervals.
80Empty-set edge cases and zero denominators should be tested with the exact pinned
81version before relying on metric values.

Base-pair set metrics

reduced = query.reduce()
difference = query.setdiff(universe)
combined = query.concat(universe)
union = query.union(universe)
pairwise = query.pintersect(universe)

jaccard = query.jaccard(universe)
covered_fraction = query.coverage(universe)
overlap_coefficient = query.overlap_coefficient(universe)
  • Jaccard: intersection_bp / union_bp.
  • Coverage: fraction of query base pairs covered by universe after overlap normalization.
  • Overlap coefficient: intersection_bp / min(query_bp, universe_bp).
  • concat does not merge; union does.
  • setdiff can split query intervals.

Empty-set edge cases and zero denominators should be tested with the exact pinned version before relying on metric values.

Raw lines 59 to 82
83## Rust index API
85The exact wrapper dependency is:
87```toml
88[dependencies]
89gtars = { version = "=0.10.0", default-features = false, features = [
90 "core", "overlaprs"
91] }
92```
94The following source-reviewed Rust template was not compiled in this audit:
96```rust
97use gtars::core::models::RegionSet;
98use gtars::overlaprs::IndexedRegionSet;
99use std::error::Error;
101fn main() -> Result<(), Box<dyn Error>> {
102 let universe = RegionSet::try_from("universe.bed")?;
103 let query = RegionSet::try_from("query.bed")?;
104 let index = IndexedRegionSet::new(universe);
106 let counts = index.count_overlaps(&query, None);
107 let flags = index.any_overlaps(&query, None);
108 let hits = index.find_overlaps(&query, None);
110 assert_eq!(counts.len(), query.len());
111 assert_eq!(flags.len(), query.len());
112 assert_eq!(hits.len(), query.len());
113 Ok(())
115```
117The optional second argument is a region filter in the component API; `None`
118queries all regions. Consult the exact
119[`gtars-overlaprs 0.6.0` docs](https://docs.rs/gtars-overlaprs/0.6.0/gtars_overlaprs/)
120compatible with the 0.10.0 wrapper (0.6.1 removes an unused error type).
121Record the actual Cargo.lock resolution.

Rust index API

The exact wrapper dependency is:

[dependencies]
gtars = { version = "=0.10.0", default-features = false, features = [
  "core", "overlaprs"
] }

The following source-reviewed Rust template was not compiled in this audit:

use gtars::core::models::RegionSet;
use gtars::overlaprs::IndexedRegionSet;
use std::error::Error;

fn main() -> Result<(), Box<dyn Error>> {
    let universe = RegionSet::try_from("universe.bed")?;
    let query = RegionSet::try_from("query.bed")?;
    let index = IndexedRegionSet::new(universe);

    let counts = index.count_overlaps(&query, None);
    let flags = index.any_overlaps(&query, None);
    let hits = index.find_overlaps(&query, None);

    assert_eq!(counts.len(), query.len());
    assert_eq!(flags.len(), query.len());
    assert_eq!(hits.len(), query.len());
    Ok(())
}

The optional second argument is a region filter in the component API; None queries all regions. Consult the exact [gtars-overlaprs 0.6.0 docs](https://docs.rs/gtars-overlaprs/0.6.0/gtars_overlaprs/) compatible with the 0.10.0 wrapper (0.6.1 removes an unused error type). Record the actual Cargo.lock resolution.

Raw lines 83 to 122
123## CLI `overlaprs` is not a count command
125The current CLI form is:
127```bash
128gtars overlaprs \
129 --query query.bed \
130 --universe universe.bed \
131 --backend bits
132```
134Valid backends are `bits` and `ailist`; the handler defaults to `bits`. The
135command writes every overlapping **universe interval** as BED3 to stdout. It does
136not emit query coordinates, query IDs, universe IDs, or one count per query.
137Repeated universe hits can therefore be indistinguishable in the output.
138Unlike `RegionSet(path)`, this CLI reader does not skip comment, browser, track,
139header, or blank rows: prepare a separate header-free BED file before invoking it.
141Use Python `count_overlaps` when row-aligned counts are required. The CLI exposes
142a `--streaming` flag in 0.10.0, but the tagged handler does not read it; do not
143claim lower memory from that flag.
145Build a non-executing local plan first:
147```bash
148python3 -B scripts/execution_plan.py \
149 --operation overlap \
150 --query query.bed \
151 --universe universe.bed \
152 --assembly GRCh38.p14 \
153 --chrom-sizes GRCh38.p14.chrom.sizes
154```

CLI overlaprs is not a count command

The current CLI form is:

gtars overlaprs \
  --query query.bed \
  --universe universe.bed \
  --backend bits

Valid backends are bits and ailist; the handler defaults to bits. The command writes every overlapping universe interval as BED3 to stdout. It does not emit query coordinates, query IDs, universe IDs, or one count per query. Repeated universe hits can therefore be indistinguishable in the output. Unlike RegionSet(path), this CLI reader does not skip comment, browser, track, header, or blank rows: prepare a separate header-free BED file before invoking it.

Use Python count_overlaps when row-aligned counts are required. The CLI exposes a --streaming flag in 0.10.0, but the tagged handler does not read it; do not claim lower memory from that flag.

Build a non-executing local plan first:

python3 -B scripts/execution_plan.py \
  --operation overlap \
  --query query.bed \
  --universe universe.bed \
  --assembly GRCh38.p14 \
  --chrom-sizes GRCh38.p14.chrom.sizes
Raw lines 123 to 155
Runs code scripts/execution_plan.py :148
156## Consensus semantics
158Python:
160```python
161from gtars.genomic_distributions import consensus
163rows = consensus([replicate_a, replicate_b, replicate_c])
164```
166CLI:
168```bash
169gtars consensus \
170 --beds replicate_a.bed replicate_b.bed replicate_c.bed \
171 --min-count 2 \
172 --output consensus.bed
173```
175The algorithm:
1771. concatenates every set;
1782. reduces all ranges to a non-overlapping union, merging adjacency;
1793. for each union range, counts how many input **sets** have at least one overlap;
1804. returns BED4-like `chr, start, end, count`, sorted by chromosome/start.
182It does not cut ranges at every support transition. For example, partially
183overlapping `[0,10)` and `[5,15)` produce union `[0,15)` with count 2, even though
184the edges are supported by one set. This is set-level support for a merged union
185component, not per-base support.
187`--min-count` filters after consensus computation and must be positive. Validate
188that it does not exceed the number of input sets.

Consensus semantics

Python:

from gtars.genomic_distributions import consensus

rows = consensus([replicate_a, replicate_b, replicate_c])

CLI:

gtars consensus \
  --beds replicate_a.bed replicate_b.bed replicate_c.bed \
  --min-count 2 \
  --output consensus.bed

The algorithm:

  1. concatenates every set;
  2. reduces all ranges to a non-overlapping union, merging adjacency;
  3. for each union range, counts how many input sets have at least one overlap;
  4. returns BED4-like chr, start, end, count, sorted by chromosome/start.

It does not cut ranges at every support transition. For example, partially overlapping [0,10) and [5,15) produce union [0,15) with count 2, even though the edges are supported by one set. This is set-level support for a merged union component, not per-base support.

--min-count filters after consensus computation and must be positive. Validate that it does not exceed the number of input sets.

Raw lines 156 to 189
190## Replicates and leakage
192- Define biological replicate/donor/patient groups before consensus.
193- Keep all samples from one patient in one train/validation/test split.
194- Build a training consensus/universe from training replicates only.
195- Do not use held-out overlap counts to tune `min-count`, merge gaps, blacklist
196 handling, or backend parameters.
197- Report per-replicate support and exclusions; a merged consensus is not evidence
198 that every replicate supports every base.

Replicates and leakage

  • Define biological replicate/donor/patient groups before consensus.
  • Keep all samples from one patient in one train/validation/test split.
  • Build a training consensus/universe from training replicates only.
  • Do not use held-out overlap counts to tune min-count, merge gaps, blacklist handling, or backend parameters.
  • Report per-replicate support and exclusions; a merged consensus is not evidence that every replicate supports every base.
Raw lines 190 to 199
200## Scaling and bounds
202- `RegionSet` loads full interval vectors and sorts them.
203- Index memory scales with universe size; hit output can scale with the number of
204 overlap pairs, much larger than either input.
205- Cap input records/bytes, output rows/bytes, memory, and wall time.
206- Pilot both backends on representative training data; identical semantics and
207 deterministic result ordering must be verified before switching.
208- Keep stdout redirected only to an approved nonexisting output path and verify
209 it after completion.

Scaling and bounds

  • RegionSet loads full interval vectors and sorts them.
  • Index memory scales with universe size; hit output can scale with the number of overlap pairs, much larger than either input.
  • Cap input records/bytes, output rows/bytes, memory, and wall time.
  • Pilot both backends on representative training data; identical semantics and deterministic result ordering must be verified before switching.
  • Keep stdout redirected only to an approved nonexisting output path and verify it after completion.
Raw lines 200 to 210
211## Removed stale APIs
213There is no current Python `gtars.igd.build_index`, `igd.query`,
214`filter_overlapping`, `filter_non_overlapping`, `overlap_fraction`, or
215`overlap_coverage` surface matching the old skill. CLI `igd` has only `create`
216and `search`; see `cli.md`.

Removed stale APIs

There is no current Python gtars.igd.build_index, igd.query, filter_overlapping, filter_non_overlapping, overlap_fraction, or overlap_coverage surface matching the old skill. CLI igd has only create and search; see cli.md.

Raw lines 211 to 217
218## Official sources (accessed 2026-10-01)
220- [Python RegionSet 0.10.0 binding](https://github.com/databio/gtars/blob/gtars-python-v0.10.0/gtars-python/src/models/region_set.rs)
221- [Rust overlaprs source at v0.10.0](https://github.com/databio/gtars/tree/gtars-v0.10.0/gtars-overlaprs)
222- [CLI overlap parser](https://github.com/databio/gtars/blob/gtars-v0.10.0/gtars-cli/src/overlaprs/cli.rs)
223- [CLI overlap handler/output](https://github.com/databio/gtars/blob/gtars-v0.10.0/gtars-cli/src/overlaprs/handlers.rs)
224- [Consensus implementation](https://github.com/databio/gtars/blob/gtars-v0.10.0/gtars-genomicdist/src/consensus.rs)
225- [Gtars overlap module guide](https://docs.bedbase.org/gtars/overlaprs/)