efficient_pca 0.1.8

Principal component computation using SVD and covariance matrix trick
Documentation
use std::process::Command;
use std::sync::Once;

static PY_DEPS_INIT: Once = Once::new();

pub fn ensure_python_packages_installed() {
    PY_DEPS_INIT.call_once(|| {
        let packages = [
            ("numpy", "numpy"),
            ("scipy", "scipy"),
            ("scikit-learn", "sklearn"),
        ];

        let mut missing = Vec::new();
        for (package_name, module_name) in packages.iter() {
            let status = Command::new("python3")
                .args(["-c", &format!("import {}", module_name)])
                .status()
                .expect("failed to invoke python3 to probe optional modules");
            if !status.success() {
                missing.push(*package_name);
            }
        }

        if missing.is_empty() {
            return;
        }

        println!(
            "Installing missing Python packages required for reference PCA: {:?}",
            missing
        );

        let mut cmd = Command::new("python3");
        cmd.args(["-m", "pip", "install", "--user"]);
        cmd.args(&missing);

        let output = cmd
            .output()
            .expect("failed to invoke pip to install python dependencies");

        if !output.status.success() {
            panic!(
                "Failed to install required python packages. Status: {:?}\nSTDOUT:\n{}\nSTDERR:\n{}",
                output.status,
                String::from_utf8_lossy(&output.stdout),
                String::from_utf8_lossy(&output.stderr)
            );
        }
    });
}