Skip to content

Commit

Permalink
Allow obtaining the mean of a distribution
Browse files Browse the repository at this point in the history
Fixes #284
  • Loading branch information
haykam821 committed Mar 15, 2024
1 parent 5e04cb9 commit ec22881
Show file tree
Hide file tree
Showing 7 changed files with 46 additions and 1 deletion.
1 change: 1 addition & 0 deletions core/src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -696,6 +696,7 @@ pub(crate) fn resolve_identifier<I: Interrupt>(
"true" => Value::Bool(true),
"false" => Value::Bool(false),
"sample" | "roll" => Value::BuiltInFunction(BuiltInFunction::Sample),
"mean" | "average" => Value::BuiltInFunction(BuiltInFunction::Mean),
"sqrt" => evaluate_to_value("x: x^(1/2)", scope, attrs, context, int)?,
"cbrt" => evaluate_to_value("x: x^(1/3)", scope, attrs, context, int)?,
"real" | "re" | "Re" => Value::BuiltInFunction(BuiltInFunction::Real),
Expand Down
2 changes: 2 additions & 0 deletions core/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ pub(crate) enum FendError {
},
NegativeNumbersNotAllowed,
ProbabilityDistributionsNotAllowed,
EmptyDistribution,
FractionToInteger,
ModuloByZero,
RandomNumbersNotAvailable,
Expand Down Expand Up @@ -173,6 +174,7 @@ impl fmt::Display for FendError {
"probability distributions are not allowed (consider using `sample`)"
)
}
Self::EmptyDistribution => write!(f, "there must be at least one part in a dist"),

Check warning on line 177 in core/src/error.rs

View check run for this annotation

Codecov / codecov/patch

core/src/error.rs#L177

Added line #L177 was not covered by tests
Self::ParseDateError(s) => write!(f, "failed to convert '{s}' to a date"),
Self::ExpectedAString => write!(f, "expected a string"),
Self::UnableToInvertFunction(name) => write!(f, "unable to invert function {name}"),
Expand Down
22 changes: 21 additions & 1 deletion core/src/num/dist.rs
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,27 @@ impl Dist {
}
res = Some(Self::from(k));
}
Ok(res.expect("there must be at least one part in a dist"))
res.ok_or(FendError::EmptyDistribution)

Check warning on line 99 in core/src/num/dist.rs

View check run for this annotation

Codecov / codecov/patch

core/src/num/dist.rs#L99

Added line #L99 was not covered by tests
}

pub(crate) fn mean<I: Interrupt>(self, int: &I) -> FResult<Self> {
if self.parts.is_empty() {
return Err(FendError::EmptyDistribution);

Check warning on line 104 in core/src/num/dist.rs

View check run for this annotation

Codecov / codecov/patch

core/src/num/dist.rs#L104

Added line #L104 was not covered by tests
}

let len = self.parts.len();

if self.parts.len() == 1 {
return Ok(self);
}

let mut result = Exact::new(Complex::from(0), true);
for (k, _v) in self.parts {
result = result.add(Exact::new(k, true), int)?;
}

result = result.div(Exact::new(Complex::from(len as u64), true), int)?;
Ok(Self::from(result.value))
}

#[allow(
Expand Down
7 changes: 7 additions & 0 deletions core/src/num/unit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -537,6 +537,13 @@ impl Value {
})
}

pub(crate) fn mean<I: Interrupt>(self, int: &I) -> FResult<Self> {
Ok(Self {
value: self.value.mean(int)?,
..self
})
}

fn convert_angle_to_rad<I: Interrupt>(
self,
scope: Option<Arc<Scope>>,
Expand Down
1 change: 1 addition & 0 deletions core/src/value.rs
Original file line number Diff line number Diff line change
Expand Up @@ -349,6 +349,7 @@ impl Value {
return Ok(Self::Base(Base::from_plain_base(n)?));
}
BuiltInFunction::Sample => arg.expect_num()?.sample(context, int)?,
BuiltInFunction::Mean => arg.expect_num()?.mean(int)?,
BuiltInFunction::Not => return Ok(Self::Bool(!arg.as_bool()?)),
BuiltInFunction::Conjugate => arg.expect_num()?.conjugate()?,
BuiltInFunction::Real => arg.expect_num()?.real()?,
Expand Down
2 changes: 2 additions & 0 deletions core/src/value/built_in_function.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ pub(crate) enum BuiltInFunction {
Log10,
Base,
Sample,
Mean,
Not,
Conjugate,
Real,
Expand Down Expand Up @@ -96,6 +97,7 @@ impl BuiltInFunction {
Self::Log10 => "log10",
Self::Base => "base",
Self::Sample => "sample",
Self::Mean => "mean",
Self::Not => "not",
Self::Conjugate => "conjugate",
Self::Real => "real",
Expand Down
12 changes: 12 additions & 0 deletions core/tests/integration_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5936,3 +5936,15 @@ fn test_roman() {
test_eval_simple("1452 to roman", "MCDLII");
test_eval_simple("20002 to roman", "MMMMMMMMMMMMMMMMMMMMII");
}

#[test]
fn test_mean() {
test_eval("mean d1", "1");
test_eval("mean d2", "1.5");
test_eval("mean d500", "250.5");

test_eval("mean (d1 + d1)", "2");
test_eval("mean (d2 + d500)", "252");

test_eval("average d500", "250.5");
}

0 comments on commit ec22881

Please sign in to comment.