diff --git a/Cargo.lock b/Cargo.lock index fcdc14a..d0aa694 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,17 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi", + "libc", + "winapi", +] + [[package]] name = "cfg-if" version = "1.0.0" @@ -19,6 +30,15 @@ dependencies = [ "wasi", ] +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + [[package]] name = "itoa" version = "1.0.10" @@ -137,6 +157,7 @@ dependencies = [ name = "traktor" version = "0.1.0" dependencies = [ + "atty", "rand", "serde", "serde_json", @@ -153,3 +174,25 @@ name = "wasi" version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/Cargo.toml b/Cargo.toml index ab22e63..531f38a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,6 +6,7 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +atty = "0.2.14" rand = "0.8.5" serde = { version = "1.0.196", features = ["derive"] } serde_json = "1.0.113" diff --git a/src/main.rs b/src/main.rs index a4e1706..754d5c8 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,5 +1,5 @@ use std::fs::File; -use std::io::{self, BufRead, BufReader}; +use std::io::{self, BufRead, BufReader, stdin, Read}; use std::env; use std::process; use serde::Serialize; @@ -102,51 +102,38 @@ fn create_cluster_info(cluster: &[Point]) -> ClusterGapInfo { } } -// Adjust the main function and subsequent calculations to work with the new structure and calculate Z-scores accordingly - - -fn calculate_cluster_density(cluster: &[u32]) -> f32 { - if cluster.len() < 2 { return 0.0; } // Adjust based on how you define density for single-element clusters - - let &max_value = cluster.iter().max().unwrap(); - let &min_value = cluster.iter().min().unwrap(); - let span = (max_value - min_value) as f32; - if span == 0.0 { - return cluster.len() as f32; // Handle clusters where all points have the same value - } - cluster.len() as f32 / span -} - -// Assume distance function is defined as before - - fn distance(p1: &Point, p2: &Point) -> u32 { if p1.value > p2.value { p1.value - p2.value } else { p2.value - p1.value } } - -fn calculate_mean_and_std_dev(densities: &[f32]) -> (f32, f32) { - let mean = densities.iter().sum::() / densities.len() as f32; - let variance = densities.iter().map(|&v| (v - mean).powi(2)).sum::() / densities.len() as f32; - (mean, variance.sqrt()) -} - -fn calculate_z_scores(densities: &[f32], mean: f32, std_dev: f32) -> Vec { - densities.iter().map(|&density| (density - mean) / std_dev).collect() -} - fn main() -> io::Result<()> { let args: Vec = env::args().collect(); - if args.len() < 4 { - eprintln!("Usage: {} ", args[0]); - process::exit(1); + let mut dataset: Vec = Vec::new(); + + // Check if data is being piped into the program + if atty::is(atty::Stream::Stdin) { + // Not receiving piped input, expect filename as argument + if args.len() < 4 { + eprintln!("Usage: {} ", args[0]); + eprintln!("Or pipe in a list of integers and provide "); + process::exit(1); + } + + let filename = &args[1]; + dataset = load_dataset(filename)?; + } else { + // Receiving piped input, read from stdin + let stdin = io::stdin(); + let reader = stdin.lock(); + for line in reader.lines() { + let value: u32 = line?.trim().parse().unwrap(); + dataset.push(Point::new(value)); + } + dataset.sort_by_key(|p| p.value); } - let filename = &args[1]; - let factor: f32 = args[2].parse().expect("Factor must be a float"); - let min_cluster_size: usize = args[3].parse().expect("Min cluster size must be an integer"); - - let dataset = load_dataset(filename)?; + let factor: f32 = args[args.len() - 2].parse().expect("Factor must be a float"); + let min_cluster_size: usize = args[args.len() - 1].parse().expect("Min cluster size must be an integer"); let mut cluster_gap_infos = calculate_densities_and_gaps(&dataset, factor, min_cluster_size);