-
Notifications
You must be signed in to change notification settings - Fork 98
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add a way to plot the output from generators
For visualization, add a simple script for generating scatter plots and a binary (via examples) to plot the inputs given various domains.
- Loading branch information
Showing
3 changed files
with
174 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -7,3 +7,6 @@ | |
Cargo.lock | ||
musl/ | ||
**.tar.gz | ||
|
||
# Files generated by binaries | ||
build/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
//! Program to write all inputs from a generator to a file, then invoke a Julia script | ||
//! to plot them. 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::io::{BufWriter, Write}; | ||
use std::path::Path; | ||
use std::process::Command; | ||
use std::{env, fs}; | ||
|
||
use libm_test::domain::Domain; | ||
use libm_test::gen::domain_logspace; | ||
|
||
const JL_PLOT: &str = "examples/plot_file.jl"; | ||
|
||
fn main() { | ||
let out_dir = Path::new("build"); | ||
if !out_dir.exists() { | ||
fs::create_dir(out_dir).unwrap(); | ||
} | ||
|
||
let jl_script = Path::new(&env::var("CARGO_MANIFEST_DIR").unwrap()).join(JL_PLOT); | ||
let mut j_args = Vec::new(); | ||
|
||
// Plot a few domains with some functions that use them. | ||
plot_one(out_dir, "sqrt", Domain::SQRT, &mut j_args); | ||
plot_one(out_dir, "cos", Domain::TRIG, &mut j_args); | ||
plot_one(out_dir, "cbrt", Domain::UNBOUNDED, &mut j_args); | ||
|
||
println!("launching script"); | ||
let mut cmd = Command::new("julia"); | ||
if !cfg!(debug_assertions) { | ||
cmd.arg("-O3"); | ||
} | ||
cmd.arg(jl_script).args(j_args).status().unwrap(); | ||
} | ||
|
||
/// Plot a single domain. | ||
fn plot_one(out_dir: &Path, name: &str, domain: Domain<f32>, j_args: &mut Vec<String>) { | ||
let base_name = out_dir.join(format!("domain-inputs-{name}")); | ||
let text_file = base_name.with_extension("txt"); | ||
|
||
{ | ||
// Scope for file and writer | ||
let f = fs::File::create(&text_file).unwrap(); | ||
let mut w = BufWriter::new(f); | ||
|
||
for input in domain_logspace::get_test_cases_inner::<f32>(domain) { | ||
writeln!(w, "{:e}", input.0).unwrap(); | ||
} | ||
w.flush().unwrap(); | ||
} | ||
|
||
// The julia script expects `name1 path1 name2 path2...` args | ||
j_args.push(name.to_owned()); | ||
j_args.push(base_name.to_str().unwrap().to_owned()); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,113 @@ | ||
"A quick script to for plotting a list of floats. | ||
Takes a list of floats and a real function, plots both on a graph in both | ||
linear and log scale. Requires [Makie] (specifically CairoMakie) for plotting. | ||
[Makie]: https://docs.makie.org/stable/ | ||
" | ||
|
||
using CairoMakie | ||
|
||
CairoMakie.activate!(px_per_unit=10) | ||
|
||
"Apply a function, returning the default if there is a domain error" | ||
function map_or_default( | ||
input::AbstractFloat, | ||
f::Function, | ||
default::AbstractFloat | ||
)::AbstractFloat | ||
try | ||
return f(input) | ||
catch | ||
return default | ||
end | ||
end | ||
|
||
"Read inputs from a file, create both linear and log plots" | ||
function plot_one( | ||
fig::Figure, | ||
base_name::String, | ||
fn_name::String, | ||
f::Function; | ||
xlims::Union{Tuple{Any,Any},Nothing}, | ||
xlims_log::Union{Tuple{Any,Any},Nothing}, | ||
)::Nothing | ||
float_file = "$base_name.txt" | ||
lin_out_file = "$base_name.png" | ||
log_out_file = "$base_name-log.png" | ||
|
||
if xlims === nothing | ||
xlims = (-6, 6) | ||
end | ||
if xlims_log === nothing | ||
xlims_log = (xlims[1] * 500, xlims[2] * 500) | ||
end | ||
|
||
inputs = readlines(float_file) | ||
|
||
# Parse floats | ||
x = map((v) -> parse(Float32, v), inputs) | ||
# Apply function to the test points | ||
y = map((v) -> map_or_default(v, f, 0.0), x) | ||
|
||
# Plot the scatter plot of our checked values as well as the continuous function | ||
ax = Axis(fig[1, 1], limits=(xlims, nothing), title=fn_name) | ||
lines!(ax, xlims[1] .. xlims[2], f, color=(:blue, 0.4)) | ||
scatter!(ax, x, y, color=(:green, 0.3)) | ||
save(lin_out_file, fig) | ||
delete!(ax) | ||
|
||
# Same as above on a log scale | ||
ax = Axis( | ||
fig[1, 1], | ||
limits=(xlims_log, nothing), | ||
xscale=Makie.pseudolog10, | ||
title="$fn_name (log scale)" | ||
) | ||
lines!(ax, xlims_log[1] .. xlims_log[2], f, color=(:blue, 0.4)) | ||
scatter!(ax, x, y, color=(:green, 0.3)) | ||
save(log_out_file, fig) | ||
delete!(ax) | ||
end | ||
|
||
# Args alternate `name1 path1 name2 path2` | ||
fn_names = ARGS[1:2:end] | ||
base_names = ARGS[2:2:end] | ||
|
||
for idx in eachindex(fn_names) | ||
fn_name = fn_names[idx] | ||
base_name = base_names[idx] | ||
|
||
xlims = nothing | ||
xlims_log = nothing | ||
|
||
fig = Figure() | ||
|
||
# Map string function names to callable functions | ||
if fn_name == "cos" | ||
f = cos | ||
xlims_log = (-pi * 10, pi * 10) | ||
elseif fn_name == "cbrt" | ||
f = cbrt | ||
xlims = (-2.0, 2.0) | ||
elseif fn_name == "sqrt" | ||
f = sqrt | ||
xlims = (-1.1, 6.0) | ||
xlims_log = (-1.1, 5000.0) | ||
else | ||
println("unrecognized function name `$fn_name`; update plot_file.jl") | ||
end | ||
|
||
println("plotting $fn_name") | ||
plot_one( | ||
fig, | ||
base_name, | ||
fn_name, | ||
f, | ||
xlims=xlims, | ||
xlims_log=xlims_log, | ||
) | ||
end | ||
|
||
base_name = ARGS[1] | ||
fn_name = ARGS[2] |