mcpcounter-rust 0.1.0

Pure-Rust port of the MCPcounter cell-population quantification methods: MCP-counter (human) and mMCP-counter (mouse), validated for numeric parity against the original R implementations.
Documentation
//! Minimal MCP-counter quick-start (mirrors the README).
//!
//! Builds a tiny in-memory expression matrix of real HUGO marker symbols and
//! runs the human MCP-counter estimator. Run with:
//!
//!     cargo run --example quickstart

use mcpcounter_rust::{mcp_counter, ExprMatrix, FeaturesType};

fn main() {
    // 6 genes (rows) x 3 samples (cols), log2-scale expression, stored row-major.
    // Five are MCP-counter markers; GAPDH is a non-marker housekeeping gene and
    // is ignored, exactly as in R (markers are matched by name against the
    // bundled signature).
    let genes = vec![
        "CD3D".to_string(),  // T cells
        "CD28".to_string(),  // T cells
        "CD8B".to_string(),  // CD8 T cells
        "CD19".to_string(),  // B lineage
        "CD79A".to_string(), // B lineage
        "GAPDH".to_string(), // not a marker -> ignored
    ];
    let samples = vec![
        "tumor_A".to_string(),
        "tumor_B".to_string(),
        "normal".to_string(),
    ];
    #[rustfmt::skip]
    let data = vec![
        //  tumor_A  tumor_B  normal
            8.1,     7.4,     2.0, // CD3D
            7.6,     7.1,     1.8, // CD28
            6.9,     6.2,     1.5, // CD8B
            4.2,     8.3,     2.1, // CD19
            4.0,     8.0,     1.9, // CD79A
           11.0,    11.1,    11.0, // GAPDH (flat housekeeping)
    ];

    let expr = ExprMatrix::new(genes, samples, data);
    let result = mcp_counter(&expr, FeaturesType::HugoSymbols);

    // Each score is the mean of a population's present markers. Populations with
    // no present markers are dropped (as in R); the rest appear in MCP-counter's
    // signature order: T cells, CD8 T cells, B lineage.
    print!("{:<14}", "population");
    for s in &result.samples {
        print!("{s:>10}");
    }
    println!();
    for (p, pop) in result.populations.iter().enumerate() {
        print!("{pop:<14}");
        for s in 0..result.samples.len() {
            print!("{:>10.3}", result.score(p, s));
        }
        println!();
    }
}