Skip to content
This repository was archived by the owner on Apr 28, 2025. It is now read-only.

Commit dc1a1da

Browse files
committed
docs
1 parent abc9e6f commit dc1a1da

File tree

3 files changed

+39
-29
lines changed

3 files changed

+39
-29
lines changed

crates/libm-test/examples/plot_domains.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
//! to plot them. Requires Julia with the `CairoMakie` dependency.
33
//!
44
//! Note that running in release mode by default generates a _lot_ more datapoints, which
5-
//! causes plotting to be extremely slow (some simplification to done in the script).
5+
//! causes plotting to be extremely slow (some simplification to be done in the script).
66
77
use std::io::{BufWriter, Write};
88
use std::path::Path;
@@ -21,9 +21,9 @@ fn main() {
2121
}
2222

2323
let jl_script = Path::new(&env::var("CARGO_MANIFEST_DIR").unwrap()).join(JL_PLOT);
24-
2524
let mut j_args = Vec::new();
2625

26+
// Plot a few domains with some functions that use them.
2727
plot_one::<SqrtDomain>(out_dir, "sqrt", &mut j_args);
2828
plot_one::<TrigDomain>(out_dir, "cos", &mut j_args);
2929
plot_one::<Unbounded>(out_dir, "cbrt", &mut j_args);
@@ -36,6 +36,7 @@ fn main() {
3636
cmd.arg(jl_script).args(j_args).status().unwrap();
3737
}
3838

39+
/// Plot a single domain.
3940
fn plot_one<D: Domain<f32>>(out_dir: &Path, name: &str, j_args: &mut Vec<String>) {
4041
let base_name = out_dir.join(format!("domain-inputs-{name}"));
4142
let text_file = base_name.with_extension("txt");

crates/libm-test/src/domain.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
1-
#![allow(unused)]
2-
31
use std::fmt;
42
use std::ops::{self, Bound};
53

6-
use crate::{Float, MathOp, MinInt, op};
4+
use crate::Float;
75

86
/// A trait to be implemented on types representing a function's domain.
97
///
@@ -26,7 +24,8 @@ where
2624
std::iter::empty()
2725
}
2826

29-
/// Points to check closer around, often zeros of the derivative.
27+
/// Additional points to check closer around. These can be e.g. undefined asymptotes or
28+
/// inflection points.
3029
fn check_points() -> impl Iterator<Item = T> {
3130
std::iter::empty()
3231
}
@@ -174,12 +173,13 @@ macro_rules! impl_has_domain {
174173
};
175174
}
176175

177-
/// Tie the functions together with their domains.
176+
// Tie functions together with their domains.
178177
impl_has_domain! {
179178
acos => InvTrigPeriodic;
180179
acosh => ACoshDomain;
181180
asin => InvTrigPeriodic;
182181
asinh => Unbounded;
182+
// TODO asymptotes
183183
atan => Unbounded;
184184
atanh => ATanhDomain;
185185
cbrt => Unbounded;

crates/libm-test/src/gen/domain.rs

Lines changed: 31 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,14 @@
1-
/*
2-
Does the following:
3-
4-
- Check 100 values near each of the bounds
5-
- If there are defined asymptotes, check those
6-
- Figure out a number of tests to do within the domain. If exhaustive, check all (but skip
7-
NaNs?)
8-
- Check near zero if defined
9-
- If unbounded, ensure that real inputs do not produce any NaNs
10-
- If periodic, check that results are identical for a few periods (?)
11-
12-
13-
*/
1+
//! A generator that makes use of the `Domain` trait
2+
//!
3+
//! Does the following:
4+
//!
5+
//! - Check 100 values near each of the bounds (default)
6+
//! - If there are defined asymptotes, check those
7+
//! - Figure out a number of tests to do within the domain. If exhaustive, check all (but skip
8+
//! NaNs?)
9+
//! - Check near zero if defined
10+
//! - If unbounded, ensure that real inputs do not produce any NaNs
11+
//! - If periodic, check that results are identical for a few periods (?)
1412
1513
use std::iter;
1614
use std::ops::Bound;
@@ -42,15 +40,16 @@ const NTESTS: usize = {
4240
}
4341
};
4442

