Skip to content

Commit

Permalink
switch from Identifier to CheckCtx
Browse files Browse the repository at this point in the history
  • Loading branch information
tgross35 committed Dec 26, 2024
1 parent e729e8c commit 1827d56
Show file tree
Hide file tree
Showing 8 changed files with 34 additions and 66 deletions.
14 changes: 8 additions & 6 deletions crates/libm-test/examples/plot_domains.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ use std::{env, fs};

use libm_test::domain::HasDomain;
use libm_test::gen::{domain_logspace, edge_cases};
use libm_test::{MathOp, op};
use libm_test::{CheckBasis, CheckCtx, MathOp, op};

const JL_PLOT: &str = "examples/plot_file.jl";

Expand Down Expand Up @@ -54,29 +54,31 @@ fn plot_one_operator<Op>(out_dir: &Path, config: &mut String)
where
Op: MathOp<FTy = f32> + HasDomain<f32>,
{
let ctx = CheckCtx::new(Op::IDENTIFIER, CheckBasis::Mpfr);
plot_one_generator(
out_dir,
Op::BASE_NAME.as_str(),
&ctx,
"logspace",
config,
domain_logspace::get_test_cases::<Op>(),
domain_logspace::get_test_cases::<Op>(&ctx),
);
plot_one_generator(
out_dir,
Op::BASE_NAME.as_str(),
&ctx,
"edge_cases",
config,
edge_cases::get_test_cases::<Op, _>(),
edge_cases::get_test_cases::<Op, _>(&ctx),
);
}
/// Plot the output of a single generator.
fn plot_one_generator(
out_dir: &Path,
fn_name: &str,
ctx: &CheckCtx,
gen_name: &str,
config: &mut String,
gen: 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();
Expand Down
8 changes: 4 additions & 4 deletions crates/libm-test/src/gen/domain_logspace.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,20 @@ use libm::support::{IntTy, MinInt};

use crate::domain::HasDomain;
use crate::op::OpITy;
use crate::run_cfg::{TestAction, TestTy};
use crate::{MathOp, logspace};
use crate::run_cfg::{GeneratorKind, TestAction};
use crate::{CheckCtx, MathOp, logspace};

/// Create a range of logarithmically spaced inputs within a function's domain.
///
/// This allows us to get reasonably thorough coverage without wasting time on values that are
/// NaN or out of range. Random tests will still cover values that are excluded here.
pub fn get_test_cases<Op>() -> impl Iterator<Item = (Op::FTy,)>
pub fn get_test_cases<Op>(ctx: &CheckCtx) -> impl Iterator<Item = (Op::FTy,)>
where
Op: MathOp + HasDomain<Op::FTy>,
IntTy<Op::FTy>: TryFrom<u64>,
{
let domain = Op::DOMAIN;
let action = crate::run_cfg::get_iterations(Op::IDENTIFIER, TestTy::Logspace, 0);
let action = crate::run_cfg::get_iterations(ctx, GeneratorKind::Logspace, 0);
let ntests = match action {
TestAction::Iterations(n) => n,
TestAction::Run => unimplemented!(),
Expand Down
4 changes: 2 additions & 2 deletions crates/libm-test/src/gen/edge_cases.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
use libm::support::Float;

use crate::domain::HasDomain;
use crate::{FloatExt, MathOp};
use crate::{CheckCtx, FloatExt, MathOp};

/// Number of values near an interesting point to check.
// FIXME(ntests): replace this with a more logical algorithm
Expand All @@ -14,7 +14,7 @@ const AROUND: usize = 100;
const MAX_CHECK_POINTS: usize = 10;

/// Create a list of values around interesting points (infinities, zeroes, NaNs).
pub fn get_test_cases<Op, F>() -> impl Iterator<Item = (F,)>
pub fn get_test_cases<Op, F>(_ctx: &CheckCtx) -> impl Iterator<Item = (F,)>
where
Op: MathOp<FTy = F> + HasDomain<F>,
F: Float,
Expand Down
10 changes: 5 additions & 5 deletions crates/libm-test/src/gen/extensive.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@ where
Op: HasDomain<Op::FTy>,
{
fn gen() -> impl Iterator<Item = Self> {
let mut start = Op::D.range_start();
let end = Op::D.range_end();
let mut start = Op::DOMAIN.range_start();
let end = Op::DOMAIN.range_end();
iter::from_fn(move || {
if start > end || start >= Op::FTy::INFINITY {
return None;
Expand All @@ -44,7 +44,7 @@ where
}

fn count() -> u64 {
u64::from(ulp_between(Op::D.range_start(), Op::D.range_end()).unwrap()) + 1
u64::from(ulp_between(Op::DOMAIN.range_start(), Op::DOMAIN.range_end()).unwrap()) + 1
}
}

Expand All @@ -54,8 +54,8 @@ where
Op: HasDomain<Op::FTy>,
{
fn gen() -> impl Iterator<Item = Self> {
let start = Op::D.range_start();
let end = Op::D.range_end();
let start = Op::DOMAIN.range_start();
let end = Op::DOMAIN.range_end();
let steps = <Op::FTy as Float>::Int::try_from(MAX_ITERATIONS)
.unwrap_or(<Op::FTy as Float>::Int::MAX);
logspace(start, end, steps).map(|v| (v,))
Expand Down
5 changes: 3 additions & 2 deletions crates/libm-test/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,16 @@ pub mod mpfloat;
mod num;
pub mod op;
mod precision;
pub mod run_cfg;
mod run_cfg;
mod test_traits;

pub use f8_impl::f8;
pub use libm::support::{Float, Int, IntTy, MinInt};
pub use num::{FloatExt, logspace};
pub use op::{BaseName, FloatTy, Identifier, MathOp, OpCFn, OpFTy, OpRustFn, OpRustRet, Ty};
pub use precision::{MaybeOverride, SpecialCase, default_ulp};
pub use test_traits::{CheckBasis, CheckCtx, CheckOutput, GenerateInput, Hex, TupleCall};
pub use run_cfg::{CheckBasis, CheckCtx, EXTENSIVE_ENV, GeneratorKind, TestAction, get_iterations};
pub use test_traits::{CheckOutput, GenerateInput, Hex, TupleCall};

/// Result type for tests is usually from `anyhow`. Most times there is no success value to
/// propagate.
Expand Down
42 changes: 1 addition & 41 deletions crates/libm-test/src/test_traits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,47 +11,7 @@ use std::fmt;

use anyhow::{Context, bail, ensure};

use crate::{BaseName, Float, Identifier, Int, MaybeOverride, SpecialCase, TestResult};

/// Context passed to [`CheckOutput`].
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct CheckCtx {
/// Allowed ULP deviation
pub ulp: u32,
pub fn_ident: Identifier,
pub base_name: BaseName,
/// Function name.
pub fn_name: &'static str,
/// Return the unsuffixed version of the function name.
pub base_name_str: &'static str,
/// Source of truth for tests.
pub basis: CheckBasis,
}

impl CheckCtx {
/// Create a new check context, using the default ULP for the function.
pub fn new(fn_ident: Identifier, basis: CheckBasis) -> Self {
let mut ret = Self {
ulp: 0,
fn_ident,
fn_name: fn_ident.as_str(),
base_name: fn_ident.base_name(),
base_name_str: fn_ident.base_name().as_str(),
basis,
};
ret.ulp = crate::default_ulp(&ret);
ret
}
}

/// Possible items to test against
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum CheckBasis {
/// Check against Musl's math sources.
Musl,
/// Check against infinite precision (MPFR).
Mpfr,
}
use crate::{CheckCtx, Float, Int, MaybeOverride, SpecialCase, TestResult};

/// Implement this on types that can generate a sequence of tuples for test input.
pub trait GenerateInput<TupleArgs> {
Expand Down
8 changes: 5 additions & 3 deletions crates/libm-test/tests/multiprecision.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,21 +83,21 @@ macro_rules! mp_domain_tests {
$(#[$meta])*
fn [< mp_edge_case_ $fn_name >]() {
type Op = libm_test::op::$fn_name::Routine;
domain_test_runner::<Op>(edge_cases::get_test_cases::<Op, _>());
domain_test_runner::<Op, _>(edge_cases::get_test_cases::<Op, _>);
}

#[test]
$(#[$meta])*
fn [< mp_logspace_ $fn_name >]() {
type Op = libm_test::op::$fn_name::Routine;
domain_test_runner::<Op>(domain_logspace::get_test_cases::<Op>());
domain_test_runner::<Op, _>(domain_logspace::get_test_cases::<Op>);
}
}
};
}

/// Test a single routine against domaine-aware inputs.
fn domain_test_runner<Op>(cases: impl Iterator<Item = (Op::FTy,)>)
fn domain_test_runner<Op, I>(gen: impl FnOnce(&CheckCtx) -> I)
where
// Complicated generics...
// The operation must take a single float argument (unary only)
Expand All @@ -108,9 +108,11 @@ where
Op: HasDomain<Op::FTy>,
// The single float argument tuple must be able to call the `RustFn` and return `RustRet`
(OpFTy<Op>,): TupleCall<OpRustFn<Op>, Output = OpRustRet<Op>>,
I: Iterator<Item = (Op::FTy,)>,
{
let mut mp_vals = Op::new_mp();
let ctx = CheckCtx::new(Op::IDENTIFIER, CheckBasis::Mpfr);
let cases = gen(&ctx);

for input in cases {
let mp_res = Op::run(&mut mp_vals, input);
Expand Down
9 changes: 6 additions & 3 deletions crates/libm-test/tests/z_extensive/run.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,10 @@ use std::time::Duration;
use indicatif::{ProgressBar, ProgressStyle};
use libm_test::gen::extensive::{self, ExtensiveInput};
use libm_test::mpfloat::MpOp;
use libm_test::run_cfg::{EXTENSIVE_ENV, TestAction, TestTy, get_iterations};
use libm_test::{CheckBasis, CheckCtx, CheckOutput, MathOp, TestResult, TupleCall};
use libm_test::{
CheckBasis, CheckCtx, CheckOutput, EXTENSIVE_ENV, GeneratorKind, MathOp, TestAction,
TestResult, TupleCall, get_iterations,
};
use libtest_mimic::{Arguments, Completion, Trial};
use rayon::prelude::*;

Expand Down Expand Up @@ -46,7 +48,8 @@ where
{
let test_name = format!("mp_extensive_{name}");
all.push(Trial::skippable_test(test_name, move || {
let action = get_iterations(Op::IDENTIFIER, TestTy::Extensive, 0);
let ctx = CheckCtx::new(Op::IDENTIFIER, CheckBasis::Mpfr);
let action = get_iterations(&ctx, GeneratorKind::Extensive, 0);
match action {
TestAction::Run => (),
TestAction::Iterations(_) => panic!("extensive tests disregard iteration counts"),
Expand Down

0 comments on commit 1827d56

Please sign in to comment.