Push zunrplorkwkt #70

Merged
coissac merged 93 commits from push-zunrplorkwkt into main 2026-08-28 23:15:38 +00:00
22 changed files with 132 additions and 50 deletions
Showing only changes of commit 96b6517541 - Show all commits
@@ -16,6 +16,22 @@ tier / Index tier, each depending only downward) are unchanged; only the
crate-vs-module packaging changed. See [obikindex::layer](layer_tier.md)
for the current module doc.
**Superseded, second event, same day (2026-08-21):** `obikpartitionner`
and `obikderep`, the two algorithm crates, are also gone — but unlike
`obikpartition`/`obilayeredmap` above, they were **not** folded into
`obikindex`. They were first (mistakenly) merged into `obikindex` as an
`algorithms` submodule, then corrected into a new sibling crate,
**`obikindexer`**, holding `obikindexer::algorithms::{partitionner,
dereplicator}` and depending on `obikindex` — never the reverse, same
dependency direction `obikpartitionner`/`obikderep` already had. Read
`obikpartitionner::X` as `obikindexer::algorithms::partitionner::X` and
`obikderep::X` as `obikindexer::algorithms::dereplicator::X` throughout
what follows. The distinction the mistake surfaced, worth keeping: data
crates (`obikindex`, holding the `index`/`partition`/`layer` model) merge
naturally into one crate as submodules; algorithm crates that operate on
that model from outside stay separate, so the dependency only ever runs
one way.
Status (2026-08-20, latest pass): (1) done — `obilayeredmap::Layer`
exists, `Mat` is gone. (1b) done — `Layer::Empty`, the first non-ready
state, added (panics on every read method). (2a) done — the
+28 -3
View File
@@ -1539,11 +1539,9 @@ dependencies = [
"obicompactvec",
"obidebruinj",
"obikentropy",
"obikrope",
"obikseq",
"obipipeline",
"obiread",
"obiskbuilder",
"obiskio",
"obisys",
"obitaxonomy",
@@ -1551,12 +1549,37 @@ dependencies = [
"rayon",
"serde",
"serde_json",
"sysinfo",
"tempfile",
"tracing",
"tracing-subscriber",
]
[[package]]
name = "obikindexer"
version = "0.1.0"
dependencies = [
"cacheline-ef",
"epserde",
"memmap2",
"niffler",
"obicompactvec",
"obikindex",
"obikrope",
"obikseq",
"obipipeline",
"obiread",
"obiskbuilder",
"obiskio",
"obisys",
"ptr_hash",
"rayon",
"serde",
"serde_json",
"sysinfo",
"tempfile",
"tracing",
]
[[package]]
name = "obikmer"
version = "1.2.2"
@@ -1568,6 +1591,7 @@ dependencies = [
"obidebruinj",
"obifastwrite",
"obikindex",
"obikindexer",
"obikphylo",
"obikrope",
"obikseq",
@@ -1595,6 +1619,7 @@ dependencies = [
"ndarray",
"obicompactvec",
"obikindex",
"obikindexer",
"obikseq",
"obipipeline",
"obiread",
+1 -1
View File
@@ -1,5 +1,5 @@
[workspace]
resolver = "3"
members = ["obikseq", "obiread", "obiskbuilder", "obifastwrite", "obikmer","obikrope","obipipeline", "obiskio","obidebruinj", "obicompactvec", "obisys", "obikindex", "obitaxonomy", "obikentropy", "obikphylo"]
members = ["obikseq", "obiread", "obiskbuilder", "obifastwrite", "obikmer","obikrope","obipipeline", "obiskio","obidebruinj", "obicompactvec", "obisys", "obikindex", "obikindexer", "obitaxonomy", "obikentropy", "obikphylo"]
[profile.release]
debug = 1
+1 -4
View File
@@ -12,8 +12,6 @@ obicompactvec = { path = "../obicompactvec" }
obidebruinj = { path = "../obidebruinj" }
obipipeline = { path = "../obipipeline" }
obikentropy = { path = "../obikentropy" }
obiread = { path = "../obiread" }
obiskbuilder = { path = "../obiskbuilder" }
cacheline-ef = "1.1"
epserde = "0.8"
ptr_hash = "1.1"
@@ -27,12 +25,11 @@ serde_json = "1"
indicatif = "0.18"
tracing = "0.1.44"
bitvec = "1"
sysinfo = "0.39"
hwlocality = { version = "1.0.0-alpha.11", features = ["vendored"], optional = true }
[dev-dependencies]
obiread = { path = "../obiread" }
obikseq = { path = "../obikseq", features = ["test-utils"] }
obikrope = { path = "../obikrope" }
tempfile = "3"
tracing-subscriber = { version = "0.3", features = ["fmt", "env-filter"] }
anyhow = "1"
-9
View File
@@ -1,9 +0,0 @@
//! Indexing-pipeline algorithms: code that operates on a
//! [`crate::index::KmerIndex`] to build or transform its content, as
//! opposed to the `index`/`partition`/`layer` modules, which are the data
//! model itself. Each algorithm is its own submodule: [`partitionner`]
//! (routing raw super-kmers into partitions, then counting), [`dereplicator`]
//! (deduplicating a partition's raw super-kmers before counting).
pub mod dereplicator;
pub mod partitionner;
+5 -5
View File
@@ -159,10 +159,10 @@ impl KmerIndex {
/// Path of partition `i`'s raw directory (`partitions/part_{i:05}`) —
/// delegates to `crate::partition`, the Partition tier's own naming
/// primitive (mirrors `layer_dir` delegating to `crate::layer`).
/// `crate::algorithms::partitionner::PartitionRouter` reaches this same
/// directory only indirectly, through this method — it depends on
/// `KmerIndex`, not the other way around, even though both now live in
/// this crate — see `DevDocMD/implementation/partition_layer_cache.md`.
/// `obikindexer::algorithms::partitionner::PartitionRouter` reaches this
/// same directory only indirectly, through this method — `obikindexer`
/// depends on `KmerIndex`, not the other way around — see
/// `DevDocMD/implementation/partition_layer_cache.md`.
pub fn partition_dir(&self, i: usize) -> PathBuf {
crate::partition::partition_dir(&self.root_path, i)
}
@@ -232,7 +232,7 @@ impl KmerIndex {
/// Write `spectrums/{label}.json` from an already-computed kmer
/// spectrum (`f0`/`f1`/abundance histogram). Takes plain values rather
/// than `crate::algorithms::partitionner::KmerSpectrum` — `KmerIndex`
/// than `obikindexer::algorithms::partitionner::KmerSpectrum` — `KmerIndex`
/// is the data model, `PartitionRouter` the algorithm that depends on
/// it (see `DevDocMD/implementation/partition_layer_cache.md`), not
/// the other way around, and this is the only field of that type it
+4 -4
View File
@@ -46,9 +46,9 @@ const SK_EXT: &str = "skmer.zst";
/// Path of a layer's raw, not-yet-dereplicated superkmer file — written by
/// whichever algorithm routes superkmers into this layer (today:
/// `crate::algorithms::partitionner::PartitionRouter`), read by whichever
/// `obikindexer::algorithms::partitionner::PartitionRouter`), read by whichever
/// algorithm dereplicates it (today:
/// `crate::algorithms::dereplicator::Dereplicator`). Naming this once
/// `obikindexer::algorithms::dereplicator::Dereplicator`). Naming this once
/// here, rather than in either algorithm submodule, is what lets the two
/// agree on the filename without depending on each other directly — see
/// `DevDocMD/implementation/partition_layer_cache.md`.
@@ -57,9 +57,9 @@ pub fn raw_superkmers_path(layer_dir: &Path) -> PathBuf {
}
/// Path of a layer's dereplicated superkmer file — written by
/// `crate::algorithms::dereplicator::Dereplicator`, read by whichever
/// `obikindexer::algorithms::dereplicator::Dereplicator`, read by whichever
/// algorithm counts kmer abundances from it (today:
/// `crate::algorithms::partitionner::PartitionRouter::count_kmer`) and,
/// `obikindexer::algorithms::partitionner::PartitionRouter::count_kmer`) and,
/// later, by `obikindex::build_index_layer` to build the real layer.
pub fn dereplicated_superkmers_path(layer_dir: &Path) -> PathBuf {
layer_dir.join(format!("dereplicated.{SK_EXT}"))
+4 -4
View File
@@ -3,11 +3,11 @@
//! section for the authoritative naming/scope discussion. Each tier is a
//! submodule: [`layer`] (was the `obilayeredmap` crate), [`partition`]
//! (was the `obikpartition` crate), [`index`] (this crate's original
//! content). [`algorithms`] (was the `obikpartitionner` and `obikderep`
//! crates) sits alongside the model: code that builds or transforms an
//! index's content rather than defining its shape.
//! content). Indexing-pipeline algorithms that build or transform an
//! index's content (the former `obikpartitionner`/`obikderep` crates) live
//! in the separate `obikindexer` crate, which depends on this one, not the
//! other way around.
pub mod algorithms;
pub mod index;
pub mod layer;
pub mod partition;
+29
View File
@@ -0,0 +1,29 @@
[package]
name = "obikindexer"
version = "0.1.0"
edition = "2024"
[dependencies]
obikindex = { path = "../obikindex" }
obikseq = { path = "../obikseq" }
obiskio = { path = "../obiskio" }
obisys = { path = "../obisys" }
obicompactvec = { path = "../obicompactvec" }
obipipeline = { path = "../obipipeline" }
obiread = { path = "../obiread" }
obiskbuilder = { path = "../obiskbuilder" }
cacheline-ef = "1.1"
epserde = "0.8"
ptr_hash = "1.1"
niffler = "3.0.0"
memmap2 = "0.9.10"
rayon = "1"
serde = { version = "1", features = ["derive"] }
serde_json = "1"
tracing = "0.1.44"
sysinfo = "0.39"
[dev-dependencies]
obikseq = { path = "../obikseq", features = ["test-utils"] }
obikrope = { path = "../obikrope" }
tempfile = "3"
@@ -14,12 +14,12 @@ use niffler::send::compression::Format;
use niffler::Level;
use obikseq::superkmer::SuperKmer;
use obikseq::Sequence;
use crate::layer::{dereplicated_superkmers_path, raw_superkmers_path};
use obikindex::layer::{dereplicated_superkmers_path, raw_superkmers_path};
use obiskio::{SKFileMeta, SKFileReader, SKFileWriter, SKResult};
/// Scratch-file extension for this algorithm's own intermediate split
/// buckets — never read by anything outside [`dereplicate_partition`],
/// unlike `raw`/`dereplicated` (see `crate::layer::{raw_superkmers_path,
/// unlike `raw`/`dereplicated` (see `obikindex::layer::{raw_superkmers_path,
/// dereplicated_superkmers_path}`, the actual cross-module contract).
const TEMP_EXT: &str = "skmer.zst";
@@ -15,7 +15,7 @@ use obisys::Progress;
use rayon::prelude::*;
use sysinfo::System;
use crate::index::KmerIndex;
use obikindex::KmerIndex;
use dereplicate::{dereplicate_partition, optimal_buckets};
@@ -84,7 +84,7 @@ impl<'a> Dereplicator<'a> {
.map(|i| {
let dir = self.index.layer_dir(i, 0);
let result = if dir.exists() {
let raw_path = crate::layer::raw_superkmers_path(&dir);
let raw_path = obikindex::layer::raw_superkmers_path(&dir);
let n_buckets = optimal_buckets(&raw_path, available_per_thread);
dereplicate_partition(&dir, level, n_buckets)
} else {
+9
View File
@@ -0,0 +1,9 @@
//! Indexing-pipeline algorithms: code that operates on an
//! [`obikindex::KmerIndex`] to build or transform its content — `obikindex`
//! itself is the `index`/`partition`/`layer` data model, not this. Each
//! algorithm is its own submodule: [`partitionner`] (routing raw super-kmers
//! into partitions, then counting), [`dereplicator`] (deduplicating a
//! partition's raw super-kmers before counting).
pub mod dereplicator;
pub mod partitionner;
@@ -6,7 +6,7 @@
//!
//! Submodules: [`router`] (`PartitionRouter`, `KmerSpectrum`, the
//! routing/counting lifecycle API — partition/layer path naming itself
//! lives on `crate::index::KmerIndex`, not here), [`count`] (unique-kmer
//! lives on `obikindex::KmerIndex`, not here), [`count`] (unique-kmer
//! enumeration, MPHF, abundance counting), `kmer_sort` (external sort
//! support for `count`).
@@ -6,9 +6,9 @@ use std::sync::atomic::{AtomicU32, AtomicU64, Ordering};
use std::sync::Arc;
use std::time::Instant;
use crate::index::KmerIndex;
use obikindex::KmerIndex;
use obikseq::RoutableSuperKmer;
use crate::layer::Layer;
use obikindex::layer::Layer;
use obiskio::SKResult;
use obisys::{progress_bar, Progress};
use rayon::prelude::*;
@@ -80,7 +80,7 @@ impl Drop for GuardedIter {
///
/// Holds `&mut KmerIndex` — this is an algorithm operating on an index, not
/// a data structure of its own; it owns no path-naming knowledge (every
/// path comes from `index.index_dir`/`crate::layer::layer_dir`/
/// path comes from `index.index_dir`/`obikindex::layer::layer_dir`/
/// `Layer::create`), only the transient routing/dereplication/counting
/// state a run needs.
///
@@ -291,7 +291,7 @@ impl<'a> PartitionRouter<'a> {
.into_par_iter()
.map(|i| {
let dir = self.layer0_dir(i);
let dedup_path = crate::layer::dereplicated_superkmers_path(&dir);
let dedup_path = obikindex::layer::dereplicated_superkmers_path(&dir);
if !dedup_path.exists() {
pb.inc(1);
return Ok(());
@@ -343,9 +343,9 @@ impl<'a> PartitionRouter<'a> {
/// Directory of partition `i`'s layer 0 — every raw/dereplicated
/// superkmer file and provisional `mphf1.bin`/`counts1.bin` this router
/// produces lives here, alongside where `build_index_layer`
/// (`crate::index`) will later turn it into the real layer 0.
/// (`obikindex`) will later turn it into the real layer 0.
fn layer0_dir(&self, i: usize) -> PathBuf {
crate::layer::layer_dir(&self.index.index_dir(i), 0)
obikindex::layer::layer_dir(&self.index.index_dir(i), 0)
}
fn check_not_closed(&self) -> SKResult<()> {
@@ -360,7 +360,7 @@ impl<'a> PartitionRouter<'a> {
if self.writers[partition].is_none() {
let dir = self.layer0_dir(partition);
Layer::create(&dir).map_err(|e| io::Error::other(e.to_string()))?;
let file_path = crate::layer::raw_superkmers_path(&dir);
let file_path = obikindex::layer::raw_superkmers_path(&dir);
let writer = SKFileWriter::create_with(file_path, Format::Zstd, self.level)?;
self.writers[partition] = Some(writer);
}
@@ -2,8 +2,8 @@ use std::collections::HashMap;
use std::fs;
use crate::algorithms::dereplicator::Dereplicator;
use crate::{IndexConfig, KmerIndex};
use crate::layer::IndexMode;
use obikindex::{IndexConfig, KmerIndex};
use obikindex::layer::IndexMode;
use obikrope::Rope;
use obikseq::SuperKmer;
use obiskbuilder::build_superkmers;
@@ -69,7 +69,7 @@ fn pipeline_counts(seqs: &[&[u8]]) -> (u64, u64) {
Dereplicator::new(&index).run(None::<fn(obisys::Progress)>).unwrap();
let part_dir = index.layer_dir(0, 0);
let dedup_path = crate::layer::dereplicated_superkmers_path(&part_dir);
let dedup_path = obikindex::layer::dereplicated_superkmers_path(&part_dir);
if !dedup_path.exists() {
return (0, 0);
}
+13
View File
@@ -0,0 +1,13 @@
//! Indexing-pipeline algorithms: code that builds or transforms an
//! `obikindex::KmerIndex`'s content, as opposed to `obikindex` itself,
//! which is the `Index { Partition { Layer } }` data model. Kept as a
//! separate crate — not a module of `obikindex` — so the dependency runs
//! one way only (algorithms depend on the data model, never the reverse)
//! and `obikindex` doesn't grow every algorithm's own dependencies.
//!
//! [`algorithms`] holds each algorithm as its own submodule: `partitionner`
//! (routing raw super-kmers into partitions, then counting), `dereplicator`
//! (deduplicating a partition's raw super-kmers before counting). A future
//! `extensions` module will sit alongside it.
pub mod algorithms;
+1
View File
@@ -18,6 +18,7 @@ obikrope = { path = "../obikrope" }
obisys = { path = "../obisys" }
obiskio = { path = "../obiskio" }
obikindex = { path = "../obikindex", default-features = false }
obikindexer = { path = "../obikindexer" }
obikphylo = { path = "../obikphylo" }
obitaxonomy = { path = "../obitaxonomy" }
clap = { version = "4", features = ["derive"] }
+2 -2
View File
@@ -2,8 +2,8 @@ use std::path::PathBuf;
use std::time::Instant;
use clap::Args;
use obikindex::algorithms::dereplicator::Dereplicator;
use obikindex::algorithms::partitionner::PartitionRouter;
use obikindexer::algorithms::dereplicator::Dereplicator;
use obikindexer::algorithms::partitionner::PartitionRouter;
use obikindex::{validate_label, GenomeInfo, IndexConfig, IndexState, KmerIndex};
use obikindex::layer::IndexMode;
+1
View File
@@ -19,5 +19,6 @@ tracing = "0.1.44"
[dev-dependencies]
obiread = { path = "../obiread" }
obikindexer = { path = "../obikindexer" }
tempfile = "3"
tracing-subscriber = { version = "0.3", features = ["fmt", "env-filter"] }
+2 -2
View File
@@ -6,8 +6,8 @@ use obikindex::layer::MphfLayer;
use obisys::Reporter;
use tempfile::tempdir;
use obikindex::algorithms::dereplicator::Dereplicator;
use obikindex::algorithms::partitionner::PartitionRouter;
use obikindexer::algorithms::dereplicator::Dereplicator;
use obikindexer::algorithms::partitionner::PartitionRouter;
use obikindex::{GenomeInfo, IndexConfig, KmerIndex, MergeMode};
use super::alignment::SnpAlignmentExt;