Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 26 additions & 31 deletions crates/asap-aware-mapping/src/accuracy/budget.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,23 +9,22 @@
//! splits are made.
use super::*;

/// `shares` of `of` equal shares of `target`, in `metric`'s composition:
/// the target of one approximate input (`shares = 1`), or of a nested
/// sub-DAG holding `shares` of the `of` inputs. `None` for an exact target
/// or an ε that is not positive and finite: no approximate input meets it.
/// `of = 1` (or 0) is `target` itself.
pub fn equal_shares(
/// The target of one of `approximate_inputs` approximate inputs that
/// compose into a value with `target`, split equally in `metric`'s
/// composition (see the module doc). `None` for an exact target or an ε
/// that is not positive and finite: no approximate input meets it. One
/// input (or none) gets `target` itself.
pub fn per_input_target(
target: &AccuracyTarget,
metric: ErrorMetric,
of: usize,
shares: usize,
metric: AccuracyMetric,
approximate_inputs: usize,
) -> Option<AccuracyTarget> {
if target.is_exact() || !(target.error.is_finite() && target.error > 0.0) {
return None;
}
let fraction = shares.min(of.max(1)) as f64 / of.max(1) as f64;
let fraction = 1.0 / approximate_inputs.max(1) as f64;
let error = match metric {
ErrorMetric::Relative => (1.0 + target.error).powf(fraction) - 1.0,
AccuracyMetric::Relative => (1.0 + target.error).powf(fraction) - 1.0,
_ => target.error * fraction,
};
Some(AccuracyTarget {
Expand All @@ -35,15 +34,6 @@ pub fn equal_shares(
})
}

/// One of `approximate_inputs` equal shares of `target` ([`equal_shares`]).
pub fn equal_share(
target: &AccuracyTarget,
metric: ErrorMetric,
approximate_inputs: usize,
) -> Option<AccuracyTarget> {
equal_shares(target, metric, approximate_inputs, 1)
}

#[cfg(test)]
mod tests {
use super::*;
Expand All @@ -52,18 +42,18 @@ mod tests {
/// target.
#[test]
fn an_additive_target_splits_epsilon_and_delta_equally() {
let target = AccuracyTarget::epsilon_delta(0.1, 0.02);
let share = equal_share(&target, ErrorMetric::ABSOLUTE, 2).unwrap();
assert_eq!(share, AccuracyTarget::epsilon_delta(0.05, 0.01));
let rest = equal_shares(&target, ErrorMetric::ABSOLUTE, 3, 2).unwrap();
assert!((rest.error - 0.1 * 2.0 / 3.0).abs() < 1e-12);
assert!((rest.failure_probability.unwrap() - 0.02 * 2.0 / 3.0).abs() < 1e-12);
let target = AccuracyTarget::max_error(0.1).failure_probability(0.02);
let share = per_input_target(&target, AccuracyMetric::ABSOLUTE, 2).unwrap();
assert_eq!(
share,
AccuracyTarget::max_error(0.05).failure_probability(0.01)
);
assert_eq!(
equal_share(&target, ErrorMetric::Rank, 1),
per_input_target(&target, AccuracyMetric::Rank, 1),
Some(target.clone())
);
assert_eq!(
equal_share(&AccuracyTarget::epsilon(0.1), ErrorMetric::Rank, 2)
per_input_target(&AccuracyTarget::max_error(0.1), AccuracyMetric::Rank, 2)
.unwrap()
.failure_probability,
None
Expand All @@ -74,19 +64,24 @@ mod tests {
/// not `n ε_i = ε`.
#[test]
fn a_relative_target_splits_multiplicatively() {
let share = equal_share(&AccuracyTarget::epsilon(0.21), ErrorMetric::Relative, 2).unwrap();
let share = per_input_target(
&AccuracyTarget::max_error(0.21),
AccuracyMetric::Relative,
2,
)
.unwrap();
assert!((share.error - 0.1).abs() < 1e-12);
}

/// No approximate input meets an exact target.
#[test]
fn an_exact_target_has_no_share() {
assert_eq!(
equal_share(&AccuracyTarget::exact(), ErrorMetric::ABSOLUTE, 2),
per_input_target(&AccuracyTarget::exact(), AccuracyMetric::ABSOLUTE, 2),
None
);
assert_eq!(
equal_share(&AccuracyTarget::epsilon(0.0), ErrorMetric::ABSOLUTE, 2),
per_input_target(&AccuracyTarget::max_error(0.0), AccuracyMetric::ABSOLUTE, 2),
None
);
}
Expand Down
Loading
Loading