| //! Program to write all inputs from a generator to a file, then invoke a Julia script to plot | |
| //! them. Output is in `target/plots`. | |
| //! | |
| //! Requires Julia with the `CairoMakie` dependency. | |
| //! | |
| //! Note that running in release mode by default generates a _lot_ more datapoints, which | |
| //! causes plotting to be extremely slow (some simplification to be done in the script). | |
| use std::fmt::Write as _; | |
| use std::io::{BufWriter, Write}; | |
| use std::path::Path; | |
| use std::process::Command; | |
| use std::{env, fs}; | |
| use libm_test::generate::spaced::SpacedInput; | |
| use libm_test::generate::{edge_cases, spaced}; | |
| use libm_test::{CheckBasis, CheckCtx, GeneratorKind, MathOp, op}; | |
| const JL_PLOT: &str = "examples/plot_file.jl"; | |
| fn main() { | |
| let manifest_env = env::var("CARGO_MANIFEST_DIR").unwrap(); | |
| let manifest_dir = Path::new(&manifest_env); | |
| let out_dir = manifest_dir.join("../../target/plots"); | |
| if !out_dir.exists() { | |
| fs::create_dir(&out_dir).unwrap(); | |
| } | |
| let jl_script = manifest_dir.join(JL_PLOT); | |
| let mut config = format!(r#"out_dir = "{}""#, out_dir.display()); | |
| config.write_str("\n\n").unwrap(); | |
| // Plot a few domains with some functions that use them. | |
| plot_one_operator::<op::sqrtf::Routine>(&out_dir, &mut config); | |
| plot_one_operator::<op::cosf::Routine>(&out_dir, &mut config); | |
| plot_one_operator::<op::cbrtf::Routine>(&out_dir, &mut config); | |
| let config_path = out_dir.join("config.toml"); | |
| fs::write(&config_path, config).unwrap(); | |
| // The script expects a path to `config.toml` to be passed as its only argument | |
| let mut cmd = Command::new("julia"); | |
| if cfg!(optimizations_enabled) { | |
| cmd.arg("-O3"); | |
| } | |
| cmd.arg(jl_script).arg(config_path); | |
| println!("launching script... {cmd:?}"); | |
| cmd.status().unwrap(); | |
| } | |
| /// Run multiple generators for a single operator. | |
| fn plot_one_operator<Op>(out_dir: &Path, config: &mut String) | |
| where | |
| Op: MathOp<RustArgs = (f32,)>, | |
| Op::RustArgs: SpacedInput<Op>, | |
| { | |
| let mut ctx = CheckCtx::new(Op::IDENTIFIER, CheckBasis::Mpfr, GeneratorKind::Spaced); | |
| plot_one_generator( | |
| out_dir, | |
| &ctx, | |
| "logspace", | |
| config, | |
| spaced::get_test_cases::<Op>(&ctx).0, | |
| ); | |
| ctx.gen_kind = GeneratorKind::EdgeCases; | |
| plot_one_generator( | |
| out_dir, | |
| &ctx, | |
| "edge_cases", | |
| config, | |
| edge_cases::get_test_cases::<Op>(&ctx).0, | |
| ); | |
| } | |
| /// Plot the output of a single generator. | |
| fn plot_one_generator( | |
| out_dir: &Path, | |
| ctx: &CheckCtx, | |
| gen_name: &str, | |
| config: &mut String, | |
| generator: impl Iterator<Item = (f32,)>, | |
| ) { | |
| let fn_name = ctx.base_name_str; | |
| let text_file = out_dir.join(format!("input-{fn_name}-{gen_name}.txt")); | |
| let f = fs::File::create(&text_file).unwrap(); | |
| let mut w = BufWriter::new(f); | |
| let mut count = 0u64; | |
| for input in generator { | |
| writeln!(w, "{:e}", input.0).unwrap(); | |
| count += 1; | |
| } | |
| w.flush().unwrap(); | |
| println!("generated {count} inputs for {fn_name}-{gen_name}"); | |
| writeln!( | |
| config, | |
| r#"[[input]] | |
| function = "{fn_name}" | |
| generator = "{gen_name}" | |
| input_file = "{}" | |
| "#, | |
| text_file.to_str().unwrap() | |
| ) | |
| .unwrap() | |
| } |