From 34ca4bd5256b8e52cd89fe25b3421ca2a8127fab Mon Sep 17 00:00:00 2001
From: rakhimov
Date: Wed, 9 Aug 2017 23:15:29 -0700
Subject: [PATCH] Add Alignment and Phase classes
Issue #153
---
src/CMakeLists.txt | 1 +
src/alignment.cc | 49 +++++++++++++++++++++
src/alignment.h | 93 ++++++++++++++++++++++++++++++++++++++++
tests/CMakeLists.txt | 1 +
tests/alignment_tests.cc | 78 +++++++++++++++++++++++++++++++++
5 files changed, 222 insertions(+)
create mode 100644 src/alignment.cc
create mode 100644 src/alignment.h
create mode 100644 tests/alignment_tests.cc
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 9457a3a502..393d68b72b 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -42,6 +42,7 @@ set(SCRAM_CORE_SRC
"${CMAKE_CURRENT_SOURCE_DIR}/ccf_group.cc"
"${CMAKE_CURRENT_SOURCE_DIR}/fault_tree.cc"
"${CMAKE_CURRENT_SOURCE_DIR}/event_tree.cc"
+ "${CMAKE_CURRENT_SOURCE_DIR}/alignment.cc"
"${CMAKE_CURRENT_SOURCE_DIR}/model.cc"
"${CMAKE_CURRENT_SOURCE_DIR}/pdag.cc"
"${CMAKE_CURRENT_SOURCE_DIR}/preprocessor.cc"
diff --git a/src/alignment.cc b/src/alignment.cc
new file mode 100644
index 0000000000..b862298305
--- /dev/null
+++ b/src/alignment.cc
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2017 Olzhas Rakhimov
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+/// @file alignment.cc
+/// Implementation of alignment and phase classes.
+
+#include "alignment.h"
+
+#include "error.h"
+
+namespace scram {
+namespace mef {
+
+Phase::Phase(std::string name, double time_fraction)
+ : Element(std::move(name)), time_fraction_(time_fraction) {
+ if (time_fraction_ <= 0 || time_fraction_ > 1)
+ throw InvalidArgument("The phase fraction must be in (0, 1].");
+}
+
+void Alignment::Add(PhasePtr phase) {
+ AddElement(std::move(phase), &phases_,
+ "Duplicate phase: ");
+}
+
+void Alignment::Validate() {
+ double sum = 0;
+ for (const PhasePtr& phase : phases_)
+ sum += phase->time_fraction();
+ if (sum != 1)
+ throw ValidationError("The phases of alignment '" + Element::name() +
+ "' do not sum to 1.");
+}
+
+} // namespace mef
+} // namespace scram
diff --git a/src/alignment.h b/src/alignment.h
new file mode 100644
index 0000000000..60add3585e
--- /dev/null
+++ b/src/alignment.h
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2017 Olzhas Rakhimov
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+/// @file alignment.h
+/// Mission and phase constructs.
+
+#ifndef SCRAM_SRC_ALIGNMENT_H_
+#define SCRAM_SRC_ALIGNMENT_H_
+
+#include
+#include
+#include
+
+#include
+
+#include "element.h"
+#include "instruction.h"
+
+namespace scram {
+namespace mef {
+
+/// Phases of alignments the models spends its time fraction.
+class Phase : public Element, private boost::noncopyable {
+ public:
+ /// @copydoc Element::Element
+ ///
+ /// @param[in] time_fraction The fraction of mission-time spent in the phase.
+ ///
+ /// @throws InvalidArgument The fraction is not a valid value in (0, 1].
+ Phase(std::string name, double time_fraction);
+
+ /// @returns The positive fraction of mission-time spent in this phase.
+ double time_fraction() const { return time_fraction_; }
+
+ /// @returns The instructions applied in this phase.
+ const std::vector& instructions() const {
+ return instructions_;
+ }
+
+ /// @param[in] instructions Zero or more instructions for this phase.
+ void instructions(std::vector instructions) {
+ instructions_ = std::move(instructions);
+ }
+
+ public:
+ double time_fraction_; ///< The positive fraction of the mission time.
+ std::vector instructions_; ///< The phase modifiers.
+};
+
+using PhasePtr = std::unique_ptr; ///< Phases are unique to alignments.
+
+/// Alignment configuration for the whole model per analysis.
+class Alignment : public Element, private boost::noncopyable {
+ public:
+ using Element::Element;
+
+ /// @returns The phases defined in the alignment.
+ const ElementTable& phases() const { return phases_; }
+
+ /// Adds a phase into alignment.
+ ///
+ /// @param[in] phase One of the unique phases for the alignment.
+ ///
+ /// @throws DuplicateArgumentError The phase is duplicate.
+ void Add(PhasePtr phase);
+
+ /// Ensures that all phases add up to be valid for the alignment.
+ ///
+ /// @throws ValidationError Phases are incomplete (e.g., don't sum to 1).
+ void Validate();
+
+ private:
+ ElementTable phases_; ///< The partitioning of the alignment.
+};
+
+} // namespace mef
+} // namespace scram
+
+#endif // SCRAM_SRC_ALIGNMENT_H_
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index febd9d35e7..b275e282f5 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -25,6 +25,7 @@ set(SCRAM_CORE_TEST_SOURCE
"${CMAKE_CURRENT_SOURCE_DIR}/expression_tests.cc"
"${CMAKE_CURRENT_SOURCE_DIR}/ccf_group_tests.cc"
"${CMAKE_CURRENT_SOURCE_DIR}/fault_tree_tests.cc"
+ "${CMAKE_CURRENT_SOURCE_DIR}/alignment_tests.cc"
"${CMAKE_CURRENT_SOURCE_DIR}/pdag_tests.cc"
"${CMAKE_CURRENT_SOURCE_DIR}/initializer_tests.cc"
"${CMAKE_CURRENT_SOURCE_DIR}/risk_analysis_tests.cc"
diff --git a/tests/alignment_tests.cc b/tests/alignment_tests.cc
new file mode 100644
index 0000000000..35263005af
--- /dev/null
+++ b/tests/alignment_tests.cc
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2017 Olzhas Rakhimov
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#include "alignment.h"
+
+#include
+
+#include "error.h"
+
+namespace scram {
+namespace mef {
+namespace test {
+
+TEST(PhaseTest, TimeFraction) {
+ EXPECT_NO_THROW(Phase("phase", 0.5));
+ EXPECT_NO_THROW(Phase("phase", 0.1));
+ EXPECT_NO_THROW(Phase("phase", 1));
+
+ EXPECT_THROW(Phase("phase", 0), InvalidArgument);
+ EXPECT_THROW(Phase("phase", 1.1), InvalidArgument);
+ EXPECT_THROW(Phase("phase", -0.1), InvalidArgument);
+}
+
+TEST(AlignmentTest, AddPhase) {
+ Alignment alignment("mission");
+ auto phase_one = std::make_unique("one", 0.5);
+ auto phase_two = std::make_unique("one", 0.1); // Duplicate name.
+ auto phase_three = std::make_unique("three", 0.1);
+
+ EXPECT_TRUE(alignment.phases().empty());
+ auto* phase_one_address = phase_one.get();
+ ASSERT_NO_THROW(alignment.Add(std::move(phase_one)));
+ EXPECT_EQ(1, alignment.phases().size());
+ EXPECT_EQ(phase_one_address, alignment.phases().begin()->get());
+
+ EXPECT_THROW(alignment.Add(std::move(phase_two)), DuplicateArgumentError);
+ EXPECT_EQ(1, alignment.phases().size());
+ EXPECT_EQ(phase_one_address, alignment.phases().begin()->get());
+
+ ASSERT_NO_THROW(alignment.Add(std::move(phase_three)));
+ EXPECT_EQ(2, alignment.phases().size());
+}
+
+TEST(AlignmentTest, Validation) {
+ Alignment alignment("mission");
+ auto phase_one = std::make_unique("one", 0.5);
+ auto phase_two = std::make_unique("two", 0.5);
+ auto phase_three = std::make_unique("three", 0.1);
+
+ EXPECT_THROW(alignment.Validate(), ValidationError);
+
+ ASSERT_NO_THROW(alignment.Add(std::move(phase_one)));
+ EXPECT_THROW(alignment.Validate(), ValidationError);
+
+ ASSERT_NO_THROW(alignment.Add(std::move(phase_two)));
+ EXPECT_NO_THROW(alignment.Validate());
+
+ ASSERT_NO_THROW(alignment.Add(std::move(phase_three)));
+ EXPECT_THROW(alignment.Validate(), ValidationError);
+}
+
+} // namespace test
+} // namespace mef
+} // namespace scram