45-
// /// Some functions have infinite asymptotes, limit how many we check.
46-
// const MAX_ASYMPTOTES: usize = 10;
43+
/// Some functions have infinite asymptotes, limit how many we check.
44+
const MAX_ASYMPTOTES: usize = 10;
4745

4846
/// Create a test case iterator.
4947
pub fn get_test_cases<F: Float, D: Domain<F>>() -> impl Iterator<Item = (F,)>
5048
where
5149
F::Int: TryFrom<usize>,
5250
{
53-
// Figure out the ranges we will test on
51+
// We generate logspaced inputs within a specific range. Use the function domain
52+
// by default but if the function is periodic, check only within that period.
5453
let (start, end) = D::PERIODIC.unwrap_or(D::DEFINED);
5554
let range_start = match start {
5655
Bound::Included(v) => v,
@@ -64,9 +63,12 @@ where
6463
};
6564

6665
let steps = F::Int::try_from(NTESTS).unwrap_or(F::Int::MAX);
66+
67+
// Always check near bounds in addition to the logspace
6768
near_bounds::<F, D>().into_iter().chain(logspace(range_start, range_end, steps)).map(|v| (v,))
6869
}
6970

71+
/// Create a vector full of values near interesting (bounds, asymptotes, etc).
7072
fn near_bounds<F: Float, D: Domain<F>>() -> Vec<F> {
7173
let mut values = Vec::new();
7274

@@ -105,15 +107,19 @@ fn near_bounds<F: Float, D: Domain<F>>() -> Vec<F> {
105107
around(x, &mut values);
106108
}
107109

108-
// Max, min, and infinities are interesting
110+
// Values around min and max are interesting
111+
values.extend(count_up(F::MIN).take(AROUND));
112+
values.extend(count_down(F::MAX).take(AROUND));
113+
114+
// Check some special values that aren't included in the above ranges
115+
values.push(F::NAN);
109116
values.push(F::MIN);
110117
values.push(F::MAX);
111118
values.push(F::INFINITY);
112119
values.push(F::NEG_INFINITY);
113120
values.push(F::NEG_ZERO);
114-
values.extend(count_up(F::MIN).take(AROUND));
115-
values.extend(count_down(F::MAX).take(AROUND));
116121

122+
// Check period endpoints (as we define them) if available
117123
if let Some((start, end)) = D::PERIODIC {
118124
validate_bound(start);
119125
validate_bound(end);
@@ -122,6 +128,8 @@ fn near_bounds<F: Float, D: Domain<F>>() -> Vec<F> {
122128
around_bound(end, &mut values);
123129

124130
let p = D::period().unwrap();
131+
132+
// Check the same points for a few period to make sure there is no drift
125133
for mul in [one / two, one, three / two, two, three] {
126134
let back = D::period_start() - mul * p;
127135
let forward = D::period_end() + mul * p;
@@ -131,11 +139,12 @@ fn near_bounds<F: Float, D: Domain<F>>() -> Vec<F> {
131139
}
132140
}
133141

134-
for (from, _to) in D::defined_asymptotes() {
142+
// Check around asymptotest
143+
for (from, _to) in D::defined_asymptotes().take(MAX_ASYMPTOTES) {
135144
around(from, &mut values);
136145
}
137146

138-
for x in D::check_points() {
147+
for x in D::check_points().take(MAX_ASYMPTOTES) {
139148
around(x, &mut values);
140149
}
141150

@@ -145,7 +154,7 @@ fn near_bounds<F: Float, D: Domain<F>>() -> Vec<F> {
145154
values
146155
}
147156

148-
/// Push `AROUND` values up and `AROUND` values down from a value.
157+
/// Push `AROUND` values up and `AROUND` values down from a value exhaustively (increments ULP).
149158
fn around<F: Float>(x: F, values: &mut Vec<F>) {
150159
values.push(x);
151160
values.extend(count_up(x).take(AROUND));

0 commit comments

Comments
 (0)