Skip to main content

uno_core/
lib.rs

1//! uno-core: MS1-only protein identification.
2//!
3//! Assigns peptide/protein identities from single-run feature files or KOTH
4//! consensus matrices. Long-format bundles retain original feature quality and
5//! per-run observations for shared-database batch search.
6
7// Structural lints: numeric kernels index several parallel buffers and scoring
8// passes many parallel slices; rewriting these for clippy would hurt clarity.
9#![allow(
10    clippy::too_many_arguments,
11    clippy::type_complexity,
12    clippy::needless_range_loop,
13    clippy::large_enum_variant
14)]
15
16mod broad_rt;
17pub mod calibrate;
18pub mod cell_evidence;
19pub mod database;
20pub mod decoy;
21pub mod digest;
22pub mod group;
23pub mod im;
24mod im_cache;
25pub mod input;
26pub mod joint;
27pub mod long_input;
28pub mod mass;
29pub mod matching;
30pub mod protein;
31pub mod quant;
32pub mod rt;
33pub mod rt_cache;
34pub mod rt_cnn;
35pub mod rt_mlp;
36pub mod score;
37
38pub use calibrate::Calibration;
39pub use database::{DigestConfig, PeptideDb, TheoPeptide};
40pub use im::{im_features, ImModel, IM_N_FEATURES};
41pub use input::{Feature, FeatureMatrix};
42pub use matching::{match_features, match_features_topk, MatchConfig, Pfm};
43pub use protein::{ProteinConfig, ProteinId};
44pub use rt::{rt_features, RtModel, RT_N_FEATURES};
45pub use rt_cnn::RtCnn;
46pub use rt_mlp::RtMlp;
47pub use score::{score, ScoreConfig, ScoreResult};
48
49/// Mix a user-chosen seed into the fixed constants behind uno's stochastic
50/// stages: the global-pool decoy shuffle, RANSAC pair sampling, CV fold
51/// assignment, and the tree booster's row/column subsampling. Seed 0 is the
52/// shipped default and returns 0, so every constant is left untouched and
53/// historical output is reproduced byte for byte; any other seed perturbs all
54/// of those stages together (`uno --seed N`). Used to measure uno's seed-to-seed
55/// spread the same way ms1searchpy's run-to-run spread is measured.
56pub fn seed_mix(seed: u64) -> u64 {
57    if seed == 0 {
58        return 0;
59    }
60    // splitmix64 finaliser: a small integer becomes a well-mixed 64-bit word.
61    let mut z = seed.wrapping_add(0x9e37_79b9_7f4a_7c15);
62    z = (z ^ (z >> 30)).wrapping_mul(0xbf58_476d_1ce4_e5b9);
63    z = (z ^ (z >> 27)).wrapping_mul(0x94d0_49bb_1331_11eb);
64    z ^ (z >> 31)
65}
66
67/// Locate a large test input, portably and without lying about coverage.
68///
69/// The benchmark inputs these tests need are gitignored (multi-gigabyte), so a
70/// fresh clone cannot run them. Three tests used to hard-code
71/// an absolute path under one home directory and silently `return` when it was missing, which
72/// reports as PASSED. That is the failure mode that let `uno` sit un-compilable at
73/// HEAD behind a green `cargo check`.
74///
75/// This resolves paths relative to the repository instead of one developer's home
76/// directory, prints a clearly marked SKIP when the input is absent, and honours
77/// `UNO_REQUIRE_TEST_DATA=1` by failing instead of skipping. Set that in CI and on
78/// the pre-benchmark checklist, where the data IS expected to be present.
79#[cfg(test)]
80pub(crate) fn test_input(rel: &str) -> Option<std::path::PathBuf> {
81    let root = std::path::Path::new(env!("CARGO_MANIFEST_DIR"))
82        .parent()
83        .and_then(|p| p.parent())
84        .expect("crates/uno-core -> repo root");
85    let p = root.join(rel);
86    if p.exists() {
87        return Some(p);
88    }
89    if std::env::var("UNO_REQUIRE_TEST_DATA").as_deref() == Ok("1") {
90        panic!(
91            "UNO_REQUIRE_TEST_DATA=1 but test input is missing: {}",
92            p.display()
93        );
94    }
95    eprintln!(
96        "SKIP: test input not present: {} (set UNO_REQUIRE_TEST_DATA=1 to make this a failure)",
97        p.display()
98    );
99    None
100}