Skip to content

Commit

Permalink
Refactor expression/exponential.{cc,h} code
Browse files Browse the repository at this point in the history
- DRY for Validation code
- Move the code out of line
- Simplify Min/Max for probability expressions

Issue #69
  • Loading branch information
rakhimov committed Feb 22, 2017
1 parent af2bd96 commit 1ff47e5
Show file tree
Hide file tree
Showing 3 changed files with 69 additions and 112 deletions.
122 changes: 59 additions & 63 deletions src/expression/exponential.cc
Expand Up @@ -20,27 +20,58 @@

#include "exponential.h"

#include <cmath>

#include "src/error.h"

namespace scram {
namespace mef {

/// Checks and throws if an expression is negative.
#define THROW_NEGATIVE_EXPR(expr, description) \
do { \
if (expr.Mean() < 0) \
throw InvalidArgument("The " description " cannot be negative."); \
if (expr.Min() < 0) \
throw InvalidArgument("The sampled " description \
" cannot be negative."); \
} while (false)

/// Check and throws if an expression is negative or 0.
#define THROW_NON_POSITIVE_EXPR(expr, description) \
do { \
if (expr.Mean() <= 0) \
throw InvalidArgument("The " description " must be positive."); \
if (expr.Min() <= 0) \
throw InvalidArgument("The sampled " description " must be positive."); \
} while (false)

namespace {

/// Negative exponential law probability.
double p_exp(double lambda, double time) {
return 1 - std::exp(-lambda * time);
}

} // namespace

ExponentialExpression::ExponentialExpression(const ExpressionPtr& lambda,
const ExpressionPtr& t)
: Expression({lambda, t}),
lambda_(*lambda),
time_(*t) {}

void ExponentialExpression::Validate() const {
if (lambda_.Mean() < 0) {
throw InvalidArgument("The rate of failure cannot be negative.");
} else if (time_.Mean() < 0) {
throw InvalidArgument("The mission time cannot be negative.");
} else if (lambda_.Min() < 0) {
throw InvalidArgument("The sampled rate of failure cannot be negative.");
} else if (time_.Min() < 0) {
throw InvalidArgument("The sampled mission time cannot be negative.");
}
THROW_NEGATIVE_EXPR(lambda_, "rate of failure");
THROW_NEGATIVE_EXPR(time_, "mission time");
}

double ExponentialExpression::Mean() noexcept {
return p_exp(lambda_.Mean(), time_.Mean());
}

double ExponentialExpression::DoSample() noexcept {
return p_exp(lambda_.Sample(), time_.Sample());
}

GlmExpression::GlmExpression(const ExpressionPtr& gamma,
Expand All @@ -54,22 +85,13 @@ GlmExpression::GlmExpression(const ExpressionPtr& gamma,
time_(*t) {}

void GlmExpression::Validate() const {
if (lambda_.Mean() < 0) {
throw InvalidArgument("The rate of failure cannot be negative.");
} else if (mu_.Mean() < 0) {
throw InvalidArgument("The rate of repair cannot be negative.");
} else if (gamma_.Mean() < 0 || gamma_.Mean() > 1) {
THROW_NON_POSITIVE_EXPR(lambda_, "rate of failure");
THROW_NEGATIVE_EXPR(mu_, "rate of repair");
THROW_NEGATIVE_EXPR(time_, "mission time");
if (gamma_.Mean() < 0 || gamma_.Mean() > 1) {
throw InvalidArgument("Invalid value for probability.");
} else if (time_.Mean() < 0) {
throw InvalidArgument("The mission time cannot be negative.");
} else if (lambda_.Min() < 0) {
throw InvalidArgument("The sampled rate of failure cannot be negative.");
} else if (mu_.Min() < 0) {
throw InvalidArgument("The sampled rate of repair cannot be negative.");
} else if (gamma_.Min() < 0 || gamma_.Max() > 1) {
throw InvalidArgument("Invalid sampled gamma value for probability.");
} else if (time_.Min() < 0) {
throw InvalidArgument("The sampled mission time cannot be negative.");
}
}

Expand Down Expand Up @@ -99,28 +121,13 @@ WeibullExpression::WeibullExpression(const ExpressionPtr& alpha,
time_(*time) {}

void WeibullExpression::Validate() const {
if (alpha_.Mean() <= 0) {
throw InvalidArgument("The scale parameter for Weibull distribution must"
" be positive.");
} else if (beta_.Mean() <= 0) {
throw InvalidArgument("The shape parameter for Weibull distribution must"
" be positive.");
} else if (t0_.Mean() < 0) {
throw InvalidArgument("Invalid value for time shift.");
} else if (time_.Mean() < 0) {
throw InvalidArgument("The mission time cannot be negative.");
} else if (time_.Mean() < t0_.Mean()) {
THROW_NON_POSITIVE_EXPR(alpha_, "scale parameter for Weibull distribution");
THROW_NON_POSITIVE_EXPR(beta_, "shape parameter for Weibull distribution");
THROW_NEGATIVE_EXPR(t0_, "time shift");
THROW_NEGATIVE_EXPR(time_, "mission time");

if (time_.Mean() < t0_.Mean()) {
throw InvalidArgument("The mission time must be longer than time shift.");
} else if (alpha_.Min() <= 0) {
throw InvalidArgument("The scale parameter for Weibull distribution must"
" be positive for sampled values.");
} else if (beta_.Min() <= 0) {
throw InvalidArgument("The shape parameter for Weibull distribution must"
" be positive for sampled values.");
} else if (t0_.Min() < 0) {
throw InvalidArgument("Invalid value for time shift in sampled values.");
} else if (time_.Min() < 0) {
throw InvalidArgument("The sampled mission time cannot be negative.");
} else if (time_.Min() < t0_.Max()) {
throw InvalidArgument("The sampled mission time must be"
" longer than time shift.");
Expand All @@ -132,6 +139,14 @@ double WeibullExpression::Compute(double alpha, double beta,
return 1 - std::exp(-std::pow((time - t0) / alpha, beta));
}

double WeibullExpression::Mean() noexcept {
return Compute(alpha_.Mean(), beta_.Mean(), t0_.Mean(), time_.Mean());
}

double WeibullExpression::DoSample() noexcept {
return Compute(alpha_.Sample(), beta_.Sample(), t0_.Sample(), time_.Sample());
}

PeriodicTest::PeriodicTest(const ExpressionPtr& lambda,
const ExpressionPtr& tau, const ExpressionPtr& theta,
const ExpressionPtr& time)
Expand All @@ -144,19 +159,9 @@ PeriodicTest::PeriodicTest(const ExpressionPtr& lambda, const ExpressionPtr& mu,
: Expression({lambda, mu, tau, theta, time}),
flavor_(new PeriodicTest::InstantTest(lambda, mu, tau, theta, time)) {}

/// Checks and throws if an expression is negative.
#define THROW_NEGATIVE_EXPR(expr, description) \
do { \
if (expr.Mean() < 0) \
throw InvalidArgument("The " description " cannot be negative."); \
if (expr.Min() < 0) \
throw InvalidArgument("The sampled " description \
" cannot be negative."); \
} while (false)

void PeriodicTest::InstantRepair::Validate() const {
THROW_NEGATIVE_EXPR(lambda_, "rate of failure");
THROW_NEGATIVE_EXPR(tau_, "time between tests");
THROW_NON_POSITIVE_EXPR(tau_, "time between tests");
THROW_NEGATIVE_EXPR(theta_, "time before tests");
THROW_NEGATIVE_EXPR(time_, "mission time");
}
Expand All @@ -168,15 +173,6 @@ void PeriodicTest::InstantTest::Validate() const {

#undef THROW_NEGATIVE_EXPR

namespace {

/// Negative exponential law probability.
double p_exp(double lambda, double time) {
return 1 - std::exp(-lambda * time);
}

} // namespace

double PeriodicTest::InstantRepair::Compute(double lambda, double tau,
double theta,
double time) noexcept {
Expand Down
58 changes: 9 additions & 49 deletions src/expression/exponential.h
Expand Up @@ -22,7 +22,7 @@
#ifndef SCRAM_SRC_EXPRESSION_EXPONENTIAL_H_
#define SCRAM_SRC_EXPRESSION_EXPONENTIAL_H_

#include <cmath>
#include <memory>

#include "src/expression.h"

Expand All @@ -41,32 +41,19 @@ class ExponentialExpression : public Expression {

/// @throws InvalidArgument The failure rate or time is negative.
void Validate() const override;

double Mean() noexcept override {
return 1 - std::exp(-(lambda_.Mean() * time_.Mean()));
}

double Max() noexcept override {
return 1 - std::exp(-(lambda_.Max() * time_.Max()));
}

double Min() noexcept override {
return 1 - std::exp(-(lambda_.Min() * time_.Min()));
}
double Mean() noexcept override;
double Max() noexcept override { return 1; }
double Min() noexcept override { return 0; }

private:
double DoSample() noexcept override {
return 1 - std::exp(-(lambda_.Sample() * time_.Sample()));
}
double DoSample() noexcept override;

Expression& lambda_; ///< Failure rate in hours.
Expression& time_; ///< Mission time in hours.
};

/// Exponential with probability of failure on demand,
/// hourly failure rate, hourly repairing rate, and time.
///
/// @todo Find the minimum and maximum values.
class GlmExpression : public Expression {
public:
/// Constructor for GLM or exponential expression with four arguments.
Expand All @@ -79,7 +66,6 @@ class GlmExpression : public Expression {
const ExpressionPtr& mu, const ExpressionPtr& t);

void Validate() const override;

double Mean() noexcept override;
double Max() noexcept override { return 1; }
double Min() noexcept override { return 0; }
Expand All @@ -88,13 +74,6 @@ class GlmExpression : public Expression {
double DoSample() noexcept override;

/// Computes the value for GLM expression.
///
/// @param[in] gamma Value for probability on demand.
/// @param[in] lambda Value for hourly rate of failure.
/// @param[in] mu Value for hourly repair rate.
/// @param[in] time Mission time in hours.
///
/// @returns Probability of failure on demand.
double Compute(double gamma, double lambda, double mu, double time) noexcept;

Expression& gamma_; ///< Probability of failure on demand.
Expand All @@ -116,33 +95,14 @@ class WeibullExpression : public Expression {
const ExpressionPtr& t0, const ExpressionPtr& time);

void Validate() const override;

double Mean() noexcept override {
return Compute(alpha_.Mean(), beta_.Mean(), t0_.Mean(), time_.Mean());
}

double Max() noexcept override {
return Compute(alpha_.Min(), beta_.Max(), t0_.Min(), time_.Max());
}

double Min() noexcept override {
return Compute(alpha_.Max(), beta_.Min(), t0_.Max(), time_.Min());
}
double Mean() noexcept override;
double Max() noexcept override { return 1; }
double Min() noexcept override { return 0; }

private:
double DoSample() noexcept override {
return Compute(alpha_.Sample(), beta_.Sample(), t0_.Sample(),
time_.Sample());
}
double DoSample() noexcept override;

/// Calculates Weibull expression.
///
/// @param[in] alpha Scale parameter.
/// @param[in] beta Shape parameter.
/// @param[in] t0 Time shift.
/// @param[in] time Mission time.
///
/// @returns Calculated value.
double Compute(double alpha, double beta, double t0, double time) noexcept;

Expression& alpha_; ///< Scale parameter.
Expand Down
1 change: 1 addition & 0 deletions src/expression/random_deviate.h
Expand Up @@ -22,6 +22,7 @@
#ifndef SCRAM_SRC_EXPRESSION_RANDOM_DEVIATE_H_
#define SCRAM_SRC_EXPRESSION_RANDOM_DEVIATE_H_

#include <memory>
#include <vector>

#include <boost/range/iterator_range.hpp>
Expand Down

0 comments on commit 1ff47e5

Please sign in to comment.