143 lines
4.2 KiB
Rust
143 lines
4.2 KiB
Rust
use statrs::statistics::{Data, Distribution};
|
|
use solutions::{RandomGenerator, Pcg32};
|
|
use plotters::prelude::*;
|
|
|
|
fn plot_histogram(
|
|
samples: &[f64],
|
|
filename: &str,
|
|
title: &str,
|
|
bins: usize,
|
|
) -> Result<(), Box<dyn std::error::Error>> {
|
|
// Create histogram bins
|
|
let mut counts = vec![0u32; bins];
|
|
for &sample in samples {
|
|
let bin = ((sample * bins as f64).floor() as usize).min(bins - 1);
|
|
counts[bin] += 1;
|
|
}
|
|
|
|
let max_count = *counts.iter().max().unwrap() as f64;
|
|
|
|
// Set up the drawing area
|
|
let root = BitMapBackend::new(filename, (800, 600)).into_drawing_area();
|
|
root.fill(&WHITE)?;
|
|
|
|
let mut chart = ChartBuilder::on(&root)
|
|
.caption(title, ("sans-serif", 30))
|
|
.margin(10)
|
|
.x_label_area_size(40)
|
|
.y_label_area_size(50)
|
|
.build_cartesian_2d(0.0..1.0, 0.0..(max_count * 1.1))?;
|
|
|
|
chart
|
|
.configure_mesh()
|
|
.x_desc("Value")
|
|
.y_desc("Count")
|
|
.draw()?;
|
|
|
|
// Draw histogram bars
|
|
chart.draw_series(
|
|
counts.iter().enumerate().map(|(i, &count)| {
|
|
let x0 = i as f64 / bins as f64;
|
|
let x1 = (i + 1) as f64 / bins as f64;
|
|
Rectangle::new([(x0, 0.0), (x1, count as f64)], BLUE.mix(0.6).filled())
|
|
}),
|
|
)?;
|
|
|
|
root.present()?;
|
|
println!("Histogram saved to: {}", filename);
|
|
Ok(())
|
|
}
|
|
|
|
fn plot_3d_scatter(
|
|
samples: &[f64],
|
|
filename: &str,
|
|
title: &str,
|
|
max_points: usize,
|
|
) -> Result<(), Box<dyn std::error::Error>> {
|
|
// Create triplets from consecutive samples
|
|
let triplets: Vec<(f64, f64, f64)> = samples
|
|
.windows(3)
|
|
.step_by(1)
|
|
.take(max_points)
|
|
.map(|w| (w[0], w[1], w[2]))
|
|
.collect();
|
|
|
|
// Set up the drawing area
|
|
let root = BitMapBackend::new(filename, (1024, 768)).into_drawing_area();
|
|
root.fill(&WHITE)?;
|
|
|
|
let mut chart = ChartBuilder::on(&root)
|
|
.caption(title, ("sans-serif", 30))
|
|
.margin(10)
|
|
.build_cartesian_3d(0.0..1.0, 0.0..1.0, 0.0..1.0)?;
|
|
|
|
// Rotate the view
|
|
chart.with_projection(|mut pb| {
|
|
pb.pitch = 0.8;
|
|
pb.yaw = 0.5;
|
|
pb.scale = 0.9;
|
|
pb.into_matrix()
|
|
});
|
|
|
|
chart.configure_axes().draw()?;
|
|
|
|
// Draw the points
|
|
chart.draw_series(
|
|
triplets
|
|
.iter()
|
|
.map(|&(x, y, z)| Circle::new((x, y, z), 2, BLUE.filled())),
|
|
)?;
|
|
|
|
root.present()?;
|
|
println!("Plot saved to: {}", filename);
|
|
Ok(())
|
|
}
|
|
|
|
fn main() {
|
|
println!("PROBLEM 3: PCG32 (Permuted Congruential Generator)");
|
|
println!("===================================================");
|
|
println!("PCG32 is a modern PRNG with excellent statistical properties.");
|
|
println!("It uses a 64-bit LCG internally with output permutation (XSH-RR).\n");
|
|
|
|
let seed = 42; // Classic seed choice!
|
|
let mut pcg = Pcg32::new(seed);
|
|
|
|
println!("Seed: {}\n", seed);
|
|
|
|
// Generate first few samples to show output
|
|
println!("First 5 random numbers:");
|
|
for i in 0..5 {
|
|
println!(" Random Number {}: {:.10}", i, pcg.next_uniform());
|
|
}
|
|
|
|
// Generate large number of samples for statistics
|
|
let n = 100_000;
|
|
println!("\nGenerating {} samples for analysis...", n);
|
|
|
|
let samples = pcg.generate_samples(n);
|
|
let data = Data::new(samples.clone());
|
|
|
|
// Calculate statistics
|
|
let mean = data.mean().unwrap();
|
|
let std_dev = data.std_dev().unwrap();
|
|
|
|
println!("\nStatistics:");
|
|
println!(" Mean: {:.6} (expected: 0.5)", mean);
|
|
println!(" Std Dev: {:.6} (expected: {:.6})", std_dev, (1.0/12.0_f64).sqrt());
|
|
|
|
// Generate histogram
|
|
println!("\nGenerating histogram...");
|
|
plot_histogram(&samples, "pcg32_histogram.png", "PCG32 - Histogram", 50)
|
|
.expect("Failed to create histogram");
|
|
|
|
// Generate 3D scatter plot
|
|
println!("Generating 3D scatter plot...");
|
|
let plot_samples = pcg.generate_samples(30000);
|
|
plot_3d_scatter(&plot_samples, "pcg32_3d.png", "PCG32 - 3D Scatter", 10000)
|
|
.expect("Failed to create 3D scatter plot");
|
|
|
|
println!("\nDone! Check the generated PNG files.");
|
|
println!("\nNote: PCG32 should show excellent uniformity and no visible");
|
|
println!("correlation patterns in the 3D plot - much better than basic LCGs!");
|
|
}
|