[scram] 01/02: Imported Upstream version 0.11.5
Olzhas Rakhimov
rakhimov-guest at moszumanska.debian.org
Mon Dec 12 11:03:26 UTC 2016
This is an automated email from the git hooks/post-receive script.
rakhimov-guest pushed a commit to branch master
in repository scram.
commit d2710fe97c2b27f108729d0728d73dc50c635786
Author: rakhimov <ol.rakhimov at gmail.com>
Date: Mon Dec 12 02:57:46 2016 -0800
Imported Upstream version 0.11.5
---
.appveyor.yml | 7 +-
.codecov.yml | 2 +-
.gitmodules | 3 +
.landscape.yml | 1 +
.travis.yml | 4 +-
.travis/doxygen.conf | 2 +-
.travis/install.sh | 25 +-
.travis/run_tests.sh | 6 +-
.travis/script.sh | 12 +-
CMakeLists.txt | 39 +-
README.rst | 38 +-
cmake/FindJeMalloc.cmake | 47 +
doc/bugs.rst | 7 +-
doc/citation.rst | 22 +
doc/coding_standards.rst | 32 +-
doc/config_file.rst | 2 +-
doc/design_description.rst | 140 +-
.../{shorthand_input.txt => aralia_input.txt} | 0
doc/fault_tree_analysis.rst | 4 +-
doc/fault_tree_generator.rst | 2 +-
doc/fta_algorithms.rst | 11 +-
doc/fta_preprocessing.rst | 2 +-
doc/gui.rst | 4 +-
doc/input_file.rst | 30 +-
doc/installation.rst | 2 +-
doc/opsa_support.rst | 45 +-
doc/performance.rst | 8 +-
doc/probability_analysis.rst | 12 +-
doc/references.rst | 24 +-
doc/release/release_checklist.rst | 16 +-
doc/release/v0.11.5.md | 36 +
doc/report_layer.rst | 12 +-
doc/{scram.man => scram.1} | 6 +-
doc/todo.rst | 5 +-
doc/xml_comments.rst | 2 +-
gui/CMakeLists.txt | 7 +-
gui/event.cpp | 46 +-
gui/event.h | 103 +-
gui/gate.h | 19 +-
input/EventTreeExample/event_tree.xml | 2 +-
install.py | 2 +-
scripts/fault_tree.py | 36 +-
scripts/fault_tree_generator.py | 19 +-
scripts/fuzz_tester.py | 72 +-
scripts/nqueens.py | 28 +-
scripts/shorthand_to_xml.py | 527 --------
scripts/{ => test}/test_fault_tree_generator.py | 21 +-
scripts/test_shorthand_to_xml.py | 427 -------
share/config.rng | 103 +-
share/input.rng | 2 +-
share/open-psa/curves.bnf | 11 -
share/open-psa/mcs.bnf | 18 -
share/open-psa/mef.dtd | 461 -------
share/open-psa/mef.rnc | 539 --------
share/open-psa/mef.rng | 1341 --------------------
share/open-psa/stat_measures.bnf | 26 -
share/report_layer.rng | 82 +-
src/CMakeLists.txt | 48 +-
src/bdd.cc | 1 -
src/bdd.h | 70 +-
src/boolean_graph.cc | 5 +-
src/boolean_graph.h | 103 +-
src/ccf_group.cc | 12 +-
src/ccf_group.h | 2 +-
src/cycle.h | 4 +-
src/event.h | 5 +-
src/expression.cc | 479 +------
src/expression.h | 659 +---------
src/expression/arithmetic.cc | 114 ++
src/expression/arithmetic.h | 196 +++
src/expression/constant.cc | 53 +
src/expression/constant.h | 82 ++
src/expression/exponential.cc | 136 ++
src/expression/exponential.h | 157 +++
.../random_deviate.cc} | 292 +----
src/expression/random_deviate.h | 267 ++++
src/ext.h | 13 +-
src/fault_tree.cc | 3 -
src/fault_tree.h | 2 +-
src/fault_tree_analysis.cc | 3 +
src/fault_tree_analysis.h | 7 +-
src/importance_analysis.cc | 1 +
src/importance_analysis.h | 44 +-
src/initializer.cc | 11 +-
src/initializer.h | 4 +-
src/logger.cc | 21 +-
src/logger.h | 18 +-
src/model.cc | 45 +
src/model.h | 39 +-
src/{logger.cc => parameter.cc} | 39 +-
src/parameter.h | 93 ++
src/preprocessor.cc | 59 +
src/preprocessor.h | 2 +
src/probability_analysis.cc | 40 +-
src/probability_analysis.h | 106 +-
src/random.h | 140 +-
src/reporter.cc | 14 +-
src/reporter.h | 13 +-
src/risk_analysis.cc | 31 +-
src/risk_analysis.h | 80 +-
src/scram.cc | 30 +-
src/settings.h | 2 +
src/uncertainty_analysis.cc | 15 +
src/uncertainty_analysis.h | 50 +-
tests/CMakeLists.txt | 2 +-
tests/bench_bscu_tests.cc | 8 +-
tests/bench_core_tests.cc | 4 +-
tests/bench_small_tree_tests.cc | 11 +-
tests/ccf_group_tests.cc | 1 +
tests/expression_tests.cc | 4 +
tests/input/empty_attribute.xml | 2 +-
tests/input/fta/doubly_defined_parameter.xml | 2 +-
tests/input/fta/run_inputs.py | 96 +-
tests/input/unsupported_feature.xml | 2 +-
tests/performance_tests.cc | 3 +-
tests/risk_analysis_tests.cc | 99 +-
tests/risk_analysis_tests.h | 134 +-
tests/test_scram_call.py | 2 +-
118 files changed, 2549 insertions(+), 5933 deletions(-)
diff --git a/.appveyor.yml b/.appveyor.yml
index 9182b76..865b8a2 100644
--- a/.appveyor.yml
+++ b/.appveyor.yml
@@ -12,6 +12,7 @@ install:
- set PATH=C:\msys64\mingw64\bin;C:\msys64\usr\bin;%PATH%
- pacman --noconfirm -Syu
- pacman --noconfirm -Syu
+ - pacman --noconfirm -S mingw-w64-x86_64-jemalloc
- pacman --noconfirm -S mingw-w64-x86_64-boost
- pacman --noconfirm -S mingw-w64-x86_64-libxml++2.6
- pacman --noconfirm -S mingw-w64-x86_64-qt5
@@ -19,15 +20,11 @@ install:
before_build:
- md install
- md build
- - cd build
build_script:
- - cmake -G "MSYS Makefiles" -DCMAKE_INSTALL_PREFIX=..\install -DCMAKE_BUILD_TYPE=%CONFIGURATION% ..
- - make -j 2
+ - python .\install.py --mingw64 --prefix=.\install --build-type=%CONFIGURATION% -j 2
after_build:
- - make install
- - cd ..
- set PATH=%PATH%;%CD%\install\bin
test_script:
diff --git a/.codecov.yml b/.codecov.yml
index 8627f00..8546493 100644
--- a/.codecov.yml
+++ b/.codecov.yml
@@ -5,4 +5,4 @@ coverage:
ignore:
- tests/*
- src/*
- - scripts/test_*
+ - scripts/test/*
diff --git a/.gitmodules b/.gitmodules
index b616270..8933f82 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -1,3 +1,6 @@
[submodule "tests/googletest"]
path = tests/googletest
url = https://github.com/rakhimov/googletest
+[submodule "scripts/translators"]
+ path = scripts/translators
+ url = https://github.com/rakhimov/translators
diff --git a/.landscape.yml b/.landscape.yml
index 890fa1b..a2a896c 100644
--- a/.landscape.yml
+++ b/.landscape.yml
@@ -10,6 +10,7 @@ mccabe:
options: {max-complexity: 15}
pylint:
enable: [bad-continuation, fixme]
+ options: {max-nested-blocks: 3}
python-targets:
- 2
- 3
diff --git a/.travis.yml b/.travis.yml
index f93444f..ae68800 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -20,7 +20,7 @@ env:
global:
- PATH=$PATH:`pwd`/install/bin
# Intel Parallel Studio
- - secure: "BM1aLsCy0NYk1TCCMeQH6H1O9B+NmZeO6QzRTjy1Xrs8wvoKsuBiazjxSZ6nVWP3F+JtjsOLzeFyELmCf4lobcw8bhzgLZ7ZFaDJl4DC31w+87RdQFYzMe5t53SfflkfBDYkbpbUrt1B7qPk5r0nYDG+QzO3T/XnvSN/0HvmEBQ="
+ - secure: "AY6adQXVk/3J43z6PHbqVxq3Bn5HZ5Qrf8fvPeF+BR56Oa4+9YryfDDJyiDRISuyh7PoDUw+PERJiZpAL3rkFefxUkYTB3hdU4lsMIAgl37MuT4/kP5CW9TC+gsPJl41y4i8XKFtJXF1K4PW2oDRZCbDDB9oUWPZjNPPe0jg4e8="
matrix:
- RELEASE=
- RELEASE=true
@@ -29,6 +29,8 @@ matrix:
exclude:
- os: osx
compiler: gcc # GCC is Clang on OS X.
+ - os: osx
+ env: RELEASE= # OS X builds are slow and limited.
include:
- os: linux
compiler: icc
diff --git a/.travis/doxygen.conf b/.travis/doxygen.conf
index b387651..5f8d038 100644
--- a/.travis/doxygen.conf
+++ b/.travis/doxygen.conf
@@ -769,7 +769,7 @@ FILE_PATTERNS = *.h *.cc *.cc.in
# be searched for input files as well.
# The default value is: NO.
-RECURSIVE = NO
+RECURSIVE = YES
# The EXCLUDE tag can be used to specify files and/or directories that should be
# excluded from the INPUT source files. This way you can easily exclude a
diff --git a/.travis/install.sh b/.travis/install.sh
index 2ff27d8..ba287b5 100755
--- a/.travis/install.sh
+++ b/.travis/install.sh
@@ -11,8 +11,8 @@ if [[ "${TRAVIS_OS_NAME}" == "osx" ]]; then
brew install ccache
fi
-sudo pip install -U pip wheel
-sudo pip install -r requirements-tests.txt
+sudo -H pip install -U pip wheel
+sudo -H pip install nose # Testing main() requires nosetests!
[[ "${TRAVIS_OS_NAME}" == "linux" ]] || exit 0
@@ -26,10 +26,10 @@ PROJECT_DIR=$PWD
cd /tmp
# Boost
-wget https://sourceforge.net/projects/iscram/files/deps/boost-scram.tar.bzip2
-tar -xf ./boost-scram.tar.bzip2 # Sets up install dir.
-sudo mv ./install/lib/* /usr/lib/
-sudo mv ./install/include/boost /usr/include/
+wget https://sourceforge.net/projects/iscram/files/deps/boost-scram.tar.gz
+tar -xf ./boost-scram.tar.gz
+sudo mv ./boost-scram/lib/* /usr/lib/
+sudo mv ./boost-scram/include/* /usr/include/
# Libxml++
LIBXMLPP='libxml++-2.38.1'
@@ -40,9 +40,18 @@ tar -xf ${LIBXMLPP}.tar.xz
cd $PROJECT_DIR
[[ -z "${RELEASE}" && "$CXX" = "g++" ]] || exit 0
+
+# Install newer doxygen due to bugs in 1.8.6 with C++11 code.
+DOXYGEN='doxygen-1.8.12.linux.bin.tar.gz'
+wget https://sourceforge.net/projects/iscram/files/deps/${DOXYGEN}
+tar -xf ${DOXYGEN}
+sudo cp doxygen-1.8.12/bin/* /usr/bin/
+
sudo apt-get install -qq ggcov
sudo apt-get install -qq valgrind
-sudo apt-get install -qq doxygen
-sudo pip install -r requirements-dev.txt
sudo apt-get install -qq lcov
+
gem install coveralls-lcov
+
+sudo -H pip install -r requirements-dev.txt
+sudo -H pip install -r requirements-tests.txt
diff --git a/.travis/run_tests.sh b/.travis/run_tests.sh
index 360e8c3..46a9827 100755
--- a/.travis/run_tests.sh
+++ b/.travis/run_tests.sh
@@ -7,13 +7,11 @@ set -ev
which scram
which scram_tests
-scram_tests --gtest_filter=-*Performance*
+scram_tests
nosetests -w ./tests/
if [[ -z "${RELEASE}" && "$CXX" = "g++" ]]; then
- nosetests --with-coverage -w ./scripts/
-else
- nosetests -w ./scripts/
+ nosetests --with-coverage -w scripts test/
fi
./scripts/fault_tree_generator.py -b 200 -a 5
diff --git a/.travis/script.sh b/.travis/script.sh
index d66b761..b1629ce 100755
--- a/.travis/script.sh
+++ b/.travis/script.sh
@@ -43,11 +43,8 @@ valgrind --tool=memcheck --leak-check=full --show-leak-kinds=definite \
|| [[ $? -ne 127 ]]
# Check documentation coverage
+which doxygen || exit 1
doxygen ./.travis/doxygen.conf > /dev/null 2> doc_errors.txt
-# Deletion of compiler generated default functions
-sed -i '/=delete/d' doc_errors.txt
-# Doxygen 1.8.6 can't deal with C++11 initializer list in constructor.
-sed -i '/expression\.cc/d' doc_errors.txt
if [[ -s doc_errors.txt ]]; then
echo "Documentation errors:" >&2
cat doc_errors.txt >&2
@@ -60,8 +57,11 @@ lizard -w -L 60 -a 5 -EIgnoreAssert -ENS -Ecpre src gui \
lizard -w -L 60 -a 5 scripts/*.py
# C++ linting
-cpplint --repository=../ --quiet src/* tests/* 2> style.txt \
+cpplint --repository=../ --quiet --recursive src/* 2> style.txt \
|| echo "TODO: Fix the C++ code"
+cpplint --repository=../ --quiet --filter=-build/include_what_you_use \
+ tests/* 2>> style.txt || echo "TODO: Fix the C++ code"
+
# Clean false positives and noise
sed -i '/Found C system header after C\+\+/d' style.txt
sed -i '/Found C system header after other header/d' style.txt
@@ -77,4 +77,4 @@ if [[ -s style.txt ]]; then
fi
# Python linting
-prospector -P .landscape ./*.py scripts/*.py
+prospector ./*.py scripts/*.py
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 8ae6226..fb3214d 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -14,16 +14,19 @@ endif()
project(SCRAM)
set(SCRAM_VERSION_MAJOR 0) # Indicate major API change after 1.0.0
set(SCRAM_VERSION_MINOR 11) # New features and improvements.
-set(SCRAM_VERSION_MICRO 4) # Bug fixes.
+set(SCRAM_VERSION_MICRO 5) # Bug fixes.
####################### Begin Options ###################
-set(BUILD_SHARED_LIBS TRUE) # Change this for static building.
+option(BUILD_SHARED_LIBS OFF)
+
+option(INSTALL_LIBS "Install the generated libraries" ON)
# Linking of external libraries, such as BOOST.
option(WITH_STATIC_LIBS "Try to link against static libraries" OFF)
-option(WITH_TCMALLOC "Use TCMalloc" ON)
+option(WITH_TCMALLOC "Use TCMalloc if available (#1 preference)" ON)
+option(WITH_JEMALLOC "Use JEMalloc if available (#2 preference)" ON)
option(WITH_COVERAGE "Instrument for coverage analysis" OFF)
option(WITH_PROFILE "Instrument for performance profiling" OFF)
@@ -43,7 +46,7 @@ CHECK_CXX_COMPILER_FLAG("-std=c++1y" COMPILER_SUPPORTS_CXX14)
if(NOT COMPILER_SUPPORTS_CXX14)
message(FATAL_ERROR "The compiler ${CMAKE_CXX_COMPILER} has no C++14 support.")
endif()
-add_definitions("-std=c++1y")
+set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++1y")
set(CMAKE_CXX_FLAGS_DEBUG
"${CMAKE_CXX_FLAGS_DEBUG} -Wall -Wextra -Werror -Wno-sign-compare -Wnon-virtual-dtor -Wno-missing-field-initializers")
@@ -66,8 +69,6 @@ elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang" OR
elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Intel")
# TODO: Bug in Intel compiler with multi-initialization with auto.
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -diag-disable=3373")
- # TODO: Bug in Intel compiler w/o GCC 5 built-in math with overlflow.
- add_definitions(-D_GLIB_TEST_OVERFLOW_FALLBACK) # TODO: Remove after glib2 version 2.48
endif()
if(WIN32)
@@ -76,6 +77,7 @@ endif()
find_program(CCACHE_FOUND ccache)
if(CCACHE_FOUND)
+ message(STATUS "Using CCache for builds")
set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE ccache)
set_property(GLOBAL PROPERTY RULE_LAUNCH_LINK ccache)
@@ -118,7 +120,9 @@ set(CMAKE_SKIP_BUILD_RPATH FALSE)
# (but later on when installing).
set(CMAKE_BUILD_WITH_INSTALL_RPATH FALSE)
-set(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/lib")
+if(INSTALL_LIBS)
+ set(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/lib")
+endif()
# Add the automatically determined parts of the RPATH,
# which point to directories outside the build tree
@@ -132,13 +136,20 @@ list(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake")
######################## Begin find libraries ######################
-set(LIBS "")
-
-# Optional TCMalloc for optimization.
-if(WITH_TCMALLOC AND NOT WITH_PROFILE)
+set(MALLOC "System Malloc")
+# Optional alternative Malloc for optimization.
+if(NOT WITH_PROFILE)
find_package(Tcmalloc)
- set(LIBS ${LIBS} ${Tcmalloc_LIBRARIES})
+ find_package(JeMalloc)
+ if(WITH_TCMALLOC AND Tcmalloc_FOUND)
+ set(LIBS ${LIBS} ${Tcmalloc_LIBRARIES})
+ set(MALLOC "TCMalloc")
+ elseif(WITH_JEMALLOC AND JEMALLOC_FOUND)
+ set(LIBS ${LIBS} ${JEMALLOC_LIBRARIES})
+ set(MALLOC "JEMalloc")
+ endif()
endif()
+message(STATUS "The memory allocator: ${MALLOC}")
# Find LibXML++ and dependencies.
set(LIBXML++_MIN_VERSION "2.38.1") # TODO: Fix the minimum version check.
@@ -161,7 +172,7 @@ endif()
unset(Boost_INCLUDE_DIR CACHE)
unset(Boost_LIBRARY_DIRS CACHE)
find_package(Boost ${BOOST_MIN_VERSION} COMPONENTS
- program_options filesystem system date_time
+ program_options filesystem system date_time random
REQUIRED)
if(Boost_USE_STATIC_LIBS)
@@ -209,6 +220,8 @@ include_directories(SYSTEM "${LibXML++_INCLUDE_DIR}")
include_directories(SYSTEM "${LibXML++Config_INCLUDE_DIR}")
include_directories(SYSTEM ${Glibmm_INCLUDE_DIRS}) # TODO: libxml++ dependency.
+include_directories("${PROJECT_SOURCE_DIR}") # Include the core headers via "src".
+
add_subdirectory("${SCRAM_SOURCE_DIR}")
add_subdirectory("${SCRAM_SHARE_DIR}")
add_subdirectory("${SCRAM_INPUT_DIR}")
diff --git a/README.rst b/README.rst
index 2c4d149..9d4a49e 100644
--- a/README.rst
+++ b/README.rst
@@ -16,9 +16,9 @@ SCRAM
:alt: Code Health
.. image:: https://codecov.io/github/rakhimov/scram/coverage.svg?branch=develop
:target: https://codecov.io/github/rakhimov/scram?branch=develop
-.. image:: https://badge.waffle.io/rakhimov/scram.svg?label=ready&title=Ready
+.. image:: https://badge.waffle.io/rakhimov/scram.svg?label=In%20Progress&title=in%20progress
:target: https://waffle.io/rakhimov/scram
- :alt: 'Stories in Ready'
+ :alt: 'Stories in Progress'
|
@@ -31,8 +31,8 @@ probability calculations with importance analysis,
and uncertainty analysis with Monte Carlo simulations.
This tool can handle non-coherent fault trees, containing NOT logic.
-SCRAM input and report files are based on OpenPSA_ Model Exchange Format.
-For the current status of the OpenPSA MEF features in SCRAM,
+SCRAM input and report files are based on the Open-PSA_ `Model Exchange Format`_.
+For the current status of the Open-PSA MEF features in SCRAM,
please see the `MEF Support`_ documentation.
A complementary GUI front-end is under development
@@ -46,7 +46,8 @@ The documentation_ contains a full description of SCRAM,
its current capabilities, and future additions.
The latest stable release is packaged for `quick installation`_ on various platforms.
-.. _OpenPSA: http://open-psa.org
+.. _Open-PSA: http://open-psa.org
+.. _Model Exchange Format: http://open-psa.github.io/mef
.. _MEF Support: http://scram-pra.org/doc/opsa_support.html
.. _documentation: http://scram-pra.org
.. _quick installation: http://scram-pra.org/doc/installation.html
@@ -80,6 +81,7 @@ Optional Dependencies
Package Minimum Version
==================== ==================
`TCMalloc` 1.7
+`JEMalloc` 3.6
==================== ==================
@@ -91,7 +93,7 @@ Package Minimum Version
==================== ==================
`GCC/G++` 4.9
`Clang/LLVM` 3.4
-`Intel` 17.0
+`Intel` 17.0.1
==================== ==================
@@ -105,7 +107,7 @@ or the following commands must be executed after a normal clone.
.. code-block:: bash
- git submodule init --update --recursive
+ git submodule update --init --recursive
Installing Dependencies (Linux and Unix)
@@ -244,8 +246,7 @@ Various other flags are described by the script's help prompt.
.../scram$ python install.py --help
-Other tools,
-such as the **fault tree generator** and **shorthand-to-XML** converter,
+Other tools, such as the **fault tree generator**,
can be found in the ``scripts`` directory.
These tools do not need compilation or installation.
@@ -273,6 +274,10 @@ Where ``package`` is replaced by the correct package name:
#. libxml++2.6
#. qt5
+and (optionally):
+
+#. jemalloc
+
If Python has not already been installed on the system,
Python installation takes the form of:
@@ -285,14 +290,14 @@ the following line will install all major dependencies:
.. code-block:: bash
- pacman --noconfirm -S python mingw-w64-x86_64-{gcc,make,cmake,boost,libxml++2.6,qt5}
+ pacman --noconfirm -S python mingw-w64-x86_64-{gcc,make,cmake,boost,libxml++2.6,qt5,jemalloc}
The building and installation can be done with the ``install.py`` script
in the root directory.
.. code-block:: bash
- .../scram$ python install.py --prefix=path/to/installation/directory -release --mingw64
+ .../scram$ python install.py --prefix=path/to/installation/directory --release --mingw64
After installation,
SCRAM must be run inside of the MSYS2 shell.
@@ -330,7 +335,7 @@ On command line, run help to get more detailed information:
scram --help
Various other useful tools and helper scripts,
-such as the **fault tree generator** and **shorthand-to-XML** converter,
+such as the **fault tree generator**,
can be found in the ``scripts`` directory.
Help prompts and the documentation have more details how to use these tools.
@@ -348,7 +353,7 @@ To test the tools in the ``scripts`` directory:
.. code-block:: bash
- nosetests -w scripts/
+ nosetests -w scripts/ test/
To test the command-line call of SCRAM:
@@ -381,14 +386,16 @@ It is recommended to build SCRAM
with assertions preserved
and sanitizers enabled, for example,
address sanitizer in GCC and Clang ``-fsanitize=address``.
+
In order to speed up the fuzz testing,
SCRAM may be built with optimizations but ``NDEBUG`` undefined.
+Additionally, multiple SCRAM instances can be run at once.
-An example command to run SCRAM 1000 times with auto-generated inputs and configurations:
+An example command to run SCRAM 1000 times with 4 parallel instances:
.. code-block:: bash
- fuzz_tester.py -n 1000
+ fuzz_tester.py -n 1000 -j 4
The fuzz tester can be guided with options listed in its help prompt.
Some options can be combined,
@@ -401,6 +408,7 @@ however, information messages are given to indicate the interpretation.
fuzz_tester.py --help
+Fuzzing inputs and configurations are auto-generated.
The fuzz tester collects run configurations, failures, and logs.
The auto-generated inputs are preserved for failed runs.
diff --git a/cmake/FindJeMalloc.cmake b/cmake/FindJeMalloc.cmake
new file mode 100644
index 0000000..f36cbc6
--- /dev/null
+++ b/cmake/FindJeMalloc.cmake
@@ -0,0 +1,47 @@
+# - Try to find jemalloc
+# Once done this will define
+# JEMALLOC_FOUND - System has jemalloc
+# JEMALLOC_INCLUDE_DIRS - The jemalloc include directories
+# JEMALLOC_LIBRARIES - The libraries needed to use jemalloc
+
+if(NOT JEMALLOC_USE_BUNDLED)
+ find_package(PkgConfig)
+ if (PKG_CONFIG_FOUND)
+ pkg_check_modules(PC_JEMALLOC QUIET jemalloc)
+ endif()
+else()
+ set(PC_JEMALLOC_INCLUDEDIR)
+ set(PC_JEMALLOC_INCLUDE_DIRS)
+ set(PC_JEMALLOC_LIBDIR)
+ set(PC_JEMALLOC_LIBRARY_DIRS)
+ set(LIMIT_SEARCH NO_DEFAULT_PATH)
+endif()
+
+set(JEMALLOC_DEFINITIONS ${PC_JEMALLOC_CFLAGS_OTHER})
+
+find_path(JEMALLOC_INCLUDE_DIR jemalloc/jemalloc.h
+ PATHS ${PC_JEMALLOC_INCLUDEDIR} ${PC_JEMALLOC_INCLUDE_DIRS}
+ ${LIMIT_SEARCH})
+
+# If we're asked to use static linkage, add libjemalloc.a as a preferred library name.
+if(JEMALLOC_USE_STATIC)
+ list(APPEND JEMALLOC_NAMES
+ "${CMAKE_STATIC_LIBRARY_PREFIX}jemalloc${CMAKE_STATIC_LIBRARY_SUFFIX}")
+endif()
+
+list(APPEND JEMALLOC_NAMES jemalloc)
+
+find_library(JEMALLOC_LIBRARY NAMES ${JEMALLOC_NAMES}
+ HINTS ${PC_JEMALLOC_LIBDIR} ${PC_JEMALLOC_LIBRARY_DIRS}
+ ${LIMIT_SEARCH})
+
+set(JEMALLOC_LIBRARIES ${JEMALLOC_LIBRARY})
+set(JEMALLOC_INCLUDE_DIRS ${JEMALLOC_INCLUDE_DIR})
+
+include(FindPackageHandleStandardArgs)
+# handle the QUIETLY and REQUIRED arguments and set JEMALLOC_FOUND to TRUE
+# if all listed variables are TRUE
+find_package_handle_standard_args(JeMalloc DEFAULT_MSG
+ JEMALLOC_LIBRARY JEMALLOC_INCLUDE_DIR)
+
+mark_as_advanced(JEMALLOC_INCLUDE_DIR JEMALLOC_LIBRARY)
diff --git a/doc/bugs.rst b/doc/bugs.rst
index aac9dca..1e42dff 100644
--- a/doc/bugs.rst
+++ b/doc/bugs.rst
@@ -13,6 +13,11 @@ Technical Issues
low-level technical issues.
- Copying Settings around is expensive (~100B)
-- mef::Gate and mef::Formula have ``type`` field instead of ``operator`` (reserved in C++)
+- core::Gate and mef::Formula have ``type`` field instead of ``operator`` (reserved in C++)
- Static variables of class type with dynamic initialization.
- Performance profile across platforms is not stable.
+- Builds are very demanding for the project size:
+ 500 MiB/job memory and 3 min total time.
+ The major contributing factors may be
+ the template-heavy code
+ and coupled physical layout of the project components.
diff --git a/doc/citation.rst b/doc/citation.rst
new file mode 100644
index 0000000..9d499c9
--- /dev/null
+++ b/doc/citation.rst
@@ -0,0 +1,22 @@
+########
+Citation
+########
+
+To cite SCRAM in publications
+=============================
+
+| Olzhas Rakhimov (|year|).
+| SCRAM version |release| documentation: Command-line Risk Analysis Multi-tool.
+| URL http://scram-pra.org/
+
+|
+
+A BibTex entry for LaTeX users
+==============================
+
+| @book{,
+| author = {Olzhas Rakhimov},
+| title = {{SCRAM} version |release| documentation: Command-line Risk Analysis Multi-tool},
+| year = {|year|},
+| url = {http://scram-pra.org/},
+| }
diff --git a/doc/coding_standards.rst b/doc/coding_standards.rst
index 82fab3e..5340661 100644
--- a/doc/coding_standards.rst
+++ b/doc/coding_standards.rst
@@ -114,8 +114,8 @@ Additional Coding Conventions
.. code-block:: cpp
double checked_div(double x, double y) {
- if (!y) throw domain_error(""); // Bad. Looks like 'if (no y) then fail'.
- // More explicit (y == 0) is better.
+ if (!y) // Bad. Looks like 'if (no y) then fail'.
+ throw domain_error(""); // More explicit (y == 0) is better.
return x / y;
}
@@ -184,13 +184,13 @@ Core C++ Code
abbreviate it to ``p_``.
Its getter/setter functions should have
corresponding names, i.e., ``p()`` and ``p(double value)``.
- Append extra description after ``p_``, e.g., ``p_total_``.
+ Append extra description after ``p_``, e.g., ``p_total_`` (a la Semantic Hungarian).
Avoid abbreviating the name to ``prob``
or fully spelling it to ``probability``.
* For non-member probability variables:
- + Prefer prefixing with ``p_``
+ + Prefer prefixing with ``p_`` (a la Semantic Hungarian)
if the name has more description to the probability value, e.g., ``p_not_event``.
+ Prefer ``prob`` abbreviation
for single word names indicating general probability values.
@@ -208,12 +208,12 @@ Core C++ Code
This gate in fault tree analysis has many names
(Voting, Combination, atleast, K/N),
and there doesn't seem to be a consensus among sources and tools.
- The OpenPSA MEF "atleast" best captures the nature of the gate;
+ The Open-PSA MEF "atleast" best captures the nature of the gate;
however, the "atleast" is awkward to use in code and API
(Atleast vs. AtLeast vs. atleast vs. at_least).
In SCRAM, the "vote" word must be used consistently
to represent this gate in code and API.
- The code that deals with the OpenPSA MEF may use the "atleast".
+ The code that deals with the Open-PSA MEF may use the "atleast".
- In performance-critical **analysis code**
(BDD variable ordering, Boolean formula rewriting/preprocessing, etc.),
@@ -271,6 +271,7 @@ C++
#. Google style conformance check with Cpplint_
#. Common C++ code problem check with cppclean_
#. Consistent code formatting with ClangFormat_
+#. Component dependency analysis with cppdep_
.. _Gcov: https://gcc.gnu.org/onlinedocs/gcc/Gcov.html
.. _Coveralls: https://coveralls.io/github/rakhimov/scram
@@ -278,9 +279,10 @@ C++
.. _Coverity: https://scan.coverity.com/projects/2555
.. _CppCheck: https://github.com/danmar/cppcheck/
.. _Lizard: https://github.com/terryyin/lizard
-.. _Cpplint: https://github.com/theandrewdavis/cpplint
+.. _Cpplint: https://github.com/cpplint/cpplint
.. _cppclean: https://github.com/myint/cppclean
.. _ClangFormat: http://clang.llvm.org/docs/ClangFormat.html
+.. _cppdep: https://pypi.python.org/pypi/cppdep
Python
@@ -291,10 +293,10 @@ Python
#. Code coverage check with coverage_ and reporting with Codecov_
#. Continuous code quality control on Landscape_ with Prospector_
-.. _Pylint: http://www.pylint.org/
+.. _Pylint: https://www.pylint.org/
.. _PyVmMonitor: http://www.pyvmmonitor.com/
-.. _coverage: http://nedbatchelder.com/code/coverage/
-.. _Codecov: https://codecov.io/github/rakhimov/scram?ref=develop
+.. _coverage: https://coverage.readthedocs.io/en/latest/
+.. _Codecov: https://codecov.io/github/rakhimov/scram
.. _Landscape: https://landscape.io/
.. _Prospector: https://github.com/landscapeio/prospector
@@ -339,7 +341,7 @@ with auto-generated analysis input files
to discover bugs, bottlenecks, and assumption failures.
.. _GoogleTest: https://github.com/google/googletest
-.. _Nose: https://nose.readthedocs.org/en/latest/
+.. _Nose: httpss://nose.readthedocs.io/en/latest/
.. _Travis CI: https://travis-ci.org/rakhimov/scram
.. _AppVeyor: https://ci.appveyor.com/project/rakhimov/scram
@@ -368,7 +370,7 @@ Version control and Versioning
- `Atomic Commit`_
- `Semantic Versioning`_
-.. _Git SCM: http://git-scm.com/
+.. _Git SCM: https://git-scm.com/
.. _Branching Model: http://nvie.com/posts/a-successful-git-branching-model/
.. _Writing Good Commit Messages: https://github.com/erlang/otp/wiki/Writing-good-commit-messages
.. _On Commit Messages: http://who-t.blogspot.com/2009/12/on-commit-messages.html
@@ -417,8 +419,8 @@ Conventions in Documentation "Source Text"
General
-------
-- Prefer :ref:`shorthand_format` for the Boolean formula documentation.
- This format uses the C-style bitwise logical operators for equations.
+- Prefer the :ref:`Aralia_format` for the Boolean formula documentation.
+ This format uses the C-style bit-wise logical operators for equations.
reST Documentation Style
@@ -427,7 +429,7 @@ reST Documentation Style
- Semantic Linefeeds
- Two blank lines between sections with bodies
- One blank line after a header before its body
-- Title ``#`` overlined and underlined
+- Part ``#`` overlined and underlined
- Chapter ``*`` overlined and underlined
- Section underlining and order ``=``, ``-``, ``~``, ``^``, ``+``
- Point nesting and order ``-``, ``*``, ``+``
diff --git a/doc/config_file.rst b/doc/config_file.rst
index e5cef38..1530070 100644
--- a/doc/config_file.rst
+++ b/doc/config_file.rst
@@ -21,5 +21,5 @@ Validation Schemas
Configuration File Example
==========================
-.. highlight:: xml
.. literalinclude:: example/config.xml
+ :language: xml
diff --git a/doc/design_description.rst b/doc/design_description.rst
index dfb38f3..6721c14 100644
--- a/doc/design_description.rst
+++ b/doc/design_description.rst
@@ -7,69 +7,73 @@ Design Description
Complex Dependency Diagram (TheDailyWTF)
-- XML Parser leverages external libraries to process XML files.
-
-- Validator validates XML configuration and input files against the RelaxNG schema.
- The validation against the schema is an integral part of the initialization.
- Values that pass the validation against the schema are not re-checked by users of those values.
-
-- Settings manages overall analysis settings per run.
-
-- Config manages program configurations and analysis settings from a configuration file.
-
-- Containers: models, fault trees, event trees, components.
-
-- Constructs: anything that is stored in containers and can be an input for analysis.
- Note that some containers are constructs as well.
-
-- Initializer processes input files to construct a model
- with fault trees, event trees, CCF, and other analysis containers and constructs.
- This initialization phase validates the values and logic supplied from the input files.
- The constructs and analyses are initialized according to the configurations
- supplied from the configuration file and command-line.
- After the initialization step,
- it is not expected that constructs of the analysis change.
-
-- Risk Analyzer operates on the valid model
- with the initialized fault, event trees, and other constructs
- to provide the requested results.
- It runs after the initialization phase with the user-specified analysis settings.
-
-- Analyzers of fault trees, event trees, CCF, uncertainty,
- and other analysis kinds.
- These analyzers are employed by the main Risk Analyzer
- to produce final results.
- Common facilities, utilities, and functionalities
- can be shared among these analyzers.
- Analyzers and analysis facilities are designed
- in the spirit of `Design by Contract`_ and `Policy-based design`_
- to keep the code simple and flexible with algorithms.
-
- * Fault Tree Analyzer operates on one fault tree with a single top event,
- and may provide primary events, intermediate events,
- and products (minimal cut sets or prime implicants) as output,
- or other information about the passed fault tree.
- This fault tree analyzer uses many other helper facilities
- specifically designed to make the analysis efficient and fast.
-
- * Probability Calculator accepts the results of Fault Tree Analyzer
- to calculate the total probability
- and to provide facilities for other Quantitative analyzers.
-
- * Importance Analyzer calculates
- importance factors of *important* basic events
- with Probability Calculator facilities.
-
- * Uncertainty Analyzer uses Probability Calculator facilities
- to sample basic event probabilities
- and calculate the total probability.
- Sampled results are processed to find statistical information,
- such as mean, confidence ranges, standard deviation, and distributions.
-
-- Supporting classes: Formula, Expressions.
-
-- Reporter outputs the results of the work of Risk Analyzer
- to specified files or streams in XML format.
+Core
+====
+
+#. XML Parser leverages external libraries to process XML files.
+
+#. Validator validates XML configuration and input files against the RelaxNG schema.
+ The validation against the schema is an integral part of the initialization.
+ Values that pass the validation against the schema are not re-checked by users of those values.
+
+#. Settings manages overall analysis settings per run.
+#. Config manages program configurations and analysis settings from a configuration file.
+#. Containers: models, fault trees, event trees, components.
+
+#. Analysis constructs: anything that is stored in containers and can be an input for analysis.
+ Note that some containers are constructs as well.
+
+ * Formula, Expressions, and other facilities used by the analysis constructs.
+
+#. Initializer processes input files to construct a model
+ with fault trees, event trees, CCF, and other analysis containers and constructs.
+ This initialization phase validates the values and logic supplied from the input files.
+ The constructs and analyses are initialized according to the configurations
+ supplied from the configuration file and command-line.
+ After the initialization step,
+ it is not expected that constructs of the analysis change.
+
+#. Risk Analyzer operates on a valid model
+ with initialized fault, event trees, and other constructs
+ to provide the requested results.
+ It runs after the initialization phase with the user-specified analysis settings.
+
+#. Analyzers of fault trees, event trees, CCF, uncertainty,
+ and other analysis kinds.
+ These analyzers are employed by the main Risk Analyzer
+ to produce final results.
+ Common facilities, utilities, and functionalities
+ can be shared among these analyzers.
+ Analyzers and analysis facilities are designed
+ in the spirit of `Design by Contract`_ and `Policy-based design`_
+ to keep the code simple and flexible with algorithms.
+
+ 1. Fault Tree Analyzer operates on one fault tree with a single top event,
+ and may provide primary events, intermediate events,
+ and products (minimal cut sets or prime implicants) as output,
+ or other information about the passed fault tree.
+ This fault tree analyzer uses many other helper facilities
+ specifically designed to make the analysis efficient and fast.
+
+ 2. Probability Calculator accepts the results of Fault Tree Analyzer
+ to calculate the total probability
+ and to provide facilities for other Quantitative analyzers.
+
+ 3. Importance Analyzer calculates
+ importance factors of *important* basic events
+ with Probability Calculator facilities.
+
+ 4. Uncertainty Analyzer uses Probability Calculator facilities
+ to sample basic event probabilities
+ and calculate the total probability.
+ Sampled results are processed to find statistical information,
+ such as mean, confidence ranges, standard deviation, and distributions.
+
+#. Reporter outputs the results of the work of Risk Analyzer
+ to specified files or streams in XML format.
+
+#. Support components:
+ Logger, XML stream, and library extensions in the ext namespace.
.. _Design by Contract: https://en.wikipedia.org/wiki/Design_by_contract
.. _Policy-based design: https://en.wikipedia.org/wiki/Policy-based_design
@@ -78,6 +82,12 @@ Design Description
API Documentation
=================
-`API Docs Generated by Doxygen`_
+`API Docs Generated by Doxygen <../api/index.xhtml>`_
-.. _API Docs Generated by Doxygen: http://scram-pra.org/api/
+
+cppdep Component Dependency Report
+==================================
+
+.. image:: ../build/scram_core.svg
+
+.. literalinclude:: ../build/dep_report.txt
diff --git a/doc/example/shorthand_input.txt b/doc/example/aralia_input.txt
similarity index 100%
rename from doc/example/shorthand_input.txt
rename to doc/example/aralia_input.txt
diff --git a/doc/fault_tree_analysis.rst b/doc/fault_tree_analysis.rst
index cc2b68c..958ae63 100644
--- a/doc/fault_tree_analysis.rst
+++ b/doc/fault_tree_analysis.rst
@@ -47,10 +47,10 @@ Representation of INHIBIT, Undeveloped, and Conditional
=======================================================
These gate and event types are not directly supported
-by the input format based on the OpenPSA [MEF]_.
+by the input format based on the Open-PSA [MEF]_.
Indeed, these types are treated just like AND gate and Basic event respectively;
therefore, the description of these types
-can be given through the OpenPSA MEF "attribute" element for gates and events.
+can be given through the Open-PSA MEF "attribute" element for gates and events.
The attribute name "flavor" is used to indicate
the different representation of an event as shown in the description bellow.
diff --git a/doc/fault_tree_generator.rst b/doc/fault_tree_generator.rst
index 0d5d5d5..cf1b8d0 100644
--- a/doc/fault_tree_generator.rst
+++ b/doc/fault_tree_generator.rst
@@ -47,7 +47,7 @@ Script Arguments
Complex gates (K/N, NOT, XOR) are created
only if the weights are given.
- Output file name.
-- Output formats: shorthand or XML(default).
+- Output formats: Aralia or XML(default).
- An option to merge gates into nested formulas for the output.
.. note::
diff --git a/doc/fta_algorithms.rst b/doc/fta_algorithms.rst
index 33aec21..dd3ce9f 100644
--- a/doc/fta_algorithms.rst
+++ b/doc/fta_algorithms.rst
@@ -76,8 +76,8 @@ complicates failure scenarios
or may be irrelevant at all
if the probability of success is close to 1.
-Minimal cut sets can be used for non-coherent analysis
-as conservative approximations.
+Minimal cut sets can be used as a conservative, approximate result
+for analysis of non-coherent fault trees.
In order to eliminate complements of variables,
it is assumed that a complement of an event always occurs, i.e., constant True or 1,
unless the complement is in the same path or set as the corresponding event.
@@ -105,7 +105,7 @@ the event is repair (success) relevant.
If an event is not in a product,
it is irrelevant.
-Given Boolean formula **f(a,b,c)**:
+Given Boolean formula :math:`f(a,b,c)`:
.. math::
@@ -118,13 +118,14 @@ Considering the complement is always True, the formula is simplified:
f(a,b,c) = a \& b \| c
Computation of prime implicants requires computation of the consensus
-when variable **a** is irrelevant:
+when variable :math:`a` is irrelevant:
.. math::
f(a,b,c) = a \& b \| \overline{a} \& c \| b \& c
-Minimal cut sets of the formula are ``{ab, c}``. Prime implicants are ``{ab, ~ac, bc}``.
+Minimal cut sets of the formula are :math:`{ab, c}`.
+Prime implicants are :math:`{ab, ~ac, bc}`.
********************
diff --git a/doc/fta_preprocessing.rst b/doc/fta_preprocessing.rst
index 45c9569..c86a1c6 100644
--- a/doc/fta_preprocessing.rst
+++ b/doc/fta_preprocessing.rst
@@ -171,7 +171,7 @@ and its failure logic to the failure destinations.
The generalization of this technique
comes from the observations
of special cases for the Shannon decomposition.
-Given a Boolean formula **f(x, y)**,
+Given a Boolean formula :math:`f(x, y)`,
the following cases are the special cases of its Shannon decomposition:
1. If ``f(x, y) = 1/True/Failure`` assuming ``x = 1/True/Failure``:
diff --git a/doc/gui.rst b/doc/gui.rst
index 0ba6e89..8fba094 100644
--- a/doc/gui.rst
+++ b/doc/gui.rst
@@ -4,7 +4,7 @@ GUI Front-End
The GUI front-end is developed with `Qt5 and Qt Creator`_.
-.. _Qt5 and Qt Creator: http://qt-project.org/
+.. _Qt5 and Qt Creator: https://www.qt.io/developers/
GUI Concerns
@@ -104,4 +104,4 @@ Human Interface Guidelines
- `XFCE HIG <https://wiki.xfce.org/dev/hig/general>`_
- `The basic concepts of UI`_
-.. _The basic concepts of UI: http://www.usability.gov/what-and-why/user-interface-design.html
+.. _The basic concepts of UI: https://www.usability.gov/what-and-why/user-interface-design.html
diff --git a/doc/input_file.rst b/doc/input_file.rst
index 6cdfc8c..469953e 100644
--- a/doc/input_file.rst
+++ b/doc/input_file.rst
@@ -8,16 +8,16 @@ See :ref:`xml_tools` for more convenient writing and reading of XML input files.
Currently, only fault trees are accepted for analysis,
and one model per run is assumed.
The input file format follows
-OpenPSA Model Exchange Format ([MEF]_) version 2.0d or later.
-The extensive description is given in the above format documentation by OpenPSA,
+the Open-PSA Model Exchange Format ([MEF]_) version 2.0d or later.
+The extensive description is given in the above format documentation by Open-PSA,
and input files should be straightforward to create and understand.
-However, not all OpenPSA formatting is supported,
+However, not all Open-PSA formatting is supported,
and some additional assumptions/restrictions are made by SCRAM.
See :ref:`opsa_support` for the format description
and current implementation with differences.
In addition to the XML format,
-the :ref:`shorthand_format` is supported indirectly.
+the :ref:`Aralia_format` is supported indirectly.
Encodings
@@ -38,7 +38,7 @@ Steps in XML Input Validation
- The first file must define the name, label, and attributes of the model.
Other files with this kind of information are ignored without a warning.
This feature allows reuse of files from other models
- without the need for the OpenPSA MEF ``include`` directives.
+ without the need for the Open-PSA MEF ``include`` directives.
#. An XML input file is validated against the RelaxNG_ :ref:`schema`.
#. The fault tree validation assumptions/requirements:
@@ -49,7 +49,7 @@ Steps in XML Input Validation
- Public names must be unique globally,
and private names must be unique locally within containers.
- References are followed according to the public and private roles
- described in the OpenPSA MEF section
+ described in the Open-PSA MEF section
*IV.3.2. Solving Name Conflicts: Public versus Private Elements*.
#. Additional validation of fault trees and values of parameters is performed:
@@ -109,18 +109,18 @@ Validation Schemas
- `RelaxNG Schema <https://github.com/rakhimov/scram/blob/master/share/input.rng>`_
-.. _shorthand_format:
+.. _Aralia_format:
-Shorthand Input Format
-======================
+Aralia Input Format
+===================
A more convenient format than the XML for writing simple fault trees
utilizes a shorter notation for gates, operators (``&``, ``|``, ``@``, ``~``, ``^``), and events
to create a collection of Boolean equations.
-The shorthand format can be converted into the XML format with `this script`_.
+The Aralia format can be converted into the XML format with `this script`_.
.. _this script:
- https://github.com/rakhimov/scram/blob/master/scripts/shorthand_to_xml.py
+ https://github.com/open-psa/translators/blob/master/aralia.py
Input File Examples
@@ -129,13 +129,13 @@ Input File Examples
Fault Tree Input File
---------------------
-.. highlight:: xml
.. literalinclude:: example/input.xml
+ :language: xml
-Shorthand Version
------------------
+Aralia Version
+--------------
-.. literalinclude:: example/shorthand_input.txt
+.. literalinclude:: example/aralia_input.txt
.. _RelaxNG: http://relaxng.org/
diff --git a/doc/installation.rst b/doc/installation.rst
index bd1c4a3..a093ca0 100644
--- a/doc/installation.rst
+++ b/doc/installation.rst
@@ -2,7 +2,7 @@
Installation Instructions
#########################
-.. note: Some SCRAM tools and tests may be absent in distribution packages.
+.. note:: Some SCRAM tools and tests may be absent in distribution packages.
Ubuntu 14.04 or later
diff --git a/doc/opsa_support.rst b/doc/opsa_support.rst
index 397083c..34acc57 100644
--- a/doc/opsa_support.rst
+++ b/doc/opsa_support.rst
@@ -1,6 +1,6 @@
-#############################
-OpenPSA Model Exchange Format
-#############################
+##################################
+The Open-PSA Model Exchange Format
+##################################
Open Probabilistic Safety Assessment Initiative hopes
to bring international community of PSA together
@@ -22,7 +22,7 @@ The initiative deals with the following issues in the current PSA:
- No universal format for industry data
In order to facilitate information exchange and quality assurance,
-OpenPSA community has developed a model exchange format([MEF]_) for PSA
+The Open-PSA community has developed a model exchange format([MEF]_) for PSA
that covers most needs to describe the analysis input for PSA tools.
Moreover, the MEF defines the following requirements
for its development and use:
@@ -41,22 +41,12 @@ This paradigm is followed from the structured programming techniques.
More information about the initiative and format can be found on http://open-psa.org
-.. _opsa_mef_schema:
-
-OpenPSA MEF Schemas
-===================
-
-- `MEF RelaxNG Schema <https://github.com/rakhimov/scram/blob/master/share/open-psa/mef.rng>`_
-- `MEF RelaxNG Compact Schema <https://github.com/rakhimov/scram/blob/master/share/open-psa/mef.rnc>`_
-- `MEF DTD <https://github.com/rakhimov/scram/blob/master/share/open-psa/mef.dtd>`_
-
-
.. _opsa_support:
-Currently Supported OpenPSA MEF Features
-========================================
+Currently Supported Open-PSA MEF Features
+=========================================
-The difference between :ref:`opsa_mef_schema` and :ref:`schema` can be used
+The difference between `the Open-PSA MEF schema`_ and SCRAM's :ref:`schema` can be used
to identify the supported and unsupported features.
- Label
@@ -88,13 +78,16 @@ to identify the supported and unsupported features.
* Constant expressions
* System mission time
* Parameter
+ * Arithmetic expressions
* Random deviate (normal, log-normal, histogram, uniform, gamma, beta)
* Built-in expressions (exponential with two parameters,
exponential with four parameters, Weibull)
+- `the Open-PSA MEF schema <https://github.com/open-psa/schemas/>`_
+
-Deviations from OpenPSA MEF
-===========================
+Deviations from the Open-PSA MEF
+================================
- Names and references are case-sensitive
and restricted to fewer characters and combinations.
@@ -108,17 +101,13 @@ Deviations from OpenPSA MEF
- Common cause model levels for factors are required
and must be strictly sequential in ascending order.
- Attributes are not inherited.
-- The decimal separator for floating-point numbers is ``.`` (dot)
- regardless of the locale.
- The scientific notation for floating-point numbers is recognized
- with ``e`` or ``E`` for the exponent.
- An empty text in XML attributes or elements is considered an error.
-OpenPSA MEF Converters
-======================
+Translators to the Open-PSA MEF
+===============================
-- `Python script`_ for :ref:`shorthand_format` to OpenPSA MEF XML conversion.
+Various translators from other formats, such as Aralia,
+can be found in `the Open-PSA MEF translators repository`_.
-.. _Python script:
- https://github.com/rakhimov/scram/blob/master/scripts/shorthand_to_xml.py
+.. _the Open-PSA MEF translators repository: https://github.com/open-psa/translators/
diff --git a/doc/performance.rst b/doc/performance.rst
index 2861edb..0c4cc60 100644
--- a/doc/performance.rst
+++ b/doc/performance.rst
@@ -33,7 +33,7 @@ System Specs Version
============== ===================
Processor Core i7-2820QM
OS Ubuntu 16.04 64bit
-GCC version 5.3.1
+GCC version 5.4.0
Boost version 1.58
Libxml2 2.9.3
TCMalloc 2.4
@@ -166,14 +166,14 @@ Debug build:
Release build:
~~~~~~~~~~~~~~
-- BDD Time: 1.6
+- BDD Time: 1.4
- ZBDD Time: 0.20
- # of BDD vertices created: 2652730
- # of ITE in unique table: 2370567
- # of ITE in BDD: 1123292 | 1160828
-- Memory: 250
+- Memory: 215
- Cache-misses: 46 % | 50 %
@@ -193,7 +193,7 @@ Release build:
- ZBDD Cut set extraction memory: 100
- Cut set indices to pointers memory: 90
-- Memory: 375
+- Memory: 310
- Cache-misses: 34 %
diff --git a/doc/probability_analysis.rst b/doc/probability_analysis.rst
index e0f15cb..99fe2d5 100644
--- a/doc/probability_analysis.rst
+++ b/doc/probability_analysis.rst
@@ -9,32 +9,32 @@ Probability Types
*****************
Various probability types and distributions are accepted
-as described in the OpenPSA Model Exchange Format [MEF]_,
+as described in the Open-PSA Model Exchange Format [MEF]_,
for example, constant values, exponential with two or four parameters,
and uniform, normal, log-normal distributions.
Bellow is a brief description.
For more information, please take a look at the [MEF]_ format documentation.
-**P-model**
+P-model
The probability of an event occurring
when the time to failure is unknown or unpredictable.
-**Lambda-model or Exponential with Two Parameters**
- The probability that a primary event will occur within given time (t).
+Lambda-model or Exponential with Two Parameters
+ The probability that a primary event will occur within given time (:math:`t`).
Appropriate for events within systems
that are continuously operating and
have a known probability of failure during a unit time period (:math:`\lambda`).
.. math::
- P = 1-\exp(-\lambda*t)
+ P = 1-e^{-\lambda \cdot t}
For small lambda and time, the approximation is
.. math::
- P \approx \lambda*t
+ P \approx \lambda \cdot t
************************
diff --git a/doc/references.rst b/doc/references.rst
index cebec4b..d1de146 100644
--- a/doc/references.rst
+++ b/doc/references.rst
@@ -17,13 +17,13 @@ Papers
.. [DR96] Y. Dutuit and A. Rauzy,
"A linear time algorithm to find modules of fault trees,"
- IEEE Trans. Rel., vol. 45, no. 3, pp. 422-425, 1996.
+ IEEE Trans. Reliab. Eng. Syst. Saf., vol. 45, no. 3, pp. 422-425, 1996.
.. [DR01] Y. Dutuit and A. Rauzy,
"Efficient algorithms to assess component and gate importance in fault tree analysis,"
- Reliab. Eng. Syst. Saf., vol. 72, no. 2, pp. 213-222, 2001.
+ IEEE Trans. Reliab. Eng. Syst. Saf., vol. 72, no. 2, pp. 213-222, 2001.
-.. [Jun09] W. Jung
+.. [Jun09] W. Jung,
"ZBDD algorithm features for an efficient probabilistic safety assessment,"
Nuc. Eng. Des., vol. 239, pp. 2085-2092, 2009.
@@ -33,27 +33,27 @@ Papers
.. [Nie94] I. Niemelä,
"On simplification of large fault trees,"
- Reliab. Eng. Syst. Saf., vol. 44, pp. 135-138, 1994.
+ IEEE Trans. Reliab. Eng. Syst. Saf., vol. 44, pp. 135-138, 1994.
.. [NR99] M. Nikolskaia and A. Rauzy,
"Fine-tuning of boolean formulae preprocessing techniques,"
in Proc. ESREL Conf., vol. 2, pp. 1027-1032, 1999.
-.. [PA09] R. Remenyte-Prescott and J. Andrews
+.. [PA09] R. Remenyte-Prescott and J. Andrews,
"An efficient real-time method of analysis for non-coherent fault trees,"
Qual. Reliab. Eng. Int., no. 25, pp. 129-150, 2009.
.. [Rau93] A. Rauzy,
"New algorithms for fault trees analysis,"
- Reliab. Eng. Syst. Saf., vol. 5, no. 59, pp. 203-211, 1993.
+ IEEE Trans. Reliab. Eng. Syst. Saf., vol. 5, no. 59, pp. 203-211, 1993.
.. [Rau01] A. Rauzy,
"Mathematical foundation of minimal cutsets,"
- IEEE Trans. Rel., vol. 50, no. 4, pp. 389-396, 2001
+ IEEE Trans. Reliab. Eng. Syst. Saf., vol. 50, no. 4, pp. 389-396, 2001
.. [Rau03] A. Rauzy,
- "Towards an efficient implementation of MOCUS," IEEE Trans.
- Reliab. Eng. Syst. Saf., vol. 52, no. 2, pp. 175-180, 2003.
+ "Towards an efficient implementation of MOCUS,"
+ IEEE Trans. Reliab. Eng. Syst. Saf., vol. 52, no. 2, pp. 175-180, 2003.
.. [WakXX] D. Wakefield,
"You can't just build trees and call it PSA"
@@ -62,9 +62,9 @@ Papers
Standards, Guides, Manuals, Handbooks
=====================================
-.. [MEF] `OpenPSA Model Exchange Format <http://open-psa.org/joomla1.5/index.php?option=com_content&view=category&id=4&Itemid=19>`_
+.. [MEF] `Open PSA Model Exchange Format <https://open-psa.github.io/mef>`_
-.. [NUREG0492] `NRC NUREG-0492 <http://www.nrc.gov/reading-rm/doc-collections/nuregs/staff/sr0492/sr0492.pdf>`_
+.. [NUREG0492] `NRC NUREG-0492 <http://www.nrc.gov/reading-rm/doc-collections/nuregs/staff/sr0492/>`_
.. [WASH1400] `NRC NUREG-75/014 (WASH-1400), Appendices III & IV <http://www.nrc.gov/reading-rm/doc-collections/nuregs/staff/sr75-014/appendix-iii-iv/>`_
@@ -80,7 +80,7 @@ Standards, Guides, Manuals, Handbooks
Web Resources
=============
-.. [OPSA] `OpenPSA Initiative <http://open-psa.org>`_
+.. [OPSA] `The Open-PSA Initiative <http://open-psa.org>`_
.. [PRA] `PRA Wiki Page <https://en.wikipedia.org/wiki/Probabilistic_risk_assessment>`_
.. [FTA] `FTA Wiki Page <https://en.wikipedia.org/wiki/Fault_tree_analysis>`_
diff --git a/doc/release/release_checklist.rst b/doc/release/release_checklist.rst
index b131d41..e1b6512 100644
--- a/doc/release/release_checklist.rst
+++ b/doc/release/release_checklist.rst
@@ -5,7 +5,7 @@ Release Checklist
.. note::
This checklist is for release actions.
A copy of this file must be used for actual marking
- without submitting it to version control system.
+ without submitting it to the version control system.
.. note:: '[-]' is used to indicate currently failing or unachieveable step.
@@ -32,7 +32,7 @@ Pre-Release
* [ ] Run all *fast* tests under Valgrind memcheck
-- [ ] Check compatibility with Python2 and Python3 (tools: Ninja-IDE)
+- [ ] Check compatibility with Python2 and Python3 (tools: pylint)
- [ ] Update documentation (RST files)
* [ ] Grammar check the documentation (optional)
@@ -61,20 +61,22 @@ Release
* Commit the release with *SCRAM x.y.z* (x, y, z being version numbers)
+- [ ] Release with GitHub automatic tagging with the release notes
+
+ * [ ] Close the milestone on GitHub
+
+- [ ] Rebase Master on Develop (Avoid merging)
+
- [ ] Update the website
- * [ ] Version number in ``conf.py`` on the ``gh-source`` branch
* [ ] Lizard CCN report
* [ ] Sitemap
-- [ ] Release with GitHub automatic tagging with the release notes
-- [ ] Rebase Master on Develop (Avoid merging)
-- [ ] Close the milestone on GitHub
- [ ] Publish the release notes on the scram-announce mailing list
Distribution
============
-- [ ] Update PPA (DEB/Ubuntu)
+- [ ] Update Alioth/PPA (Debian/Ubuntu)
- [ ] Installation package (NSIS/Windows)
diff --git a/doc/release/v0.11.5.md b/doc/release/v0.11.5.md
new file mode 100644
index 0000000..3e3d620
--- /dev/null
+++ b/doc/release/v0.11.5.md
@@ -0,0 +1,36 @@
+# Release Notes v0.11.5 : Debian Science Package
+
+This release includes patches from the initial Debian packaging
+at SCRAM's Alioth [repository](https://anonscm.debian.org/git/debian-science/packages/scram.git/).
+In addition, some changes have been inspired by
+the Open-PSA community workshop and its new [presence](https://github.com/open-psa/) at GitHub.
+
+
+## Minor Changes
+
+- Optional link against JEMalloc
+- Debian Science package
+- Parallelized fuzz testing
+- Move the Open-PSA schemas to https://github.com/open-psa/schemas
+- Move the ``shorthand_to_xml.py`` translator to https://github.com/open-psa/translators
+- Rename the shorthand format to the Aralia format
+- Improved build-times after dependency analysis and refactoring with
+ [cppdep](https://github.com/rakhimov/cppdep)
+- Python API documentation generation with Sphinx
+
+
+## Bug Fixes
+
+- CCF Alpha factor wrong formula (#146)
+- Misinterpretation of Log-Normal Deviate Error Factor and Level parameters (#147)
+
+
+## Since v0.11.4
+
+55 commits resulted in 123 files changed, 3114 insertions(+), 5925 deletions(-)
+
+- Core : 47 files changed, 1969 insertions(+), 1640 deletions(-)
+- Scripts : 9 files changed, 284 insertions(+), 1203 deletions(-)
+- GUI : 4 files changed, 112 insertions(+), 63 deletions(-)
+- Tests : 15 files changed, 177 insertions(+), 195 deletions(-)
+- Documentation : 25 files changed, 344 insertions(+), 279 deletions(-)
diff --git a/doc/report_layer.rst b/doc/report_layer.rst
index dcd9dcb..09a3e35 100644
--- a/doc/report_layer.rst
+++ b/doc/report_layer.rst
@@ -2,12 +2,12 @@
Report Layer
############
-***********
-OpenPSA MEF
-***********
+****************
+The Open-PSA MEF
+****************
The results of calculations are reported in the XML format
-suggested by OpenPSA Model Exchange Format ([MEF]_).
+suggested by the Open-PSA Model Exchange Format ([MEF]_).
It is expected that the standardized report format be used by other tools
to further analyze and operate on the results of PSA tools.
The report contains two constructs:
@@ -59,7 +59,7 @@ The report contains two constructs:
Encodings
=========
-There is no specification for file encodings in OpenPSA MEF.
+There is no specification for file encodings in the Open-PSA MEF.
SCRAM results are reported with the UTF-8 character set
regardless of what the input file encodings are.
@@ -97,5 +97,5 @@ Suggested tools:
Report File Example
===================
-.. highlight:: xml
.. literalinclude:: example/report.xml
+ :language: xml
diff --git a/doc/scram.man b/doc/scram.1
similarity index 93%
rename from doc/scram.man
rename to doc/scram.1
index 3028f5e..ff90c31 100644
--- a/doc/scram.man
+++ b/doc/scram.1
@@ -1,4 +1,4 @@
-.TH SCRAM "1" "September 2016" "SCRAM 0.11.4" "SCRAM Manual"
+.TH SCRAM "1" "December 2016" "SCRAM 0.11.5" "SCRAM Manual"
.SH NAME
SCRAM \- Command-line Risk Analysis Multi-tool
.SH SYNOPSIS
@@ -14,7 +14,7 @@ and uncertainty analysis with Monte Carlo simulations.
This tool can handle non-coherent fault trees, containing NOT logic.
.PP
\fBSCRAM\fP works with PRA models and constructs described
-in OpenPSA Model Exchange Format.
+in the Open-PSA Model Exchange Format.
.SH OPTIONS
.TP
\fB\-\-version\fR
@@ -42,7 +42,7 @@ Perform qualitative analysis with Zero-Suppressed Binary Decision Diagrams
Perform qualitative analysis with the MOCUS algorithm
.TP
\fB\-\-prime\-implicants\fR
-Calcualte prime implicants instead of minimal cut sets
+Calculate prime implicants instead of minimal cut sets
.TP
\fB\-\-probability\fR arg
Perform probability analysis
diff --git a/doc/todo.rst b/doc/todo.rst
index 510ec9a..404e246 100644
--- a/doc/todo.rst
+++ b/doc/todo.rst
@@ -7,7 +7,7 @@ Low Hanging Fruits
- `Issues on GitHub <https://github.com/rakhimov/scram/issues>`_
- `TODO list in the code <http://scram-pra.org/api/todo.xhtml>`_
-- `Bugs and Issues <https://github.com/rakhimov/scram/blob/develop/bugs.rst>`_
+- `Bugs and Issues <https://github.com/rakhimov/scram/blob/develop/doc/bugs.rst>`_
.. note:: The following To-Do items are features with high uncertainties.
@@ -48,7 +48,7 @@ Minor
Multi-rooted graph analysis. *Low*
- Importance factor calculation for gates (formulas). *Low*
- Uncertainty analysis for importance factors. *Moderate*
-- OpenPSA MEF Support:
+- The Open-PSA MEF Support:
* Expressions. *Moderate*
* "Include directive" in input files to include other input files. *Low*
@@ -60,7 +60,6 @@ Platform Support
- Installation Package for Windows.
- Installation Package for Mac OS X.
-- Compilation and testing on ARM.
Code
diff --git a/doc/xml_comments.rst b/doc/xml_comments.rst
index ebe3a29..c74c6fc 100644
--- a/doc/xml_comments.rst
+++ b/doc/xml_comments.rst
@@ -21,7 +21,7 @@ Recommended Tools
- `Emacs <http://www.gnu.org/software/emacs/>`_ with
`nXML mode <http://www.gnu.org/software/emacs/manual/html_mono/nxml-mode.html>`_
-- `Notepad++ <http://notepad-plus-plus.org/>`_ with XML Tools plug-in
+- `Notepad++ <https://notepad-plus-plus.org/>`_ with XML Tools plug-in
- `xmllint <http://xmlsoft.org/xmllint.html>`_ with RelaxNG schema
diff --git a/gui/CMakeLists.txt b/gui/CMakeLists.txt
index 2012572..7fff2f1 100644
--- a/gui/CMakeLists.txt
+++ b/gui/CMakeLists.txt
@@ -13,9 +13,11 @@ elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Intel")
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -diag-disable=1875")
endif()
-set(CMAKE_INCLUDE_CURRENT_DIR ON)
+if(Qt5Widgets_VERSION_STRING VERSION_EQUAL "5.7.0")
+ set(CMAKE_CXX_STANDARD 14) # TODO: Bug in CMake with Qt 5.7.0.
+endif()
-include_directories("${PROJECT_SOURCE_DIR}") # Include the core headers via "src".
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTOUIC ON)
@@ -25,7 +27,6 @@ set(SCRAM_GUI_RES "${CMAKE_CURRENT_SOURCE_DIR}/res.qrc")
set(SCRAM_GUI_SRC
"${CMAKE_CURRENT_SOURCE_DIR}/mainwindow.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/event.cpp"
- "${CMAKE_CURRENT_SOURCE_DIR}/gate.cpp"
)
set(SCRAM_GUI_BIN "${CMAKE_CURRENT_SOURCE_DIR}/main.cpp")
set(SCRAM_GUI_TS_DIR "${CMAKE_CURRENT_SOURCE_DIR}/translations")
diff --git a/gui/event.cpp b/gui/event.cpp
index c5bf24f..e185e8e 100644
--- a/gui/event.cpp
+++ b/gui/event.cpp
@@ -21,14 +21,20 @@
#include <QPainter>
#include <QPainterPath>
#include <QRectF>
-#include <QSize>
#include <QStyleOptionGraphicsItem>
namespace scram {
namespace gui {
-Event::Event(QGraphicsView *view) : m_view(view) {
+template <class T>
+Event::Event(const T &, QGraphicsView *view)
+ : m_view(view), m_typeGraphics(Event::getTypeGraphics<T>(units()))
+{
m_view->scene()->addItem(this);
+ if (m_typeGraphics) {
+ m_typeGraphics->setParentItem(this);
+ m_typeGraphics->setPos(0, 5.5 * units().height());
+ }
}
QSize Event::units() const
@@ -37,15 +43,24 @@ QSize Event::units() const
return {font.averageCharWidth(), font.height()};
}
+void Event::setTypeGraphics(QGraphicsItem *item)
+{
+ delete m_typeGraphics;
+ m_typeGraphics = item;
+ m_typeGraphics->setParentItem(this);
+ m_typeGraphics->setPos(0, 5.5 * units().height());
+}
+
QRectF Event::boundingRect() const
{
int w = units().width();
int h = units().height();
- return QRectF(-8 * w, 0, 16 * w, 5.5 * h + 10 * w);
+ return QRectF(-8 * w, 0, 16 * w, 5.5 * h);
}
-void Event::paint(QPainter *painter, const QStyleOptionGraphicsItem */*option*/,
- QWidget */*widget*/)
+void Event::paint(QPainter *painter,
+ const QStyleOptionGraphicsItem * /*option*/,
+ QWidget * /*widget*/)
{
int w = units().width();
int h = units().height();
@@ -55,28 +70,25 @@ void Event::paint(QPainter *painter, const QStyleOptionGraphicsItem */*option*/,
painter->drawLine(QPointF(0, 3 * h), QPointF(0, 4 * h));
- QRectF nameRect(-5 * w, 4 *h, 10 * w, h);
+ QRectF nameRect(-5 * w, 4 * h, 10 * w, h);
painter->drawRect(nameRect);
painter->drawText(nameRect, Qt::AlignCenter, m_name);
painter->drawLine(QPointF(0, 5 * h), QPointF(0, 5.5 * h));
}
-void BasicEvent::paint(QPainter *painter,
- const QStyleOptionGraphicsItem *option,
- QWidget *widget)
+template <>
+QGraphicsItem *Event::getTypeGraphics<BasicEvent>(const QSize &units)
{
- Event::paint(painter, option, widget);
- double r = 5 * units().width();
- painter->drawEllipse(QPointF(0, 5.5 * units().height() + r), r, r);
+ double r = 5 * units.width();
+ double d = 2 * r;
+ return new QGraphicsEllipseItem(-r, 0, d, d);
}
-void IntermediateEvent::paint(QPainter *painter,
- const QStyleOptionGraphicsItem *option,
- QWidget *widget)
+BasicEvent::BasicEvent(QGraphicsView *view) : Event(*this, view) {}
+
+IntermediateEvent::IntermediateEvent(QGraphicsView *view) : Event(*this, view)
{
- Event::paint(painter, option, widget);
- m_gate->paint(painter, option);
}
} // namespace gui
diff --git a/gui/event.h b/gui/event.h
index a3dd2a7..17d5a74 100644
--- a/gui/event.h
+++ b/gui/event.h
@@ -22,6 +22,7 @@
#include <QGraphicsItem>
#include <QGraphicsView>
+#include <QSize>
#include "gate.h"
@@ -30,18 +31,23 @@ namespace gui {
/**
* @brief The base class for probabilistic events in a fault tree.
+ *
+ * The base event item provides
+ * only the boxes containing the name and description of the event.
+ * A derived class must provide
+ * the symbolic representation of its kind.
+ *
+ * The sizes are measured in units of character height and average width.
+ * This class provides the reference units for derived classes to use.
+ * All derived class shapes should stay within the allowed box limits
+ * to make the fault tree structure layered.
+ *
+ * The derived classes must confine themselves in (10 width x 10 width) box.
*/
class Event : public QGraphicsItem
{
public:
/**
- * @brief Assigns an event to a presentation view.
- *
- * @param view The host view.
- */
- explicit Event(QGraphicsView *view);
-
- /**
* @brief Assigns the short name or ID for the event.
*
* @param name Identifying string name for the event.
@@ -53,7 +59,7 @@ public:
* If the name has not been set,
* the string is empty.
*/
- const QString& getName() const { return m_name; }
+ const QString &getName() const { return m_name; }
/**
* @brief Adds description to the event.
@@ -67,22 +73,67 @@ public:
* @return Description of the event.
* Empty string if no description is provided.
*/
- const QString& getDescription() { return m_description; }
+ const QString &getDescription() { return m_description; }
QRectF boundingRect() const final;
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
- QWidget *widget) override;
+ QWidget *widget) final;
protected:
/**
+ * @brief Assigns an event to a presentation view.
+ *
+ * The graphical representation of the derived type
+ * is deduced by calling getTypeGraphics.
+ *
+ * @tparam T The derived class type.
+ *
+ * @param view The host view.
+ */
+ template <class T> Event(const T &, QGraphicsView *view);
+
+ /**
+ * @brief Provides the graphical representation of the derived type.
+ *
+ * @tparam T The derived class type.
+ *
+ * @param units The unit height and width for drawings.
+ *
+ * @return Graphics item to be attached to the event graphics.
+ * nullptr if the item is undefined upon construction (default).
+ *
+ * @post The item is unowned and allocated on the heap
+ * in order to be owned by the base event graphics item.
+ */
+ template <class T>
+ static QGraphicsItem *getTypeGraphics(const QSize & /*units*/)
+ {
+ return nullptr;
+ }
+
+ /**
+ * @return The graphics of the derived class.
+ */
+ QGraphicsItem *getTypeGraphics() const { return m_typeGraphics; }
+
+ /**
+ * @brief Releases the current derived class item,
+ * and sets the new one.
+ *
+ * @param item The new item to represent the derived type.
+ */
+ void setTypeGraphics(QGraphicsItem *item);
+
+ /**
* @return Unit width (x) and height (y) for shapes.
*/
QSize units() const;
private:
- QGraphicsView *m_view; ///< The host view.
- QString m_name; ///< Identifying name of the event.
- QString m_description; ///< Description of the event.
+ QGraphicsView *m_view; ///< The host view.
+ QString m_name; ///< Identifying name of the event.
+ QString m_description; ///< Description of the event.
+ QGraphicsItem *m_typeGraphics; ///< The graphics of the derived type.
};
/**
@@ -91,10 +142,10 @@ private:
class BasicEvent : public Event
{
public:
- using Event::Event;
-
- void paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
- QWidget *widget) override;
+ /**
+ * @param view The host view.
+ */
+ explicit BasicEvent(QGraphicsView *view);
};
/**
@@ -103,25 +154,25 @@ public:
class IntermediateEvent : public Event
{
public:
- using Event::Event;
+ /**
+ * @param view The host view.
+ */
+ explicit IntermediateEvent(QGraphicsView *view);
/**
* @brief Sets the Boolean logic for the intermediate event inputs.
*
* @param gate The logic gate of the intermediate event.
*/
- void setGate(std::unique_ptr<Gate> gate) { m_gate = std::move(gate); }
+ void setGate(std::unique_ptr<Gate> gate)
+ {
+ setTypeGraphics(gate.release());
+ }
/**
* @return The logic gate of the intermediate event.
*/
- Gate* getGate() const { return m_gate.get(); }
-
- void paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
- QWidget *widget) override;
-
-private:
- std::unique_ptr<Gate> m_gate; ///< The logic of the intermediate event.
+ Gate *getGate() const { return static_cast<Gate *>(getTypeGraphics()); }
};
} // namespace gui
diff --git a/gui/gate.h b/gui/gate.h
index a6123e0..11f6c7b 100644
--- a/gui/gate.h
+++ b/gui/gate.h
@@ -18,8 +18,7 @@
#ifndef GATE_H
#define GATE_H
-#include <QPainter>
-#include <QStyleOptionGraphicsItem>
+#include <QGraphicsItem>
namespace scram {
namespace gui {
@@ -27,22 +26,8 @@ namespace gui {
/**
* @brief The abstract base class for various gate types.
*/
-class Gate
+class Gate : public QGraphicsItem
{
-public:
- Gate(const Gate&) = delete;
- Gate& operator=(const Gate&) = delete;
-
- virtual ~Gate() = default;
-
- /**
- * @brief Paints the shape of the gate without its inputs.
- *
- * @param painter The reciever of the image.
- * @param option Holder of reference units for the sizes.
- */
- virtual void paint(QPainter *painter,
- const QStyleOptionGraphicsItem *option) = 0;
};
} // namespace gui
diff --git a/input/EventTreeExample/event_tree.xml b/input/EventTreeExample/event_tree.xml
index 1d1b080..312348a 100644
--- a/input/EventTreeExample/event_tree.xml
+++ b/input/EventTreeExample/event_tree.xml
@@ -1,6 +1,6 @@
<?xml version="1.0"?>
<!--
-This is an event tree example taken from OpenPSA MEF description.
+This is an event tree example taken from the Open-PSA MEF description.
-->
<opsa-mef>
<define-event-tree name="my-first-event-tree">
diff --git a/install.py b/install.py
index 342b698..9cb6d8f 100755
--- a/install.py
+++ b/install.py
@@ -43,6 +43,7 @@ def generate_make_files(args):
sys.exit("CMake could not be found, "
"please install CMake before developing SCRAM.")
cmake_cmd = ["cmake", os.path.abspath(root_dir)]
+ cmake_cmd += ["-DBUILD_SHARED_LIBS=ON"]
if args.prefix:
cmake_cmd += ["-DCMAKE_INSTALL_PREFIX=" + absexpanduser(args.prefix)]
@@ -52,7 +53,6 @@ def generate_make_files(args):
cmake_cmd += ["-DCMAKE_BUILD_TYPE=Release"]
else:
cmake_cmd += ["-DCMAKE_BUILD_TYPE=Debug"]
- cmake_cmd += ["--warn-uninitialized"]
cmake_cmd += ["-Wdev"]
if args.profile:
diff --git a/scripts/fault_tree.py b/scripts/fault_tree.py
index ad07b2b..e2a6a21 100644
--- a/scripts/fault_tree.py
+++ b/scripts/fault_tree.py
@@ -77,13 +77,13 @@ class BasicEvent(Event):
self.prob = prob
def to_xml(self):
- """Produces OpenPSA MEF XML definition of the basic event."""
+ """Produces the Open-PSA MEF XML definition of the basic event."""
return ("<define-basic-event name=\"" + self.name + "\">\n"
"<float value=\"" + str(self.prob) + "\"/>\n"
"</define-basic-event>\n")
- def to_shorthand(self):
- """Produces the shorthand definition of the basic event."""
+ def to_aralia(self):
+ """Produces the Aralia definition of the basic event."""
return "p(" + self.name + ") = " + str(self.prob) + "\n"
@@ -105,13 +105,13 @@ class HouseEvent(Event):
self.state = state
def to_xml(self):
- """Produces OpenPSA MEF XML definition of the house event."""
+ """Produces the Open-PSA MEF XML definition of the house event."""
return ("<define-house-event name=\"" + self.name + "\">\n"
"<constant value=\"" + self.state + "\"/>\n"
"</define-house-event>\n")
- def to_shorthand(self):
- """Produces the shorthand definition of the house event."""
+ def to_aralia(self):
+ """Produces the Aralia definition of the house event."""
return "s(" + self.name + ") = " + str(self.state) + "\n"
@@ -194,7 +194,7 @@ class Gate(Event): # pylint: disable=too-many-instance-attributes
return ancestors
def to_xml(self, nest=0):
- """Produces OpenPSA MEF XML definition of the gate.
+ """Produces the Open-PSA MEF XML definition of the gate.
Args:
nest: The level for nesting formulas of argument gates.
@@ -241,10 +241,10 @@ class Gate(Event): # pylint: disable=too-many-instance-attributes
mef_xml += "</define-gate>\n"
return mef_xml
- def to_shorthand(self):
- """Produces the shorthand definition of the gate.
+ def to_aralia(self):
+ """Produces the Aralia definition of the gate.
- The transformation to the shorthand format
+ The transformation to the Aralia format
does not support complement or undefined arguments.
Raises:
@@ -303,7 +303,7 @@ class CcfGroup(object): # pylint: disable=too-few-public-methods
self.factors = []
def to_xml(self):
- """Produces OpenPSA MEF XML definition of the CCF group."""
+ """Produces the Open-PSA MEF XML definition of the CCF group."""
mef_xml = ("<define-CCF-group name=\"" + self.name + "\""
" model=\"" + self.model + "\">\n<members>\n")
for member in self.members:
@@ -353,7 +353,7 @@ class FaultTree(object): # pylint: disable=too-many-instance-attributes
self.non_ccf_events = [] # must be assigned directly.
def to_xml(self, nest=0):
- """Produces OpenPSA MEF XML definition of the fault tree.
+ """Produces the Open-PSA MEF XML definition of the fault tree.
The fault tree is produced breadth-first.
The output XML representation is not formatted for human readability.
@@ -391,10 +391,10 @@ class FaultTree(object): # pylint: disable=too-many-instance-attributes
mef_xml += "</opsa-mef>\n"
return mef_xml
- def to_shorthand(self):
- """Produces the shorthand definition of the fault tree.
+ def to_aralia(self):
+ """Produces the Aralia definition of the fault tree.
- Note that the shorthand format does not support advanced features.
+ Note that the Aralia format does not support advanced features.
The fault tree must be valid and well formed for printing.
Returns:
@@ -406,13 +406,13 @@ class FaultTree(object): # pylint: disable=too-many-instance-attributes
out_txt = self.name + "\n\n"
sorted_gates = toposort_gates([self.top_gate], self.gates)
for gate in sorted_gates:
- out_txt += gate.to_shorthand()
+ out_txt += gate.to_aralia()
out_txt += "\n"
for basic_event in self.basic_events:
- out_txt += basic_event.to_shorthand()
+ out_txt += basic_event.to_aralia()
out_txt += "\n"
for house_event in self.house_events:
- out_txt += house_event.to_shorthand()
+ out_txt += house_event.to_aralia()
return out_txt
diff --git a/scripts/fault_tree_generator.py b/scripts/fault_tree_generator.py
index 78de1b8..f4d04ed 100755
--- a/scripts/fault_tree_generator.py
+++ b/scripts/fault_tree_generator.py
@@ -17,8 +17,8 @@
"""Generates a fault tree of various complexities.
-The generated fault tree can be put into an XML file with the OpenPSA MEF
-or a shorthand format file.
+The generated fault tree can be put into an XML file with the Open-PSA MEF
+or the Aralia format file.
The resulting fault tree is topologically sorted.
This script helps create complex fault trees in a short time
@@ -40,7 +40,7 @@ all the other factors set by the user are
guaranteed to be preserved and used as they are.
"""
-from __future__ import print_function, division
+from __future__ import print_function, division, absolute_import
from collections import deque
import random
@@ -578,6 +578,9 @@ def init_gates(gates_queue, common_basic, common_gate, fault_tree):
max_tries = len(common_gate) # the number of maximum tries
num_tries = 0 # the number of tries to get a common gate
+ # pylint: disable=too-many-nested-blocks
+ # This code is both hot and coupled for performance reasons.
+ # There may be a better solution than the current approach.
while gate.num_arguments() < num_arguments:
s_percent = random.random() # sample percentage of gates
s_common = random.random() # sample the reuse frequency
@@ -885,14 +888,14 @@ def manage_cmd_args(argv=None):
default=0, metavar="int")
parser.add_argument("-o", "--out", type=str, default="fault_tree.xml",
metavar="path", help="a file to write the fault tree")
- parser.add_argument("--shorthand", action="store_true",
- help="apply the shorthand format to the output")
+ parser.add_argument("--aralia", action="store_true",
+ help="apply the Aralia format to the output")
parser.add_argument("--nest", type=int, default=0, metavar="int",
help="nestedness of Boolean formulae in the XML output")
args = parser.parse_args(argv)
if args.nest < 0:
raise ap.ArgumentTypeError("The nesting factor cannot be negative")
- if args.shorthand:
+ if args.aralia:
if args.out == "fault_tree.xml":
args.out = "fault_tree.txt"
return args
@@ -940,8 +943,8 @@ def main(argv=None):
factors = setup_factors(args)
fault_tree = generate_fault_tree(args.ft_name, args.root, factors)
with open(args.out, "w") as tree_file:
- if args.shorthand:
- tree_file.write(fault_tree.to_shorthand())
+ if args.aralia:
+ tree_file.write(fault_tree.to_aralia())
else:
write_info(fault_tree, tree_file, args.seed)
write_summary(fault_tree, tree_file)
diff --git a/scripts/fuzz_tester.py b/scripts/fuzz_tester.py
index eb1a8ab..051f433 100755
--- a/scripts/fuzz_tester.py
+++ b/scripts/fuzz_tester.py
@@ -28,9 +28,9 @@ the script is handy to discover
complex auto-generated analysis inputs and configurations.
"""
-from __future__ import print_function
-
import hashlib
+import logging
+import multiprocessing
import os
import random
import resource
@@ -73,29 +73,29 @@ class Config(object):
def configure(args):
"""Adjusts configurations with the cmd-line arguments."""
if args.cross_validate:
- print("Cross validating algorithms")
+ logging.info("Cross validating algorithms")
Config.analysis = [""]
Config.switch = []
Config.approximation = [""]
return
if args.prime_implicants:
- print("Focusing on Prime Implicants")
+ logging.info("Focusing on Prime Implicants")
Config.analysis = ["--bdd"]
Config.approximation = [""]
Config.additional.append("--prime-implicants")
elif args.mocus:
- print("Focusing on MOCUS")
+ logging.info("Focusing on MOCUS")
Config.analysis = ["--mocus"]
elif args.bdd:
- print("Focusing on BDD")
+ logging.info("Focusing on BDD")
Config.analysis = ["--bdd"]
elif args.zbdd:
- print("Focusing on ZBDD")
+ logging.info("Focusing on ZBDD")
Config.analysis = ["--zbdd"]
if args.preprocessor:
- print("Focusing on Preprocessor")
+ logging.info("Focusing on Preprocessor")
Config.restrict()
@@ -186,7 +186,7 @@ def call_scram(input_file):
0 for successful runs.
"""
cmd = generate_analysis_call(input_file)
- print(cmd)
+ logging.info(cmd)
cmd += ["--verbosity", "5", "-o", "/dev/null"]
log_file = open(get_log_file_name(input_file), "w")
log_file.write(str(cmd) + "\n")
@@ -210,7 +210,7 @@ def cross_validate(input_file):
1 for failed runs.
"""
cmd = generate_analysis_call(input_file)
- print(cmd)
+ logging.info(cmd)
cmd += ["--print"]
log_file = open(get_log_file_name(input_file), "w")
log_file.write(str(cmd) + "\n")
@@ -276,15 +276,19 @@ def main():
help="focus on Prime Implicants")
parser.add_argument("--time-limit", type=int, metavar="seconds",
help="CPU time limit for each run")
+ parser.add_argument("-j", "--jobs", type=int, metavar="N",
+ help="allow N runs (jobs) at once")
parser.add_argument("-o", "--output-dir", type=str, metavar="path",
help="directory to put results")
args = parser.parse_args()
+ logging.basicConfig(level=logging.INFO)
+
if call(["which", "scram"]):
- print("SCRAM is not found in the PATH.")
+ logging.error("SCRAM is not found in the PATH.")
return 2
if args.output_dir and not os.path.isdir(args.output_dir):
- print("The output directory doesn't exist.")
+ logging.error("The output directory doesn't exist.")
return 2
if args.time_limit:
@@ -292,19 +296,41 @@ def main():
(args.time_limit, args.time_limit))
Config.configure(args)
- call_function = cross_validate if args.cross_validate else call_scram
- ret = 0
- for i in range(args.num_runs):
- input_file = generate_input(args.normal, args.coherent, args.output_dir)
- if call_function(input_file):
- print("SCRAM failed: " + input_file)
- ret = 1
- continue
+ return any(list(get_map(args.jobs)(Fuzzer(args), range(args.num_runs))))
+
+
+def get_map(working_threads):
+ """Returns the map method for jobs."""
+ if working_threads <= 1:
+ return map
+ return multiprocessing.Pool(processes=working_threads).imap_unordered
+
+
+class Fuzzer(object): # pylint: disable=too-few-public-methods
+ """Runs fuzz testing."""
+
+ def __init__(self, args):
+ """Saves the argument for later use."""
+ self.args = args
+ self.call_function = (cross_validate
+ if args.cross_validate else call_scram)
+
+ def __call__(self, job_number):
+ """Returns 1 for failure and 0 for success."""
+ input_file = generate_input(self.args.normal, self.args.coherent,
+ self.args.output_dir)
+ num_runs = job_number + 1
+ if self.call_function(input_file):
+ logging.info("SCRAM failed run " + str(num_runs) + ": " +
+ input_file)
+ return 1
os.remove(input_file)
os.remove(get_log_file_name(input_file))
- if not (i + 1) % 10:
- print("\n========== Finished run #%d ==========\n" % (i + 1))
- return ret
+ if not num_runs % 10:
+ logging.info(
+ "\n========== Finished run #" + str(num_runs) + " ==========\n")
+ return 0
+
if __name__ == "__main__":
sys.exit(main())
diff --git a/scripts/nqueens.py b/scripts/nqueens.py
index 8497473..9291938 100755
--- a/scripts/nqueens.py
+++ b/scripts/nqueens.py
@@ -17,7 +17,7 @@
"""Generates a fault tree representation of the N Queens problem.
-The representation is given in the shorthand format.
+The representation is given in the Aralia format.
"""
from __future__ import print_function
@@ -62,20 +62,24 @@ def gate(i, j=None):
def print_constraints(n): # pylint: disable=invalid-name
"""Prints the main setup constraints for n queens."""
+ def _append_attacked_positions(i, j, logic):
+ """Appends positions attacked by the (i, j) queen into logic."""
+ for k in range(1, n + 1):
+ if k != j:
+ logic.append(position(i, k, True))
+ if k != i:
+ logic.append(position(k, j, True))
+ diag_one = j + k - i
+ if diag_one > 0 and diag_one <= n:
+ logic.append(position(k, diag_one, True))
+ diag_two = j + i - k
+ if diag_two > 0 and diag_two <= n:
+ logic.append(position(k, diag_two, True))
+
for i in range(1, n + 1):
for j in range(1, n + 1):
logic = [position(i, j, False)]
- for k in range(1, n + 1):
- if k != j:
- logic.append(position(i, k, True))
- if k != i:
- logic.append(position(k, j, True))
- diag_one = j + k - i
- if diag_one > 0 and diag_one <= n:
- logic.append(position(k, diag_one, True))
- diag_two = j + i - k
- if diag_two > 0 and diag_two <= n:
- logic.append(position(k, diag_two, True))
+ _append_attacked_positions(i, j, logic)
print(gate(i, j) + " := " + " & ".join(logic))
diff --git a/scripts/shorthand_to_xml.py b/scripts/shorthand_to_xml.py
deleted file mode 100755
index b8ca6ac..0000000
--- a/scripts/shorthand_to_xml.py
+++ /dev/null
@@ -1,527 +0,0 @@
-#!/usr/bin/env python
-#
-# Copyright (C) 2014-2016 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 <http://www.gnu.org/licenses/>.
-
-"""Converts the shorthand notation for fault trees into an XML file.
-
-The output file is formatted according to the OpenPSA MEF.
-The default output file name is the input file name with the XML extension.
-
-The shorthand notation is described as follows:
-AND gate: gate_name := (arg1 & arg2 & ...)
-OR gate: gate_name := (arg1 | arg2 | ...)
-ATLEAST(k/n) gate: gate_name := @(k, [arg1, arg2, ...])
-NOT gate: gate_name := ~(arg)
-XOR gate: gate_name := (arg1 ^ arg2)
-NULL gate: gate_name := arg
-Probability of a basic event: p(event_name) = probability
-Boolean state of a house event: s(event_name) = state
-
-Some requirements and additions to the shorthand format:
-1. The names and references are not case-sensitive
- and must be formatted according to 'XML NCNAME datatype'
- without double dashes('--'), period('.'), and trailing '-'.
-2. Arguments can be complemented with '~'.
-3. Undefined arguments are processed as 'events' to the final XML output.
- Only warnings are emitted in the case of undefined events.
-4. Name clashes or redefinitions are errors.
-5. Cycles in the graph are detected by the script as errors.
-6. The top gate is detected by the script.
- Only one top gate is allowed
- unless otherwise specified by the user.
-7. Repeated arguments are considered an error.
-8. The script is flexible with whitespace characters in the input file.
-9. Parentheses are optional for logical operators except for ATLEAST.
-"""
-
-from __future__ import print_function
-
-import os
-import re
-import sys
-
-import argparse as ap
-
-from fault_tree import Event, BasicEvent, HouseEvent, Gate, FaultTree
-
-
-class ParsingError(Exception):
- """General parsing errors."""
-
- pass
-
-
-class FormatError(Exception):
- """Common errors in writing the shorthand format."""
-
- pass
-
-
-class FaultTreeError(Exception):
- """Indication of problems in the fault tree."""
-
- pass
-
-
-class LateBindingGate(Gate):
- """Representation of a gate with arguments defined late or not at all.
-
- Attributes:
- event_arguments: String names of arguments.
- """
-
- def __init__(self, name, operator=None, k_num=None):
- """Initializes a gate.
-
- Args:
- name: Identifier of the event.
- operator: Boolean operator of this formula.
- k_num: Min number for the combination operator.
- """
- super(LateBindingGate, self).__init__(name, operator, k_num)
- self.event_arguments = []
-
- def num_arguments(self):
- """Returns the number of arguments."""
- return len(self.event_arguments)
-
-
-class LateBindingFaultTree(FaultTree):
- """Representation of a fault tree for shorthand to XML purposes.
-
- Attributes:
- multi_top: A flag to indicate to allow multiple top gates.
- """
-
- def __init__(self, name=None, multi_top=False):
- """Initializes an empty fault tree.
-
- Args:
- name: The name of the system described by the fault tree container.
- multi_top: A flag to indicate multi-rooted container.
- """
- super(LateBindingFaultTree, self).__init__(name)
- self.multi_top = multi_top
- self.__gates = {}
- self.__basic_events = {}
- self.__house_events = {}
- self.__undef_events = {}
-
- def __check_redefinition(self, name):
- """Checks if an event is being redefined.
-
- Args:
- name: The name under investigation.
-
- Raises:
- FaultTreeError: The given name already exists.
- """
- if (name.lower() in self.__basic_events or
- name.lower() in self.__gates or
- name.lower() in self.__house_events):
- raise FaultTreeError("Redefinition of an event: " + name)
-
- def __visit(self, gate):
- """Recursively visits the given gate sub-tree to detect a cycle.
-
- Upon visiting the descendant gates,
- their marks are changed from temporary to permanent.
-
- Args:
- gate: The current gate.
-
- Returns:
- None if no cycle is found.
- A list of event names in a detected cycle path in reverse order.
- """
- if not gate.mark:
- gate.mark = "temp"
- for child in gate.g_arguments:
- cycle = self.__visit(child)
- if cycle:
- cycle.append(gate.name)
- return cycle
- gate.mark = "perm"
- elif gate.mark == "temp":
- return [gate.name] # a cycle is detected
- return None # the permanent mark
-
- @staticmethod
- def __raise_cycle(cycle):
- """Prints the detected cycle with the error.
-
- Args:
- cycle: A list of gate names in the cycle path in reverse order.
-
- Raises:
- FaultTreeError: Error with a message containing the cycle.
- """
- start = cycle[0]
- cycle.reverse() # print top-down
- raise FaultTreeError("Detected a cycle: " +
- "->".join(cycle[cycle.index(start):]))
-
- def __detect_cycle(self):
- """Checks if the fault tree has a cycle.
-
- Raises:
- FaultTreeError: There is a cycle in the fault tree.
- """
- assert self.top_gates is not None
- for top_gate in self.top_gates:
- cycle = self.__visit(top_gate)
- if cycle:
- LateBindingFaultTree.__raise_cycle(cycle)
-
- detached_gates = [x for x in self.gates if not x.mark]
- if detached_gates:
- error_msg = "Detected detached gates that may be in a cycle\n"
- error_msg += str([x.name for x in detached_gates])
- try:
- for gate in detached_gates:
- cycle = self.__visit(gate)
- if cycle:
- LateBindingFaultTree.__raise_cycle(cycle)
- except FaultTreeError as error:
- error_msg += "\n" + str(error)
- raise FaultTreeError(error_msg)
-
- def __detect_top(self):
- """Detects the top gate of the developed fault tree.
-
- Raises:
- FaultTreeError: Multiple or no top gates are detected.
- """
- top_gates = [x for x in self.gates if x.is_orphan()]
- if len(top_gates) > 1 and not self.multi_top:
- names = [x.name for x in top_gates]
- raise FaultTreeError("Detected multiple top gates:\n" + str(names))
- elif not top_gates:
- raise FaultTreeError("No top gate is detected")
- self.top_gates = top_gates
-
- def add_basic_event(self, name, prob):
- """Creates and adds a new basic event into the fault tree.
-
- Args:
- name: A name for the new basic event.
- prob: The probability of the new basic event.
-
- Raises:
- FaultTreeError: The given name already exists.
- """
- self.__check_redefinition(name)
- event = BasicEvent(name, prob)
- self.__basic_events.update({name.lower(): event})
- self.basic_events.append(event)
-
- def add_house_event(self, name, state):
- """Creates and adds a new house event into the fault tree.
-
- Args:
- name: A name for the new house event.
- state: The state of the new house event ("true" or "false").
-
- Raises:
- FaultTreeError: The given name already exists.
- """
- self.__check_redefinition(name)
- event = HouseEvent(name, state)
- self.__house_events.update({name.lower(): event})
- self.house_events.append(event)
-
- def add_gate(self, name, operator, arguments, k_num=None):
- """Creates and adds a new gate into the fault tree.
-
- Args:
- name: A name for the new gate.
- operator: A gate operator for the new gate.
- arguments: Collection of argument event names of the new gate.
- k_num: K number is required for a combination type of a gate.
-
- Raises:
- FaultTreeError: The given name already exists.
- """
- self.__check_redefinition(name)
- gate = LateBindingGate(name, operator, k_num)
- gate.event_arguments = arguments
- self.__gates.update({name.lower(): gate})
- self.gates.append(gate)
-
- def populate(self):
- """Assigns arguments to gates and parents to arguments.
-
- Raises:
- FaultTreeError: There are problems with the fault tree.
- """
- for gate in self.gates:
- assert gate.num_arguments() > 0
- for event_arg in gate.event_arguments:
- complement = event_arg.startswith("~")
- event_name = event_arg.lstrip("~").lower()
- if event_name in self.__gates:
- gate.add_argument(self.__gates[event_name], complement)
- elif event_name in self.__basic_events:
- gate.add_argument(self.__basic_events[event_name],
- complement)
- elif event_name in self.__house_events:
- gate.add_argument(self.__house_events[event_name],
- complement)
- elif event_name in self.__undef_events:
- gate.add_argument(self.__undef_events[event_name],
- complement)
- else:
- print("Warning. Unidentified event: " + event_name)
- event_node = Event(event_name)
- self.__undef_events.update({event_name: event_node})
- gate.add_argument(event_node, complement)
-
- for basic_event in self.basic_events:
- if basic_event.is_orphan():
- print("Warning. Orphan basic event: " + basic_event.name)
- for house_event in self.house_events:
- if house_event.is_orphan():
- print("Warning. Orphan house event: " + house_event.name)
- self.__detect_top()
- self.__detect_cycle()
-
- def undefined_events(self):
- """Returns list of undefined events."""
- return self.__undef_events.values()
-
-
-# Pattern for names and references
-_NAME_SIG = r"[a-zA-Z]\w*(-\w+)*"
-_LITERAL = r"~?" + _NAME_SIG
-_RE_FT_NAME = re.compile(r"^(" + _NAME_SIG + r")$") # Fault tree name
-# Probability description for a basic event
-_RE_PROB = re.compile(r"^p\(\s*(?P<name>" + _NAME_SIG +
- r")\s*\)\s*=\s*(?P<prob>1|0|0\.\d+)$")
-# State description for a house event
-_RE_STATE = re.compile(r"^s\(\s*(?P<name>" + _NAME_SIG +
- r")\s*\)\s*=\s*(?P<state>true|false)$")
-# General gate name and pattern
-_GATE_SIG = r"^(?P<name>" + _NAME_SIG + r")\s*:=\s*"
-_RE_GATE = re.compile(_GATE_SIG + r"(?P<formula>.+)$")
-# Optional parentheses for formulas
-_RE_PAREN = re.compile(r"\(([^()]+)\)$")
-# Gate type identifications
-_RE_AND = re.compile(r"(" + _LITERAL + r"(\s*&\s*" + _LITERAL + r"\s*)+)$")
-_RE_OR = re.compile(r"(" + _LITERAL + r"(\s*\|\s*" + _LITERAL + r"\s*)+)$")
-_VOTE_ARGS = r"\[(\s*" + _LITERAL + r"(\s*,\s*" + _LITERAL + r"\s*){2,})\]"
-_RE_VOTE = re.compile(r"@\(\s*([2-9])\s*,\s*" + _VOTE_ARGS + r"\s*\)\s*$")
-_RE_XOR = re.compile(r"(" + _LITERAL + r"\s*\^\s*" + _LITERAL + r")$")
-_RE_NOT = re.compile(r"~\(\s*(" + _LITERAL + r")\s*\)$")
-_RE_NULL = re.compile(r"(" + _LITERAL + r")$")
-
-
-def get_arguments(arguments_string, splitter):
- """Splits the input string into arguments of a formula.
-
- Args:
- arguments_string: String contaning arguments.
- splitter: Splitter specific to the operator, i.e. "&", "|", ','.
-
- Returns:
- arguments list from the input string.
-
- Raises:
- FaultTreeError: Repeated arguments for the formula.
- """
- arguments = arguments_string.strip().split(splitter)
- arguments = [x.strip() for x in arguments]
- if len(arguments) > len(set([x.lower() for x in arguments])):
- raise FaultTreeError("Repeated arguments:\n" + arguments_string)
- return arguments
-
-
-def get_formula(line):
- """Constructs formula from the given line.
-
- Args:
- line: A string containing a Boolean equation.
-
- Returns:
- A formula operator, arguments, and k_num.
-
- Raises:
- ParsingError: Parsing is unsuccessful.
- FormatError: Formatting problems in the input.
- FaultTreeError: Problems in the structure of the formula.
- """
- line = line.strip()
- if _RE_PAREN.match(line):
- line = _RE_PAREN.match(line).group(1).strip()
- arguments = None
- operator = None
- k_num = None
- if _RE_OR.match(line):
- arguments = _RE_OR.match(line).group(1)
- arguments = get_arguments(arguments, "|")
- operator = "or"
- elif _RE_XOR.match(line):
- arguments = _RE_XOR.match(line).group(1)
- arguments = get_arguments(arguments, "^")
- operator = "xor"
- elif _RE_AND.match(line):
- arguments = _RE_AND.match(line).group(1)
- arguments = get_arguments(arguments, "&")
- operator = "and"
- elif _RE_VOTE.match(line):
- k_num, arguments = _RE_VOTE.match(line).group(1, 2)
- arguments = get_arguments(arguments, ",")
- if int(k_num) >= len(arguments):
- raise FaultTreeError(
- "Invalid k/n for the combination formula:\n" + line)
- operator = "atleast"
- elif _RE_NOT.match(line):
- arguments = _RE_NOT.match(line).group(1)
- arguments = [arguments.strip()]
- operator = "not"
- elif _RE_NULL.match(line):
- arguments = _RE_NULL.match(line).group(1)
- arguments = [arguments.strip()]
- operator = "null" # pass-through
- else:
- raise ParsingError("Cannot interpret the formula:\n" + line)
- return operator, arguments, k_num
-
-
-def interpret_line(line, fault_tree):
- """Interprets a line from the shorthand format input.
-
- Args:
- line: The line in the shorthand format.
- fault_tree: The fault tree container to update.
-
- Raises:
- ParsingError: Parsing is unsuccessful.
- FormatError: Formatting problems in the input.
- FaultTreeError: Problems in the structure of the fault tree.
- """
- line = line.strip()
- if not line:
- return
- if _RE_GATE.match(line):
- gate_name, formula_line = _RE_GATE.match(line).group("name", "formula")
- operator, arguments, k_num = get_formula(formula_line)
- fault_tree.add_gate(gate_name, operator, arguments, k_num)
- elif _RE_PROB.match(line):
- event_name, prob = _RE_PROB.match(line).group("name", "prob")
- fault_tree.add_basic_event(event_name, prob)
- elif _RE_STATE.match(line):
- event_name, state = _RE_STATE.match(line).group("name", "state")
- fault_tree.add_house_event(event_name, state)
- elif _RE_FT_NAME.match(line):
- if fault_tree.name:
- raise FormatError("Redefinition of the fault tree name:\n%s to %s" %
- (fault_tree.name, line))
- fault_tree.name = _RE_FT_NAME.match(line).group(1)
- else:
- raise ParsingError("Cannot interpret the line.")
-
-
-def parse_input(shorthand_file, multi_top=False):
- """Parses an input file with a shorthand description of a fault tree.
-
- Args:
- shorthand_file: The input file open for reads.
- multi_top: If the input contains a fault tree with multiple top gates.
-
- Returns:
- The fault tree described in the input file.
-
- Raises:
- ParsingError: Parsing is unsuccessful.
- FormatError: Formatting problems in the input.
- FaultTreeError: Problems in the structure of the fault tree.
- """
- fault_tree = LateBindingFaultTree()
- assert fault_tree.name is None
- line_num = 0
- line = None
- try:
- for line in shorthand_file:
- line_num += 1
- interpret_line(line, fault_tree)
- except ParsingError as err:
- raise ParsingError(str(err) + "\nIn line %d:\n" % line_num + line)
- except FormatError as err:
- raise FormatError(str(err) + "\nIn line %d:\n" % line_num + line)
- except FaultTreeError as err:
- raise FaultTreeError(str(err) + "\nIn line %d:\n" % line_num + line)
- if fault_tree.name is None:
- raise FormatError("The fault tree name is not given.")
- fault_tree.multi_top = multi_top
- fault_tree.populate()
- return fault_tree
-
-
-def main(argv=None):
- """Verifies arguments and calls parser and writer.
-
- Args:
- argv: An optional list containing the command-line arguments.
- If None, the command-line arguments from sys will be used.
-
- Raises:
- ArgumentTypeError: Problemns with the arguments.
- IOError: Input or output files are not accessible.
- ParsingError: Problems parsing the input file.
- FormatError: Formatting issues in the input.
- FaultTreeError: The input fault tree is malformed.
- """
- description = "Shorthand => OpenPSA MEF XML Converter"
- parser = ap.ArgumentParser(description=description)
- parser.add_argument("input_file", type=str,
- help="input file with the shorthand notation")
- parser.add_argument("--multi-top", help="multiple top events",
- action="store_true")
- parser.add_argument("-o", "--out",
- help="output file to write the converted input")
- args = parser.parse_args(argv)
-
- fault_tree = None
- with open(args.input_file, "r") as shorthand_file:
- fault_tree = parse_input(shorthand_file, args.multi_top)
-
- out = args.out
- if not out:
- out = os.path.basename(args.input_file)
- out = out[:out.rfind(".")] + ".xml"
-
- with open(out, "w") as tree_file:
- tree_file.write("<?xml version=\"1.0\"?>\n")
- tree_file.write(fault_tree.to_xml())
-
-if __name__ == "__main__":
- try:
- main()
- except ap.ArgumentTypeError as err:
- print("Argument Error:\n" + str(err))
- sys.exit(2)
- except IOError as err:
- print("IO Error:\n" + str(err))
- sys.exit(1)
- except ParsingError as err:
- print("Parsing Error:\n" + str(err))
- sys.exit(1)
- except FormatError as err:
- print("Format Error:\n" + str(err))
- sys.exit(1)
- except FaultTreeError as err:
- print("Error in the fault tree:\n" + str(err))
- sys.exit(1)
diff --git a/scripts/test_fault_tree_generator.py b/scripts/test/test_fault_tree_generator.py
similarity index 93%
rename from scripts/test_fault_tree_generator.py
rename to scripts/test/test_fault_tree_generator.py
index c8e6b1f..103850d 100644
--- a/scripts/test_fault_tree_generator.py
+++ b/scripts/test/test_fault_tree_generator.py
@@ -15,7 +15,7 @@
"""Tests for the fault tree generator."""
-from __future__ import division
+from __future__ import division, absolute_import
import random
from subprocess import call
@@ -121,7 +121,7 @@ class FaultTreeGeneratorTestCase(TestCase):
def setUp(self):
"""Initializes the generator factors for default complexity."""
- self.output = NamedTemporaryFile()
+ self.output = NamedTemporaryFile(mode="w+")
random.seed(123)
self.factors = Factors()
self.factors.set_min_max_prob(0.01, 0.1)
@@ -148,18 +148,18 @@ class FaultTreeGeneratorTestCase(TestCase):
doc = etree.parse(test_file)
assert_true(relaxng.validate(doc))
- def test_shorthand_output(self):
- """Checks if the shorthand format output passes validation."""
+ def test_aralia_output(self):
+ """Checks if the Aralia format output passes validation."""
self.factors.set_gate_weights([1, 1, 1, 0.1, 0.1])
self.factors.num_house = 10
self.factors.num_ccf = 10
self.factors.calculate()
fault_tree = generate_fault_tree("TestingTree", "root", self.factors)
assert_is_not_none(fault_tree)
- self.output.write(fault_tree.to_shorthand())
+ self.output.write(fault_tree.to_aralia())
self.output.file.flush()
- tmp = NamedTemporaryFile()
- cmd = ["./shorthand_to_xml.py", self.output.name, "-o", tmp.name]
+ tmp = NamedTemporaryFile(mode="w+")
+ cmd = ["./translators/aralia.py", self.output.name, "-o", tmp.name]
assert_equal(0, call(cmd))
def test_constrain_num_gates(self):
@@ -175,7 +175,7 @@ class FaultTreeGeneratorTestCase(TestCase):
def test_main():
"""Tests the main() of the generator."""
- tmp = NamedTemporaryFile()
+ tmp = NamedTemporaryFile(mode="w+")
main(["-b", "200", "-g", "200", "-o", tmp.name])
relaxng_doc = etree.parse("../share/input.rng")
relaxng = etree.RelaxNG(relaxng_doc)
@@ -183,6 +183,7 @@ def test_main():
doc = etree.parse(test_file)
assert_true(relaxng.validate(doc))
- main(["-b", "200", "-g", "200", "-o", tmp.name, "--shorthand"])
- cmd = ["./shorthand_to_xml.py", tmp.name, "-o", NamedTemporaryFile().name]
+ main(["-b", "200", "-g", "200", "-o", tmp.name, "--aralia"])
+ cmd = ["./translators/aralia.py", tmp.name, "-o",
+ NamedTemporaryFile(mode="w+").name]
assert_equal(0, call(cmd))
diff --git a/scripts/test_shorthand_to_xml.py b/scripts/test_shorthand_to_xml.py
deleted file mode 100644
index b2d38c9..0000000
--- a/scripts/test_shorthand_to_xml.py
+++ /dev/null
@@ -1,427 +0,0 @@
-# Copyright (C) 2014-2016 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 <http://www.gnu.org/licenses/>.
-
-"""Tests for the shorthand-to-XML converter."""
-
-import os
-from tempfile import NamedTemporaryFile
-from unittest import TestCase
-
-from lxml import etree
-from nose.tools import assert_raises, assert_is_not_none, assert_equal, \
- assert_true
-
-from shorthand_to_xml import ParsingError, FormatError, FaultTreeError, \
- parse_input, main
-
-
-def parse_input_file(name, multi_top=False):
- """Calls the input file parser to get the fault tree."""
- with open(name) as shorthand_file:
- return parse_input(shorthand_file, multi_top)
-
-
-def test_correct():
- """Tests the valid overall process."""
- tmp = NamedTemporaryFile()
- tmp.write("ValidFaultTree\n\n")
- tmp.write("root := g1 | g2 | g3 | g4 | g7 | e1\n")
- tmp.write("g1 := e2 & g3 & g5\n")
- tmp.write("g2 := h1 & g6\n")
- tmp.write("g3 := (g6 ^ e2)\n")
- tmp.write("g4 := @(2, [g5, e3, e4])\n")
- tmp.write("g5 := ~(e3)\n")
- tmp.write("g6 := (e3 | e4)\n\n")
- tmp.write("g7 := g8\n\n")
- tmp.write("g8 := ~e2 & ~e3\n\n")
- tmp.write("p(e1) = 0.1\n")
- tmp.write("p(e2) = 0.2\n")
- tmp.write("p(e3) = 0.3\n")
- tmp.write("s(h1) = true\n")
- tmp.write("s(h2) = false\n")
- tmp.flush()
- fault_tree = parse_input_file(tmp.name)
- assert_is_not_none(fault_tree)
- yield assert_equal, 9, len(fault_tree.gates)
- yield assert_equal, 3, len(fault_tree.basic_events)
- yield assert_equal, 2, len(fault_tree.house_events)
- yield assert_equal, 1, len(fault_tree.undefined_events())
- out = NamedTemporaryFile()
- out.write("<?xml version=\"1.0\"?>\n")
- out.write(fault_tree.to_xml())
- out.flush()
- relaxng_doc = etree.parse("../share/input.rng")
- relaxng = etree.RelaxNG(relaxng_doc)
- with open(out.name, "r") as test_file:
- doc = etree.parse(test_file)
- assert_true(relaxng.validate(doc))
-
-
-def test_ft_name_redefinition():
- """Tests the redefinition of the fault tree name."""
- tmp = NamedTemporaryFile()
- tmp.write("FaultTreeName\n")
- tmp.write("AnotherFaultTree\n")
- tmp.write("g1 := e1\n")
- tmp.flush()
- assert_raises(FormatError, parse_input_file, tmp.name)
-
-
-def test_ncname_ft():
- """The name of the fault tree must conform to NCNAME format."""
- tmp = NamedTemporaryFile()
- tmp.write("Contains Whitespace Characters\n")
- tmp.flush()
- yield assert_raises, ParsingError, parse_input_file, tmp.name
- tmp = NamedTemporaryFile()
- tmp.write("Peri.od\n")
- tmp.flush()
- yield assert_raises, ParsingError, parse_input_file, tmp.name
- tmp = NamedTemporaryFile()
- tmp.write("EndWithDash-\n")
- tmp.flush()
- yield assert_raises, ParsingError, parse_input_file, tmp.name
- tmp = NamedTemporaryFile()
- tmp.write("Double--Dash\n")
- tmp.flush()
- yield assert_raises, ParsingError, parse_input_file, tmp.name
- tmp = NamedTemporaryFile()
- tmp.write("42StartWithNumbers\n")
- tmp.flush()
- yield assert_raises, ParsingError, parse_input_file, tmp.name
- tmp = NamedTemporaryFile()
- tmp.write("Correct-Name_42\n")
- tmp.write("g1 := e1 & e2\n") # dummy gate
- tmp.flush()
- yield parse_input_file, tmp.name
-
-
-def test_no_ft_name():
- """Tests the case where no fault tree name is provided."""
- tmp = NamedTemporaryFile()
- tmp.write("g1 := g2 & e1\n")
- tmp.write("g2 := h1 & e1\n")
- tmp.flush()
- assert_raises(FormatError, parse_input_file, tmp.name)
-
-
-def test_illegal_format():
- """Test Arithmetic operators."""
- tmp = NamedTemporaryFile()
- tmp.write("FT\n")
- tmp.write("g1 := g2 + e1\n")
- tmp.flush()
- yield assert_raises, ParsingError, parse_input_file, tmp.name
- tmp = NamedTemporaryFile()
- tmp.write("FT\n")
- tmp.write("g1 := g2 * e1\n")
- tmp.flush()
- yield assert_raises, ParsingError, parse_input_file, tmp.name
- tmp = NamedTemporaryFile()
- tmp.write("FT\n")
- tmp.write("g1 := -e1\n")
- tmp.flush()
- yield assert_raises, ParsingError, parse_input_file, tmp.name
- tmp = NamedTemporaryFile()
- tmp.write("FT\n")
- tmp.write("g1 := g2 / e1\n")
- tmp.flush()
- yield assert_raises, ParsingError, parse_input_file, tmp.name
-
-
-def test_repeated_argument():
- """Tests the formula with a repeated argument."""
- tmp = NamedTemporaryFile()
- tmp.write("FT\n")
- tmp.write("g1 := g2 & e1\n")
- tmp.write("g2 := E1 & e1\n") # repeated argument with uppercase
- tmp.flush()
- assert_raises(FaultTreeError, parse_input_file, tmp.name)
-
-
-def test_missing_parenthesis():
- """Tests cases with a missing opening or closing parentheses."""
- tmp = NamedTemporaryFile()
- tmp.write("WrongParentheses\n")
- tmp.write("g1 := a | b)")
- tmp.flush()
- yield assert_raises, ParsingError, parse_input_file, tmp.name
- tmp = NamedTemporaryFile()
- tmp.write("WrongParentheses\n")
- tmp.write("g1 := (a | b")
- tmp.flush()
- yield assert_raises, ParsingError, parse_input_file, tmp.name
-
-
-def test_nested_parentheses():
- """Tests cases with nested parentheses."""
- tmp = NamedTemporaryFile()
- tmp.write("WrongParentheses\n")
- tmp.write("g1 := ((a | b))")
- tmp.flush()
- yield assert_raises, ParsingError, parse_input_file, tmp.name
-
-
-def test_vote_gate_arguments():
- """K/N or Combination gate/operator should have its K < its N."""
- tmp = NamedTemporaryFile()
- tmp.write("FT\n")
- tmp.write("g1 := @(3, [a, b, c])") # K = N
- tmp.flush()
- yield assert_raises, FaultTreeError, parse_input_file, tmp.name
- tmp = NamedTemporaryFile()
- tmp.write("FT\n")
- tmp.write("g1 := @(4, [a, b, c])") # K > N
- tmp.flush()
- yield assert_raises, FaultTreeError, parse_input_file, tmp.name
-
-
-def test_null_gate():
- """Tests if NULL type gates are recognized correctly."""
- tmp = NamedTemporaryFile()
- tmp.write("FT\n")
- tmp.write("g1 := a")
- tmp.flush()
- fault_tree = parse_input_file(tmp.name)
- assert_is_not_none(fault_tree)
- yield assert_equal, 1, len(fault_tree.gates)
- yield assert_equal, "g1", fault_tree.gates[0].name
- yield assert_true, "a" in fault_tree.gates[0].event_arguments
- yield assert_equal, "null", fault_tree.gates[0].operator
-
-
-def test_not_gate():
- """Tests if NOT type gates are recognized correctly."""
- tmp = NamedTemporaryFile()
- tmp.write("FT\n")
- tmp.write("g1 := ~(a)")
- tmp.flush()
- fault_tree = parse_input_file(tmp.name)
- assert_is_not_none(fault_tree)
- yield assert_equal, 1, len(fault_tree.gates)
- yield assert_equal, "g1", fault_tree.gates[0].name
- yield assert_true, "a" in fault_tree.gates[0].event_arguments
- yield assert_equal, "not", fault_tree.gates[0].operator
-
-
-def test_no_top_event():
- """Detection of cases without top gate definitions.
-
- Note that this also means that there is a cycle that includes the root.
- """
- tmp = NamedTemporaryFile()
- tmp.write("FT\n")
- tmp.write("g1 := g2 & e1\n")
- tmp.write("g2 := g1 & e1\n")
- tmp.flush()
- assert_raises(FaultTreeError, parse_input_file, tmp.name)
-
-
-def test_multi_top():
- """Multiple root events without the flag causes a problem by default."""
- tmp = NamedTemporaryFile()
- tmp.write("FT\n")
- tmp.write("g1 := e2 & e1\n")
- tmp.write("g2 := h1 & e1\n")
- tmp.flush()
- yield assert_raises, FaultTreeError, parse_input_file, tmp.name
- yield assert_is_not_none, parse_input_file(tmp.name, True) # with the flag
-
-
-def test_redefinition():
- """Tests name collision detection of events."""
- tmp = NamedTemporaryFile()
- tmp.write("FT\n")
- tmp.write("g1 := g2 & e1\n")
- tmp.write("g2 := h1 & e1\n")
- tmp.write("g2 := e2 & e1\n") # redefining an event
- tmp.flush()
- assert_raises(FaultTreeError, parse_input_file, tmp.name)
-
-
-def test_orphan_events():
- """Tests cases with orphan house and basic event events."""
- tmp = NamedTemporaryFile()
- tmp.write("FT\n")
- tmp.write("g1 := g2 & e1\n")
- tmp.write("g2 := h1 & e1\n")
- tmp.write("p(e1) = 0.5\n")
- tmp.write("s(h1) = false\n")
- tmp.flush()
- yield assert_is_not_none, parse_input_file(tmp.name)
- tmp.write("p(e2) = 0.1\n") # orphan basic event
- tmp.flush()
- yield assert_is_not_none, parse_input_file(tmp.name)
- tmp.write("s(h2) = true\n") # orphan house event
- tmp.flush()
- yield assert_is_not_none, parse_input_file(tmp.name)
-
-
-def test_cycle_detection():
- """Tests cycles in the fault tree."""
- tmp = NamedTemporaryFile()
- tmp.write("FT\n")
- tmp.write("g1 := g2 & e1\n")
- tmp.write("g2 := g3 & e1\n")
- tmp.write("g3 := g2 & e1\n") # cycle
- tmp.flush()
- yield assert_raises, FaultTreeError, parse_input_file, tmp.name
- tmp = NamedTemporaryFile()
- tmp.write("FT\n")
- tmp.write("g1 := u1 & g2 & e1\n")
- tmp.write("g2 := u2 & g3 & e1\n") # nested formula cycle
- tmp.write("g3 := u3 & g2 & e1\n") # cycle
- tmp.flush()
- yield assert_raises, FaultTreeError, parse_input_file, tmp.name
-
-
-def test_detached_gates():
- """Some cycles may get detached from the original fault tree."""
- tmp = NamedTemporaryFile()
- tmp.write("FT\n")
- tmp.write("g1 := e2 & e1\n")
- tmp.write("g2 := g3 & e1\n") # detached gate
- tmp.write("g3 := g2 & e1\n") # cycle
- tmp.flush()
- assert_raises(FaultTreeError, parse_input_file, tmp.name)
-
-
-class ComplementArgTestCase(TestCase):
- """Complement arguments of gates."""
-
- def setUp(self):
- """Launches a temporary file."""
- self.tmp = NamedTemporaryFile()
- self.tmp.write("FT\n")
-
- def check_gate(self, symbol, operator, custom_gate=None):
- """Default g1 gate test with e2 as a complement argument."""
- if custom_gate:
- self.tmp.write(custom_gate)
- else:
- self.tmp.write("g1 := e1 %s ~e2\n" % symbol)
- self.tmp.flush()
- fault_tree = parse_input_file(self.tmp.name)
- assert_is_not_none(fault_tree)
- assert_equal(1, len(fault_tree.gates))
- gate = fault_tree.gates[0]
- assert_equal("g1", gate.name)
- assert_equal(operator, gate.operator)
- if not custom_gate:
- assert_true("e1" in gate.event_arguments)
- assert_true("~e2" in gate.event_arguments)
- assert_equal(1, len(gate.complement_arguments))
- assert_equal("e2", [x.name for x in gate.complement_arguments][0])
-
- def test_or(self):
- """OR formula with complement arguments."""
- self.check_gate("|", "or")
-
- def test_xor(self):
- """XOR formula with complement arguments."""
- self.check_gate("^", "xor")
-
- def test_and(self):
- """AND Formula with complement arguments."""
- self.check_gate("&", "and")
-
- def test_vote(self):
- """Combination with complement arguments."""
- self.check_gate("@", "atleast", "g1 := @(2, [e1, ~e2, e3])")
-
- def test_null(self):
- """NULL with a single complement argument."""
- self.check_gate("", "null", "g1 := ~e2")
-
- def test_not(self):
- """NOT of a complement argument."""
- self.check_gate("", "not", "g1 := ~(~e2)")
-
- def test_cancellation(self):
- """Supplies argument and its complement."""
- self.check_gate("&", "and", "g1 := ~e2 & e2")
-
-
-class NestedFormulaTestCase(TestCase):
- """Nested logical operator tests."""
-
- def setUp(self):
- """Launches a temporary file."""
- self.tmp = NamedTemporaryFile()
- self.tmp.write("FT\n")
-
- def test_or_xor(self):
- """Formula with OR and XOR operators."""
- self.tmp.write("g1 := e1 | e2 ^ e3\n")
- self.tmp.flush()
- assert_raises(ParsingError, parse_input_file, self.tmp.name)
-
- def test_or_and(self):
- """Formula with OR and AND operators."""
- self.tmp.write("g1 := e1 | e2 & e3\n")
- self.tmp.flush()
- assert_raises(ParsingError, parse_input_file, self.tmp.name)
-
- def test_or_vote(self):
- """Formula with OR and K/N operators."""
- self.tmp.write("g1 := e1 | @(2, [e2, e3, e4])\n")
- self.tmp.flush()
- assert_raises(ParsingError, parse_input_file, self.tmp.name)
-
- def test_xor_xor(self):
- """Formula with XOR and XOR operators.
-
- Note that this is a special case
- because most analysis restricts XOR operator to two arguments,
- so nested formula of XOR operators must be created.
- """
- self.tmp.write("g1 := e1 ^ e2 ^ e3\n")
- self.tmp.flush()
- assert_raises(ParsingError, parse_input_file, self.tmp.name)
-
- def test_xor_and(self):
- """Formula with XOR and AND operators."""
- self.tmp.write("g1 := e1 ^ e2 & e3\n")
- self.tmp.flush()
- assert_raises(ParsingError, parse_input_file, self.tmp.name)
-
- def test_not_not(self):
- """Formula with NOT and NOT operators.
-
- This is a special case. It is considered an error without parentheses.
- """
- self.tmp.write("g1 := ~~e1\n")
- self.tmp.flush()
- assert_raises(ParsingError, parse_input_file, self.tmp.name)
- tmp = NamedTemporaryFile()
- tmp.write("FT\n")
- tmp.write("g1 := ~e1~a\n")
- tmp.flush()
- assert_raises(ParsingError, parse_input_file, tmp.name)
-
-
-def test_main():
- """Tests the main function."""
- tmp = NamedTemporaryFile()
- tmp.write("FT\n")
- tmp.write("g1 := g2 & e1\n")
- tmp.write("g2 := g3 & e1\n")
- tmp.write("g3 := e2 & e1\n")
- tmp.flush()
- main([tmp.name])
- out = os.path.basename(tmp.name)
- out = out[:out.rfind(".")] + ".xml"
- assert_true(os.path.exists(out))
- os.remove(out)
diff --git a/share/config.rng b/share/config.rng
index 4ee85ad..c8dbf0a 100644
--- a/share/config.rng
+++ b/share/config.rng
@@ -5,11 +5,11 @@
<element name="config">
<element name="input-files">
<oneOrMore>
- <element name="file"> <data type="string"/> </element>
+ <element name="file"> <data type="anyURI"/> </element>
</oneOrMore>
</element>
<optional>
- <element name="output-path"> <data type="string"/> </element>
+ <element name="output-path"> <data type="anyURI"/> </element>
</optional>
<ref name="options"/>
</element>
@@ -20,9 +20,11 @@
<optional>
<element name="algorithm">
<attribute name="name">
- <data type="string">
- <param name="pattern">mocus|bdd|zbdd</param>
- </data>
+ <choice>
+ <value>mocus</value>
+ <value>bdd</value>
+ <value>zbdd</value>
+ </choice>
</attribute>
</element>
</optional>
@@ -33,24 +35,16 @@
<element name="analysis">
<interleave>
<optional>
- <attribute name="probability">
- <data type="boolean"/>
- </attribute>
+ <attribute name="probability"> <data type="boolean"/> </attribute>
</optional>
<optional>
- <attribute name="importance">
- <data type="boolean"/>
- </attribute>
+ <attribute name="importance"> <data type="boolean"/> </attribute>
</optional>
<optional>
- <attribute name="uncertainty">
- <data type="boolean"/>
- </attribute>
+ <attribute name="uncertainty"> <data type="boolean"/> </attribute>
</optional>
<optional>
- <attribute name="ccf">
- <data type="boolean"/>
- </attribute>
+ <attribute name="ccf"> <data type="boolean"/> </attribute>
</optional>
</interleave>
</element>
@@ -58,54 +52,45 @@
<optional>
<element name="approximation">
<attribute name="name">
- <data type="string">
- <param name="pattern">rare-event|mcub</param>
- </data>
+ <choice>
+ <value>rare-event</value>
+ <value>mcub</value>
+ </choice>
</attribute>
</element>
</optional>
<optional>
- <element name="limits">
- <interleave>
- <optional>
- <element name="product-order">
- <data type="nonNegativeInteger"/>
- </element>
- </optional>
- <optional>
- <element name="mission-time">
- <data type="double"/>
- </element>
- </optional>
- <optional>
- <element name="cut-off">
- <data type="double"/>
- </element>
- </optional>
- <optional>
- <element name="number-of-trials">
- <data type="nonNegativeInteger"/>
- </element>
- </optional>
- <optional>
- <element name="number-of-quantiles">
- <data type="nonNegativeInteger"/>
- </element>
- </optional>
- <optional>
- <element name="number-of-bins">
- <data type="nonNegativeInteger"/>
- </element>
- </optional>
- <optional>
- <element name="seed">
- <data type="nonNegativeInteger"/>
- </element>
- </optional>
- </interleave>
- </element>
+ <ref name="limits"/>
</optional>
</element>
</define>
+ <define name="limits">
+ <element name="limits">
+ <interleave>
+ <optional>
+ <element name="product-order"> <data type="nonNegativeInteger"/> </element>
+ </optional>
+ <optional>
+ <element name="mission-time"> <data type="double"/> </element>
+ </optional>
+ <optional>
+ <element name="cut-off"> <data type="double"/> </element>
+ </optional>
+ <optional>
+ <element name="number-of-trials"> <data type="nonNegativeInteger"/> </element>
+ </optional>
+ <optional>
+ <element name="number-of-quantiles"> <data type="nonNegativeInteger"/> </element>
+ </optional>
+ <optional>
+ <element name="number-of-bins"> <data type="nonNegativeInteger"/> </element>
+ </optional>
+ <optional>
+ <element name="seed"> <data type="nonNegativeInteger"/> </element>
+ </optional>
+ </interleave>
+ </element>
+ </define>
+
</grammar>
diff --git a/share/input.rng b/share/input.rng
index 847246c..012a079 100644
--- a/share/input.rng
+++ b/share/input.rng
@@ -60,7 +60,7 @@
<define name="NonEmptyString"> <!-- Texts without LF and other special chars. -->
<data type="normalizedString">
- <param name="pattern">.*\S+.*</param>
+ <param name="minLength">1</param>
</data>
</define>
diff --git a/share/open-psa/curves.bnf b/share/open-psa/curves.bnf
deleted file mode 100644
index 26fd94e..0000000
--- a/share/open-psa/curves.bnf
+++ /dev/null
@@ -1,11 +0,0 @@
-curve ::=
- <curve
- [ name="identifier" ]
- [ description="text" ]
- [ X-title="string" Y-title="string" [ Z-title="string" ] ]
- [ X-unit="unit" Y-unit="unit" [ Z-unit="unit" ] ]
- >
- <point X="float" Y="float" [ Z="float" ] />*
- </curve>
-
-unit ::= seconds | hours | ...
diff --git a/share/open-psa/mcs.bnf b/share/open-psa/mcs.bnf
deleted file mode 100644
index ddf085a..0000000
--- a/share/open-psa/mcs.bnf
+++ /dev/null
@@ -1,18 +0,0 @@
-sum-of-products ::=
- <sum-of-products
- [ name="identifier" ]
- [ description="text" ]
- [ basic-events="integer" ]
- [ products="integer" ]
- >
- product*
- </sum-of-products>
-
-product ::=
- <product [ order="integer" ]>
- literal*
- </product>
-
-literal ::=
- <basic-event name="identifier"/>
- | <not> <basic-event name="identifier"/> </not>
diff --git a/share/open-psa/mef.dtd b/share/open-psa/mef.dtd
deleted file mode 100644
index 5d28186..0000000
--- a/share/open-psa/mef.dtd
+++ /dev/null
@@ -1,461 +0,0 @@
-<!--
- WARNING: This DTD will fail to validate Boolean operations
- involving AND, OR, NOT due to the redefinition conflict
- with Formulae AND, OR, NOT.
--->
-
-<!-- Advance declaration of ENTITIES -->
-
-<!-- IV.3. Formulae -->
-<!ENTITY % formula
- "(event | gate | house-event | basic-event | constant
-| and | or | not | xor | iff | nand | nor | atleast | cardinality)">
-
-
-<!-- V.2.1. Entities -->
-<!ENTITY % value "(bool | int | float)">
-<!ENTITY % numerical-operation
- "(neg | add | sub | mul | div | pi | abs | acos | asin | atan | cos
-| cosh | exp | log | log10 | mod | pow | sin | sinh | tan | tanh
-| sqrt | ceil | floor | min | max | mean)">
-<!ENTITY % Boolean-operation "(bool_not | bool_and | bool_or | eq | df
-| lt | gt | leq | geq)">
-<!ENTITY % conditional-operation "(ite | switch)">
-<!ENTITY % operation
- "(%numerical-operation; | %Boolean-operation; | %conditional-operation;)">
-<!ENTITY % built-in
- "(exponential | GLM | Weibull | periodic-test | extern-function)">
-<!ENTITY % random-deviate
- "(uniform-deviate | normal-deviate | lognormal-deviate | gamma-deviate
-| beta-deviate | histogram)">
-<!ENTITY % test-event "(test-initiating-event | test-functional-event)">
-<!ENTITY % expression
- "(%value; | parameter | system-mission-time | %operation; | %built-in;
-| %random-deviate; | %test-event;)">
-
-<!-- II.3. Instructions, Rules -->
-
-<!ENTITY % set "(set-gate | set-house-event | set-basic-event | set-parameter)">
-<!ENTITY % collect "(collect-formula | collect-expression)">
-<!ENTITY % instruction "(%set; | %collect; | if | block | rule | event-tree)">
-
-
-<!-- I. Calculation Layer -->
-
-<!-- I.1. Models -->
-
-<!ELEMENT opsa-mef
- (label?, attributes?,
- (
- define-event-tree
- | define-alignment
- | define-consequence-group | define-consequence
- | define-rule
- | define-initiating-event-group | define-initiating-event
- | define-fault-tree
- | define-substitution
- | define-CCF-group
- | include
- )*,
- model-data?
- )
->
-
-<!ELEMENT label (#PCDATA)>
-
-<!ELEMENT attributes (attribute*)>
-<!ELEMENT attribute EMPTY>
-<!ATTLIST attribute
- name CDATA #REQUIRED
- value CDATA #REQUIRED
- type CDATA #IMPLIED
->
-
-<!ELEMENT include EMPTY>
-<!ATTLIST include file CDATA #REQUIRED>
-
-
-<!-- I.2. Consequences, Consequence Groups -->
-
-<!ELEMENT define-consequence (label?, attributes?, initiating-event, sequence)>
-<!ATTLIST define-consequence name CDATA #REQUIRED>
-
-<!ELEMENT define-consequence-group
- (label?, attributes?, (consequence | consequence-group)*)>
-<!ATTLIST define-consequence-group name CDATA #REQUIRED>
-
-<!ELEMENT consequence EMPTY>
-<!ATTLIST consequence name CDATA #REQUIRED>
-
-<!ELEMENT consequence-group EMPTY>
-<!ATTLIST consequence-group name CDATA #REQUIRED>
-
-<!ELEMENT sequence EMPTY>
-<!ATTLIST sequence name CDATA #REQUIRED>
-
-
-<!-- I.3. Missions, Phases -->
-
-<!ELEMENT define-alignment (label?, attributes?, (%instruction;)*)>
-<!ATTLIST define-alignment
- name CDATA #REQUIRED
- time-fraction CDATA #REQUIRED
->
-
-
-<!-- II. Event Tree Layer -->
-
-<!-- II.1. Initiating events, Initiating event Groups -->
-
-<!ENTITY % collected-item "(basic-event | gate | parameter)">
-
-<!ELEMENT define-initiating-event
- (label?, attributes?, (%collected-item; | consequence | consequence-group))>
-<!ATTLIST define-initiating-event name CDATA #REQUIRED>
-
-<!ELEMENT define-initiating-event-group
- (label?, attributes?, (initiating-event | initiating-event-group)+)>
-<!ATTLIST define-initiating-event-group name CDATA #REQUIRED>
-
-<!ELEMENT initiating-event EMPTY>
-<!ATTLIST initiating-event
- name CDATA #REQUIRED
- event-tree CDATA #IMPLIED
->
-
-<!ELEMENT initiating-event-group EMPTY>
-<!ATTLIST initiating-event-group
- name CDATA #REQUIRED
- event-tree CDATA #IMPLIED
->
-
-
-<!-- II.2. Event Trees -->
-
-<!ENTITY % end-state "(sequence | branch)">
-<!ENTITY % branch "((%instruction;)*, (fork | %end-state;))">
-
-<!ELEMENT define-event-tree
- (label?, attributes?,
- define-functional-event*,
- define-sequence*,
- define-branch*,
- initial-state)
->
-<!ATTLIST define-event-tree name CDATA #REQUIRED>
-
-<!ELEMENT define-functional-event (label?, attributes?)>
-<!ATTLIST define-functional-event name CDATA #REQUIRED>
-
-<!ELEMENT define-sequence (label?, attributes?, (%instruction;)+)>
-<!ATTLIST define-sequence name CDATA #REQUIRED>
-
-<!ELEMENT define-branch (label?, attributes?, %branch;)>
-<!ATTLIST define-branch name CDATA #REQUIRED>
-
-<!ELEMENT fork (path)+>
-<!ATTLIST fork functional-event CDATA #REQUIRED>
-
-<!ELEMENT path (%branch;)>
-<!ATTLIST path state CDATA #REQUIRED>
-
-<!ELEMENT initial-state (%branch;)>
-
-<!ELEMENT branch EMPTY>
-<!ATTLIST branch name CDATA #REQUIRED>
-
-
-<!-- II.3. Instructions, Rules -->
-
-<!ENTITY % directions "(forward | backward | both)">
-
-<!ELEMENT set-gate (%formula;)>
-<!ATTLIST set-gate
- name CDATA #REQUIRED
- direction (directions) #IMPLIED
->
-
-<!ELEMENT set-house-event (constant)>
-<!ATTLIST set-house-event
- name CDATA #REQUIRED
- direction (directions) #IMPLIED
->
-
-<!ELEMENT set-basic-event (%expression;)>
-<!ATTLIST set-basic-event
- name CDATA #REQUIRED
- direction (directions) #IMPLIED
->
-
-<!ELEMENT set-parameter (%expression;)>
-<!ATTLIST set-parameter
- name CDATA #REQUIRED
- direction (directions) #IMPLIED
->
-
-<!ELEMENT if (%expression;, %instruction;, (%instruction;)?)>
-<!ELEMENT collect-formula (%formula;)>
-<!ELEMENT collect-expression (%expression;)>
-<!ELEMENT block ((%instruction;)*)>
-
-<!ELEMENT event-tree EMPTY>
-<!ATTLIST event-tree name CDATA #REQUIRED>
-
-<!ELEMENT rule EMPTY>
-<!ATTLIST rule name CDATA #REQUIRED>
-
-<!ELEMENT define-rule (label?, attributes?, (%instruction;)+)>
-<!ATTLIST define-rule name CDATA #REQUIRED>
-
-
-<!-- III. Meta-Logical Layer -->
-
-<!-- III.1. CCF-Groups -->
-
-<!ELEMENT define-CCF-group
- (label?, attributes?, members, distribution, (factor | factors))>
-<!ATTLIST define-CCF-group
- name CDATA #REQUIRED
- model (beta-factor | MGL | alpha-factor | phi-factor) #REQUIRED
->
-
-<!ELEMENT members (basic-event+)>
-<!ELEMENT factors (factor+)>
-
-<!ELEMENT factor (%expression;)>
-<!ATTLIST factor level CDATA #REQUIRED>
-
-
-<!-- III.2. Substitutions -->
-
-<!ELEMENT distribution (%expression;)>
-<!ELEMENT define-substitution
- (label?, attributes?, hypothesis, source?, target)>
-<!ATTLIST define-substitution
- name CDATA #IMPLIED
- type CDATA #IMPLIED
->
-
-<!ELEMENT hypothesis (%formula;)>
-<!ELEMENT source (basic-event+)>
-<!ELEMENT target (basic-event+ | %formula;)>
-
-
-<!-- IV. Fault Tree Layer -->
-
-<!-- IV.1. Definitions of Fault Trees & Components -->
-
-<!ELEMENT define-fault-tree
- (label?, attributes?,
- (
- define-substitution | define-CCF-group
- | define-component
- | define-gate | define-house-event
- | define-basic-event | define-parameter
- | include
- )*
- )
->
-<!ATTLIST define-fault-tree name CDATA #REQUIRED>
-
-<!ELEMENT define-component
- (label?, attributes?,
- (
- define-substitution | define-CCF-group
- | define-component
- | define-gate | define-house-event
- | define-basic-event | define-parameter
- | include
- )*
- )
->
-<!ATTLIST define-component
- name CDATA #REQUIRED
- role (private | public) #IMPLIED
->
-
-<!ELEMENT model-data
- (define-house-event | define-basic-event | define-parameter | include)*>
-
-
-<!-- IV.2. Definitions of Gates, House Events & Basic Events -->
-
-<!ELEMENT define-gate (label?, attributes?, %formula;)>
-<!ATTLIST define-gate
- name CDATA #REQUIRED
- role (private | public) #IMPLIED
->
-
-<!ELEMENT define-house-event (label?, attributes?, constant?)>
-<!ATTLIST define-house-event
- name CDATA #REQUIRED
- role (private | public) #IMPLIED
->
-
-<!ELEMENT define-basic-event (label?, attributes?, (%expression;)?)>
-<!ATTLIST define-basic-event
- name CDATA #REQUIRED
- role (private | public) #IMPLIED
->
-
-
-<!-- IV.3. Formulae -->
-
-<!ENTITY % event-type "(gate | house-event | basic-event)">
-
-<!ELEMENT event EMPTY>
-<!ATTLIST event
- name CDATA #REQUIRED
- type %event-type; #IMPLIED
->
-
-<!ELEMENT gate EMPTY>
-<!ATTLIST gate name CDATA #REQUIRED>
-
-<!ELEMENT house-event EMPTY>
-<!ATTLIST house-event name CDATA #REQUIRED>
-
-<!ELEMENT basic-event EMPTY>
-<!ATTLIST basic-event name CDATA #REQUIRED>
-
-<!ELEMENT and ((%formula;)+)>
-<!ELEMENT or ((%formula;)+)>
-<!ELEMENT not (%formula;)>
-<!ELEMENT xor ((%formula;)+)>
-<!ELEMENT iff ((%formula;)+)>
-<!ELEMENT nand ((%formula;)+)>
-<!ELEMENT nor ((%formula;)+)>
-<!ELEMENT atleast ((%formula;)+)>
-<!ATTLIST atleast min CDATA #REQUIRED>
-
-<!ELEMENT cardinality ((%formula;)+)>
-<!ATTLIST cardinality min CDATA #REQUIRED max CDATA #REQUIRED>
-
-<!ELEMENT imply (%formula;, %formula;)>
-
-<!ELEMENT constant EMPTY>
-<!ATTLIST constant value (true | false) #REQUIRED>
-
-
-<!-- V. Stochastic Layer -->
-
-<!-- V.1. Definition of Parameters -->
-
-<!ENTITY % units
- "(bool | int | float | hours | hours-1 | years | years-1 | fit | demands)">
-<!ELEMENT define-parameter (label?, attributes?, %expression;)>
-<!ATTLIST define-parameter
- name CDATA #REQUIRED
- role (private | public) #IMPLIED
- unit %units; #IMPLIED
->
-
-
-<!-- V.2. Expressions -->
-
-<!-- V.2.1. Entities -->
-
-<!-- V.2.2. Constants, Parameters -->
-
-<!ELEMENT bool EMPTY>
-<!ATTLIST bool value (true | false) #REQUIRED>
-
-<!ELEMENT int EMPTY>
-<!ATTLIST int value CDATA #REQUIRED>
-
-<!ELEMENT float EMPTY>
-<!ATTLIST float value CDATA #REQUIRED>
-
-<!ELEMENT system-mission-time EMPTY>
-<!ATTLIST system-mission-time unit %units; #IMPLIED>
-
-<!ELEMENT parameter EMPTY>
-<!ATTLIST parameter
- name CDATA #REQUIRED
- unit %units; #IMPLIED
->
-
-
-<!-- V.2.3. Numerical Expressions -->
-
-<!ELEMENT neg (%expression;)>
-<!ELEMENT add ((%expression;)+)>
-<!ELEMENT sub ((%expression;)+)>
-<!ELEMENT mul ((%expression;)+)>
-<!ELEMENT div ((%expression;)+)>
-<!ELEMENT pi EMPTY>
-<!ELEMENT abs (%expression;)>
-<!ELEMENT acos (%expression;)>
-<!ELEMENT asin (%expression;)>
-<!ELEMENT atan (%expression;)>
-<!ELEMENT cos (%expression;)>
-<!ELEMENT cosh (%expression;)>
-<!ELEMENT exp (%expression;)>
-<!ELEMENT log (%expression;)>
-<!ELEMENT log10 (%expression;)>
-<!ELEMENT mod (%expression;, %expression;)>
-<!ELEMENT pow (%expression;, %expression;)>
-<!ELEMENT sin (%expression;)>
-<!ELEMENT sinh (%expression;)>
-<!ELEMENT tan (%expression;)>
-<!ELEMENT tanh (%expression;)>
-<!ELEMENT sqrt (%expression;)>
-<!ELEMENT ceil (%expression;)>
-<!ELEMENT floor (%expression;)>
-<!ELEMENT min ((%expression;)+)>
-<!ELEMENT max ((%expression;)+)>
-<!ELEMENT mean ((%expression;)+)>
-
-
-<!-- V.2.4. Boolean Expressions -->
-
-<!-- NOTE: Boolean AND, OR, NOT are renamed to avoid redefinition. -->
-<!ELEMENT bool_not (%expression;)>
-<!ELEMENT bool_and ((%expression;)+)>
-<!ELEMENT bool_or ((%expression;)+)>
-<!ELEMENT eq (%expression;, %expression;)>
-<!ELEMENT df (%expression;, %expression;)>
-<!ELEMENT lt (%expression;, %expression;)>
-<!ELEMENT gt (%expression;, %expression;)>
-<!ELEMENT leq (%expression;, %expression;)>
-<!ELEMENT geq (%expression;, %expression;)>
-
-
-<!-- V.2.5. Conditional Expressions -->
-
-<!ELEMENT ite (%expression;, %expression;, %expression;)>
-<!ELEMENT switch (case*, %expression;)>
-<!ELEMENT case (%expression;, %expression;)>
-
-
-<!-- V.2.6. Built-ins -->
-
-<!ELEMENT exponential (%expression;, %expression;)>
-<!ELEMENT GLM (%expression;, %expression;, %expression;, %expression;)>
-<!ELEMENT Weibull (%expression;, %expression;, %expression;, %expression;)>
-<!ELEMENT periodic-test ((%expression;)+)>
-<!ELEMENT extern-function ((%expression;)*)>
-<!ATTLIST extern-function name CDATA #REQUIRED>
-
-
-<!-- V.2.7. Random-Deviates -->
-
-<!ELEMENT uniform-deviate (%expression;, %expression;)>
-<!ELEMENT normal-deviate (%expression;, %expression;)>
-<!ELEMENT lognormal-deviate (%expression;, %expression;, %expression;)>
-<!ELEMENT gamma-deviate (%expression;, %expression;)>
-<!ELEMENT beta-deviate (%expression;, %expression;)>
-<!ELEMENT histogram (%expression;, bin+)>
-<!ELEMENT bin (%expression;, %expression;)>
-
-
-<!-- V.2.8. Test-Events -->
-
-<!ELEMENT test-initiating-event EMPTY>
-<!ATTLIST test-initiating-event name CDATA #REQUIRED>
-
-<!ELEMENT test-functional-event EMPTY>
-<!ATTLIST test-functional-event
- name CDATA #REQUIRED
- state CDATA #REQUIRED
->
diff --git a/share/open-psa/mef.rnc b/share/open-psa/mef.rnc
deleted file mode 100644
index f0eee9f..0000000
--- a/share/open-psa/mef.rnc
+++ /dev/null
@@ -1,539 +0,0 @@
-# ###############################################################
-
-# I. Calculation Layer
-
-# ###############################################################
-
-# =============================================================
-
-# I.1. Models
-
-# =============================================================
-start =
- element opsa-mef {
- name?,
- label?,
- attributes?,
- (event-tree-definition
- | alignment-definition
- | consequence-group-definition
- | consequence-definition
- | rule-definition
- | initiating-event-group-definition
- | initiating-event-definition
- | fault-tree-definition
- | substitution-definition
- | CCF-group-definition
- | include-directive)*,
- element model-data {
- (house-event-definition
- | basic-event-definition
- | parameter-definition
- | include-directive)*
- }?
- }
-Identifier = xsd:NCName { pattern = "[^\-.]+(-[^\-.]+)*" }
-name = attribute name { Identifier }
-reference =
- attribute name {
- xsd:NCName {
- pattern = "([^\-.]+(-[^\-.]+)*)(\.\i[^\-.]*(-[^\-.]+)*)*"
- }
- }
-label = element label { text }
-attributes =
- element attributes {
- element attribute {
- name,
- attribute value { xsd:string },
- attribute type { xsd:string }?
- }*
- }
-include-directive =
- element include {
- attribute file { xsd:string }
- }
-# =============================================================
-
-# I.2. Consequences, Consequence Groups
-
-# =============================================================
-consequence-definition =
- element define-consequence {
- name,
- label?,
- attributes?,
- element initiating-event { name },
- element sequence { name }
- }
-consequence-group-definition =
- element define-consequence-group {
- name, label?, attributes?, (consequence | consequence-group)
- }
-consequence = element consequence { name }
-consequence-group = element consequence-group { name }
-# =============================================================
-
-# I.3. Missions, Phases
-
-# =============================================================
-alignment-definition =
- element define-alignment {
- name, label?, attributes?, phase-definition+
- }
-phase-definition =
- element define-phase {
- name,
- attribute time-fraction { xsd:float },
- label?,
- attributes?,
- instruction*
- }
-# ###############################################################
-
-# II. Event Tree Layer
-
-# ###############################################################
-
-# =============================================================
-
-# II.1. Initiating events, Initiating event Groups
-
-# =============================================================
-initiating-event-definition =
- element define-initiating-event {
- name,
- attribute event-tree { Identifier }?,
- label?,
- attributes?,
- (collected-item | consequence | consequence-group)?
- }
-initiating-event-group-definition =
- element define-initiating-event-group {
- name,
- attribute event-tree { Identifier }?,
- label?,
- attributes?,
- initiating-event+
- }
-initiating-event =
- element initiating-event { name }
- | element initiating-event-group { name }
-collected-item = basic-event | gate | parameter
-# =============================================================
-
-# II.2. Event Trees
-
-# =============================================================
-event-tree-definition =
- element define-event-tree {
- name,
- label?,
- attributes?,
- functional-event-definition*,
- sequence-definition*,
- branch-definition*,
- initial-state
- }
-functional-event-definition =
- element define-functional-event { name, label?, attributes? }
-sequence-definition =
- element define-sequence { name, label?, attributes?, instruction+ }
-branch-definition =
- element define-branch { name, label?, attributes?, branch }
-initial-state = element initial-state { branch }
-branch = instruction*, (fork | end-state)
-fork =
- element fork {
- attribute functional-event { Identifier },
- path+
- }
-path =
- element path {
- attribute state { Identifier },
- branch
- }
-end-state =
- element sequence { name }
- | element branch { name }
-# =============================================================
-
-# II.3. Instructions, Rules
-
-# =============================================================
-instruction = set | collect | if-then-else | block | rule | link
-set = set-gate | set-house-event | set-basic-event | set-parameter
-set-gate =
- element set-gate {
- name,
- attribute direction { direction }?,
- formula
- }
-set-house-event =
- element set-house-event {
- name,
- attribute direction { direction }?,
- Boolean-constant
- }
-set-basic-event =
- element set-basic-event {
- name,
- attribute direction { direction }?,
- expression
- }
-set-parameter =
- element set-parameter {
- name,
- attribute direction { direction }?,
- expression
- }
-direction = "forward" | "backward" | "both"
-if-then-else = element if { expression, instruction, instruction? }
-collect = collect-formula | collect-expression
-collect-formula = element collect-formula { formula }
-collect-expression = element collect-expression { expression }
-block = element block { instruction* }
-rule = element rule { name }
-link = element event-tree { name }
-rule-definition =
- element define-rule { name, label?, attributes?, instruction+ }
-# ###############################################################
-
-# III. Meta-Logical Layer
-
-# ###############################################################
-
-# =============================================================
-
-# III.1. CCF-Groups
-
-# =============================================================
-CCF-group-definition =
- element define-CCF-group {
- name,
- attribute model { CCF-model },
- label?,
- attributes?,
- members,
- distribution,
- factors
- }
-members = element members { basic-event+ }
-factors =
- element factors { factor+ }
- | factor
-factor =
- element factor {
- attribute level { xsd:nonNegativeInteger }?,
- expression
- }
-distribution = element distribution { expression }
-CCF-model = "beta-factor" | "MGL" | "alpha-factor" | "phi-factor"
-# =============================================================
-
-# III.2. Substitutions
-
-# =============================================================
-substitution-definition =
- element define-substitution {
- name?,
- attribute type { xsd:string }?,
- label?,
- attributes?,
- element hypothesis { formula },
- element source { basic-event+ }?,
- element target { basic-event+ | Boolean-constant }
- }
-# ###############################################################
-
-# IV. Fault Tree Layer
-
-# ###############################################################
-
-# =============================================================
-
-# IV.1. Definitions of Fault Trees & Components
-
-# =============================================================
-fault-tree-definition =
- element define-fault-tree {
- name,
- label?,
- attributes?,
- (substitution-definition
- | CCF-group-definition
- | event-definition
- | component-definition
- | parameter-definition
- | include-directive)*
- }
-component-definition =
- element define-component {
- name,
- role?,
- label?,
- attributes?,
- (substitution-definition
- | CCF-group-definition
- | event-definition
- | component-definition
- | parameter-definition
- | include-directive)*
- }
-role = attribute role { "private" | "public" }
-event-definition =
- gate-definition | house-event-definition | basic-event-definition
-# =============================================================
-
-# IV.2. Definitions of Gates, House Events & Basic Events
-
-# =============================================================
-gate-definition =
- element define-gate { name, role?, label?, attributes?, formula }
-house-event-definition =
- element define-house-event {
- name, role?, label?, attributes?, Boolean-constant?
- }
-basic-event-definition =
- element define-basic-event {
- name, role?, label?, attributes?, expression?
- }
-# =============================================================
-
-# IV.3. Formulae
-
-# =============================================================
-formula =
- event
- | Boolean-constant
- | element and { formula+ }
- | element or { formula+ }
- | element not { formula }
- | element xor { formula+ }
- | element iff { formula+ }
- | element nand { formula+ }
- | element nor { formula+ }
- | element atleast {
- attribute min { xsd:nonNegativeInteger },
- formula+
- }
- | element cardinality {
- attribute min { xsd:nonNegativeInteger },
- attribute max { xsd:nonNegativeInteger },
- formula+
- }
- | element imply { formula, formula }
-event =
- element event {
- reference,
- attribute type { event-type }?
- }
- | gate
- | house-event
- | basic-event
-event-type = "gate" | "basic-event" | "house-event"
-gate = element gate { reference }
-house-event = element house-event { reference }
-basic-event = element basic-event { reference }
-Boolean-constant =
- element constant {
- attribute value { Boolean-value }
- }
-Boolean-value = "true" | "false"
-# ###############################################################
-
-# V. Stochastic Layer
-
-# ###############################################################
-
-# =============================================================
-
-# V.1. Definition of Parameters
-
-# =============================================================
-parameter-definition =
- element define-parameter {
- name,
- role?,
- attribute unit { units }?,
- label?,
- attributes?,
- expression
- }
-units =
- "bool"
- | "int"
- | "float"
- | "hours"
- | "hours-1"
- | "years"
- | "years-1"
- | "fit"
- | "demands"
-# =============================================================
-
-# V.2. Expressions
-
-# =============================================================
-
-# ***********************************************************
-
-# V.2.1. Entities
-
-# ***********************************************************
-expression =
- constant
- | parameter
- | operation
- | built-in
- | random-deviate
- | test-event
-constant = bool | int | float
-parameter =
- element parameter {
- reference,
- attribute unit { units }?
- }
- | element system-mission-time {
- attribute unit { units }?
- }
-operation =
- numerical-operation | Boolean-operation | conditional-operation
-built-in = exponential | GLM | Weibull | periodic-test | extern-function
-random-deviate =
- uniform-deviate
- | normal-deviate
- | lognormal-deviate
- | gamma-deviate
- | beta-deviate
- | histogram
-test-event = test-initiating-event | test-functional-event
-# ***********************************************************
-
-# V.2.2. Constants, Parameters
-
-# ***********************************************************
-bool =
- element bool {
- attribute value { Boolean-value }
- }
-int =
- element int {
- attribute value { xsd:integer }
- }
-float =
- element float {
- attribute value { xsd:float }
- }
-# ***********************************************************
-
-# V.2.3. Numerical Expressions
-
-# ***********************************************************
-numerical-operation =
- element neg { expression }
- | element add { expression+ }
- | element sub { expression+ }
- | element mul { expression+ }
- | element div { expression+ }
- | element pi { empty }
- | element abs { expression }
- | element acos { expression }
- | element asin { expression }
- | element atan { expression }
- | element cos { expression }
- | element cosh { expression }
- | element exp { expression }
- | element log { expression }
- | element log10 { expression }
- | element mod { expression, expression }
- | element pow { expression, expression }
- | element sin { expression }
- | element sinh { expression }
- | element tan { expression }
- | element tanh { expression }
- | element sqrt { expression }
- | element ceil { expression }
- | element floor { expression }
- | element min { expression+ }
- | element max { expression+ }
- | element mean { expression+ }
-# ***********************************************************
-
-# V.2.4. Boolean Expressions
-
-# ***********************************************************
-Boolean-operation =
- element not { expression }
- | element and { expression+ }
- | element or { expression+ }
- | element eq { expression, expression }
- | element df { expression, expression }
- | element lt { expression, expression }
- | element gt { expression, expression }
- | element leq { expression, expression }
- | element geq { expression, expression }
-# ***********************************************************
-
-# V.2.5. Conditional Expressions
-
-# ***********************************************************
-conditional-operation = if-then-else-operation | switch-operation
-if-then-else-operation =
- element ite { expression, expression, expression }
-switch-operation = element switch { case-operation*, expression }
-case-operation = element case { expression, expression }
-# ***********************************************************
-
-# V.2.6. Built-ins
-
-# ***********************************************************
-exponential = element exponential { expression, expression }
-GLM = element GLM { expression, expression, expression, expression }
-Weibull =
- element Weibull { expression, expression, expression, expression }
-periodic-test =
- element periodic-test {
- expression, expression, expression, expression
- }
- | element periodic-test {
- expression, expression, expression, expression, expression
- }
- | element periodic-test {
- expression,
- expression,
- expression,
- expression,
- expression,
- expression,
- expression,
- expression,
- expression,
- expression,
- expression
- }
-extern-function = element extern-function { name, expression* }
-# ***********************************************************
-
-# V.2.7. Random-Deviates
-
-# ***********************************************************
-uniform-deviate = element uniform-deviate { expression, expression }
-normal-deviate = element normal-deviate { expression, expression }
-lognormal-deviate =
- element lognormal-deviate { expression, expression, expression }
-gamma-deviate = element gamma-deviate { expression, expression }
-beta-deviate = element beta-deviate { expression, expression }
-histogram = element histogram { bin+ }
-bin = element bin { expression, expression }
-# ***********************************************************
-
-# V.2.8. Test-Events
-
-# ***********************************************************
-test-initiating-event = element test-initiating-event { name }
-test-functional-event =
- element test-functional-event {
- name,
- attribute state { xsd:string }
- }
diff --git a/share/open-psa/mef.rng b/share/open-psa/mef.rng
deleted file mode 100644
index c67a6cb..0000000
--- a/share/open-psa/mef.rng
+++ /dev/null
@@ -1,1341 +0,0 @@
-<grammar xmlns="http://relaxng.org/ns/structure/1.0"
- datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes">
-
-<!-- ############################################################### -->
-<!-- I. Calculation Layer -->
-<!-- ############################################################### -->
-
- <!-- ============================================================= -->
- <!-- I.1. Models -->
- <!-- ============================================================= -->
-
- <start>
- <element name="opsa-mef">
- <optional>
- <ref name="name"/>
- </optional>
- <optional>
- <ref name="label"/>
- </optional>
- <optional>
- <ref name="attributes"/>
- </optional>
- <zeroOrMore>
- <choice>
- <ref name="event-tree-definition"/>
- <ref name="alignment-definition"/>
- <ref name="consequence-group-definition"/>
- <ref name="consequence-definition"/>
- <ref name="rule-definition"/>
- <ref name="initiating-event-group-definition"/>
- <ref name="initiating-event-definition"/>
- <ref name="fault-tree-definition"/>
- <ref name="substitution-definition"/>
- <ref name="CCF-group-definition"/>
- <ref name="include-directive"/>
- </choice>
- </zeroOrMore>
- <optional>
- <element name="model-data">
- <zeroOrMore>
- <choice>
- <ref name="house-event-definition"/>
- <ref name="basic-event-definition"/>
- <ref name="parameter-definition"/>
- <ref name="include-directive"/>
- </choice>
- </zeroOrMore>
- </element>
- </optional>
- </element>
- </start>
-
- <define name="Identifier">
- <data type="NCName">
- <param name="pattern">[^\-.]+(-[^\-.]+)*</param>
- </data>
- </define>
-
- <define name="name">
- <attribute name="name"> <ref name="Identifier"/> </attribute>
- </define>
-
- <define name="reference">
- <attribute name="name">
- <data type="NCName">
- <param name="pattern">([^\-.]+(-[^\-.]+)*)(\.\i[^\-.]*(-[^\-.]+)*)*</param>
- </data>
- </attribute>
- </define>
-
- <define name="label">
- <element name="label"> <text/> </element>
- </define>
-
- <define name="attributes">
- <element name="attributes">
- <zeroOrMore>
- <element name="attribute">
- <ref name="name"/>
- <attribute name="value"> <data type="string"/> </attribute>
- <optional>
- <attribute name="type"> <data type="string"/> </attribute>
- </optional>
- </element>
- </zeroOrMore>
- </element>
- </define>
-
- <define name="include-directive">
- <element name="include">
- <attribute name="file"> <data type="string"/> </attribute>
- </element>
- </define>
-
-
- <!-- ============================================================= -->
- <!-- I.2. Consequences, Consequence Groups -->
- <!-- ============================================================= -->
-
- <define name="consequence-definition">
- <element name="define-consequence">
- <ref name="name"/>
- <optional>
- <ref name="label"/>
- </optional>
- <optional>
- <ref name="attributes"/>
- </optional>
- <element name="initiating-event">
- <ref name="name"/>
- </element>
- <element name="sequence">
- <ref name="name"/>
- </element>
- </element>
- </define>
-
- <define name="consequence-group-definition">
- <element name="define-consequence-group">
- <ref name="name"/>
- <optional>
- <ref name="label"/>
- </optional>
- <optional>
- <ref name="attributes"/>
- </optional>
- <choice>
- <ref name="consequence"/>
- <ref name="consequence-group"/>
- </choice>
- </element>
- </define>
-
- <define name="consequence">
- <element name="consequence">
- <ref name="name"/>
- </element>
- </define>
-
- <define name="consequence-group">
- <element name="consequence-group">
- <ref name="name"/>
- </element>
- </define>
-
- <!-- ============================================================= -->
- <!-- I.3. Missions, Phases -->
- <!-- ============================================================= -->
-
- <define name="alignment-definition">
- <element name="define-alignment">
- <ref name="name"/>
- <optional>
- <ref name="label"/>
- </optional>
- <optional>
- <ref name="attributes"/>
- </optional>
- <oneOrMore>
- <ref name="phase-definition"/>
- </oneOrMore>
- </element>
- </define>
-
- <define name="phase-definition">
- <element name="define-phase">
- <ref name="name"/>
- <attribute name="time-fraction"> <data type="double"/> </attribute>
- <optional>
- <ref name="label"/>
- </optional>
- <optional>
- <ref name="attributes"/>
- </optional>
- <zeroOrMore>
- <ref name="instruction"/>
- </zeroOrMore>
- </element>
- </define>
-
-
-<!-- ############################################################### -->
-<!-- II. Event Tree Layer -->
-<!-- ############################################################### -->
-
- <!-- ============================================================= -->
- <!-- II.1. Initiating events, Initiating event Groups -->
- <!-- ============================================================= -->
-
- <define name="initiating-event-definition">
- <element name="define-initiating-event">
- <ref name="name"/>
- <optional>
- <attribute name="event-tree"> <ref name="Identifier"/> </attribute>
- </optional>
- <optional>
- <ref name="label"/>
- </optional>
- <optional>
- <ref name="attributes"/>
- </optional>
- <optional>
- <choice>
- <ref name="collected-item"/>
- <ref name="consequence"/>
- <ref name="consequence-group"/>
- </choice>
- </optional>
- </element>
- </define>
-
- <define name="initiating-event-group-definition">
- <element name="define-initiating-event-group">
- <ref name="name"/>
- <optional>
- <attribute name="event-tree"> <ref name="Identifier"/> </attribute>
- </optional>
- <optional>
- <ref name="label"/>
- </optional>
- <optional>
- <ref name="attributes"/>
- </optional>
- <oneOrMore>
- <ref name="initiating-event"/>
- </oneOrMore>
- </element>
- </define>
-
- <define name="initiating-event">
- <choice>
- <element name="initiating-event">
- <ref name="name"/>
- </element>
- <element name="initiating-event-group">
- <ref name="name"/>
- </element>
- </choice>
- </define>
-
- <define name="collected-item">
- <choice>
- <ref name="basic-event"/>
- <ref name="gate"/>
- <ref name="parameter"/>
- </choice>
- </define>
-
-
- <!-- ============================================================= -->
- <!-- II.2. Event Trees -->
- <!-- ============================================================= -->
-
- <define name="event-tree-definition">
- <element name="define-event-tree">
- <ref name="name"/>
- <optional>
- <ref name="label"/>
- </optional>
- <optional>
- <ref name="attributes"/>
- </optional>
- <zeroOrMore>
- <ref name="functional-event-definition"/>
- </zeroOrMore>
- <zeroOrMore>
- <ref name="sequence-definition"/>
- </zeroOrMore>
- <zeroOrMore>
- <ref name="branch-definition"/>
- </zeroOrMore>
- <ref name="initial-state"/>
- </element>
- </define>
-
- <define name="functional-event-definition">
- <element name="define-functional-event">
- <ref name="name"/>
- <optional>
- <ref name="label"/>
- </optional>
- <optional>
- <ref name="attributes"/>
- </optional>
- </element>
- </define>
-
- <define name="sequence-definition">
- <element name="define-sequence">
- <ref name="name"/>
- <optional>
- <ref name="label"/>
- </optional>
- <optional>
- <ref name="attributes"/>
- </optional>
- <oneOrMore>
- <ref name="instruction"/>
- </oneOrMore>
- </element>
- </define>
-
- <define name="branch-definition">
- <element name="define-branch">
- <ref name="name"/>
- <optional>
- <ref name="label"/>
- </optional>
- <optional>
- <ref name="attributes"/>
- </optional>
- <ref name="branch"/>
- </element>
- </define>
-
- <define name="initial-state">
- <element name="initial-state">
- <ref name="branch"/>
- </element>
- </define>
-
- <define name="branch">
- <zeroOrMore>
- <ref name="instruction"/>
- </zeroOrMore>
- <choice>
- <ref name="fork"/>
- <ref name="end-state"/>
- </choice>
- </define>
-
- <define name="fork">
- <element name="fork">
- <attribute name="functional-event"> <ref name="Identifier"/> </attribute>
- <oneOrMore>
- <ref name="path"/>
- </oneOrMore>
- </element>
- </define>
-
- <define name="path">
- <element name="path">
- <attribute name="state"> <ref name="Identifier"/> </attribute>
- <ref name="branch"/>
- </element>
- </define>
-
- <define name="end-state">
- <choice>
- <element name="sequence">
- <ref name="name"/>
- </element>
- <element name="branch">
- <ref name="name"/>
- </element>
- </choice>
- </define>
-
- <!-- ============================================================= -->
- <!-- II.3. Instructions, Rules -->
- <!-- ============================================================= -->
-
- <define name="instruction">
- <choice>
- <ref name="set"/>
- <ref name="collect"/>
- <ref name="if-then-else"/>
- <ref name="block"/>
- <ref name="rule"/>
- <ref name="link"/>
- </choice>
- </define>
-
- <define name="set">
- <choice>
- <ref name="set-gate"/>
- <ref name="set-house-event"/>
- <ref name="set-basic-event"/>
- <ref name="set-parameter"/>
- </choice>
- </define>
-
- <define name="set-gate">
- <element name="set-gate">
- <ref name="name"/>
- <optional>
- <attribute name="direction">
- <ref name="direction"/>
- </attribute>
- </optional>
- <ref name="formula"/>
- </element>
- </define>
-
- <define name="set-house-event">
- <element name="set-house-event">
- <ref name="name"/>
- <optional>
- <attribute name="direction">
- <ref name="direction"/>
- </attribute>
- </optional>
- <ref name="Boolean-constant"/>
- </element>
- </define>
-
- <define name="set-basic-event">
- <element name="set-basic-event">
- <ref name="name"/>
- <optional>
- <attribute name="direction">
- <ref name="direction"/>
- </attribute>
- </optional>
- <ref name="expression"/>
- </element>
- </define>
-
- <define name="set-parameter">
- <element name="set-parameter">
- <ref name="name"/>
- <optional>
- <attribute name="direction">
- <ref name="direction"/>
- </attribute>
- </optional>
- <ref name="expression"/>
- </element>
- </define>
-
- <define name="direction">
- <choice>
- <value>forward</value>
- <value>backward</value>
- <value>both</value>
- </choice>
- </define>
-
- <define name="if-then-else">
- <element name="if">
- <ref name="expression"/>
- <ref name="instruction"/>
- <optional>
- <ref name="instruction"/>
- </optional>
- </element>
- </define>
-
- <define name="collect">
- <choice>
- <ref name="collect-formula"/>
- <ref name="collect-expression"/>
- </choice>
- </define>
-
- <define name="collect-formula">
- <element name="collect-formula">
- <ref name="formula"/>
- </element>
- </define>
-
- <define name="collect-expression">
- <element name="collect-expression">
- <ref name="expression"/>
- </element>
- </define>
-
- <define name="block">
- <element name="block">
- <zeroOrMore>
- <ref name="instruction"/>
- </zeroOrMore>
- </element>
- </define>
-
- <define name="rule">
- <element name="rule">
- <ref name="name"/>
- </element>
- </define>
-
- <define name="link">
- <element name="event-tree">
- <ref name="name"/>
- </element>
- </define>
-
- <define name="rule-definition">
- <element name="define-rule">
- <ref name="name"/>
- <optional>
- <ref name="label"/>
- </optional>
- <optional>
- <ref name="attributes"/>
- </optional>
- <oneOrMore>
- <ref name="instruction"/>
- </oneOrMore>
- </element>
- </define>
-
-
-<!-- ############################################################### -->
-<!-- III. Meta-Logical Layer -->
-<!-- ############################################################### -->
-
- <!-- ============================================================= -->
- <!-- III.1. CCF-Groups -->
- <!-- ============================================================= -->
-
- <define name="CCF-group-definition">
- <element name="define-CCF-group">
- <ref name="name"/>
- <attribute name="model">
- <ref name="CCF-model"/>
- </attribute>
- <optional>
- <ref name="label"/>
- </optional>
- <optional>
- <ref name="attributes"/>
- </optional>
- <ref name="members"/>
- <ref name="distribution"/>
- <ref name="factors"/>
- </element>
- </define>
-
- <define name="members">
- <element name="members">
- <oneOrMore>
- <ref name="basic-event"/>
- </oneOrMore>
- </element>
- </define>
-
- <define name="factors">
- <choice>
- <element name="factors">
- <oneOrMore>
- <ref name="factor"/>
- </oneOrMore>
- </element>
- <ref name="factor"/>
- </choice>
- </define>
-
- <define name="factor">
- <element name="factor">
- <optional>
- <attribute name="level"> <data type="nonNegativeInteger"/> </attribute>
- </optional>
- <ref name="expression"/>
- </element>
- </define>
-
- <define name="distribution">
- <element name="distribution">
- <ref name="expression"/>
- </element>
- </define>
-
- <define name="CCF-model">
- <choice>
- <value>beta-factor</value>
- <value>MGL</value>
- <value>alpha-factor</value>
- <value>phi-factor</value>
- </choice>
- </define>
-
- <!-- ============================================================= -->
- <!-- III.2. Substitutions -->
- <!-- ============================================================= -->
-
- <define name="substitution-definition">
- <element name="define-substitution">
- <optional>
- <ref name="name"/>
- </optional>
- <optional>
- <attribute name="type"> <data type="string"/> </attribute>
- </optional>
- <optional>
- <ref name="label"/>
- </optional>
- <optional>
- <ref name="attributes"/>
- </optional>
- <element name="hypothesis">
- <ref name="formula"/>
- </element>
- <optional>
- <element name="source">
- <oneOrMore>
- <ref name="basic-event"/>
- </oneOrMore>
- </element>
- </optional>
- <element name="target">
- <choice>
- <oneOrMore>
- <ref name="basic-event"/>
- </oneOrMore>
- <ref name="Boolean-constant"/>
- </choice>
- </element>
- </element>
- </define>
-
-
-<!-- ############################################################### -->
-<!-- IV. Fault Tree Layer -->
-<!-- ############################################################### -->
-
- <!-- ============================================================= -->
- <!-- IV.1. Definitions of Fault Trees & Components -->
- <!-- ============================================================= -->
-
- <define name="fault-tree-definition">
- <element name="define-fault-tree">
- <ref name="name"/>
- <optional>
- <ref name="label"/>
- </optional>
- <optional>
- <ref name="attributes"/>
- </optional>
- <zeroOrMore>
- <choice>
- <ref name="substitution-definition"/>
- <ref name="CCF-group-definition"/>
- <ref name="event-definition"/>
- <ref name="component-definition"/>
- <ref name="parameter-definition"/>
- <ref name="include-directive"/>
- </choice>
- </zeroOrMore>
- </element>
- </define>
-
- <define name="component-definition">
- <element name="define-component">
- <ref name="name"/>
- <optional>
- <ref name="role"/>
- </optional>
- <optional>
- <ref name="label"/>
- </optional>
- <optional>
- <ref name="attributes"/>
- </optional>
- <zeroOrMore>
- <choice>
- <ref name="substitution-definition"/>
- <ref name="CCF-group-definition"/>
- <ref name="event-definition"/>
- <ref name="component-definition"/>
- <ref name="parameter-definition"/>
- <ref name="include-directive"/>
- </choice>
- </zeroOrMore>
- </element>
- </define>
-
- <define name="role">
- <attribute name="role">
- <choice>
- <value>private</value>
- <value>public</value>
- </choice>
- </attribute>
- </define>
-
- <define name="event-definition">
- <choice>
- <ref name="gate-definition"/>
- <ref name="house-event-definition"/>
- <ref name="basic-event-definition"/>
- </choice>
- </define>
-
- <!-- ============================================================= -->
- <!-- IV.2. Definitions of Gates, House Events & Basic Events -->
- <!-- ============================================================= -->
-
- <define name="gate-definition">
- <element name="define-gate">
- <ref name="name"/>
- <optional>
- <ref name="role"/>
- </optional>
- <optional>
- <ref name="label"/>
- </optional>
- <optional>
- <ref name="attributes"/>
- </optional>
- <ref name="formula"/>
- </element>
- </define>
-
- <define name="house-event-definition">
- <element name="define-house-event">
- <ref name="name"/>
- <optional>
- <ref name="role"/>
- </optional>
- <optional>
- <ref name="label"/>
- </optional>
- <optional>
- <ref name="attributes"/>
- </optional>
- <optional>
- <ref name="Boolean-constant"/>
- </optional>
- </element>
- </define>
-
- <define name="basic-event-definition">
- <element name="define-basic-event">
- <ref name="name"/>
- <optional>
- <ref name="role"/>
- </optional>
- <optional>
- <ref name="label"/>
- </optional>
- <optional>
- <ref name="attributes"/>
- </optional>
- <optional>
- <ref name="expression"/>
- </optional>
- </element>
- </define>
-
-
- <!-- ============================================================= -->
- <!-- IV.3. Formulae -->
- <!-- ============================================================= -->
-
- <define name="formula">
- <choice>
- <ref name="event"/>
- <ref name="Boolean-constant"/>
- <element name="and">
- <oneOrMore>
- <ref name="formula"/>
- </oneOrMore>
- </element>
- <element name="or">
- <oneOrMore>
- <ref name="formula"/>
- </oneOrMore>
- </element>
- <element name="not">
- <ref name="formula"/>
- </element>
- <element name="xor">
- <oneOrMore>
- <ref name="formula"/>
- </oneOrMore>
- </element>
- <element name="iff">
- <oneOrMore>
- <ref name="formula"/>
- </oneOrMore>
- </element>
- <element name="nand">
- <oneOrMore>
- <ref name="formula"/>
- </oneOrMore>
- </element>
- <element name="nor">
- <oneOrMore>
- <ref name="formula"/>
- </oneOrMore>
- </element>
- <element name="atleast">
- <attribute name="min"> <data type="nonNegativeInteger"/> </attribute>
- <oneOrMore>
- <ref name="formula"/>
- </oneOrMore>
- </element>
- <element name="cardinality">
- <attribute name="min"> <data type="nonNegativeInteger"/> </attribute>
- <attribute name="max"> <data type="nonNegativeInteger"/> </attribute>
- <oneOrMore>
- <ref name="formula"/>
- </oneOrMore>
- </element>
- <element name="imply">
- <ref name="formula"/>
- <ref name="formula"/>
- </element>
- </choice>
- </define>
-
- <define name="event">
- <choice>
- <element name="event">
- <ref name="reference"/>
- <optional>
- <attribute name="type">
- <ref name="event-type"/>
- </attribute>
- </optional>
- </element>
- <ref name="gate"/>
- <ref name="house-event"/>
- <ref name="basic-event"/>
- </choice>
- </define>
-
- <define name="event-type">
- <choice>
- <value>gate</value>
- <value>basic-event</value>
- <value>house-event</value>
- </choice>
- </define>
-
- <define name="gate">
- <element name="gate">
- <ref name="reference"/>
- </element>
- </define>
-
- <define name="house-event">
- <element name="house-event">
- <ref name="reference"/>
- </element>
- </define>
-
- <define name="basic-event">
- <element name="basic-event">
- <ref name="reference"/>
- </element>
- </define>
-
- <define name="Boolean-constant">
- <element name="constant">
- <attribute name="value">
- <ref name="Boolean-value"/>
- </attribute>
- </element>
- </define>
-
- <define name="Boolean-value">
- <choice>
- <value>true</value>
- <value>false</value>
- </choice>
- </define>
-
-
-<!-- ############################################################### -->
-<!-- V. Stochastic Layer -->
-<!-- ############################################################### -->
-
- <!-- ============================================================= -->
- <!-- V.1. Definition of Parameters -->
- <!-- ============================================================= -->
-
- <define name="parameter-definition">
- <element name="define-parameter">
- <ref name="name"/>
- <optional>
- <ref name="role"/>
- </optional>
- <optional>
- <attribute name="unit">
- <ref name="units"/>
- </attribute>
- </optional>
- <optional>
- <ref name="label"/>
- </optional>
- <optional>
- <ref name="attributes"/>
- </optional>
- <ref name="expression"/>
- </element>
- </define>
-
- <define name="units">
- <choice>
- <value>bool</value>
- <value>int</value>
- <value>float</value>
- <value>hours</value>
- <value>hours-1</value>
- <value>years</value>
- <value>years-1</value>
- <value>fit</value>
- <value>demands</value>
- </choice>
- </define>
-
- <!-- ============================================================= -->
- <!-- V.2. Expressions -->
- <!-- ============================================================= -->
-
- <!-- *********************************************************** -->
- <!-- V.2.1. Entities -->
- <!-- *********************************************************** -->
-
- <define name="expression">
- <choice>
- <ref name="constant"/>
- <ref name="parameter"/>
- <ref name="operation"/>
- <ref name="built-in"/>
- <ref name="random-deviate"/>
- <ref name="test-event"/>
- </choice>
- </define>
-
- <define name="constant">
- <choice>
- <ref name="bool"/>
- <ref name="int"/>
- <ref name="float"/>
- </choice>
- </define>
-
- <define name="parameter">
- <choice>
- <element name="parameter">
- <ref name="reference"/>
- <optional>
- <attribute name="unit">
- <ref name="units"/>
- </attribute>
- </optional>
- </element>
- <element name="system-mission-time">
- <optional>
- <attribute name="unit">
- <ref name="units"/>
- </attribute>
- </optional>
- </element>
- </choice>
- </define>
-
- <define name="operation">
- <choice>
- <ref name="numerical-operation"/>
- <ref name="Boolean-operation"/>
- <ref name="conditional-operation"/>
- </choice>
- </define>
-
- <define name="built-in">
- <choice>
- <ref name="exponential"/>
- <ref name="GLM"/>
- <ref name="Weibull"/>
- <ref name="periodic-test"/>
- <ref name="extern-function"/>
- </choice>
- </define>
-
- <define name="random-deviate">
- <choice>
- <ref name="uniform-deviate"/>
- <ref name="normal-deviate"/>
- <ref name="lognormal-deviate"/>
- <ref name="gamma-deviate"/>
- <ref name="beta-deviate"/>
- <ref name="histogram"/>
- </choice>
- </define>
-
- <define name="test-event">
- <choice>
- <ref name="test-initiating-event"/>
- <ref name="test-functional-event"/>
- </choice>
- </define>
-
- <!-- *********************************************************** -->
- <!-- V.2.2. Constants, Parameters -->
- <!-- *********************************************************** -->
-
- <define name="bool">
- <element name="bool">
- <attribute name="value">
- <ref name="Boolean-value"/>
- </attribute>
- </element>
- </define>
-
- <define name="int">
- <element name="int">
- <attribute name="value">
- <data type="integer"/>
- </attribute>
- </element>
- </define>
-
- <define name="float">
- <element name="float">
- <attribute name="value">
- <data type="double"/>
- </attribute>
- </element>
- </define>
-
- <!-- *********************************************************** -->
- <!-- V.2.3. Numerical Expressions -->
- <!-- *********************************************************** -->
-
- <define name="numerical-operation">
- <choice>
- <element name="neg">
- <ref name="expression"/>
- </element>
- <element name="add">
- <oneOrMore>
- <ref name="expression"/>
- </oneOrMore>
- </element>
- <element name="sub">
- <oneOrMore>
- <ref name="expression"/>
- </oneOrMore>
- </element>
- <element name="mul">
- <oneOrMore>
- <ref name="expression"/>
- </oneOrMore>
- </element>
- <element name="div">
- <oneOrMore>
- <ref name="expression"/>
- </oneOrMore>
- </element>
- <element name="pi"> <empty/> </element>
- <element name="abs">
- <ref name="expression"/>
- </element>
- <element name="acos">
- <ref name="expression"/>
- </element>
- <element name="asin">
- <ref name="expression"/>
- </element>
- <element name="atan">
- <ref name="expression"/>
- </element>
- <element name="cos">
- <ref name="expression"/>
- </element>
- <element name="cosh">
- <ref name="expression"/>
- </element>
- <element name="exp">
- <ref name="expression"/>
- </element>
- <element name="log">
- <ref name="expression"/>
- </element>
- <element name="log10">
- <ref name="expression"/>
- </element>
- <element name="mod">
- <ref name="expression"/>
- <ref name="expression"/>
- </element>
- <element name="pow">
- <ref name="expression"/>
- <ref name="expression"/>
- </element>
- <element name="sin">
- <ref name="expression"/>
- </element>
- <element name="sinh">
- <ref name="expression"/>
- </element>
- <element name="tan">
- <ref name="expression"/>
- </element>
- <element name="tanh">
- <ref name="expression"/>
- </element>
- <element name="sqrt">
- <ref name="expression"/>
- </element>
- <element name="ceil">
- <ref name="expression"/>
- </element>
- <element name="floor">
- <ref name="expression"/>
- </element>
- <element name="min">
- <oneOrMore>
- <ref name="expression"/>
- </oneOrMore>
- </element>
- <element name="max">
- <oneOrMore>
- <ref name="expression"/>
- </oneOrMore>
- </element>
- <element name="mean">
- <oneOrMore>
- <ref name="expression"/>
- </oneOrMore>
- </element>
- </choice>
- </define>
-
- <!-- *********************************************************** -->
- <!-- V.2.4. Boolean Expressions -->
- <!-- *********************************************************** -->
-
- <define name="Boolean-operation">
- <choice>
- <element name="not">
- <ref name="expression"/>
- </element>
- <element name="and">
- <oneOrMore>
- <ref name="expression"/>
- </oneOrMore>
- </element>
- <element name="or">
- <oneOrMore>
- <ref name="expression"/>
- </oneOrMore>
- </element>
- <element name="eq">
- <ref name="expression"/>
- <ref name="expression"/>
- </element>
- <element name="df">
- <ref name="expression"/>
- <ref name="expression"/>
- </element>
- <element name="lt">
- <ref name="expression"/>
- <ref name="expression"/>
- </element>
- <element name="gt">
- <ref name="expression"/>
- <ref name="expression"/>
- </element>
- <element name="leq">
- <ref name="expression"/>
- <ref name="expression"/>
- </element>
- <element name="geq">
- <ref name="expression"/>
- <ref name="expression"/>
- </element>
- </choice>
- </define>
-
- <!-- *********************************************************** -->
- <!-- V.2.5. Conditional Expressions -->
- <!-- *********************************************************** -->
-
- <define name="conditional-operation">
- <choice>
- <ref name="if-then-else-operation"/>
- <ref name="switch-operation"/>
- </choice>
- </define>
-
- <define name="if-then-else-operation">
- <element name="ite">
- <ref name="expression"/>
- <ref name="expression"/>
- <ref name="expression"/>
- </element>
- </define>
-
- <define name="switch-operation">
- <element name="switch">
- <zeroOrMore>
- <ref name="case-operation"/>
- </zeroOrMore>
- <ref name="expression"/>
- </element>
- </define>
-
- <define name="case-operation">
- <element name="case">
- <ref name="expression"/>
- <ref name="expression"/>
- </element>
- </define>
-
- <!-- *********************************************************** -->
- <!-- V.2.6. Built-ins -->
- <!-- *********************************************************** -->
-
- <define name="exponential">
- <element name="exponential">
- <ref name="expression"/>
- <ref name="expression"/>
- </element>
- </define>
-
- <define name="GLM">
- <element name="GLM">
- <ref name="expression"/>
- <ref name="expression"/>
- <ref name="expression"/>
- <ref name="expression"/>
- </element>
- </define>
-
- <define name="Weibull">
- <element name="Weibull">
- <ref name="expression"/>
- <ref name="expression"/>
- <ref name="expression"/>
- <ref name="expression"/>
- </element>
- </define>
-
- <define name="periodic-test">
- <choice>
- <element name="periodic-test">
- <ref name="expression"/>
- <ref name="expression"/>
- <ref name="expression"/>
- <ref name="expression"/>
- </element>
- <element name="periodic-test">
- <ref name="expression"/>
- <ref name="expression"/>
- <ref name="expression"/>
- <ref name="expression"/>
- <ref name="expression"/>
- </element>
- <element name="periodic-test">
- <ref name="expression"/>
- <ref name="expression"/>
- <ref name="expression"/>
- <ref name="expression"/>
- <ref name="expression"/>
- <ref name="expression"/>
- <ref name="expression"/>
- <ref name="expression"/>
- <ref name="expression"/>
- <ref name="expression"/>
- <ref name="expression"/>
- </element>
- </choice>
- </define>
-
- <define name="extern-function">
- <element name="extern-function">
- <ref name="name"/>
- <zeroOrMore>
- <ref name="expression"/>
- </zeroOrMore>
- </element>
- </define>
-
- <!-- *********************************************************** -->
- <!-- V.2.7. Random-Deviates -->
- <!-- *********************************************************** -->
-
- <define name="uniform-deviate">
- <element name="uniform-deviate">
- <ref name="expression"/>
- <ref name="expression"/>
- </element>
- </define>
-
- <define name="normal-deviate">
- <element name="normal-deviate">
- <ref name="expression"/>
- <ref name="expression"/>
- </element>
- </define>
-
- <define name="lognormal-deviate">
- <element name="lognormal-deviate">
- <ref name="expression"/>
- <ref name="expression"/>
- <ref name="expression"/>
- </element>
- </define>
-
- <define name="gamma-deviate">
- <element name="gamma-deviate">
- <ref name="expression"/>
- <ref name="expression"/>
- </element>
- </define>
-
- <define name="beta-deviate">
- <element name="beta-deviate">
- <ref name="expression"/>
- <ref name="expression"/>
- </element>
- </define>
-
- <define name="histogram">
- <element name="histogram">
- <oneOrMore>
- <ref name="bin"/>
- </oneOrMore>
- </element>
- </define>
-
- <define name="bin">
- <element name="bin">
- <ref name="expression"/>
- <ref name="expression"/>
- </element>
- </define>
-
- <!-- *********************************************************** -->
- <!-- V.2.8. Test-Events -->
- <!-- *********************************************************** -->
-
- <define name="test-initiating-event">
- <element name="test-initiating-event">
- <ref name="name"/>
- </element>
- </define>
-
- <define name="test-functional-event">
- <element name="test-functional-event">
- <ref name="name"/>
- <attribute name="state"> <data type="string"/> </attribute>
- </element>
- </define>
-
-</grammar>
diff --git a/share/open-psa/stat_measures.bnf b/share/open-psa/stat_measures.bnf
deleted file mode 100644
index 90a79ed..0000000
--- a/share/open-psa/stat_measures.bnf
+++ /dev/null
@@ -1,26 +0,0 @@
-measure ::=
- <measure
- [ name="identifier" ]
- [ description="text" ]
- >
- [ <mean value="float" > ]
- [ <standard-deviation value="float" > ]
- [ <confidence-range
- percentage="float"
- lower-bound="float"
- upper-bound="float" > ]
- [ <error-factor percentage="float" value="float" > ]
- [ quantiles ]
- </measure>
-
-quantiles ::=
- <quantiles number="integer" >
- quantile+
- </quantiles>
-
-quantile ::=
- <quantile number="integer"
- [ mean="float" ]
- [ lower-bound="float" ]
- [ upper-bound="float" ]
- />
diff --git a/share/report_layer.rng b/share/report_layer.rng
index f8fdedf..51c7e11 100644
--- a/share/report_layer.rng
+++ b/share/report_layer.rng
@@ -12,6 +12,13 @@
</element>
</start>
+ <define name="probability-data"> <!-- [0.0, 1.0] values for probability -->
+ <data type="double">
+ <param name="minInclusive">0</param>
+ <param name="maxInclusive">1</param>
+ </data>
+ </define>
+
<!-- ############################################################### -->
<!-- I. Information Layer -->
<!-- ############################################################### -->
@@ -20,7 +27,7 @@
<element name="information">
<optional>
<element name="software">
- <attribute name="name"> <data type="NCName"/> </attribute>
+ <attribute name="name"> <data type="string"/> </attribute>
<attribute name="version"> <data type="string"/> </attribute>
<optional>
<attribute name="contacts"> <text/> </attribute>
@@ -28,7 +35,7 @@
</element>
</optional>
<optional>
- <element name="time"> <text/> </element>
+ <element name="time"> <data type="string"/> </element>
</optional>
<optional>
<element name="performance">
@@ -85,7 +92,7 @@
</element>
</optional>
<optional>
- <element name="cut-off"> <data type="double"/> </element>
+ <element name="cut-off"> <ref name="probability-data"/> </element>
</optional>
<optional>
<element name="number-of-sums">
@@ -211,7 +218,7 @@
</attribute>
</optional>
<optional>
- <attribute name="probability"> <data type="double"/> </attribute>
+ <attribute name="probability"> <ref name="probability-data"/> </attribute>
</optional>
<optional>
<element name="warning"> <text/> </element>
@@ -230,10 +237,10 @@
</attribute>
</optional>
<optional>
- <attribute name="probability"> <data type="double"/> </attribute>
+ <attribute name="probability"> <ref name="probability-data"/> </attribute>
</optional>
<optional>
- <attribute name="contribution"> <data type="double"/> </attribute>
+ <attribute name="contribution"> <ref name="probability-data"/> </attribute>
</optional>
<zeroOrMore>
<ref name="literal"/>
@@ -287,25 +294,39 @@
</optional>
<optional>
<element name="mean">
- <attribute name="value"> <data type="double"/> </attribute>
+ <attribute name="value"> <ref name="probability-data"/> </attribute>
</element>
</optional>
<optional>
<element name="standard-deviation">
- <attribute name="value"> <data type="double"/> </attribute>
+ <attribute name="value"> <ref name="probability-data"/> </attribute>
</element>
</optional>
<optional>
<element name="confidence-range">
- <attribute name="percentage"> <data type="double"/> </attribute>
- <attribute name="lower-bound"> <data type="double"/> </attribute>
- <attribute name="upper-bound"> <data type="double"/> </attribute>
+ <attribute name="percentage">
+ <data type="double">
+ <param name="minExclusive">0</param>
+ <param name="maxExclusive">100</param>
+ </data>
+ </attribute>
+ <attribute name="lower-bound"> <ref name="probability-data"/> </attribute>
+ <attribute name="upper-bound"> <ref name="probability-data"/> </attribute>
</element>
</optional>
<optional>
<element name="error-factor">
- <attribute name="percentage"> <data type="double"/> </attribute>
- <attribute name="value"> <data type="double"/> </attribute>
+ <attribute name="percentage">
+ <data type="double">
+ <param name="minExclusive">0</param>
+ <param name="maxExclusive">100</param>
+ </data>
+ </attribute>
+ <attribute name="value">
+ <data type="double">
+ <param name="minExclusive">0</param>
+ </data>
+ </attribute>
</element>
</optional>
<optional>
@@ -328,16 +349,7 @@
<define name="quantile">
<element name="quantile">
- <attribute name="number"> <data type="nonNegativeInteger"/> </attribute>
- <optional>
- <attribute name="value"> <data type="double"/> </attribute>
- </optional>
- <optional>
- <attribute name="lower-bound"> <data type="double"/> </attribute>
- </optional>
- <optional>
- <attribute name="upper-bound"> <data type="double"/> </attribute>
- </optional>
+ <ref name="bin-data"/>
</element>
</define>
@@ -352,19 +364,23 @@
<define name="bin">
<element name="bin">
- <attribute name="number"> <data type="nonNegativeInteger"/> </attribute>
- <optional>
- <attribute name="value"> <data type="double"/> </attribute>
- </optional>
- <optional>
- <attribute name="lower-bound"> <data type="double"/> </attribute>
- </optional>
- <optional>
- <attribute name="upper-bound"> <data type="double"/> </attribute>
- </optional>
+ <ref name="bin-data"/>
</element>
</define>
+ <define name="bin-data">
+ <attribute name="number"> <data type="nonNegativeInteger"/> </attribute>
+ <optional>
+ <attribute name="value"> <data type="double"/> </attribute>
+ </optional>
+ <optional>
+ <attribute name="lower-bound"> <data type="double"/> </attribute>
+ </optional>
+ <optional>
+ <attribute name="upper-bound"> <data type="double"/> </attribute>
+ </optional>
+ </define>
+
<!-- ============================================================= -->
<!-- II.3. Curves -->
<!-- ============================================================= -->
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 5c6000c..0b3f6bd 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -34,6 +34,11 @@ set(SCRAM_CORE_SRC
"${CMAKE_CURRENT_SOURCE_DIR}/cycle.cc"
"${CMAKE_CURRENT_SOURCE_DIR}/element.cc"
"${CMAKE_CURRENT_SOURCE_DIR}/expression.cc"
+ "${CMAKE_CURRENT_SOURCE_DIR}/parameter.cc"
+ "${CMAKE_CURRENT_SOURCE_DIR}/expression/constant.cc"
+ "${CMAKE_CURRENT_SOURCE_DIR}/expression/arithmetic.cc"
+ "${CMAKE_CURRENT_SOURCE_DIR}/expression/exponential.cc"
+ "${CMAKE_CURRENT_SOURCE_DIR}/expression/random_deviate.cc"
"${CMAKE_CURRENT_SOURCE_DIR}/event.cc"
"${CMAKE_CURRENT_SOURCE_DIR}/ccf_group.cc"
"${CMAKE_CURRENT_SOURCE_DIR}/fault_tree.cc"
@@ -54,30 +59,31 @@ set(SCRAM_CORE_SRC
)
add_library(scramcore ${SCRAM_CORE_SRC})
-set_target_properties(scramcore
- PROPERTIES
- INSTALL_NAME_DIR "${CMAKE_INSTALL_PREFIX}/lib"
- INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/lib"
- LINK_FLAGS "${LIB_LINK_FLAGS}"
- )
-
-target_link_libraries(scramcore ${LIBS})
-
-if(WIN32)
- install(
- TARGETS scramcore
- RUNTIME DESTINATION bin COMPONENT scram
- LIBRARY DESTINATION lib COMPONENT scram
- ARCHIVE DESTINATION lib COMPONENT scram
- )
-else()
- install(
- TARGETS scramcore
- DESTINATION lib
- COMPONENT scram
+if(INSTALL_LIBS)
+ set_target_properties(scramcore
+ PROPERTIES
+ INSTALL_NAME_DIR "${CMAKE_INSTALL_PREFIX}/lib"
+ INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/lib"
+ LINK_FLAGS "${LIB_LINK_FLAGS}"
)
+ if(WIN32)
+ install(
+ TARGETS scramcore
+ RUNTIME DESTINATION bin COMPONENT scram
+ LIBRARY DESTINATION lib COMPONENT scram
+ ARCHIVE DESTINATION lib COMPONENT scram
+ )
+ else()
+ install(
+ TARGETS scramcore
+ DESTINATION lib
+ COMPONENT scram
+ )
+ endif()
endif()
+target_link_libraries(scramcore ${LIBS})
+
add_executable(scram scram.cc)
target_link_libraries(scram scramcore ${Boost_LIBRARIES})
diff --git a/src/bdd.cc b/src/bdd.cc
index fffce5e..8a961a9 100644
--- a/src/bdd.cc
+++ b/src/bdd.cc
@@ -23,7 +23,6 @@
#include <boost/multiprecision/miller_rabin.hpp>
#include <boost/range/algorithm.hpp>
-#include "event.h"
#include "ext.h"
#include "logger.h"
#include "zbdd.h"
diff --git a/src/bdd.h b/src/bdd.h
index 33458af..d118d8f 100644
--- a/src/bdd.h
+++ b/src/bdd.h
@@ -40,19 +40,15 @@
namespace scram {
namespace core {
-/// Control flags and pointers for communication
-/// between BDD vertex pointers and BDD tables.
-struct ControlBlock {
- void* vertex; ///< The manager of the control block.
- int weak_count; ///< Pointers in tables.
-};
-
/// The default management of BDD vertices.
///
/// @tparam T The type of the main functional BDD vertex.
template <class T>
using IntrusivePtr = boost::intrusive_ptr<T>;
+template <class T>
+class Vertex; // Manager of its own entry in the unique table.
+
/// A weak pointer to store in BDD unique tables.
/// This weak pointer is unique pointer as well
/// because vertices should not be easily shared among multiple BDDs.
@@ -60,17 +56,20 @@ using IntrusivePtr = boost::intrusive_ptr<T>;
/// @tparam T The type of the main functional BDD vertex.
template <class T>
class WeakIntrusivePtr final : private boost::noncopyable {
+ friend class Vertex<T>; // Communicates the destruction of the vertex.
+
public:
/// Default constructor is to allow initialization in tables.
- WeakIntrusivePtr() noexcept : control_block_(nullptr) {}
+ WeakIntrusivePtr() noexcept : vertex_(nullptr) {}
/// Constructs from the shared pointer.
/// However, there is no weak-to-shared constructor.
///
/// @param[in] ptr Fully initialized intrusive pointer.
explicit WeakIntrusivePtr(const IntrusivePtr<T>& ptr) noexcept
- : control_block_(get_control_block(ptr.get())) {
- control_block_->weak_count++;
+ : vertex_(ptr.get()) {
+ assert(vertex_->table_ptr_ == nullptr && "Non-unique table pointers.");
+ vertex_->table_ptr_ = this;
}
/// Copy assignment from shared pointers
@@ -85,35 +84,25 @@ class WeakIntrusivePtr final : private boost::noncopyable {
return *this;
}
- /// Decrements weak count in the control block.
- /// If this is the last pointer and vertex is gone,
- /// the control block is deleted.
+ /// Communicates the pointer destruction to the vertex.
~WeakIntrusivePtr() noexcept {
- if (control_block_) {
- if (--control_block_->weak_count == 0 &&
- control_block_->vertex == nullptr) {
- delete control_block_;
- }
- }
+ if (vertex_)
+ vertex_->table_ptr_ = nullptr;
}
/// @returns true if the managed vertex is deleted or not initialized.
- bool expired() const { return !control_block_ || !control_block_->vertex; }
+ bool expired() const { return !vertex_; }
/// @returns The intrusive pointer of the vertex.
- ///
- /// @warning Hard failure for uninitialized pointers.
- IntrusivePtr<T> lock() const {
- return IntrusivePtr<T>(static_cast<T*>(control_block_->vertex));
- }
+ /// nullptr if the vertex is deleted or not initialized.
+ IntrusivePtr<T> lock() const { return IntrusivePtr<T>(vertex_); }
/// @returns The raw pointer to the vertex.
- ///
- /// @warning Hard failure for uninitialized pointers.
- T* get() const { return static_cast<T*>(control_block_->vertex); }
+ /// nullptr if the vertex is deleted or not initialized.
+ T* get() const { return vertex_; }
private:
- ControlBlock* control_block_; ///< To receive information from vertices.
+ T* vertex_; ///< A communication pointer with the vertex.
};
template <class T>
@@ -130,12 +119,7 @@ class Terminal; // Forward declaration for Vertex to manage.
/// @pre Vertices are not shared among separate BDD instances.
template <class T>
class Vertex : private boost::noncopyable {
- /// @param[in] ptr Vertex pointer managed by intrusive pointers.
- ///
- /// @returns The control block of intrusive counting for tables.
- friend ControlBlock* get_control_block(Vertex<T>* ptr) noexcept {
- return ptr->control_block_;
- }
+ friend class WeakIntrusivePtr<T>; // Mutual friendship to manage table entry.
/// Increases the reference count for new intrusive pointers.
///
@@ -165,7 +149,7 @@ class Vertex : private boost::noncopyable {
explicit Vertex(int id)
: id_(id),
use_count_(0),
- control_block_(new ControlBlock{this}) {}
+ table_ptr_(nullptr) {}
/// @returns Identifier of the BDD graph rooted by this vertex.
int id() const { return id_; }
@@ -183,20 +167,18 @@ class Vertex : private boost::noncopyable {
}
protected:
- /// Communicates the destruction via the control block
- /// if there's anyone left to care.
+ /// Communicates the destruction
+ /// via the pointer to the unique table entry
+ /// if there's any.
~Vertex() noexcept {
- if (control_block_->weak_count == 0) {
- delete control_block_;
- } else {
- control_block_->vertex = nullptr;
- }
+ if (table_ptr_)
+ table_ptr_->vertex_ = nullptr;
}
private:
int id_; ///< Unique identifier of the BDD graph with this vertex.
int use_count_; ///< Reference count for the intrusive pointer.
- ControlBlock* control_block_; ///< Communication channel for pointers.
+ WeakIntrusivePtr<T>* table_ptr_; ///< Entry in the unique table.
};
/// Representation of terminal vertices in BDD graphs.
diff --git a/src/boolean_graph.cc b/src/boolean_graph.cc
index 23f95d1..9cdc3e5 100644
--- a/src/boolean_graph.cc
+++ b/src/boolean_graph.cc
@@ -24,11 +24,14 @@
#include "boolean_graph.h"
+#include <iostream>
#include <string>
+#include <unordered_set>
#include <boost/math/special_functions/sign.hpp>
#include <boost/range/algorithm.hpp>
+#include "event.h"
#include "logger.h"
namespace scram {
@@ -837,7 +840,7 @@ std::ostream& operator<<(std::ostream& os, const VariablePtr& variable) {
namespace {
-/// Gate formula signature for printing in the shorthand format.
+/// Gate formula signature for printing in the Aralia format.
struct FormulaSig {
std::string begin; ///< Beginning of the formula string.
std::string op; ///< Operator between the formula arguments.
diff --git a/src/boolean_graph.h b/src/boolean_graph.h
index a59f04a..ecadb4f 100644
--- a/src/boolean_graph.h
+++ b/src/boolean_graph.h
@@ -30,34 +30,37 @@
#ifndef SCRAM_SRC_BOOLEAN_GRAPH_H_
#define SCRAM_SRC_BOOLEAN_GRAPH_H_
-#include <cassert>
#include <cstdint>
#include <algorithm>
-#include <array>
-#include <iostream>
+#include <iosfwd>
#include <memory>
#include <unordered_map>
-#include <unordered_set>
#include <utility>
#include <vector>
#include <boost/container/flat_set.hpp>
-#include <boost/functional/hash.hpp>
#include <boost/noncopyable.hpp>
-#include "event.h"
#include "ext.h"
#include "linear_map.h"
namespace scram {
+
+namespace mef { // Declarations to decouple from the initialization code.
+class Gate;
+class BasicEvent;
+class HouseEvent;
+class Formula;
+} // namespace mef
+
namespace core {
-class Gate; // Indexed gate parent of nodes.
+class Gate; // An indexed gate parent of nodes.
using GatePtr = std::shared_ptr<Gate>; ///< Shared gates in the graph.
-using GateWeakPtr = std::weak_ptr<Gate>; ///< Acyclic ptr to parent gates.
+using GateWeakPtr = std::weak_ptr<Gate>; ///< An acyclic ptr to parent gates.
-/// Manager of information about parents.
+/// A manager of information about parents.
/// Only gates can manipulate the data.
class NodeParentManager : private boost::noncopyable {
friend class Gate; ///< The main manipulator of parent information.
@@ -65,10 +68,10 @@ class NodeParentManager : private boost::noncopyable {
public:
using Parent = std::pair<int, GateWeakPtr>; ///< Parent index and ptr.
- /// Map of parent gate positive indices and weak pointers to them.
+ /// A map type of parent gate positive indices and weak pointers to them.
using ParentMap = ext::linear_map<int, GateWeakPtr, ext::MoveEraser>;
- /// @returns Parents of a node.
+ /// @returns The parents of a node.
const ParentMap& parents() const { return parents_; }
protected:
@@ -290,7 +293,7 @@ enum State : std::uint8_t {
kUnityState ///< The set is unity. This set guarantees failure.
};
-/// Indexed gate for use in BooleanGraph.
+/// An indexed gate for use in BooleanGraph.
/// Initially this gate can represent any type of gate or logic;
/// however, this gate can be only of OR and AND type
/// at the end of all simplifications and processing.
@@ -298,23 +301,23 @@ enum State : std::uint8_t {
/// before any complex analysis is done.
class Gate : public Node, public std::enable_shared_from_this<Gate> {
public:
- /// Argument entry type in the gate's argument containers.
+ /// An argument entry type in the gate's argument containers.
/// The entry contains
/// the positive or negative index (indicating a complement)
- /// and a pointer to the argument node.
+ /// and the pointer to the argument node.
///
/// @tparam T The type of the argument node.
template <class T>
using Arg = std::pair<int, std::shared_ptr<T>>;
- /// The associative container type to store the gate arguments.
- /// This container type maps the index of the argument to a pointer to it.
+ /// An associative container type to store the gate arguments.
+ /// This container type maps the index of the argument to the pointer to it.
///
/// @tparam T The type of the argument node.
template <class T>
using ArgMap = ext::linear_map<int, std::shared_ptr<T>, ext::MoveEraser>;
- /// The ordered set of gate argument indices.
+ /// An ordered set of gate argument indices.
using ArgSet = boost::container::flat_set<int>;
/// Creates an indexed gate with its unique index.
@@ -754,65 +757,7 @@ inline const Gate::ArgMap<Constant>& Gate::args<Constant>() const {
return constant_args_;
}
-/// Container of unique gates.
-/// This container acts like an unordered set of gates.
-/// The gates are equivalent
-/// if they have the same semantics.
-/// However, this set does not test
-/// for the isomorphism of the gates' Boolean formulas.
-class GateSet {
- public:
- /// Inserts a gate into the set
- /// if it is semantically unique.
- ///
- /// @param[in] gate The gate to insert.
- ///
- /// @returns A pair of the unique gate and
- /// the insertion success flag.
- std::pair<GatePtr, bool> insert(const GatePtr& gate) noexcept {
- auto result = table_[gate->type()].insert(gate);
- return {*result.first, result.second};
- }
-
- private:
- /// Functor for hashing gates by their arguments.
- ///
- /// @note The hashing discards the logic of the gate.
- struct Hash {
- /// Operator overload for hashing.
- ///
- /// @param[in] gate The gate which hash must be calculated.
- ///
- /// @returns Hash value of the gate
- /// from its arguments but not logic.
- std::size_t operator()(const GatePtr& gate) const noexcept {
- return boost::hash_range(gate->args().begin(), gate->args().end());
- }
- };
- /// Functor for equality test for gates by their arguments.
- ///
- /// @note The equality discards the logic of the gate.
- struct Equal {
- /// Operator overload for gate argument equality test.
- ///
- /// @param[in] lhs The first gate.
- /// @param[in] rhs The second gate.
- ///
- /// @returns true if the gate arguments are equal.
- bool operator()(const GatePtr& lhs, const GatePtr& rhs) const noexcept {
- assert(lhs->type() == rhs->type());
- if (lhs->args() != rhs->args())
- return false;
- if (lhs->type() == kVote && lhs->vote_number() != rhs->vote_number())
- return false;
- return true;
- }
- };
- /// Container of gates grouped by their types.
- std::array<std::unordered_set<GatePtr, Hash, Equal>, kNumOperators> table_;
-};
-
-class Preprocessor;
+class Preprocessor; ///< @todo This can be decoupled.
/// BooleanGraph is a propositional directed acyclic graph (PDAG).
/// This class provides a simpler representation of a fault tree
@@ -885,7 +830,7 @@ class BooleanGraph : private boost::noncopyable {
return basic_events_[index - 1];
}
- /// Prints the Boolean graph in the shorthand format.
+ /// Prints the Boolean graph in the Aralia format.
/// This is a helper for logging and debugging.
/// The output is the standard error.
///
@@ -1082,14 +1027,14 @@ class BooleanGraph : private boost::noncopyable {
std::vector<std::weak_ptr<Gate>> null_gates_;
};
-/// Prints Boolean graph nodes in the shorthand format.
+/// Prints Boolean graph nodes in the Aralia format.
/// @{
std::ostream& operator<<(std::ostream& os, const ConstantPtr& constant);
std::ostream& operator<<(std::ostream& os, const VariablePtr& variable);
std::ostream& operator<<(std::ostream& os, const GatePtr& gate);
/// @}
-/// Prints the BooleanGraph as a fault tree in the shorthand format.
+/// Prints the BooleanGraph as a fault tree in the Aralia format.
/// This function is mostly for debugging purposes.
/// The output is not meant to be human readable.
///
diff --git a/src/ccf_group.cc b/src/ccf_group.cc
index d1400c7..04a0269 100644
--- a/src/ccf_group.cc
+++ b/src/ccf_group.cc
@@ -22,6 +22,9 @@
#include <boost/range/algorithm.hpp>
+#include "expression/arithmetic.h"
+#include "expression/constant.h"
+
namespace scram {
namespace mef {
@@ -283,16 +286,19 @@ CcfGroup::ExpressionMap AlphaFactorModel::CalculateProbabilities() {
assert(CcfGroup::factors().size() == max_level);
std::vector<ExpressionPtr> sum_args;
for (const std::pair<int, ExpressionPtr>& factor : CcfGroup::factors()) {
- sum_args.push_back(factor.second);
+ sum_args.emplace_back(new Mul(
+ {ExpressionPtr(new ConstantExpression(factor.first)), factor.second}));
}
ExpressionPtr sum(new Add(std::move(sum_args)));
int num_members = CcfGroup::members().size();
for (int i = 0; i < max_level; ++i) {
double mult = CalculateCombinationReciprocal(num_members - 1, i);
- ExpressionPtr k(new ConstantExpression(mult));
+ ExpressionPtr level(new ConstantExpression(i + 1));
ExpressionPtr fraction(new Div({CcfGroup::factors()[i].second, sum}));
- ExpressionPtr prob(new Mul({k, fraction, CcfGroup::distribution()}));
+ ExpressionPtr prob(
+ new Mul({level, ExpressionPtr(new ConstantExpression(mult)), fraction,
+ CcfGroup::distribution()}));
probabilities.emplace_back(i + 1, prob);
}
assert(probabilities.size() == max_level);
diff --git a/src/ccf_group.h b/src/ccf_group.h
index 339128c..cb94d44 100644
--- a/src/ccf_group.h
+++ b/src/ccf_group.h
@@ -219,7 +219,7 @@ class AlphaFactorModel : public CcfGroup {
/// Phi factor model is a simplification,
/// where fractions of k-member group failure is given directly.
/// Thus, Q_k = phi_k * Q_total.
-/// This model is described in the OpenPSA Model Exchange Format.
+/// This model is described in the Open-PSA Model Exchange Format.
class PhiFactorModel : public CcfGroup {
public:
using CcfGroup::CcfGroup;
diff --git a/src/cycle.h b/src/cycle.h
index 6b70aeb..e5fd066 100644
--- a/src/cycle.h
+++ b/src/cycle.h
@@ -21,13 +21,11 @@
#ifndef SCRAM_SRC_CYCLE_H_
#define SCRAM_SRC_CYCLE_H_
-#include <cassert>
-
#include <string>
#include <vector>
#include "event.h"
-#include "expression.h"
+#include "parameter.h"
namespace scram {
namespace mef {
diff --git a/src/event.h b/src/event.h
index 8091bbf..7f6fbec 100644
--- a/src/event.h
+++ b/src/event.h
@@ -23,7 +23,6 @@
#include <cstdint>
-#include <array>
#include <memory>
#include <string>
#include <vector>
@@ -319,8 +318,8 @@ const int kNumOperators = 8;
/// String representations of the operators.
/// The ordering is the same as the Operator enum.
-const std::array<const char*, kNumOperators> kOperatorToString = {
- "and", "or", "atleast", "xor", "not", "nand", "nor", "null"};
+const char* const kOperatorToString[] = {"and", "or", "atleast", "xor",
+ "not", "nand", "nor", "null"};
/// Boolean formula with operators and arguments.
/// Formulas are not expected to be shared.
diff --git a/src/expression.cc b/src/expression.cc
index daa3bf2..8dbfcac 100644
--- a/src/expression.cc
+++ b/src/expression.cc
@@ -16,19 +16,11 @@
*/
/// @file expression.cc
-/// Implementation of various expressions
-/// for basic event probability description.
+/// Implementation of the expression base class.
#include "expression.h"
-#include <algorithm>
-
-#include <boost/math/constants/constants.hpp>
-#include <boost/range/algorithm.hpp>
-
-#include "error.h"
#include "ext.h"
-#include "random.h"
namespace scram {
namespace mef {
@@ -59,474 +51,5 @@ bool Expression::IsConstant() noexcept {
args_, [](const ExpressionPtr& arg) { return arg->IsConstant(); });
}
-Parameter::Parameter(std::string name, std::string base_path,
- RoleSpecifier role)
- : Expression({}),
- Element(std::move(name)),
- Role(role, std::move(base_path)),
- Id(*this, *this),
- unit_(kUnitless),
- unused_(true),
- expression_(nullptr) {}
-
-void Parameter::expression(const ExpressionPtr& expression) {
- if (expression_)
- throw LogicError("Parameter expression is already set.");
- expression_ = expression.get();
- Expression::AddArg(expression);
-}
-
-MissionTime::MissionTime()
- : Expression({}),
- mission_time_(-1),
- unit_(kHours) {}
-
-const ExpressionPtr ConstantExpression::kOne(new ConstantExpression(1));
-const ExpressionPtr ConstantExpression::kZero(new ConstantExpression(0));
-const ExpressionPtr ConstantExpression::kPi(
- new ConstantExpression(boost::math::constants::pi<double>()));
-
-ConstantExpression::ConstantExpression(double val)
- : Expression({}),
- value_(val) {}
-
-ConstantExpression::ConstantExpression(int val)
- : Expression({}),
- value_(val) {}
-
-ConstantExpression::ConstantExpression(bool val)
- : Expression({}),
- value_(val) {}
-
-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.");
- }
-}
-
-GlmExpression::GlmExpression(const ExpressionPtr& gamma,
- const ExpressionPtr& lambda,
- const ExpressionPtr& mu,
- const ExpressionPtr& t)
- : Expression({gamma, lambda, mu, t}),
- gamma_(*gamma),
- lambda_(*lambda),
- mu_(*mu),
- 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 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.");
- }
-}
-
-double GlmExpression::Mean() noexcept {
- return Compute(gamma_.Mean(), lambda_.Mean(), mu_.Mean(), time_.Mean());
-}
-
-double GlmExpression::GetSample() noexcept {
- return Compute(gamma_.Sample(), lambda_.Sample(), mu_.Sample(),
- time_.Sample());
-}
-
-double GlmExpression::Compute(double gamma, double lambda, double mu,
- double time) noexcept {
- double r = lambda + mu;
- return (lambda - (lambda - gamma * r) * std::exp(-r * time)) / r;
-}
-
-WeibullExpression::WeibullExpression(const ExpressionPtr& alpha,
- const ExpressionPtr& beta,
- const ExpressionPtr& t0,
- const ExpressionPtr& time)
- : Expression({alpha, beta, t0, time}),
- alpha_(*alpha),
- beta_(*beta),
- t0_(*t0),
- 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 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.");
- }
-}
-
-double WeibullExpression::Compute(double alpha, double beta,
- double t0, double time) noexcept {
- return 1 - std::exp(-std::pow((time - t0) / alpha, beta));
-}
-
-UniformDeviate::UniformDeviate(const ExpressionPtr& min,
- const ExpressionPtr& max)
- : RandomDeviate({min, max}),
- min_(*min),
- max_(*max) {}
-
-void UniformDeviate::Validate() const {
- if (min_.Mean() >= max_.Mean()) {
- throw InvalidArgument("Min value is more than max for Uniform"
- " distribution.");
- } else if (min_.Max() >= max_.Min()) {
- throw InvalidArgument("Sampled min value is more than sampled max"
- " for Uniform distribution.");
- }
-}
-
-double UniformDeviate::GetSample() noexcept {
- return Random::UniformRealGenerator(min_.Sample(), max_.Sample());
-}
-
-NormalDeviate::NormalDeviate(const ExpressionPtr& mean,
- const ExpressionPtr& sigma)
- : RandomDeviate({mean, sigma}),
- mean_(*mean),
- sigma_(*sigma) {}
-
-void NormalDeviate::Validate() const {
- if (sigma_.Mean() <= 0) {
- throw InvalidArgument("Standard deviation cannot be negative or zero.");
- } else if (sigma_.Min() <= 0) {
- throw InvalidArgument("Sampled standard deviation is negative or zero.");
- }
-}
-
-double NormalDeviate::GetSample() noexcept {
- return Random::NormalGenerator(mean_.Sample(), sigma_.Sample());
-}
-
-LogNormalDeviate::LogNormalDeviate(const ExpressionPtr& mean,
- const ExpressionPtr& ef,
- const ExpressionPtr& level)
- : RandomDeviate({mean, ef, level}),
- mean_(*mean),
- ef_(*ef),
- level_(*level) {}
-
-void LogNormalDeviate::Validate() const {
- if (level_.Mean() <= 0 || level_.Mean() >= 1) {
- throw InvalidArgument("The confidence level is not within (0, 1).");
- } else if (ef_.Mean() <= 1) {
- throw InvalidArgument("The Error Factor for Log-Normal distribution"
- " cannot be less than 1.");
- } else if (mean_.Mean() <= 0) {
- throw InvalidArgument("The mean of Log-Normal distribution cannot be"
- " negative or zero.");
- } else if (level_.Min() <= 0 || level_.Max() >= 1) {
- throw InvalidArgument("The confidence level doesn't sample within (0, 1).");
-
- } else if (ef_.Min() <= 1) {
- throw InvalidArgument("The Sampled Error Factor for Log-Normal"
- " distribution cannot be less than 1.");
- } else if (mean_.Min() <= 0) {
- throw InvalidArgument("The sampled mean of Log-Normal distribution"
- " cannot be negative or zero.");
- }
-}
-
-double LogNormalDeviate::GetSample() noexcept {
- double sigma = ComputeScale(level_.Sample(), ef_.Sample());
- double mu = ComputeLocation(mean_.Sample(), sigma);
- return Random::LogNormalGenerator(mu, sigma);
-}
-
-double LogNormalDeviate::Max() noexcept {
- double sigma = ComputeScale(level_.Mean(), ef_.Mean());
- double mu = ComputeLocation(mean_.Max(), sigma);
- return std::exp(
- std::sqrt(2) * std::pow(boost::math::erfc(1 / 50), -1) * sigma + mu);
-}
-
-double LogNormalDeviate::ComputeScale(double level, double ef) noexcept {
- double p = level + (1 - level) / 2;
- double z = std::sqrt(2) * boost::math::erfc_inv(2 * p);
- return std::log(ef) / std::abs(z);
-}
-
-double LogNormalDeviate::ComputeLocation(double mean, double sigma) noexcept {
- return std::log(mean) - std::pow(sigma, 2) / 2;
-}
-
-GammaDeviate::GammaDeviate(const ExpressionPtr& k, const ExpressionPtr& theta)
- : RandomDeviate({k, theta}),
- k_(*k),
- theta_(*theta) {}
-
-void GammaDeviate::Validate() const {
- if (k_.Mean() <= 0) {
- throw InvalidArgument("The k shape parameter for Gamma distribution"
- " cannot be negative or zero.");
- } else if (theta_.Mean() <= 0) {
- throw InvalidArgument("The theta scale parameter for Gamma distribution"
- " cannot be negative or zero.");
- } else if (k_.Min() <= 0) {
- throw InvalidArgument("Sampled k shape parameter for Gamma distribution"
- " cannot be negative or zero.");
- } else if (theta_.Min() <= 0) {
- throw InvalidArgument("Sampled theta scale parameter for Gamma "
- "distribution cannot be negative or zero.");
- }
-}
-
-double GammaDeviate::GetSample() noexcept {
- return Random::GammaGenerator(k_.Sample(), theta_.Sample());
-}
-
-BetaDeviate::BetaDeviate(const ExpressionPtr& alpha, const ExpressionPtr& beta)
- : RandomDeviate({alpha, beta}),
- alpha_(*alpha),
- beta_(*beta) {}
-
-void BetaDeviate::Validate() const {
- if (alpha_.Mean() <= 0) {
- throw InvalidArgument("The alpha shape parameter for Beta distribution"
- " cannot be negative or zero.");
- } else if (beta_.Mean() <= 0) {
- throw InvalidArgument("The beta shape parameter for Beta distribution"
- " cannot be negative or zero.");
- } else if (alpha_.Min() <= 0) {
- throw InvalidArgument("Sampled alpha shape parameter for"
- " Beta distribution cannot be negative or zero.");
- } else if (beta_.Min() <= 0) {
- throw InvalidArgument("Sampled beta shape parameter for Beta"
- " distribution cannot be negative or zero.");
- }
-}
-
-double BetaDeviate::GetSample() noexcept {
- return Random::BetaGenerator(alpha_.Sample(), beta_.Sample());
-}
-
-Histogram::Histogram(std::vector<ExpressionPtr> boundaries,
- std::vector<ExpressionPtr> weights)
- : RandomDeviate(std::move(boundaries)) { // Partial registration!
- int num_intervals = Expression::args().size() - 1;
- if (weights.size() != num_intervals) {
- throw InvalidArgument("The number of weights is not equal to the number"
- " of intervals.");
- }
-
- // Complete the argument registration.
- for (const ExpressionPtr& arg : weights)
- Expression::AddArg(arg);
-
- boundaries_.first = Expression::args().begin();
- boundaries_.second = std::next(boundaries_.first, num_intervals + 1);
- weights_.first = boundaries_.second;
- weights_.second = Expression::args().end();
-}
-
-double Histogram::Mean() noexcept {
- double sum_weights = 0;
- double sum_product = 0;
- auto it_b = boundaries_.first;
- double prev_bound = (*it_b++)->Mean();
- for (auto it_w = weights_.first; it_w != weights_.second; ++it_w, ++it_b) {
- double cur_bound = (*it_b)->Mean();
- double cur_weight = (*it_w)->Mean();
- sum_product += (cur_bound - prev_bound) * cur_weight;
- sum_weights += cur_weight;
- prev_bound = cur_bound;
- }
- return sum_product / (prev_bound * sum_weights);
-}
-
-namespace {
-
-/// Iterator adaptor for retrieving sampled values.
-template <class Iterator>
-class sampler_iterator : public Iterator {
- public:
- /// Initializes the wrapper with to-be-sampled iterator.
- explicit sampler_iterator(const Iterator& it) : Iterator(it) {}
-
- /// Hides the wrapped iterator's operator*.
- ///
- /// @returns The sampled value of the expression under the iterator.
- double operator*() { return Iterator::operator*()->Sample(); }
-};
-
-/// Helper function for type deduction upon sampler_iterator construction.
-template <class Iterator>
-sampler_iterator<Iterator> make_sampler(const Iterator& it) {
- return sampler_iterator<Iterator>(it);
-}
-
-} // namespace
-
-double Histogram::GetSample() noexcept {
-#ifdef _LIBCPP_VERSION // libc++ chokes on iterator categories.
- std::vector<double> samples;
- for (auto it = boundaries_.first; it != boundaries_.second; ++it) {
- samples.push_back((*it)->Sample());
- }
- return Random::HistogramGenerator(
- samples.begin(), samples.end(), make_sampler(weights_.first));
-#else
- return Random::HistogramGenerator(make_sampler(boundaries_.first),
- make_sampler(boundaries_.second),
- make_sampler(weights_.first));
-#endif
-}
-
-void Histogram::CheckBoundaries() const {
- auto it = boundaries_.first;
- if ((*it)->IsConstant() == false || (*it)->Mean() != 0) {
- throw InvalidArgument("Histogram lower boundary must be 0.");
- }
- for (++it; it != boundaries_.second; ++it) {
- const auto& prev_expr = *std::prev(it);
- const auto& cur_expr = *it;
- if (prev_expr->Mean() >= cur_expr->Mean()) {
- throw InvalidArgument("Histogram upper boundaries are not strictly"
- " increasing and positive.");
- } else if (prev_expr->Max() >= cur_expr->Min()) {
- throw InvalidArgument("Histogram sampled upper boundaries must"
- " be strictly increasing and positive.");
- }
- }
-}
-
-void Histogram::CheckWeights() const {
- for (auto it = weights_.first; it != weights_.second; ++it) {
- if ((*it)->Mean() < 0) {
- throw InvalidArgument("Histogram weights can't be negative.");
- } else if ((*it)->Min() < 0) {
- throw InvalidArgument("Histogram sampled weights can't be negative.");
- }
- }
-}
-
-Neg::Neg(const ExpressionPtr& expression)
- : Expression({expression}),
- expression_(*expression) {}
-
-BinaryExpression::BinaryExpression(std::vector<ExpressionPtr> args)
- : Expression(std::move(args)) {
- if (Expression::args().size() < 2)
- throw InvalidArgument("Expression requires 2 or more arguments.");
-}
-
-double Mul::Mean() noexcept {
- double mean = 1;
- for (const ExpressionPtr& arg : Expression::args())
- mean *= arg->Mean();
- return mean;
-}
-
-double Mul::GetSample() noexcept {
- double result = 1;
- for (const ExpressionPtr& arg : Expression::args())
- result *= arg->Sample();
- return result;
-}
-
-double Mul::GetExtremum(bool maximum) noexcept {
- double max_val = 1; // Maximum possible product.
- double min_val = 1; // Minimum possible product.
- for (const ExpressionPtr& arg : Expression::args()) {
- double mult_max = arg->Max();
- double mult_min = arg->Min();
- double max_max = max_val * mult_max;
- double max_min = max_val * mult_min;
- double min_max = min_val * mult_max;
- double min_min = min_val * mult_min;
- max_val = std::max({max_max, max_min, min_max, min_min});
- min_val = std::min({max_max, max_min, min_max, min_min});
- }
- return maximum ? max_val : min_val;
-}
-
-void Div::Validate() const {
- auto it = Expression::args().begin();
- for (++it; it != Expression::args().end(); ++it) {
- const auto& expr = *it;
- if (!expr->Mean() || !expr->Max() || !expr->Min())
- throw InvalidArgument("Division by 0.");
- }
-}
-
-double Div::Mean() noexcept {
- auto it = Expression::args().begin();
- double mean = (*it)->Mean();
- for (++it; it != Expression::args().end(); ++it) {
- mean /= (*it)->Mean();
- }
- return mean;
-}
-
-double Div::GetSample() noexcept {
- auto it = Expression::args().begin();
- double result = (*it)->Sample();
- for (++it; it != Expression::args().end(); ++it)
- result /= (*it)->Sample();
- return result;
-}
-
-double Div::GetExtremum(bool maximum) noexcept {
- auto it = Expression::args().begin();
- double max_value = (*it)->Max(); // Maximum possible result.
- double min_value = (*it)->Min(); // Minimum possible result.
- for (++it; it != Expression::args().end(); ++it) {
- double div_max = (*it)->Max();
- double div_min = (*it)->Min();
- double max_max = max_value / div_max;
- double max_min = max_value / div_min;
- double min_max = min_value / div_max;
- double min_min = min_value / div_min;
- max_value = std::max({max_max, max_min, min_max, min_min});
- min_value = std::min({max_max, max_min, min_max, min_min});
- }
- return maximum ? max_value : min_value;
-}
-
} // namespace mef
} // namespace scram
diff --git a/src/expression.h b/src/expression.h
index 3e3ed44..19a0d7e 100644
--- a/src/expression.h
+++ b/src/expression.h
@@ -16,23 +16,17 @@
*/
/// @file expression.h
-/// Expressions that describe basic events.
+/// Provides the base class for all expressions
+/// and units for expression values.
#ifndef SCRAM_SRC_EXPRESSION_H_
#define SCRAM_SRC_EXPRESSION_H_
-#include <cmath>
#include <cstdint>
-#include <array>
#include <memory>
-#include <string>
-#include <utility>
#include <vector>
-#include <boost/math/special_functions/beta.hpp>
-#include <boost/math/special_functions/erf.hpp>
-#include <boost/math/special_functions/gamma.hpp>
#include <boost/noncopyable.hpp>
#include "element.h"
@@ -153,653 +147,12 @@ enum Units : std::uint8_t {
kDemands
};
-/// The number of elements in the Units enum.
-const int kNumUnits = 10;
+const int kNumUnits = 10; ///< The number of elements in the Units enum.
/// String representations of the Units in the same order as the enum.
-const std::array<const char*, kNumUnits> kUnitsToString = {
- "unitless", "bool", "int", "float", "hours",
- "hours-1", "years", "years-1", "fit", "demands"};
-
-/// This class provides a representation of a variable
-/// in basic event description.
-/// It is both expression and element description.
-class Parameter : public Expression,
- public Element,
- public Role,
- public Id,
- public NodeMark {
- public:
- /// Creates a parameter as a variable for future references.
- ///
- /// @param[in] name The name of this variable (Case sensitive).
- /// @param[in] base_path The series of containers to get this parameter.
- /// @param[in] role The role of the parameter within the model or container.
- ///
- /// @throws LogicError The name is empty.
- /// @throws InvalidArgument The name or reference paths are malformed.
- explicit Parameter(std::string name, std::string base_path = "",
- RoleSpecifier role = RoleSpecifier::kPublic);
-
- /// Sets the expression of this parameter.
- ///
- /// @param[in] expression The expression to describe this parameter.
- ///
- /// @throws LogicError The parameter expression is already set.
- void expression(const ExpressionPtr& expression);
-
- /// @returns The unit of this parameter.
- Units unit() const { return unit_; }
-
- /// Sets the unit of this parameter.
- ///
- /// @param[in] unit A valid unit.
- void unit(Units unit) { unit_ = unit; }
-
- /// @returns The usage state of this parameter.
- bool unused() { return unused_; }
-
- /// Sets the usage state for this parameter.
- ///
- /// @param[in] state The usage state for this parameter.
- void unused(bool state) { unused_ = state; }
-
- double Mean() noexcept override { return expression_->Mean(); }
- double Max() noexcept override { return expression_->Max(); }
- double Min() noexcept override { return expression_->Min(); }
-
- private:
- double GetSample() noexcept override { return expression_->Sample(); }
-
- Units unit_; ///< Units of this parameter.
- bool unused_; ///< Usage state.
- Expression* expression_; ///< Expression for this parameter.
-};
-
-using ParameterPtr = std::shared_ptr<Parameter>; ///< Shared parameters.
-
-/// This is for the system mission time.
-class MissionTime : public Expression {
- public:
- MissionTime();
-
- /// Sets the mission time.
- /// This function is expected to be used only once.
- ///
- /// @param[in] time The mission time.
- void mission_time(double time) {
- assert(time >= 0);
- mission_time_ = time;
- }
-
- /// @returns The unit of the system mission time.
- Units unit() const { return unit_; }
-
- /// Sets the unit of this parameter.
- ///
- /// @param[in] unit A valid unit.
- void unit(Units unit) { unit_ = unit; }
-
- double Mean() noexcept override { return mission_time_; }
- bool IsConstant() noexcept override { return true; }
-
- private:
- double GetSample() noexcept override { return mission_time_; }
-
- double mission_time_; ///< The system mission time.
- Units unit_; ///< Units of this parameter.
-};
-
-/// Indicates a constant value.
-class ConstantExpression : public Expression {
- public:
- static const ExpressionPtr kOne; ///< Constant 1 or True.
- static const ExpressionPtr kZero; ///< Constant 0 or False.
- static const ExpressionPtr kPi; ///< Constant PI value.
-
- /// Constructor for numerical values.
- ///
- /// @param[in] val Float numerical value.
- explicit ConstantExpression(double val);
-
- /// Constructor for numerical values.
- ///
- /// @param[in] val Integer numerical value.
- explicit ConstantExpression(int val);
-
- /// Constructor for boolean values.
- ///
- /// @param[in] val true for 1 and false for 0 value of this constant.
- explicit ConstantExpression(bool val);
-
- double Mean() noexcept override { return value_; }
- bool IsConstant() noexcept override { return true; }
-
- private:
- double GetSample() noexcept override { return value_; }
- double value_; ///< The Constant value.
-};
-
-/// Negative exponential distribution
-/// with hourly failure rate and time.
-class ExponentialExpression : public Expression {
- public:
- /// Constructor for exponential expression with two arguments.
- ///
- /// @param[in] lambda Hourly rate of failure.
- /// @param[in] t Mission time in hours.
- ExponentialExpression(const ExpressionPtr& lambda, const ExpressionPtr& t);
-
- /// @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()));
- }
-
- private:
- double GetSample() noexcept override {
- return 1 - std::exp(-(lambda_.Sample() * time_.Sample()));
- }
-
- 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.
- ///
- /// @param[in] gamma Probability of failure on demand.
- /// @param[in] lambda Hourly rate of failure.
- /// @param[in] mu Hourly repairing rate.
- /// @param[in] t Mission time in hours.
- GlmExpression(const ExpressionPtr& gamma, const ExpressionPtr& lambda,
- 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; }
-
- private:
- double GetSample() 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.
- Expression& lambda_; ///< Failure rate in hours.
- Expression& mu_; ///< Repair rate in hours.
- Expression& time_; ///< Mission time in hours.
-};
-
-/// Weibull distribution with scale, shape, time shift, and time.
-class WeibullExpression : public Expression {
- public:
- /// Constructor for Weibull distribution.
- ///
- /// @param[in] alpha Scale parameter.
- /// @param[in] beta Shape parameter.
- /// @param[in] t0 Time shift.
- /// @param[in] time Mission time.
- WeibullExpression(const ExpressionPtr& alpha, const ExpressionPtr& beta,
- 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());
- }
-
- private:
- double GetSample() noexcept override {
- return Compute(alpha_.Sample(), beta_.Sample(), t0_.Sample(),
- time_.Sample());
- }
-
- /// 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.
- Expression& beta_; ///< Shape parameter.
- Expression& t0_; ///< Time shift in hours.
- Expression& time_; ///< Mission time in hours.
-};
-
-/// Abstract base class for all deviate expressions.
-/// These expressions provide quantification for uncertainty and sensitivity.
-class RandomDeviate : public Expression {
- public:
- using Expression::Expression;
-
- bool IsConstant() noexcept override { return false; }
-};
-
-/// Uniform distribution.
-class UniformDeviate : public RandomDeviate {
- public:
- /// Setup for uniform distribution.
- ///
- /// @param[in] min Minimum value of the distribution.
- /// @param[in] max Maximum value of the distribution.
- UniformDeviate(const ExpressionPtr& min, const ExpressionPtr& max);
-
- /// @throws InvalidArgument The min value is more or equal to max value.
- void Validate() const override;
-
- double Mean() noexcept override { return (min_.Mean() + max_.Mean()) / 2; }
- double Max() noexcept override { return max_.Max(); }
- double Min() noexcept override { return min_.Min(); }
-
- private:
- double GetSample() noexcept override;
-
- Expression& min_; ///< Minimum value of the distribution.
- Expression& max_; ///< Maximum value of the distribution.
-};
-
-/// Normal distribution.
-class NormalDeviate : public RandomDeviate {
- public:
- /// Setup for normal distribution.
- ///
- /// @param[in] mean The mean of the distribution.
- /// @param[in] sigma The standard deviation of the distribution.
- NormalDeviate(const ExpressionPtr& mean, const ExpressionPtr& sigma);
-
- /// @throws InvalidArgument The sigma is negative or zero.
- void Validate() const override;
-
- double Mean() noexcept override { return mean_.Mean(); }
-
- /// @returns ~99.9% percentile value.
- ///
- /// @warning This is only an approximation of the maximum value.
- double Max() noexcept override { return mean_.Max() + 6 * sigma_.Max(); }
-
- /// @returns Less than 0.1% percentile value.
- ///
- /// @warning This is only an approximation.
- double Min() noexcept override { return mean_.Min() - 6 * sigma_.Max(); }
-
- private:
- double GetSample() noexcept override;
-
- Expression& mean_; ///< Mean value of normal distribution.
- Expression& sigma_; ///< Standard deviation of normal distribution.
-};
-
-/// Log-normal distribution.
-class LogNormalDeviate : public RandomDeviate {
- public:
- /// Setup for log-normal distribution.
- ///
- /// @param[in] mean The mean of the log-normal distribution
- /// not the mean of underlying normal distribution,
- /// which is parameter mu.
- /// mu is the location parameter,
- /// sigma is the scale factor.
- /// E(x) = exp(mu + sigma^2 / 2)
- /// @param[in] ef The error factor of the log-normal distribution.
- /// EF = exp(z * sigma)
- /// @param[in] level The confidence level.
- LogNormalDeviate(const ExpressionPtr& mean, const ExpressionPtr& ef,
- const ExpressionPtr& level);
-
- /// @throws InvalidArgument (mean <= 0) or (ef <= 0) or invalid level
- void Validate() const override;
-
- double Mean() noexcept override { return mean_.Mean(); }
-
- /// 99 percentile estimate.
- double Max() noexcept override;
-
- double Min() noexcept override { return 0; }
-
- private:
- double GetSample() noexcept override;
-
- /// Computes the scale parameter of the distribution.
- ///
- /// @param[in] level The confidence level.
- /// @param[in] ef The error factor of the log-normal distribution.
- ///
- /// @returns Scale parameter (sigma) value.
- double ComputeScale(double level, double ef) noexcept;
-
- /// Computes the location parameter of the distribution.
- ///
- /// @param[in] mean The mean of the log-normal distribution.
- /// @param[in] sigma The scale parameter of the distribution.
- ///
- /// @returns Value of location parameter (mu) value.
- double ComputeLocation(double mean, double sigma) noexcept;
-
- Expression& mean_; ///< Mean value of the log-normal distribution.
- Expression& ef_; ///< Error factor of the log-normal distribution.
- Expression& level_; ///< Confidence level of the log-normal distribution.
-};
-
-/// Gamma distribution.
-class GammaDeviate : public RandomDeviate {
- public:
- /// Setup for Gamma distribution.
- ///
- /// @param[in] k Shape parameter of Gamma distribution.
- /// @param[in] theta Scale parameter of Gamma distribution.
- GammaDeviate(const ExpressionPtr& k, const ExpressionPtr& theta);
-
- /// @throws InvalidArgument (k <= 0) or (theta <= 0)
- void Validate() const override;
-
- double Mean() noexcept override { return k_.Mean() * theta_.Mean(); }
-
- /// @returns 99 percentile.
- double Max() noexcept override {
- using boost::math::gamma_q;
- double k_max = k_.Max();
- return theta_.Max() *
- std::pow(gamma_q(k_max, gamma_q(k_max, 0) - 0.99), -1);
- }
-
- double Min() noexcept override { return 0; }
-
- private:
- double GetSample() noexcept override;
-
- Expression& k_; ///< The shape parameter of the gamma distribution.
- Expression& theta_; ///< The scale factor of the gamma distribution.
-};
-
-/// Beta distribution.
-class BetaDeviate : public RandomDeviate {
- public:
- /// Setup for Beta distribution.
- ///
- /// @param[in] alpha Alpha shape parameter of Gamma distribution.
- /// @param[in] beta Beta shape parameter of Gamma distribution.
- BetaDeviate(const ExpressionPtr& alpha, const ExpressionPtr& beta);
-
- /// @throws InvalidArgument (alpha <= 0) or (beta <= 0)
- void Validate() const override;
-
- double Mean() noexcept override {
- double alpha_mean = alpha_.Mean();
- return alpha_mean / (alpha_mean + beta_.Mean());
- }
-
- /// @returns 99 percentile.
- double Max() noexcept override {
- return std::pow(boost::math::ibeta(alpha_.Max(), beta_.Max(), 0.99), -1);
- }
-
- double Min() noexcept override { return 0; }
-
- private:
- double GetSample() noexcept override;
-
- Expression& alpha_; ///< The alpha shape parameter.
- Expression& beta_; ///< The beta shape parameter.
-};
-
-/// Histogram distribution.
-class Histogram : public RandomDeviate {
- public:
- /// Histogram distribution setup.
- ///
- /// @param[in] boundaries The bounds of intervals.
- /// @param[in] weights The positive weights of intervals
- /// restricted by the upper boundaries.
- /// Therefore, the number of weights must be
- /// equal to the number of intervals.
- ///
- /// @throws InvalidArgument The boundaries container size is not equal to
- /// weights container size + 1.
- ///
- /// @note This description of histogram sampling is mostly for probabilities.
- /// Therefore, it is not flexible.
- /// Currently, it allows sampling both boundaries and weights.
- /// This behavior makes checking
- /// for valid arrangement of the boundaries mandatory
- /// for each sampling.
- /// Moreover, the first starting point is assumed but not defined.
- /// The starting point is assumed to be 0,
- /// which leaves only positive values for boundaries.
- /// This behavior is restrictive
- /// and should be handled accordingly.
- Histogram(std::vector<ExpressionPtr> boundaries,
- std::vector<ExpressionPtr> weights);
-
- /// @throws InvalidArgument The boundaries are not strictly increasing,
- /// or weights are negative.
- void Validate() const override {
- CheckBoundaries();
- CheckWeights();
- }
-
- double Mean() noexcept override;
- double Max() noexcept override {
- return (*std::prev(boundaries_.second))->Max();
- }
- double Min() noexcept override { return 0; }
-
- private:
- /// Access to args.
- using Iterator = std::vector<ExpressionPtr>::const_iterator;
-
- double GetSample() noexcept override;
-
- /// Checks if values of boundary expressions are strictly increasing.
- ///
- /// @throws InvalidArgument The mean values are not strictly increasing.
- void CheckBoundaries() const;
-
- /// Checks if values of weights are non-negative.
- ///
- /// @throws InvalidArgument The mean values are negative.
- void CheckWeights() const;
-
- std::pair<Iterator, Iterator> boundaries_; ///< Boundaries of the intervals.
- std::pair<Iterator, Iterator> weights_; ///< Weights of the intervals.
-};
-
-/// This class for negation of numerical value or another expression.
-class Neg : public Expression {
- public:
- /// Construct a new expression
- /// that negates a given argument expression.
- ///
- /// @param[in] expression The expression to be negated.
- explicit Neg(const ExpressionPtr& expression);
-
- double Mean() noexcept override { return -expression_.Mean(); }
- double Max() noexcept override { return -expression_.Min(); }
- double Min() noexcept override { return -expression_.Max(); }
-
- private:
- double GetSample() noexcept override { return -expression_.Sample(); }
-
- Expression& expression_; ///< Expression that is used for negation.
-};
-
-/// Base class for expressions that require 2 or more arguments.
-class BinaryExpression : public Expression {
- public:
- /// Checks the number of provided arguments upon initialization.
- ///
- /// @param[in] args Arguments of this expression.
- ///
- /// @throws InvalidArgument The number of arguments is fewer than 2.
- explicit BinaryExpression(std::vector<ExpressionPtr> args);
-};
-
-/// This expression adds all the given expressions' values.
-class Add : public BinaryExpression {
- public:
- using BinaryExpression::BinaryExpression;
-
- double Mean() noexcept override { return Compute(&Expression::Mean); }
- double Max() noexcept override { return Compute(&Expression::Max); }
- double Min() noexcept override { return Compute(&Expression::Min); }
-
- private:
- double GetSample() noexcept override {
- return Compute(&Expression::Sample);
- }
-
- /// Adds all argument expression values.
- ///
- /// @param[in] value The getter function for the arg expression value.
- ///
- /// @returns The sum of the expression values.
- double Compute(double (Expression::*value)()) {
- double result = 0;
- for (const ExpressionPtr& arg : Expression::args())
- result += ((*arg).*value)();
- return result;
- }
-};
-
-/// This expression performs subtraction operation.
-/// First expression minus the rest of the given expressions' values.
-class Sub : public BinaryExpression {
- public:
- using BinaryExpression::BinaryExpression;
-
- double Mean() noexcept override { return Compute(&Expression::Mean); }
- double Max() noexcept override {
- return Compute(&Expression::Max, &Expression::Min);
- }
- double Min() noexcept override {
- return Compute(&Expression::Min, &Expression::Max);
- }
-
- private:
- double GetSample() noexcept override {
- return Compute(&Expression::Sample);
- }
-
- /// Performs the subtraction of all argument expression values.
- ///
- /// @param[in] first_value The getter function for the first arg expression.
- /// @param[in] rest_value The getter function for the rest arg expressions.
- /// If not given, it is equal to first_value.
- ///
- /// @returns first_value() - sum(rest_value()).
- double Compute(double (Expression::*first_value)(),
- double (Expression::*rest_value)() = nullptr) {
- if (!rest_value)
- rest_value = first_value;
-
- auto it = Expression::args().begin();
- double result = ((**it).*first_value)();
- for (++it; it != Expression::args().end(); ++it) {
- result -= ((**it).*rest_value)();
- }
- return result;
- }
-};
-
-/// This expression performs multiplication operation.
-class Mul : public BinaryExpression {
- public:
- using BinaryExpression::BinaryExpression;
-
- double Mean() noexcept override;
-
- /// Finds maximum product
- /// from the given arguments' minimum and maximum values.
- /// Negative values may introduce sign cancellation.
- ///
- /// @returns Maximum possible value of the product.
- double Max() noexcept override { return GetExtremum(/*max=*/true); }
-
- /// Finds minimum product
- /// from the given arguments' minimum and maximum values.
- /// Negative values may introduce sign cancellation.
- ///
- /// @returns Minimum possible value of the product.
- double Min() noexcept override { return GetExtremum(/*max=*/false); }
-
- private:
- double GetSample() noexcept override;
-
- /// @param[in] maximum Flag to return maximum value.
- ///
- /// @returns One of extremums.
- double GetExtremum(bool maximum) noexcept;
-};
-
-/// This expression performs division operation.
-/// The expression divides the first given argument by
-/// the rest of argument expressions.
-class Div : public BinaryExpression {
- public:
- using BinaryExpression::BinaryExpression;
-
- /// @throws InvalidArgument Division by 0.
- void Validate() const override;
-
- double Mean() noexcept override;
-
- /// Finds maximum results of division
- /// of the given arguments' minimum and maximum values.
- /// Negative values may introduce sign cancellation.
- ///
- /// @returns Maximum value for division of arguments.
- double Max() noexcept override { return GetExtremum(/*max=*/true); }
-
- /// Finds minimum results of division
- /// of the given arguments' minimum and maximum values.
- /// Negative values may introduce sign cancellation.
- ///
- /// @returns Minimum value for division of arguments.
- double Min() noexcept override { return GetExtremum(/*max=*/false); }
-
- private:
- double GetSample() noexcept override;
-
- /// @param[in] maximum Flag to return maximum value.
- ///
- /// @returns One of extremums.
- double GetExtremum(bool maximum) noexcept;
-};
+const char* const kUnitsToString[] = {"unitless", "bool", "int", "float",
+ "hours", "hours-1", "years", "years-1",
+ "fit", "demands"};
} // namespace mef
} // namespace scram
diff --git a/src/expression/arithmetic.cc b/src/expression/arithmetic.cc
new file mode 100644
index 0000000..ccb0022
--- /dev/null
+++ b/src/expression/arithmetic.cc
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2014-2016 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 <http://www.gnu.org/licenses/>.
+ */
+
+/// @file arithmetic.cc
+/// Implementation of various arithmetic expressions.
+
+#include "arithmetic.h"
+
+#include <algorithm>
+
+#include "src/error.h"
+
+namespace scram {
+namespace mef {
+
+Neg::Neg(const ExpressionPtr& expression)
+ : Expression({expression}),
+ expression_(*expression) {}
+
+BinaryExpression::BinaryExpression(std::vector<ExpressionPtr> args)
+ : Expression(std::move(args)) {
+ if (Expression::args().size() < 2)
+ throw InvalidArgument("Expression requires 2 or more arguments.");
+}
+
+double Mul::Mean() noexcept {
+ double mean = 1;
+ for (const ExpressionPtr& arg : Expression::args())
+ mean *= arg->Mean();
+ return mean;
+}
+
+double Mul::GetSample() noexcept {
+ double result = 1;
+ for (const ExpressionPtr& arg : Expression::args())
+ result *= arg->Sample();
+ return result;
+}
+
+double Mul::GetExtremum(bool maximum) noexcept {
+ double max_val = 1; // Maximum possible product.
+ double min_val = 1; // Minimum possible product.
+ for (const ExpressionPtr& arg : Expression::args()) {
+ double mult_max = arg->Max();
+ double mult_min = arg->Min();
+ double max_max = max_val * mult_max;
+ double max_min = max_val * mult_min;
+ double min_max = min_val * mult_max;
+ double min_min = min_val * mult_min;
+ max_val = std::max({max_max, max_min, min_max, min_min});
+ min_val = std::min({max_max, max_min, min_max, min_min});
+ }
+ return maximum ? max_val : min_val;
+}
+
+void Div::Validate() const {
+ auto it = Expression::args().begin();
+ for (++it; it != Expression::args().end(); ++it) {
+ const auto& expr = *it;
+ if (!expr->Mean() || !expr->Max() || !expr->Min())
+ throw InvalidArgument("Division by 0.");
+ }
+}
+
+double Div::Mean() noexcept {
+ auto it = Expression::args().begin();
+ double mean = (*it)->Mean();
+ for (++it; it != Expression::args().end(); ++it) {
+ mean /= (*it)->Mean();
+ }
+ return mean;
+}
+
+double Div::GetSample() noexcept {
+ auto it = Expression::args().begin();
+ double result = (*it)->Sample();
+ for (++it; it != Expression::args().end(); ++it)
+ result /= (*it)->Sample();
+ return result;
+}
+
+double Div::GetExtremum(bool maximum) noexcept {
+ auto it = Expression::args().begin();
+ double max_value = (*it)->Max(); // Maximum possible result.
+ double min_value = (*it)->Min(); // Minimum possible result.
+ for (++it; it != Expression::args().end(); ++it) {
+ double div_max = (*it)->Max();
+ double div_min = (*it)->Min();
+ double max_max = max_value / div_max;
+ double max_min = max_value / div_min;
+ double min_max = min_value / div_max;
+ double min_min = min_value / div_min;
+ max_value = std::max({max_max, max_min, min_max, min_min});
+ min_value = std::min({max_max, max_min, min_max, min_min});
+ }
+ return maximum ? max_value : min_value;
+}
+
+} // namespace mef
+} // namespace scram
diff --git a/src/expression/arithmetic.h b/src/expression/arithmetic.h
new file mode 100644
index 0000000..cd0e99c
--- /dev/null
+++ b/src/expression/arithmetic.h
@@ -0,0 +1,196 @@
+/*
+ * Copyright (C) 2014-2016 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 <http://www.gnu.org/licenses/>.
+ */
+
+/// @file arithmetic.h
+/// A collection of arithmetic expressions.
+
+#ifndef SCRAM_SRC_EXPRESSION_ARITHMETIC_H_
+#define SCRAM_SRC_EXPRESSION_ARITHMETIC_H_
+
+#include <vector>
+
+#include "src/expression.h"
+
+namespace scram {
+namespace mef {
+
+/// This class for negation of numerical value or another expression.
+class Neg : public Expression {
+ public:
+ /// Construct a new expression
+ /// that negates a given argument expression.
+ ///
+ /// @param[in] expression The expression to be negated.
+ explicit Neg(const ExpressionPtr& expression);
+
+ double Mean() noexcept override { return -expression_.Mean(); }
+ double Max() noexcept override { return -expression_.Min(); }
+ double Min() noexcept override { return -expression_.Max(); }
+
+ private:
+ double GetSample() noexcept override { return -expression_.Sample(); }
+
+ Expression& expression_; ///< Expression that is used for negation.
+};
+
+/// Base class for expressions that require 2 or more arguments.
+class BinaryExpression : public Expression {
+ public:
+ /// Checks the number of provided arguments upon initialization.
+ ///
+ /// @param[in] args Arguments of this expression.
+ ///
+ /// @throws InvalidArgument The number of arguments is fewer than 2.
+ explicit BinaryExpression(std::vector<ExpressionPtr> args);
+};
+
+/// This expression adds all the given expressions' values.
+class Add : public BinaryExpression {
+ public:
+ using BinaryExpression::BinaryExpression;
+
+ double Mean() noexcept override { return Compute(&Expression::Mean); }
+ double Max() noexcept override { return Compute(&Expression::Max); }
+ double Min() noexcept override { return Compute(&Expression::Min); }
+
+ private:
+ double GetSample() noexcept override {
+ return Compute(&Expression::Sample);
+ }
+
+ /// Adds all argument expression values.
+ ///
+ /// @param[in] value The getter function for the arg expression value.
+ ///
+ /// @returns The sum of the expression values.
+ double Compute(double (Expression::*value)()) {
+ double result = 0;
+ for (const ExpressionPtr& arg : Expression::args())
+ result += ((*arg).*value)();
+ return result;
+ }
+};
+
+/// This expression performs subtraction operation.
+/// First expression minus the rest of the given expressions' values.
+class Sub : public BinaryExpression {
+ public:
+ using BinaryExpression::BinaryExpression;
+
+ double Mean() noexcept override { return Compute(&Expression::Mean); }
+ double Max() noexcept override {
+ return Compute(&Expression::Max, &Expression::Min);
+ }
+ double Min() noexcept override {
+ return Compute(&Expression::Min, &Expression::Max);
+ }
+
+ private:
+ double GetSample() noexcept override {
+ return Compute(&Expression::Sample);
+ }
+
+ /// Performs the subtraction of all argument expression values.
+ ///
+ /// @param[in] first_value The getter function for the first arg expression.
+ /// @param[in] rest_value The getter function for the rest arg expressions.
+ /// If not given, it is equal to first_value.
+ ///
+ /// @returns first_value() - sum(rest_value()).
+ double Compute(double (Expression::*first_value)(),
+ double (Expression::*rest_value)() = nullptr) {
+ if (!rest_value)
+ rest_value = first_value;
+
+ auto it = Expression::args().begin();
+ double result = ((**it).*first_value)();
+ for (++it; it != Expression::args().end(); ++it) {
+ result -= ((**it).*rest_value)();
+ }
+ return result;
+ }
+};
+
+/// This expression performs multiplication operation.
+class Mul : public BinaryExpression {
+ public:
+ using BinaryExpression::BinaryExpression;
+
+ double Mean() noexcept override;
+
+ /// Finds maximum product
+ /// from the given arguments' minimum and maximum values.
+ /// Negative values may introduce sign cancellation.
+ ///
+ /// @returns Maximum possible value of the product.
+ double Max() noexcept override { return GetExtremum(/*max=*/true); }
+
+ /// Finds minimum product
+ /// from the given arguments' minimum and maximum values.
+ /// Negative values may introduce sign cancellation.
+ ///
+ /// @returns Minimum possible value of the product.
+ double Min() noexcept override { return GetExtremum(/*max=*/false); }
+
+ private:
+ double GetSample() noexcept override;
+
+ /// @param[in] maximum Flag to return maximum value.
+ ///
+ /// @returns One of extremums.
+ double GetExtremum(bool maximum) noexcept;
+};
+
+/// This expression performs division operation.
+/// The expression divides the first given argument by
+/// the rest of argument expressions.
+class Div : public BinaryExpression {
+ public:
+ using BinaryExpression::BinaryExpression;
+
+ /// @throws InvalidArgument Division by 0.
+ void Validate() const override;
+
+ double Mean() noexcept override;
+
+ /// Finds maximum results of division
+ /// of the given arguments' minimum and maximum values.
+ /// Negative values may introduce sign cancellation.
+ ///
+ /// @returns Maximum value for division of arguments.
+ double Max() noexcept override { return GetExtremum(/*max=*/true); }
+
+ /// Finds minimum results of division
+ /// of the given arguments' minimum and maximum values.
+ /// Negative values may introduce sign cancellation.
+ ///
+ /// @returns Minimum value for division of arguments.
+ double Min() noexcept override { return GetExtremum(/*max=*/false); }
+
+ private:
+ double GetSample() noexcept override;
+
+ /// @param[in] maximum Flag to return maximum value.
+ ///
+ /// @returns One of extremums.
+ double GetExtremum(bool maximum) noexcept;
+};
+
+} // namespace mef
+} // namespace scram
+
+#endif // SCRAM_SRC_EXPRESSION_ARITHMETIC_H_
diff --git a/src/expression/constant.cc b/src/expression/constant.cc
new file mode 100644
index 0000000..7da0ed2
--- /dev/null
+++ b/src/expression/constant.cc
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2014-2016 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 <http://www.gnu.org/licenses/>.
+ */
+
+/// @file constant.cc
+/// Implementation of various constant expressions.
+
+#include "constant.h"
+
+#include <boost/math/constants/constants.hpp>
+
+#include "src/error.h"
+
+namespace scram {
+namespace mef {
+
+const ExpressionPtr ConstantExpression::kOne(new ConstantExpression(1));
+const ExpressionPtr ConstantExpression::kZero(new ConstantExpression(0));
+const ExpressionPtr ConstantExpression::kPi(
+ new ConstantExpression(boost::math::constants::pi<double>()));
+
+ConstantExpression::ConstantExpression(double value)
+ : Expression({}),
+ value_(value) {}
+
+ConstantExpression::ConstantExpression(int value)
+ : ConstantExpression(static_cast<double>(value)) {}
+
+ConstantExpression::ConstantExpression(bool value)
+ : ConstantExpression(static_cast<double>(value)) {}
+
+MissionTime::MissionTime(double time, Units unit)
+ : ConstantExpression(time),
+ unit_(unit) {
+ if (time < 0)
+ throw LogicError("Mission time cannot be negative.");
+}
+
+} // namespace mef
+} // namespace scram
diff --git a/src/expression/constant.h b/src/expression/constant.h
new file mode 100644
index 0000000..58975a4
--- /dev/null
+++ b/src/expression/constant.h
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2014-2016 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 <http://www.gnu.org/licenses/>.
+ */
+
+/// @file constant.h
+/// Constant expressions that cannot have uncertainties.
+
+#ifndef SCRAM_SRC_EXPRESSION_CONSTANT_H_
+#define SCRAM_SRC_EXPRESSION_CONSTANT_H_
+
+#include "src/expression.h"
+
+namespace scram {
+namespace mef {
+
+/// Indicates a constant value.
+class ConstantExpression : public Expression {
+ public:
+ static const ExpressionPtr kOne; ///< Constant 1 or True.
+ static const ExpressionPtr kZero; ///< Constant 0 or False.
+ static const ExpressionPtr kPi; ///< Constant PI value.
+
+ /// Constructor for numerical values.
+ ///
+ /// @param[in] value Float numerical value.
+ explicit ConstantExpression(double value);
+
+ /// Constructor for numerical values.
+ ///
+ /// @param[in] value Integer numerical value.
+ explicit ConstantExpression(int value);
+
+ /// Constructor for boolean values.
+ ///
+ /// @param[in] value true for 1 and false for 0 value of this constant.
+ explicit ConstantExpression(bool value);
+
+ double Mean() noexcept override { return value_; }
+ bool IsConstant() noexcept override { return true; }
+
+ private:
+ double GetSample() noexcept override { return value_; }
+
+ const double value_; ///< The universal value to represent int, bool, double.
+};
+
+/// The system mission time.
+class MissionTime : public ConstantExpression {
+ public:
+ /// Sets the mission time.
+ /// This function is expected to be used only once.
+ ///
+ /// @param[in] time The mission time.
+ /// @param[in] unit The unit of the given ``time`` argument.
+ ///
+ /// @throws LogicError The time value is negative.
+ explicit MissionTime(double time, Units unit = kHours);
+
+ /// @returns The unit of the system mission time.
+ Units unit() const { return unit_; }
+
+ private:
+ Units unit_; ///< Units of this parameter.
+};
+
+} // namespace mef
+} // namespace scram
+
+#endif // SCRAM_SRC_EXPRESSION_CONSTANT_H_
diff --git a/src/expression/exponential.cc b/src/expression/exponential.cc
new file mode 100644
index 0000000..3ddf1dd
--- /dev/null
+++ b/src/expression/exponential.cc
@@ -0,0 +1,136 @@
+/*
+ * Copyright (C) 2014-2016 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 <http://www.gnu.org/licenses/>.
+ */
+
+/// @file exponential.cc
+/// Implementation of various exponential expressions.
+
+#include "exponential.h"
+
+#include "src/error.h"
+
+namespace scram {
+namespace mef {
+
+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.");
+ }
+}
+
+GlmExpression::GlmExpression(const ExpressionPtr& gamma,
+ const ExpressionPtr& lambda,
+ const ExpressionPtr& mu,
+ const ExpressionPtr& t)
+ : Expression({gamma, lambda, mu, t}),
+ gamma_(*gamma),
+ lambda_(*lambda),
+ mu_(*mu),
+ 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 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.");
+ }
+}
+
+double GlmExpression::Mean() noexcept {
+ return Compute(gamma_.Mean(), lambda_.Mean(), mu_.Mean(), time_.Mean());
+}
+
+double GlmExpression::GetSample() noexcept {
+ return Compute(gamma_.Sample(), lambda_.Sample(), mu_.Sample(),
+ time_.Sample());
+}
+
+double GlmExpression::Compute(double gamma, double lambda, double mu,
+ double time) noexcept {
+ double r = lambda + mu;
+ return (lambda - (lambda - gamma * r) * std::exp(-r * time)) / r;
+}
+
+WeibullExpression::WeibullExpression(const ExpressionPtr& alpha,
+ const ExpressionPtr& beta,
+ const ExpressionPtr& t0,
+ const ExpressionPtr& time)
+ : Expression({alpha, beta, t0, time}),
+ alpha_(*alpha),
+ beta_(*beta),
+ t0_(*t0),
+ 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 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.");
+ }
+}
+
+double WeibullExpression::Compute(double alpha, double beta,
+ double t0, double time) noexcept {
+ return 1 - std::exp(-std::pow((time - t0) / alpha, beta));
+}
+
+} // namespace mef
+} // namespace scram
diff --git a/src/expression/exponential.h b/src/expression/exponential.h
new file mode 100644
index 0000000..81f974a
--- /dev/null
+++ b/src/expression/exponential.h
@@ -0,0 +1,157 @@
+/*
+ * Copyright (C) 2014-2016 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 <http://www.gnu.org/licenses/>.
+ */
+
+/// @file exponential.h
+/// Expressions and distributions
+/// that are described with exponential formulas.
+
+#ifndef SCRAM_SRC_EXPRESSION_EXPONENTIAL_H_
+#define SCRAM_SRC_EXPRESSION_EXPONENTIAL_H_
+
+#include <cmath>
+
+#include "src/expression.h"
+
+namespace scram {
+namespace mef {
+
+/// Negative exponential distribution
+/// with hourly failure rate and time.
+class ExponentialExpression : public Expression {
+ public:
+ /// Constructor for exponential expression with two arguments.
+ ///
+ /// @param[in] lambda Hourly rate of failure.
+ /// @param[in] t Mission time in hours.
+ ExponentialExpression(const ExpressionPtr& lambda, const ExpressionPtr& t);
+
+ /// @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()));
+ }
+
+ private:
+ double GetSample() noexcept override {
+ return 1 - std::exp(-(lambda_.Sample() * time_.Sample()));
+ }
+
+ 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.
+ ///
+ /// @param[in] gamma Probability of failure on demand.
+ /// @param[in] lambda Hourly rate of failure.
+ /// @param[in] mu Hourly repairing rate.
+ /// @param[in] t Mission time in hours.
+ GlmExpression(const ExpressionPtr& gamma, const ExpressionPtr& lambda,
+ 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; }
+
+ private:
+ double GetSample() 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.
+ Expression& lambda_; ///< Failure rate in hours.
+ Expression& mu_; ///< Repair rate in hours.
+ Expression& time_; ///< Mission time in hours.
+};
+
+/// Weibull distribution with scale, shape, time shift, and time.
+class WeibullExpression : public Expression {
+ public:
+ /// Constructor for Weibull distribution.
+ ///
+ /// @param[in] alpha Scale parameter.
+ /// @param[in] beta Shape parameter.
+ /// @param[in] t0 Time shift.
+ /// @param[in] time Mission time.
+ WeibullExpression(const ExpressionPtr& alpha, const ExpressionPtr& beta,
+ 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());
+ }
+
+ private:
+ double GetSample() noexcept override {
+ return Compute(alpha_.Sample(), beta_.Sample(), t0_.Sample(),
+ time_.Sample());
+ }
+
+ /// 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.
+ Expression& beta_; ///< Shape parameter.
+ Expression& t0_; ///< Time shift in hours.
+ Expression& time_; ///< Mission time in hours.
+};
+
+} // namespace mef
+} // namespace scram
+
+#endif // SCRAM_SRC_EXPRESSION_EXPONENTIAL_H_
diff --git a/src/expression.cc b/src/expression/random_deviate.cc
similarity index 50%
copy from src/expression.cc
copy to src/expression/random_deviate.cc
index daa3bf2..57f3925 100644
--- a/src/expression.cc
+++ b/src/expression/random_deviate.cc
@@ -15,196 +15,23 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-/// @file expression.cc
-/// Implementation of various expressions
-/// for basic event probability description.
+/// @file random_deviate.cc
+/// Implementations of random deviate expressions.
-#include "expression.h"
+#include "random_deviate.h"
-#include <algorithm>
+#include <cmath>
-#include <boost/math/constants/constants.hpp>
-#include <boost/range/algorithm.hpp>
+#include <boost/math/special_functions/beta.hpp>
+#include <boost/math/special_functions/erf.hpp>
+#include <boost/math/special_functions/gamma.hpp>
-#include "error.h"
-#include "ext.h"
-#include "random.h"
+#include "src/error.h"
+#include "src/random.h"
namespace scram {
namespace mef {
-Expression::Expression(std::vector<ExpressionPtr> args)
- : args_(std::move(args)),
- sampled_value_(0),
- sampled_(false) {}
-
-double Expression::Sample() noexcept {
- if (!sampled_) {
- sampled_ = true;
- sampled_value_ = this->GetSample();
- }
- return sampled_value_;
-}
-
-void Expression::Reset() noexcept {
- if (!sampled_)
- return;
- sampled_ = false;
- for (const ExpressionPtr& arg : args_)
- arg->Reset();
-}
-
-bool Expression::IsConstant() noexcept {
- return ext::all_of(
- args_, [](const ExpressionPtr& arg) { return arg->IsConstant(); });
-}
-
-Parameter::Parameter(std::string name, std::string base_path,
- RoleSpecifier role)
- : Expression({}),
- Element(std::move(name)),
- Role(role, std::move(base_path)),
- Id(*this, *this),
- unit_(kUnitless),
- unused_(true),
- expression_(nullptr) {}
-
-void Parameter::expression(const ExpressionPtr& expression) {
- if (expression_)
- throw LogicError("Parameter expression is already set.");
- expression_ = expression.get();
- Expression::AddArg(expression);
-}
-
-MissionTime::MissionTime()
- : Expression({}),
- mission_time_(-1),
- unit_(kHours) {}
-
-const ExpressionPtr ConstantExpression::kOne(new ConstantExpression(1));
-const ExpressionPtr ConstantExpression::kZero(new ConstantExpression(0));
-const ExpressionPtr ConstantExpression::kPi(
- new ConstantExpression(boost::math::constants::pi<double>()));
-
-ConstantExpression::ConstantExpression(double val)
- : Expression({}),
- value_(val) {}
-
-ConstantExpression::ConstantExpression(int val)
- : Expression({}),
- value_(val) {}
-
-ConstantExpression::ConstantExpression(bool val)
- : Expression({}),
- value_(val) {}
-
-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.");
- }
-}
-
-GlmExpression::GlmExpression(const ExpressionPtr& gamma,
- const ExpressionPtr& lambda,
- const ExpressionPtr& mu,
- const ExpressionPtr& t)
- : Expression({gamma, lambda, mu, t}),
- gamma_(*gamma),
- lambda_(*lambda),
- mu_(*mu),
- 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 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.");
- }
-}
-
-double GlmExpression::Mean() noexcept {
- return Compute(gamma_.Mean(), lambda_.Mean(), mu_.Mean(), time_.Mean());
-}
-
-double GlmExpression::GetSample() noexcept {
- return Compute(gamma_.Sample(), lambda_.Sample(), mu_.Sample(),
- time_.Sample());
-}
-
-double GlmExpression::Compute(double gamma, double lambda, double mu,
- double time) noexcept {
- double r = lambda + mu;
- return (lambda - (lambda - gamma * r) * std::exp(-r * time)) / r;
-}
-
-WeibullExpression::WeibullExpression(const ExpressionPtr& alpha,
- const ExpressionPtr& beta,
- const ExpressionPtr& t0,
- const ExpressionPtr& time)
- : Expression({alpha, beta, t0, time}),
- alpha_(*alpha),
- beta_(*beta),
- t0_(*t0),
- 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 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.");
- }
-}
-
-double WeibullExpression::Compute(double alpha, double beta,
- double t0, double time) noexcept {
- return 1 - std::exp(-std::pow((time - t0) / alpha, beta));
-}
-
UniformDeviate::UniformDeviate(const ExpressionPtr& min,
const ExpressionPtr& max)
: RandomDeviate({min, max}),
@@ -281,14 +108,12 @@ double LogNormalDeviate::GetSample() noexcept {
double LogNormalDeviate::Max() noexcept {
double sigma = ComputeScale(level_.Mean(), ef_.Mean());
double mu = ComputeLocation(mean_.Max(), sigma);
- return std::exp(
- std::sqrt(2) * std::pow(boost::math::erfc(1 / 50), -1) * sigma + mu);
+ return std::exp(3 * sigma + mu);
}
double LogNormalDeviate::ComputeScale(double level, double ef) noexcept {
- double p = level + (1 - level) / 2;
- double z = std::sqrt(2) * boost::math::erfc_inv(2 * p);
- return std::log(ef) / std::abs(z);
+ double z = -std::sqrt(2) * boost::math::erfc_inv(2 * level);
+ return std::log(ef) / z;
}
double LogNormalDeviate::ComputeLocation(double mean, double sigma) noexcept {
@@ -316,6 +141,12 @@ void GammaDeviate::Validate() const {
}
}
+double GammaDeviate::Max() noexcept {
+ using boost::math::gamma_q;
+ double k_max = k_.Max();
+ return theta_.Max() * std::pow(gamma_q(k_max, gamma_q(k_max, 0) - 0.99), -1);
+}
+
double GammaDeviate::GetSample() noexcept {
return Random::GammaGenerator(k_.Sample(), theta_.Sample());
}
@@ -341,6 +172,10 @@ void BetaDeviate::Validate() const {
}
}
+double BetaDeviate::Max() noexcept {
+ return std::pow(boost::math::ibeta(alpha_.Max(), beta_.Max(), 0.99), -1);
+}
+
double BetaDeviate::GetSample() noexcept {
return Random::BetaGenerator(alpha_.Sample(), beta_.Sample());
}
@@ -445,88 +280,5 @@ void Histogram::CheckWeights() const {
}
}
-Neg::Neg(const ExpressionPtr& expression)
- : Expression({expression}),
- expression_(*expression) {}
-
-BinaryExpression::BinaryExpression(std::vector<ExpressionPtr> args)
- : Expression(std::move(args)) {
- if (Expression::args().size() < 2)
- throw InvalidArgument("Expression requires 2 or more arguments.");
-}
-
-double Mul::Mean() noexcept {
- double mean = 1;
- for (const ExpressionPtr& arg : Expression::args())
- mean *= arg->Mean();
- return mean;
-}
-
-double Mul::GetSample() noexcept {
- double result = 1;
- for (const ExpressionPtr& arg : Expression::args())
- result *= arg->Sample();
- return result;
-}
-
-double Mul::GetExtremum(bool maximum) noexcept {
- double max_val = 1; // Maximum possible product.
- double min_val = 1; // Minimum possible product.
- for (const ExpressionPtr& arg : Expression::args()) {
- double mult_max = arg->Max();
- double mult_min = arg->Min();
- double max_max = max_val * mult_max;
- double max_min = max_val * mult_min;
- double min_max = min_val * mult_max;
- double min_min = min_val * mult_min;
- max_val = std::max({max_max, max_min, min_max, min_min});
- min_val = std::min({max_max, max_min, min_max, min_min});
- }
- return maximum ? max_val : min_val;
-}
-
-void Div::Validate() const {
- auto it = Expression::args().begin();
- for (++it; it != Expression::args().end(); ++it) {
- const auto& expr = *it;
- if (!expr->Mean() || !expr->Max() || !expr->Min())
- throw InvalidArgument("Division by 0.");
- }
-}
-
-double Div::Mean() noexcept {
- auto it = Expression::args().begin();
- double mean = (*it)->Mean();
- for (++it; it != Expression::args().end(); ++it) {
- mean /= (*it)->Mean();
- }
- return mean;
-}
-
-double Div::GetSample() noexcept {
- auto it = Expression::args().begin();
- double result = (*it)->Sample();
- for (++it; it != Expression::args().end(); ++it)
- result /= (*it)->Sample();
- return result;
-}
-
-double Div::GetExtremum(bool maximum) noexcept {
- auto it = Expression::args().begin();
- double max_value = (*it)->Max(); // Maximum possible result.
- double min_value = (*it)->Min(); // Minimum possible result.
- for (++it; it != Expression::args().end(); ++it) {
- double div_max = (*it)->Max();
- double div_min = (*it)->Min();
- double max_max = max_value / div_max;
- double max_min = max_value / div_min;
- double min_max = min_value / div_max;
- double min_min = min_value / div_min;
- max_value = std::max({max_max, max_min, min_max, min_min});
- min_value = std::min({max_max, max_min, min_max, min_min});
- }
- return maximum ? max_value : min_value;
-}
-
} // namespace mef
} // namespace scram
diff --git a/src/expression/random_deviate.h b/src/expression/random_deviate.h
new file mode 100644
index 0000000..2dfc2fc
--- /dev/null
+++ b/src/expression/random_deviate.h
@@ -0,0 +1,267 @@
+/*
+ * Copyright (C) 2014-2016 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 <http://www.gnu.org/licenses/>.
+ */
+
+/// @file random_deviate.h
+/// A collection of deviate expressions with random distributions
+/// sampled at run-time.
+
+#ifndef SCRAM_SRC_EXPRESSION_RANDOM_DEVIATE_H_
+#define SCRAM_SRC_EXPRESSION_RANDOM_DEVIATE_H_
+
+#include <utility>
+#include <vector>
+
+#include "src/expression.h"
+
+namespace scram {
+namespace mef {
+
+/// Abstract base class for all deviate expressions.
+/// These expressions provide quantification for uncertainty and sensitivity.
+class RandomDeviate : public Expression {
+ public:
+ using Expression::Expression;
+
+ bool IsConstant() noexcept override { return false; }
+};
+
+/// Uniform distribution.
+class UniformDeviate : public RandomDeviate {
+ public:
+ /// Setup for uniform distribution.
+ ///
+ /// @param[in] min Minimum value of the distribution.
+ /// @param[in] max Maximum value of the distribution.
+ UniformDeviate(const ExpressionPtr& min, const ExpressionPtr& max);
+
+ /// @throws InvalidArgument The min value is more or equal to max value.
+ void Validate() const override;
+
+ double Mean() noexcept override { return (min_.Mean() + max_.Mean()) / 2; }
+ double Max() noexcept override { return max_.Max(); }
+ double Min() noexcept override { return min_.Min(); }
+
+ private:
+ double GetSample() noexcept override;
+
+ Expression& min_; ///< Minimum value of the distribution.
+ Expression& max_; ///< Maximum value of the distribution.
+};
+
+/// Normal distribution.
+class NormalDeviate : public RandomDeviate {
+ public:
+ /// Setup for normal distribution.
+ ///
+ /// @param[in] mean The mean of the distribution.
+ /// @param[in] sigma The standard deviation of the distribution.
+ NormalDeviate(const ExpressionPtr& mean, const ExpressionPtr& sigma);
+
+ /// @throws InvalidArgument The sigma is negative or zero.
+ void Validate() const override;
+
+ double Mean() noexcept override { return mean_.Mean(); }
+
+ /// @returns ~99.9% percentile value.
+ ///
+ /// @warning This is only an approximation of the maximum value.
+ double Max() noexcept override { return mean_.Max() + 6 * sigma_.Max(); }
+
+ /// @returns Less than 0.1% percentile value.
+ ///
+ /// @warning This is only an approximation.
+ double Min() noexcept override { return mean_.Min() - 6 * sigma_.Max(); }
+
+ private:
+ double GetSample() noexcept override;
+
+ Expression& mean_; ///< Mean value of normal distribution.
+ Expression& sigma_; ///< Standard deviation of normal distribution.
+};
+
+/// Log-normal distribution defined by
+/// its expected value and error factor of certain confidence level.
+class LogNormalDeviate : public RandomDeviate {
+ public:
+ /// Setup for log-normal distribution.
+ ///
+ /// @param[in] mean The mean of the log-normal distribution
+ /// not the mean of underlying normal distribution,
+ /// which is parameter mu.
+ /// mu is the location parameter,
+ /// sigma is the scale factor.
+ /// E(x) = exp(mu + sigma^2 / 2)
+ /// @param[in] ef The error factor of the log-normal distribution.
+ /// EF = exp(z_alpha * sigma)
+ /// @param[in] level The confidence level.
+ LogNormalDeviate(const ExpressionPtr& mean, const ExpressionPtr& ef,
+ const ExpressionPtr& level);
+
+ /// @throws InvalidArgument (mean <= 0) or (ef <= 0) or invalid level
+ void Validate() const override;
+
+ double Mean() noexcept override { return mean_.Mean(); }
+
+ /// 99.9 percentile estimate.
+ double Max() noexcept override;
+
+ double Min() noexcept override { return 0; }
+
+ private:
+ double GetSample() noexcept override;
+
+ /// Computes the scale parameter of the distribution.
+ ///
+ /// @param[in] level The confidence level.
+ /// @param[in] ef The error factor of the log-normal distribution.
+ ///
+ /// @returns Scale parameter (sigma) value.
+ double ComputeScale(double level, double ef) noexcept;
+
+ /// Computes the location parameter of the distribution.
+ ///
+ /// @param[in] mean The mean of the log-normal distribution.
+ /// @param[in] sigma The scale parameter of the distribution.
+ ///
+ /// @returns Value of location parameter (mu) value.
+ double ComputeLocation(double mean, double sigma) noexcept;
+
+ Expression& mean_; ///< Mean value of the log-normal distribution.
+ Expression& ef_; ///< Error factor of the log-normal distribution.
+ Expression& level_; ///< Confidence level of the log-normal distribution.
+};
+
+/// Gamma distribution.
+class GammaDeviate : public RandomDeviate {
+ public:
+ /// Setup for Gamma distribution.
+ ///
+ /// @param[in] k Shape parameter of Gamma distribution.
+ /// @param[in] theta Scale parameter of Gamma distribution.
+ GammaDeviate(const ExpressionPtr& k, const ExpressionPtr& theta);
+
+ /// @throws InvalidArgument (k <= 0) or (theta <= 0)
+ void Validate() const override;
+
+ double Mean() noexcept override { return k_.Mean() * theta_.Mean(); }
+
+ /// @returns 99 percentile.
+ double Max() noexcept override;
+
+ double Min() noexcept override { return 0; }
+
+ private:
+ double GetSample() noexcept override;
+
+ Expression& k_; ///< The shape parameter of the gamma distribution.
+ Expression& theta_; ///< The scale factor of the gamma distribution.
+};
+
+/// Beta distribution.
+class BetaDeviate : public RandomDeviate {
+ public:
+ /// Setup for Beta distribution.
+ ///
+ /// @param[in] alpha Alpha shape parameter of Gamma distribution.
+ /// @param[in] beta Beta shape parameter of Gamma distribution.
+ BetaDeviate(const ExpressionPtr& alpha, const ExpressionPtr& beta);
+
+ /// @throws InvalidArgument (alpha <= 0) or (beta <= 0)
+ void Validate() const override;
+
+ double Mean() noexcept override {
+ double alpha_mean = alpha_.Mean();
+ return alpha_mean / (alpha_mean + beta_.Mean());
+ }
+
+ /// @returns 99 percentile.
+ double Max() noexcept override;
+
+ double Min() noexcept override { return 0; }
+
+ private:
+ double GetSample() noexcept override;
+
+ Expression& alpha_; ///< The alpha shape parameter.
+ Expression& beta_; ///< The beta shape parameter.
+};
+
+/// Histogram distribution.
+class Histogram : public RandomDeviate {
+ public:
+ /// Histogram distribution setup.
+ ///
+ /// @param[in] boundaries The bounds of intervals.
+ /// @param[in] weights The positive weights of intervals
+ /// restricted by the upper boundaries.
+ /// Therefore, the number of weights must be
+ /// equal to the number of intervals.
+ ///
+ /// @throws InvalidArgument The boundaries container size is not equal to
+ /// weights container size + 1.
+ ///
+ /// @note This description of histogram sampling is mostly for probabilities.
+ /// Therefore, it is not flexible.
+ /// Currently, it allows sampling both boundaries and weights.
+ /// This behavior makes checking
+ /// for valid arrangement of the boundaries mandatory
+ /// for each sampling.
+ /// Moreover, the first starting point is assumed but not defined.
+ /// The starting point is assumed to be 0,
+ /// which leaves only positive values for boundaries.
+ /// This behavior is restrictive
+ /// and should be handled accordingly.
+ Histogram(std::vector<ExpressionPtr> boundaries,
+ std::vector<ExpressionPtr> weights);
+
+ /// @throws InvalidArgument The boundaries are not strictly increasing,
+ /// or weights are negative.
+ void Validate() const override {
+ CheckBoundaries();
+ CheckWeights();
+ }
+
+ double Mean() noexcept override;
+ double Max() noexcept override {
+ return (*std::prev(boundaries_.second))->Max();
+ }
+ double Min() noexcept override { return 0; }
+
+ private:
+ /// Access to args.
+ using Iterator = std::vector<ExpressionPtr>::const_iterator;
+
+ double GetSample() noexcept override;
+
+ /// Checks if values of boundary expressions are strictly increasing.
+ ///
+ /// @throws InvalidArgument The mean values are not strictly increasing.
+ void CheckBoundaries() const;
+
+ /// Checks if values of weights are non-negative.
+ ///
+ /// @throws InvalidArgument The mean values are negative.
+ void CheckWeights() const;
+
+ std::pair<Iterator, Iterator> boundaries_; ///< Boundaries of the intervals.
+ std::pair<Iterator, Iterator> weights_; ///< Weights of the intervals.
+};
+
+} // namespace mef
+} // namespace scram
+
+#endif // SCRAM_SRC_EXPRESSION_RANDOM_DEVIATE_H_
diff --git a/src/ext.h b/src/ext.h
index 65f5047..e428313 100644
--- a/src/ext.h
+++ b/src/ext.h
@@ -23,7 +23,6 @@
#include <algorithm>
#include <memory>
-#include <type_traits>
#include <boost/range/algorithm/find_if.hpp>
@@ -143,6 +142,18 @@ bool all_of(const SinglePassRange& rng, UnaryPredicate pred) {
}
/// @}
+/// Passes an unmanaged resource to a smart pointer
+/// with automatic type deduction.
+/// This is a helper function to avoid boilerplate code.
+/// This helper would be unnecessary
+/// if template arguments could be deduced from constructors.
+///
+/// @param[in] dumb_handle A raw pointer to the resource.
+///
+/// @returns A smart pointer exclusively owning the resource.
+template <typename T>
+auto make_unique(T* dumb_handle) { return std::unique_ptr<T>(dumb_handle); }
+
} // namespace ext
#endif // SCRAM_SRC_EXT_H_
diff --git a/src/fault_tree.cc b/src/fault_tree.cc
index 25102be..88e1ef4 100644
--- a/src/fault_tree.cc
+++ b/src/fault_tree.cc
@@ -20,9 +20,6 @@
#include "fault_tree.h"
-#include <utility>
-
-#include "cycle.h"
#include "error.h"
namespace scram {
diff --git a/src/fault_tree.h b/src/fault_tree.h
index a0d50a1..817174e 100644
--- a/src/fault_tree.h
+++ b/src/fault_tree.h
@@ -31,7 +31,7 @@
#include "ccf_group.h"
#include "element.h"
#include "event.h"
-#include "expression.h"
+#include "parameter.h"
namespace scram {
namespace mef {
diff --git a/src/fault_tree_analysis.cc b/src/fault_tree_analysis.cc
index b7f2fa8..97106e8 100644
--- a/src/fault_tree_analysis.cc
+++ b/src/fault_tree_analysis.cc
@@ -21,11 +21,14 @@
#include "fault_tree_analysis.h"
#include <algorithm>
+#include <iostream>
#include <utility>
#include <boost/container/flat_set.hpp>
#include <boost/range/algorithm.hpp>
+#include "event.h"
+
namespace scram {
namespace core {
diff --git a/src/fault_tree_analysis.h b/src/fault_tree_analysis.h
index 0b93604..adfcd44 100644
--- a/src/fault_tree_analysis.h
+++ b/src/fault_tree_analysis.h
@@ -31,12 +31,17 @@
#include "analysis.h"
#include "boolean_graph.h"
-#include "event.h"
#include "logger.h"
#include "preprocessor.h"
#include "settings.h"
namespace scram {
+
+namespace mef { // Decouple from the analysis code.
+class Gate;
+class BasicEvent;
+} // namespace mef
+
namespace core {
/// Event or its complement
diff --git a/src/importance_analysis.cc b/src/importance_analysis.cc
index c60e1d5..77a88e1 100644
--- a/src/importance_analysis.cc
+++ b/src/importance_analysis.cc
@@ -24,6 +24,7 @@
#include <algorithm>
#include <unordered_set>
+#include "event.h"
#include "logger.h"
namespace scram {
diff --git a/src/importance_analysis.h b/src/importance_analysis.h
index cb62ba8..3572fc7 100644
--- a/src/importance_analysis.h
+++ b/src/importance_analysis.h
@@ -28,11 +28,15 @@
#include <vector>
#include "bdd.h"
-#include "event.h"
#include "probability_analysis.h"
#include "settings.h"
namespace scram {
+
+namespace mef { // Decouple from the analysis code header.
+class BasicEvent;
+} // namespace mef
+
namespace core {
/// Collection of importance factors for variables.
@@ -126,11 +130,6 @@ class ImportanceAnalyzerBase : public ImportanceAnalysis {
/// to calculate the total and conditional probabilities for factors.
///
/// @param[in] prob_analyzer Instantiated probability analyzer.
- ///
- /// @pre Probability analyzer can work with modified probability values.
- ///
- /// @post Probability analyzer's probability values are
- /// reset to the original values (event probabilities).
explicit ImportanceAnalyzerBase(
ProbabilityAnalyzer<Calculator>* prob_analyzer)
: ImportanceAnalysis(prob_analyzer),
@@ -167,32 +166,35 @@ class ImportanceAnalyzerBase : public ImportanceAnalysis {
template <class Calculator>
class ImportanceAnalyzer : public ImportanceAnalyzerBase<Calculator> {
public:
- using ImportanceAnalyzerBase<Calculator>::ImportanceAnalyzerBase;
+ /// @copydoc ImportanceAnalyzerBase<Calculator>::ImportanceAnalyzerBase
+ explicit ImportanceAnalyzer(ProbabilityAnalyzer<Calculator>* prob_analyzer)
+ : ImportanceAnalyzerBase<Calculator>(prob_analyzer),
+ p_vars_(prob_analyzer->p_vars()) {}
private:
double CalculateMif(int index) noexcept override;
+ std::vector<double> p_vars_; ///< A private copy of variable probabilities.
};
template <class Calculator>
double ImportanceAnalyzer<Calculator>::CalculateMif(int index) noexcept {
using Base = ImportanceAnalyzerBase<Calculator>;
- std::vector<double>& p_vars = Base::prob_analyzer()->p_vars();
+
+ double p_store = p_vars_[index]; // Save the original value for restoring.
+
// Calculate P(top/event)
- p_vars[index] = 1;
- double p_e = Base::prob_analyzer()->CalculateTotalProbability();
- assert(p_e >= 0);
- if (p_e > 1)
- p_e = 1;
+ p_vars_[index] = 1;
+ double p_e = Base::prob_analyzer()->CalculateTotalProbability(p_vars_);
+ assert(p_e >= 0 && p_e <= 1);
// Calculate P(top/Not event)
- p_vars[index] = 0;
- double p_not_e = Base::prob_analyzer()->CalculateTotalProbability();
- assert(p_not_e >= 0);
- if (p_not_e > 1)
- p_not_e = 1;
-
- // Restore the probability.
- p_vars[index] = Base::prob_analyzer()->graph()->GetBasicEvent(index)->p();
+ p_vars_[index] = 0;
+ double p_not_e = Base::prob_analyzer()->CalculateTotalProbability(p_vars_);
+ assert(p_not_e >= 0 && p_not_e <= 1);
+
+ // Restore the probability for next importance calculation.
+ p_vars_[index] = p_store;
+
return p_e - p_not_e;
}
diff --git a/src/initializer.cc b/src/initializer.cc
index 34153f0..fd0081c 100644
--- a/src/initializer.cc
+++ b/src/initializer.cc
@@ -28,6 +28,9 @@
#include "cycle.h"
#include "env.h"
#include "error.h"
+#include "expression/arithmetic.h"
+#include "expression/exponential.h"
+#include "expression/random_deviate.h"
#include "logger.h"
#include "xml.h"
@@ -62,8 +65,7 @@ RoleSpecifier GetRole(const std::string& s, RoleSpecifier parent_role) {
Initializer::Initializer(const std::vector<std::string>& xml_files,
core::Settings settings)
: settings_(std::move(settings)),
- mission_time_(std::make_shared<MissionTime>()) {
- mission_time_->mission_time(settings_.mission_time());
+ mission_time_(std::make_shared<MissionTime>(settings_.mission_time())) {
try {
ProcessInputFiles(xml_files);
} catch (const CycleError&) {
@@ -368,7 +370,8 @@ FormulaPtr Initializer::GetFormula(const xmlpp::Element* formula_node,
type = "null";
}
- int pos = boost::find(kOperatorToString, type) - kOperatorToString.begin();
+ int pos =
+ boost::find(kOperatorToString, type) - std::begin(kOperatorToString);
assert(pos < kNumOperators && "Unexpected operator type.");
FormulaPtr formula(new Formula(static_cast<Operator>(pos)));
@@ -533,7 +536,7 @@ ParameterPtr Initializer::RegisterParameter(const xmlpp::Element* param_node,
// Attach units.
std::string unit = GetAttributeValue(param_node, "unit");
if (!unit.empty()) {
- int pos = boost::find(kUnitsToString, unit) - kUnitsToString.begin();
+ int pos = boost::find(kUnitsToString, unit) - std::begin(kUnitsToString);
assert(pos < kNumUnits && "Unexpected unit kind.");
parameter->unit(static_cast<Units>(pos));
}
diff --git a/src/initializer.h b/src/initializer.h
index d18f7c3..6f15306 100644
--- a/src/initializer.h
+++ b/src/initializer.h
@@ -34,8 +34,10 @@
#include "element.h"
#include "event.h"
#include "expression.h"
+#include "expression/constant.h"
#include "fault_tree.h"
#include "model.h"
+#include "parameter.h"
#include "settings.h"
namespace scram {
@@ -133,7 +135,7 @@ class Initializer : private boost::noncopyable {
/// Attaches attributes and a label to the elements of the analysis.
/// These attributes are not XML attributes
- /// but OpenPSA format defined arbitrary attributes
+ /// but the Open-PSA format defined arbitrary attributes
/// and a label that can be attached to many analysis elements.
///
/// @param[in] element_node XML element.
diff --git a/src/logger.cc b/src/logger.cc
index 8828171..250a561 100644
--- a/src/logger.cc
+++ b/src/logger.cc
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2014-2015 Olzhas Rakhimov
+ * Copyright (C) 2014-2016 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
@@ -20,6 +20,8 @@
#include "logger.h"
+#include <cstdio>
+
#include <string>
#include "error.h"
@@ -31,11 +33,26 @@ const char* const Logger::kLevelToString_[] = {"ERROR", "WARNING", "INFO",
"DEBUG4", "DEBUG5"};
LogLevel Logger::report_level_ = ERROR;
+Logger::~Logger() noexcept {
+ os_ << std::endl;
+ // fprintf used for thread safety.
+ std::fprintf(stderr, "%s", os_.str().c_str());
+ std::fflush(stderr);
+}
+
void Logger::SetVerbosity(int level) {
- if (level < 0 || level > kMaxVerbosity)
+ if (level < 0 || level > kMaxVerbosity) {
throw InvalidArgument("Log verbosity must be between 0 and " +
std::to_string(kMaxVerbosity));
+ }
report_level_ = static_cast<LogLevel>(level);
}
+std::ostringstream& Logger::Get(LogLevel level) {
+ os_ << Logger::kLevelToString_[level] << ": ";
+ if (level >= DEBUG1)
+ os_ << std::string(level - DEBUG1 + 1, '\t');
+ return os_;
+}
+
} // namespace scram
diff --git a/src/logger.h b/src/logger.h
index 1da2858..e274cef 100644
--- a/src/logger.h
+++ b/src/logger.h
@@ -30,11 +30,9 @@
#define SCRAM_SRC_LOGGER_H_
#include <cstdint>
-#include <cstdio>
#include <chrono>
#include <sstream>
-#include <string>
#include <boost/noncopyable.hpp>
@@ -96,12 +94,7 @@ const int kMaxVerbosity = 7; ///< The index of the last level.
class Logger : private boost::noncopyable {
public:
/// Flashes all the logs into the standard error upon destruction.
- ~Logger() noexcept {
- os_ << std::endl;
- // fprintf used for thread safety.
- std::fprintf(stderr, "%s", os_.str().c_str());
- std::fflush(stderr);
- }
+ ~Logger() noexcept;
/// @returns Reference to the cut-off level for reporting.
static LogLevel report_level() { return report_level_; }
@@ -124,19 +117,16 @@ class Logger : private boost::noncopyable {
/// @param[in] level The log level for the information.
///
/// @returns Formatted output stringstream with the log level information.
- std::ostringstream& Get(LogLevel level) {
- os_ << Logger::kLevelToString_[level] << ": ";
- os_ << std::string(level < DEBUG1 ? 0 : level - DEBUG1 + 1, '\t');
- return os_;
- }
+ std::ostringstream& Get(LogLevel level);
private:
/// Translates the logging level into a string.
/// The index is the value of the enum.
static const char* const kLevelToString_[];
- std::ostringstream os_; ///< Main stringstream to gather the logs.
static LogLevel report_level_; ///< Cut-off log level for reporting.
+
+ std::ostringstream os_; ///< Main stringstream to gather the logs.
};
} // namespace scram
diff --git a/src/model.cc b/src/model.cc
index d1e4c60..820e98f 100644
--- a/src/model.cc
+++ b/src/model.cc
@@ -20,6 +20,8 @@
#include "model.h"
+#include "ext.h"
+
namespace scram {
namespace mef {
@@ -68,6 +70,49 @@ void Model::AddCcfGroup(const CcfGroupPtr& ccf_group) {
}
}
+ParameterPtr Model::GetParameter(const std::string& entity_reference,
+ const std::string& base_path) {
+ return GetEntity(entity_reference, base_path, parameters_);
+}
+
+HouseEventPtr Model::GetHouseEvent(const std::string& entity_reference,
+ const std::string& base_path) {
+ return GetEntity(entity_reference, base_path, house_events_);
+}
+
+BasicEventPtr Model::GetBasicEvent(const std::string& entity_reference,
+ const std::string& base_path) {
+ return GetEntity(entity_reference, base_path, basic_events_);
+}
+
+GatePtr Model::GetGate(const std::string& entity_reference,
+ const std::string& base_path) {
+ return GetEntity(entity_reference, base_path, gates_);
+}
+
+template <class T>
+std::shared_ptr<T> Model::GetEntity(const std::string& entity_reference,
+ const std::string& base_path,
+ const LookupTable<T>& container) {
+ assert(!entity_reference.empty());
+ if (!base_path.empty()) { // Check the local scope.
+ if (auto it = ext::find(container.entities_by_path,
+ base_path + "." + entity_reference))
+ return *it;
+ }
+
+ auto at = [&entity_reference](const auto& reference_container) {
+ if (auto it = ext::find(reference_container, entity_reference))
+ return *it;
+ throw std::out_of_range("The event cannot be found.");
+ };
+
+ if (entity_reference.find('.') == std::string::npos) // Public entity.
+ return at(container.entities_by_id);
+
+ return at(container.entities_by_path); // Direct access.
+}
+
/// Helper macro for Model::BindEvent event discovery.
#define BIND_EVENT(access, path_reference) \
if (auto it = ext::find(gates_.access, path_reference)) \
diff --git a/src/model.h b/src/model.h
index f6eff84..4e89120 100644
--- a/src/model.h
+++ b/src/model.h
@@ -34,9 +34,8 @@
#include "ccf_group.h"
#include "element.h"
#include "event.h"
-#include "ext.h"
-#include "expression.h"
#include "fault_tree.h"
+#include "parameter.h"
namespace scram {
namespace mef {
@@ -122,21 +121,13 @@ class Model : public Element, boost::noncopyable {
/// @throws std::out_of_range The entity cannot be found.
/// @{
ParameterPtr GetParameter(const std::string& entity_reference,
- const std::string& base_path) {
- return GetEntity(entity_reference, base_path, parameters_);
- }
+ const std::string& base_path);
HouseEventPtr GetHouseEvent(const std::string& entity_reference,
- const std::string& base_path) {
- return GetEntity(entity_reference, base_path, house_events_);
- }
+ const std::string& base_path);
BasicEventPtr GetBasicEvent(const std::string& entity_reference,
- const std::string& base_path) {
- return GetEntity(entity_reference, base_path, basic_events_);
- }
+ const std::string& base_path);
GatePtr GetGate(const std::string& entity_reference,
- const std::string& base_path) {
- return GetEntity(entity_reference, base_path, gates_);
- }
+ const std::string& base_path);
/// @}
/// Binds a formula with its argument event.
@@ -202,25 +193,7 @@ class Model : public Element, boost::noncopyable {
template <class T>
std::shared_ptr<T> GetEntity(const std::string& entity_reference,
const std::string& base_path,
- const LookupTable<T>& container) {
- assert(!entity_reference.empty());
- if (!base_path.empty()) { // Check the local scope.
- if (auto it = ext::find(container.entities_by_path,
- base_path + "." + entity_reference))
- return *it;
- }
-
- auto at = [&entity_reference](const auto& reference_container) {
- if (auto it = ext::find(reference_container, entity_reference))
- return *it;
- throw std::out_of_range("The event cannot be found.");
- };
-
- if (entity_reference.find('.') == std::string::npos) // Public entity.
- return at(container.entities_by_id);
-
- return at(container.entities_by_path); // Direct access.
- }
+ const LookupTable<T>& container);
/// A collection of defined constructs in the model.
/// @{
diff --git a/src/logger.cc b/src/parameter.cc
similarity index 51%
copy from src/logger.cc
copy to src/parameter.cc
index 8828171..6754f81 100644
--- a/src/logger.cc
+++ b/src/parameter.cc
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2014-2015 Olzhas Rakhimov
+ * Copyright (C) 2014-2016 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
@@ -15,27 +15,32 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-/// @file logger.cc
-/// Initializing static members of Logger class.
+/// @file parameter.cc
+/// Implementation of expression parameters.
-#include "logger.h"
-
-#include <string>
+#include "parameter.h"
#include "error.h"
namespace scram {
-
-const char* const Logger::kLevelToString_[] = {"ERROR", "WARNING", "INFO",
- "DEBUG1", "DEBUG2", "DEBUG3",
- "DEBUG4", "DEBUG5"};
-LogLevel Logger::report_level_ = ERROR;
-
-void Logger::SetVerbosity(int level) {
- if (level < 0 || level > kMaxVerbosity)
- throw InvalidArgument("Log verbosity must be between 0 and " +
- std::to_string(kMaxVerbosity));
- report_level_ = static_cast<LogLevel>(level);
+namespace mef {
+
+Parameter::Parameter(std::string name, std::string base_path,
+ RoleSpecifier role)
+ : Expression({}),
+ Element(std::move(name)),
+ Role(role, std::move(base_path)),
+ Id(*this, *this),
+ unit_(kUnitless),
+ unused_(true),
+ expression_(nullptr) {}
+
+void Parameter::expression(const ExpressionPtr& expression) {
+ if (expression_)
+ throw LogicError("Parameter expression is already set.");
+ expression_ = expression.get();
+ Expression::AddArg(expression);
}
+} // namespace mef
} // namespace scram
diff --git a/src/parameter.h b/src/parameter.h
new file mode 100644
index 0000000..fbfd1a2
--- /dev/null
+++ b/src/parameter.h
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2014-2016 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 <http://www.gnu.org/licenses/>.
+ */
+
+/// @file parameter.h
+/// Parameter expressions that act like a shareable variable.
+
+#ifndef SCRAM_SRC_PARAMETER_H_
+#define SCRAM_SRC_PARAMETER_H_
+
+#include <memory>
+#include <string>
+
+#include "element.h"
+#include "expression.h"
+
+namespace scram {
+namespace mef {
+
+/// This class provides a representation of a variable
+/// in basic event description.
+/// It is both expression and element description.
+class Parameter : public Expression,
+ public Element,
+ public Role,
+ public Id,
+ public NodeMark {
+ public:
+ /// Creates a parameter as a variable for future references.
+ ///
+ /// @param[in] name The name of this variable (Case sensitive).
+ /// @param[in] base_path The series of containers to get this parameter.
+ /// @param[in] role The role of the parameter within the model or container.
+ ///
+ /// @throws LogicError The name is empty.
+ /// @throws InvalidArgument The name or reference paths are malformed.
+ explicit Parameter(std::string name, std::string base_path = "",
+ RoleSpecifier role = RoleSpecifier::kPublic);
+
+ /// Sets the expression of this parameter.
+ ///
+ /// @param[in] expression The expression to describe this parameter.
+ ///
+ /// @throws LogicError The parameter expression is already set.
+ void expression(const ExpressionPtr& expression);
+
+ /// @returns The unit of this parameter.
+ Units unit() const { return unit_; }
+
+ /// Sets the unit of this parameter.
+ ///
+ /// @param[in] unit A valid unit.
+ void unit(Units unit) { unit_ = unit; }
+
+ /// @returns The usage state of this parameter.
+ bool unused() { return unused_; }
+
+ /// Sets the usage state for this parameter.
+ ///
+ /// @param[in] state The usage state for this parameter.
+ void unused(bool state) { unused_ = state; }
+
+ double Mean() noexcept override { return expression_->Mean(); }
+ double Max() noexcept override { return expression_->Max(); }
+ double Min() noexcept override { return expression_->Min(); }
+
+ private:
+ double GetSample() noexcept override { return expression_->Sample(); }
+
+ Units unit_; ///< Units of this parameter.
+ bool unused_; ///< Usage state.
+ Expression* expression_; ///< Expression for this parameter.
+};
+
+using ParameterPtr = std::shared_ptr<Parameter>; ///< Shared parameters.
+
+} // namespace mef
+} // namespace scram
+
+#endif // SCRAM_SRC_PARAMETER_H_
diff --git a/src/preprocessor.cc b/src/preprocessor.cc
index e2a734c..f901b25 100644
--- a/src/preprocessor.cc
+++ b/src/preprocessor.cc
@@ -78,6 +78,7 @@
#include <queue>
#include <unordered_set>
+#include <boost/functional/hash.hpp>
#include <boost/math/special_functions/sign.hpp>
#include <boost/range/algorithm.hpp>
#include <boost/range/algorithm_ext.hpp>
@@ -117,6 +118,64 @@ void Preprocessor::Run() noexcept {
}
}
+/// Container of unique gates.
+/// This container acts like an unordered set of gates.
+/// The gates are equivalent
+/// if they have the same semantics.
+/// However, this set does not test
+/// for the isomorphism of the gates' Boolean formulas.
+class Preprocessor::GateSet {
+ public:
+ /// Inserts a gate into the set
+ /// if it is semantically unique.
+ ///
+ /// @param[in] gate The gate to insert.
+ ///
+ /// @returns A pair of the unique gate and
+ /// the insertion success flag.
+ std::pair<GatePtr, bool> insert(const GatePtr& gate) noexcept {
+ auto result = table_[gate->type()].insert(gate);
+ return {*result.first, result.second};
+ }
+
+ private:
+ /// Functor for hashing gates by their arguments.
+ ///
+ /// @note The hashing discards the logic of the gate.
+ struct Hash {
+ /// Operator overload for hashing.
+ ///
+ /// @param[in] gate The gate which hash must be calculated.
+ ///
+ /// @returns Hash value of the gate
+ /// from its arguments but not logic.
+ std::size_t operator()(const GatePtr& gate) const noexcept {
+ return boost::hash_range(gate->args().begin(), gate->args().end());
+ }
+ };
+ /// Functor for equality test for gates by their arguments.
+ ///
+ /// @note The equality discards the logic of the gate.
+ struct Equal {
+ /// Operator overload for gate argument equality test.
+ ///
+ /// @param[in] lhs The first gate.
+ /// @param[in] rhs The second gate.
+ ///
+ /// @returns true if the gate arguments are equal.
+ bool operator()(const GatePtr& lhs, const GatePtr& rhs) const noexcept {
+ assert(lhs->type() == rhs->type());
+ if (lhs->args() != rhs->args())
+ return false;
+ if (lhs->type() == kVote && lhs->vote_number() != rhs->vote_number())
+ return false;
+ return true;
+ }
+ };
+ /// Container of gates grouped by their types.
+ std::array<std::unordered_set<GatePtr, Hash, Equal>, kNumOperators> table_;
+};
+
namespace { // Boolean graph structure verification tools.
/// Functor to sanity check the marks of Boolean graph gates.
diff --git a/src/preprocessor.h b/src/preprocessor.h
index 95e0bd1..dfcf8f7 100644
--- a/src/preprocessor.h
+++ b/src/preprocessor.h
@@ -64,6 +64,8 @@ class Preprocessor : private boost::noncopyable {
virtual void Run() noexcept = 0;
protected:
+ class GateSet; ///< Container of unique gates by semantics.
+
/// The initial phase of preprocessing.
/// The most basic cleanup algorithms are applied.
/// The cleanup should benefit all other phases
diff --git a/src/probability_analysis.cc b/src/probability_analysis.cc
index 99c16c7..ea7e63f 100644
--- a/src/probability_analysis.cc
+++ b/src/probability_analysis.cc
@@ -21,6 +21,10 @@
#include "probability_analysis.h"
+#include "event.h"
+#include "logger.h"
+#include "settings.h"
+
namespace scram {
namespace core {
@@ -65,7 +69,7 @@ double RareEventCalculator::Calculate(
assert(!cut_set.empty() && "Detected an empty cut set.");
sum += CutSetProbabilityCalculator::Calculate(cut_set, p_vars);
}
- return sum;
+ return sum > 1 ? 1 : sum;
}
double McubCalculator::Calculate(
@@ -81,6 +85,13 @@ double McubCalculator::Calculate(
return 1 - m;
}
+void ProbabilityAnalyzerBase::ExtractVariableProbabilities() {
+ p_vars_.push_back(-1); // Padding.
+ for (const mef::BasicEvent* event : graph_->basic_events()) {
+ p_vars_.push_back(event->p());
+ }
+}
+
ProbabilityAnalyzer<Bdd>::ProbabilityAnalyzer(FaultTreeAnalyzer<Bdd>* fta)
: ProbabilityAnalyzerBase(fta),
owner_(false) {
@@ -95,22 +106,28 @@ ProbabilityAnalyzer<Bdd>::~ProbabilityAnalyzer() noexcept {
delete bdd_graph_;
}
-double ProbabilityAnalyzer<Bdd>::CalculateTotalProbability() noexcept {
+double ProbabilityAnalyzer<Bdd>::CalculateTotalProbability(
+ const std::vector<double>& p_vars) noexcept {
CLOCK(calc_time); // BDD based calculation time.
LOG(DEBUG4) << "Calculating probability with BDD...";
current_mark_ = !current_mark_;
- double prob = CalculateProbability(bdd_graph_->root().vertex, current_mark_);
+ double prob =
+ CalculateProbability(bdd_graph_->root().vertex, current_mark_, p_vars);
if (bdd_graph_->root().complement)
prob = 1 - prob;
LOG(DEBUG4) << "Calculated probability " << prob << " in " << DUR(calc_time);
return prob;
}
-void ProbabilityAnalyzer<Bdd>::CreateBdd(const mef::Gate& root) noexcept {
+void ProbabilityAnalyzer<Bdd>::CreateBdd(
+ const FaultTreeAnalysis& fta) noexcept {
+ CLOCK(total_time);
+
CLOCK(ft_creation);
BooleanGraph* bool_graph =
- new BooleanGraph(root, Analysis::settings().ccf_analysis());
+ new BooleanGraph(fta.top_event(), Analysis::settings().ccf_analysis());
LOG(DEBUG2) << "Boolean graph is created in " << DUR(ft_creation);
+
CLOCK(prep_time); // Overall preprocessing time.
LOG(DEBUG2) << "Preprocessing...";
Preprocessor* preprocessor = new CustomPreprocessor<Bdd>(bool_graph);
@@ -123,11 +140,14 @@ void ProbabilityAnalyzer<Bdd>::CreateBdd(const mef::Gate& root) noexcept {
bdd_graph_ = new Bdd(bool_graph, Analysis::settings());
LOG(DEBUG2) << "BDD is created in " << DUR(bdd_time);
delete bool_graph; // The original graph of FTA is usable with the BDD.
+
+ Analysis::AddAnalysisTime(DUR(total_time));
}
double ProbabilityAnalyzer<Bdd>::CalculateProbability(
const Bdd::VertexPtr& vertex,
- bool mark) noexcept {
+ bool mark,
+ const std::vector<double>& p_vars) noexcept {
if (vertex->terminal())
return 1;
ItePtr ite = Ite::Ptr(vertex);
@@ -137,14 +157,14 @@ double ProbabilityAnalyzer<Bdd>::CalculateProbability(
double p_var = 0;
if (ite->module()) {
const Bdd::Function& res = bdd_graph_->modules().find(ite->index())->second;
- p_var = CalculateProbability(res.vertex, mark);
+ p_var = CalculateProbability(res.vertex, mark, p_vars);
if (res.complement)
p_var = 1 - p_var;
} else {
- p_var = ProbabilityAnalyzerBase::p_vars()[ite->index()];
+ p_var = p_vars[ite->index()];
}
- double high = CalculateProbability(ite->high(), mark);
- double low = CalculateProbability(ite->low(), mark);
+ double high = CalculateProbability(ite->high(), mark, p_vars);
+ double low = CalculateProbability(ite->low(), mark, p_vars);
if (ite->complement_edge())
low = 1 - low;
ite->p(p_var * high + (1 - p_var) * low);
diff --git a/src/probability_analysis.h b/src/probability_analysis.h
index ff7373d..2f6510a 100644
--- a/src/probability_analysis.h
+++ b/src/probability_analysis.h
@@ -26,10 +26,7 @@
#include "analysis.h"
#include "bdd.h"
#include "boolean_graph.h"
-#include "event.h"
#include "fault_tree_analysis.h"
-#include "logger.h"
-#include "settings.h"
namespace scram {
namespace core {
@@ -114,10 +111,10 @@ class RareEventCalculator : private CutSetProbabilityCalculator {
///
/// @pre Absolute indices of events directly map to vector indices.
///
- /// @post The returned probability value may not be acceptable.
- /// That is, it may be out of the acceptable [0, 1] range.
- /// The caller of this function must decide
- /// what to do in this case.
+ /// @post In case the calculated probability exceeds 1,
+ /// the probability is adjusted to 1.
+ /// It is very unwise to use the rare-event approximation
+ /// with large probability values.
double Calculate(const std::vector<CutSet>& cut_sets,
const std::vector<double>& p_vars) noexcept;
};
@@ -148,7 +145,12 @@ class ProbabilityAnalyzerBase : public ProbabilityAnalysis {
///
/// @param[in] fta Finished fault tree analyzer with results.
template <class Algorithm>
- explicit ProbabilityAnalyzerBase(const FaultTreeAnalyzer<Algorithm>* fta);
+ explicit ProbabilityAnalyzerBase(const FaultTreeAnalyzer<Algorithm>* fta)
+ : ProbabilityAnalysis(fta),
+ graph_(fta->graph()),
+ products_(fta->algorithm()->products()) {
+ ExtractVariableProbabilities();
+ }
/// @returns The original Boolean graph from the fault tree analyzer.
const BooleanGraph* graph() const { return graph_; }
@@ -156,38 +158,28 @@ class ProbabilityAnalyzerBase : public ProbabilityAnalysis {
/// @returns The resulting products of the fault tree analyzer.
const std::vector<Product>& products() const { return products_; }
- /// @returns A modifiable mapping for probability values and indices.
- ///
- /// @pre Quantitative analyzers aware of how Probability analyzer works.
- /// @pre Quantitative analyzers will cleanup after themselves.
- ///
- /// @warning This is a hack
- /// due to tight coupling of Quantitative analyzers.
- ///
- /// @todo Redesign the use and manipulation of variable probabilities.
- std::vector<double>& p_vars() { return p_vars_; }
+ /// @returns A mapping for probability values and indices.
+ const std::vector<double>& p_vars() const { return p_vars_; }
protected:
~ProbabilityAnalyzerBase() = default;
private:
+ /// Upon construction of the probability analysis,
+ /// stores the variable probabilities in a continuous container
+ /// for retrieval by their indices instead of pointers.
+ ///
+ /// @note This function may seem redundant,
+ /// for it's super-short and simple to do it inline in the constructor.
+ /// The main benefit of the out-of-line implementation
+ /// is compile-time decoupling from the input BasicEvent classes.
+ void ExtractVariableProbabilities();
+
const BooleanGraph* graph_; ///< Boolean graph from the fault tree analysis.
const std::vector<Product>& products_; ///< A collection of products.
std::vector<double> p_vars_; ///< Variable probabilities.
};
-template <class Algorithm>
-ProbabilityAnalyzerBase::ProbabilityAnalyzerBase(
- const FaultTreeAnalyzer<Algorithm>* fta)
- : ProbabilityAnalysis(fta),
- graph_(fta->graph()),
- products_(fta->algorithm()->products()) {
- p_vars_.push_back(-1); // Padding.
- for (const mef::BasicEvent* event : graph_->basic_events()) {
- p_vars_.push_back(event->p());
- }
-}
-
/// Fault-tree-analysis-aware probability analyzer.
/// Probability analyzer provides the main engine for probability analysis.
///
@@ -197,15 +189,27 @@ class ProbabilityAnalyzer : public ProbabilityAnalyzerBase {
public:
using ProbabilityAnalyzerBase::ProbabilityAnalyzerBase;
+ /// Calculates the total probability
+ /// with a different set of probability values
+ /// than the one given upon construction.
+ ///
+ /// @param[in] p_vars A map of probabilities of the graph variables.
+ /// The indices of the variables must map
+ /// exactly to the vector indices.
+ ///
+ /// @returns The total probability calculated with the given values.
+ double CalculateTotalProbability(const std::vector<double>& p_vars) noexcept {
+ return calc_.Calculate(ProbabilityAnalyzerBase::products(), p_vars);
+ }
+
+ private:
/// Calculates the total probability.
///
/// @returns The total probability of the graph or the sum of products.
double CalculateTotalProbability() noexcept override {
- return calc_.Calculate(ProbabilityAnalyzerBase::products(),
- ProbabilityAnalyzerBase::p_vars());
+ return CalculateTotalProbability(ProbabilityAnalyzerBase::p_vars());
}
- private:
Calculator calc_; ///< Provider of the calculation logic.
};
@@ -221,7 +225,12 @@ class ProbabilityAnalyzer<Bdd> : public ProbabilityAnalyzerBase {
///
/// @param[in] fta Finished fault tree analyzer with results.
template <class Algorithm>
- explicit ProbabilityAnalyzer(const FaultTreeAnalyzer<Algorithm>* fta);
+ explicit ProbabilityAnalyzer(const FaultTreeAnalyzer<Algorithm>* fta)
+ : ProbabilityAnalyzerBase(fta),
+ current_mark_(false),
+ owner_(true) {
+ CreateBdd(*fta);
+ }
/// Reuses BDD structures from Fault tree analyzer.
///
@@ -240,47 +249,44 @@ class ProbabilityAnalyzer<Bdd> : public ProbabilityAnalyzerBase {
/// @returns Binary decision diagram used for calculations.
Bdd* bdd_graph() { return bdd_graph_; }
+ /// @copydoc ProbabilityAnalyzer::CalculateTotalProbability
+ double CalculateTotalProbability(const std::vector<double>& p_vars) noexcept;
+
+ private:
/// Calculates the total probability.
///
/// @returns The total probability of the graph.
- double CalculateTotalProbability() noexcept override;
+ double CalculateTotalProbability() noexcept override {
+ return CalculateTotalProbability(ProbabilityAnalyzerBase::p_vars());
+ }
- private:
/// Creates a new BDD for use by the analyzer.
///
- /// @param[in] root The root gate of the fault tree.
+ /// @param[in] fta The fault tree analysis providing the root gate.
///
/// @pre The function is called in the constructor only once.
- void CreateBdd(const mef::Gate& root) noexcept;
+ void CreateBdd(const FaultTreeAnalysis& fta) noexcept;
/// Calculates exact probability
/// of a function graph represented by its root BDD vertex.
///
/// @param[in] vertex The root vertex of a function graph.
/// @param[in] mark A flag to mark traversed vertices.
+ /// @param[in] p_vars The probabilities of the variables
+ /// mapped by their indices.
///
/// @returns Probability value.
///
/// @warning If a vertex is already marked with the input mark,
/// it will not be traversed and updated with a probability value.
- double CalculateProbability(const Bdd::VertexPtr& vertex, bool mark) noexcept;
+ double CalculateProbability(const Bdd::VertexPtr& vertex, bool mark,
+ const std::vector<double>& p_vars) noexcept;
Bdd* bdd_graph_; ///< The main BDD graph for analysis.
bool current_mark_; ///< To keep track of BDD current mark.
bool owner_; ///< Indication that pointers are handles.
};
-template <class Algorithm>
-ProbabilityAnalyzer<Bdd>::ProbabilityAnalyzer(
- const FaultTreeAnalyzer<Algorithm>* fta)
- : ProbabilityAnalyzerBase(fta),
- current_mark_(false),
- owner_(true) {
- CLOCK(main_time);
- CreateBdd(fta->top_event());
- Analysis::AddAnalysisTime(DUR(main_time));
-}
-
} // namespace core
} // namespace scram
diff --git a/src/random.h b/src/random.h
index 178676c..457d3f9 100644
--- a/src/random.h
+++ b/src/random.h
@@ -24,9 +24,10 @@
#include <cassert>
#include <cmath>
-#include <array>
#include <random>
-#include <vector>
+
+#include <boost/random/beta_distribution.hpp>
+#include <boost/random/triangle_distribution.hpp>
namespace scram {
@@ -36,6 +37,9 @@ namespace scram {
/// In other words, the user should make sure
/// that the passed parameters are valid.
/// For example, standard deviation cannot be negative.
+///
+/// This facility wraps the engine and distributions.
+/// It provides convenience and reproducibility for the whole analysis.
class Random {
public:
/// Sets the seed of the underlying random number generator.
@@ -45,16 +49,15 @@ class Random {
Random::rng_.seed(static_cast<unsigned>(seed));
}
- /// RNG from uniform distribution.
+ /// RNG from a uniform distribution.
///
- /// @param[in] min Lower bound.
- /// @param[in] max Upper bound.
+ /// @param[in] lower Lower bound.
+ /// @param[in] upper Upper bound.
///
/// @returns A sampled value.
- static double UniformRealGenerator(double min, double max) noexcept {
- assert(min < max);
- std::uniform_real_distribution<double> dist(min, max);
- return dist(rng_);
+ static double UniformRealGenerator(double lower, double upper) noexcept {
+ assert(lower < upper);
+ return std::uniform_real_distribution<>(lower, upper)(rng_);
}
/// RNG from a triangular distribution.
@@ -68,31 +71,29 @@ class Random {
double upper) noexcept {
assert(lower < mode);
assert(mode < upper);
- static const std::array<double, 3> weights = {0, 1, 0};
- std::array<double, 3> intervals = {lower, mode, upper};
- std::piecewise_linear_distribution<double> dist(intervals.begin(),
- intervals.end(),
- weights.begin());
- return dist(rng_);
+ return boost::random::triangle_distribution<>(lower, mode, upper)(rng_);
}
/// RNG from a piecewise linear distribution.
///
- /// @param[in] intervals Interval points for the distribution.
- /// The values must be strictly increasing.
- /// @param[in] weights Weights at the boundaries.
- /// The number of weights must be equal to
- /// the number of intervals (points - 1).
- /// Extra weights are ignored.
+ /// @tparam IteratorB Input iterator of interval boundaries returning double.
+ /// @tparam IteratorW Input iterator of weights returning double.
+ ///
+ /// @param[in] first_b The begin of the interval boundaries.
+ /// @param[in] last_b The sentinel end of the interval boundaries.
+ /// @param[in] first_w The begin of the interval weights.
///
/// @returns A sampled value.
- static double PiecewiseLinearGenerator(
- const std::vector<double>& intervals,
- const std::vector<double>& weights) noexcept {
- std::piecewise_linear_distribution<double> dist(intervals.begin(),
- intervals.end(),
- weights.begin());
- return dist(rng_);
+ ///
+ /// @pre Interval points for the distribution must be strictly increasing.
+ ///
+ /// @pre The number of weights must be equal to
+ /// the number of intervals (boundaries - 1).
+ /// Extra weights are ignored.
+ template <class IteratorB, class IteratorW>
+ static double PiecewiseLinearGenerator(IteratorB first_b, IteratorB last_b,
+ IteratorW first_w) noexcept {
+ return std::piecewise_linear_distribution<>(first_b, last_b, first_w)(rng_);
}
/// RNG from a histogram distribution.
@@ -114,35 +115,31 @@ class Random {
template <class IteratorB, class IteratorW>
static double HistogramGenerator(IteratorB first_b, IteratorB last_b,
IteratorW first_w) noexcept {
- std::piecewise_constant_distribution<double> dist(first_b, last_b, first_w);
+ std::piecewise_constant_distribution<> dist(first_b, last_b, first_w);
return dist(rng_);
}
/// RNG from a discrete distribution.
///
- /// @tparam T Type of discrete values.
+ /// @tparam Iterator Input iterator of weights returning double.
///
- /// @param[in] values Discrete values.
- /// @param[in] weights Weights for the corresponding values.
- /// The size must be the same as the values vector size.
+ /// @param[in] first1 The begin of the interval weights.
+ /// @param[in] last1 The sentinel end of the interval weights.
///
- /// @returns A sample Value from the value vector.
- template <typename T>
- static T DiscreteGenerator(const std::vector<T>& values,
- const std::vector<double>& weights) noexcept {
- assert(values.size() == weights.size());
- return values[DiscreteGenerator(weights)];
+ /// @returns Integer in the range [0, n).
+ template <class Iterator>
+ static int DiscreteGenerator(Iterator first1, Iterator last1) noexcept {
+ return std::discrete_distribution<>(first1, last1)(rng_);
}
- /// RNG from Binomial distribution.
+ /// RNG from a Binomial distribution.
///
/// @param[in] n Number of trials.
/// @param[in] p Probability of success.
///
/// @returns The number of successes.
static int BinomialGenerator(int n, double p) noexcept {
- std::binomial_distribution<int> dist(n, p);
- return dist(rng_);
+ return std::binomial_distribution<>(n, p)(rng_);
}
/// RNG from a normal distribution.
@@ -153,11 +150,10 @@ class Random {
/// @returns A sampled value.
static double NormalGenerator(double mean, double sigma) noexcept {
assert(sigma >= 0);
- std::normal_distribution<double> dist(mean, sigma);
- return dist(rng_);
+ return std::normal_distribution<>(mean, sigma)(rng_);
}
- /// RNG from lognormal distribution.
+ /// RNG from a lognormal distribution.
///
/// @param[in] m The m location parameter of the distribution.
/// @param[in] s The s scale factor of the distribution.
@@ -165,11 +161,10 @@ class Random {
/// @returns A sampled value.
static double LogNormalGenerator(double m, double s) noexcept {
assert(s >= 0);
- std::lognormal_distribution<double> dist(m, s);
- return dist(rng_);
+ return std::lognormal_distribution<>(m, s)(rng_);
}
- /// RNG from Gamma distribution.
+ /// RNG from a Gamma distribution.
///
/// @param[in] k Shape parameter of Gamma distribution.
/// @param[in] theta Scale parameter of Gamma distribution.
@@ -182,11 +177,10 @@ class Random {
static double GammaGenerator(double k, double theta) noexcept {
assert(k > 0);
assert(theta > 0);
- std::gamma_distribution<double> gamma_dist(k);
- return theta * gamma_dist(rng_);
+ return std::gamma_distribution<>(k)(rng_) * theta;
}
- /// RNG from Beta distribution.
+ /// RNG from a Beta distribution.
///
/// @param[in] alpha Alpha shape parameter of Beta distribution.
/// @param[in] beta Beta shape parameter of Beta distribution.
@@ -195,14 +189,10 @@ class Random {
static double BetaGenerator(double alpha, double beta) noexcept {
assert(alpha > 0);
assert(beta > 0);
- std::gamma_distribution<double> gamma_dist_x(alpha);
- std::gamma_distribution<double> gamma_dist_y(beta);
- double x = gamma_dist_x(rng_);
- double y = gamma_dist_y(rng_);
- return x / (x + y);
+ return boost::random::beta_distribution<>(alpha, beta)(rng_);
}
- /// RNG from Weibull distribution.
+ /// RNG from a Weibull distribution.
///
/// @param[in] k Shape parameter of Weibull distribution.
/// @param[in] lambda Scale parameter of Weibull distribution.
@@ -211,43 +201,40 @@ class Random {
static double WeibullGenerator(double k, double lambda) noexcept {
assert(k > 0);
assert(lambda > 0);
- std::weibull_distribution<double> dist(k, lambda);
- return dist(rng_);
+ return std::weibull_distribution<>(k, lambda)(rng_);
}
- /// RNG from Exponential distribution.
+ /// RNG from an Exponential distribution.
///
/// @param[in] lambda Rate parameter of Exponential distribution.
///
/// @returns A sampled value.
static double ExponentialGenerator(double lambda) noexcept {
assert(lambda > 0);
- std::exponential_distribution<double> dist(lambda);
- return dist(rng_);
+ return std::exponential_distribution<>(lambda)(rng_);
}
- /// RNG from Poisson distribution.
+ /// RNG from a Poisson distribution.
///
/// @param[in] mean The mean value for Poisson distribution.
///
/// @returns A sampled value.
static int PoissonGenerator(int mean) noexcept {
assert(mean > 0);
- std::poisson_distribution<int> dist(mean);
- return dist(rng_);
+ return std::poisson_distribution<>(mean)(rng_);
}
- /// RNG from log-uniform distribution.
+ /// RNG from a log-uniform distribution.
///
- /// @param[in] min Lower bound.
- /// @param[in] max Upper bound.
+ /// @param[in] lower Lower bound.
+ /// @param[in] upper Upper bound.
///
/// @returns A sampled value.
- static double LogUniformGenerator(double min, double max) noexcept {
- return std::exp(UniformRealGenerator(min, max));
+ static double LogUniformGenerator(double lower, double upper) noexcept {
+ return std::exp(UniformRealGenerator(lower, upper));
}
- /// RNG from log-triangular distribution.
+ /// RNG from a log-triangular distribution.
///
/// @param[in] lower Lower bound.
/// @param[in] mode The peak of the distribution.
@@ -260,17 +247,6 @@ class Random {
}
private:
- /// RNG from a discrete distribution.
- ///
- /// @param[in] weights Weights for the range [0, n),
- /// where n is the size of the vector.
- ///
- /// @returns Integer in the range [0, n).
- static int DiscreteGenerator(const std::vector<double>& weights) noexcept {
- std::discrete_distribution<int> dist(weights.begin(), weights.end());
- return dist(rng_);
- }
-
static std::mt19937 rng_; ///< The random number generator.
};
diff --git a/src/reporter.cc b/src/reporter.cc
index 68be8ea..d8e7906 100644
--- a/src/reporter.cc
+++ b/src/reporter.cc
@@ -20,13 +20,16 @@
#include "reporter.h"
+#include <fstream>
+#include <ostream>
#include <vector>
#include <boost/date_time.hpp>
#include "ccf_group.h"
-#include "expression.h"
+#include "error.h"
#include "logger.h"
+#include "parameter.h"
#include "version.h"
namespace scram {
@@ -58,6 +61,15 @@ void Reporter::Report(const core::RiskAnalysis& risk_an, std::ostream& out) {
LOG(DEBUG1) << "Finished reporting in " << DUR(report_time);
}
+void Reporter::Report(const core::RiskAnalysis& risk_an,
+ const std::string& file) {
+ std::ofstream of(file.c_str());
+ if (!of.good())
+ throw IOError(file + " : Cannot write the output file.");
+
+ Report(risk_an, of);
+}
+
/// Describes the fault tree analysis and techniques.
template <>
void Reporter::ReportCalculatedQuantity<core::FaultTreeAnalysis>(
diff --git a/src/reporter.h b/src/reporter.h
index 25e21fc..4f21c8a 100644
--- a/src/reporter.h
+++ b/src/reporter.h
@@ -21,7 +21,7 @@
#ifndef SCRAM_SRC_REPORTER_H_
#define SCRAM_SRC_REPORTER_H_
-#include <ostream>
+#include <iosfwd>
#include <string>
#include "event.h"
@@ -36,7 +36,7 @@
namespace scram {
-/// This class reports the results of the analyses.
+/// Facilities to report analysis results.
class Reporter {
public:
/// Reports the results of risk analysis on a model.
@@ -49,6 +49,15 @@ class Reporter {
/// There is going to be no appending to the stream after the report.
void Report(const core::RiskAnalysis& risk_an, std::ostream& out);
+ /// A convenience function to generate the report into a file.
+ /// This function overwrites the file.
+ ///
+ /// @param[in] risk_an Risk analysis with results.
+ /// @param[out] file The output destination.
+ ///
+ /// @throws IOError The output file is not accessible.
+ void Report(const core::RiskAnalysis& risk_an, const std::string& file);
+
private:
/// This function populates information
/// about the software, settings, time, methods, model, etc.
diff --git a/src/risk_analysis.cc b/src/risk_analysis.cc
index 78241e1..52c087f 100644
--- a/src/risk_analysis.cc
+++ b/src/risk_analysis.cc
@@ -20,19 +20,12 @@
#include "risk_analysis.h"
-#include <fstream>
-#include <utility>
-#include <vector>
-
#include "bdd.h"
-#include "error.h"
-#include "expression.h"
+#include "ext.h"
#include "fault_tree.h"
#include "logger.h"
#include "mocus.h"
-#include "model.h"
#include "random.h"
-#include "reporter.h"
#include "zbdd.h"
namespace scram {
@@ -48,6 +41,7 @@ void RiskAnalysis::Analyze() noexcept {
// Otherwise it defaults to the implementation dependent value.
if (Analysis::settings().seed() >= 0)
Random::seed(Analysis::settings().seed());
+
for (const mef::FaultTreePtr& ft : model_->fault_trees()) {
for (const mef::Gate* target : ft->top_events()) {
LOG(INFO) << "Running analysis: " << target->id();
@@ -85,7 +79,7 @@ void RiskAnalysis::RunAnalysis(const std::string& name,
RunAnalysis<Algorithm, McubCalculator>(name, fta);
}
}
- fault_tree_analyses_.emplace(name, FaultTreeAnalysisPtr(fta));
+ fault_tree_analyses_.emplace(name, ext::make_unique(fta));
}
template <class Algorithm, class Calculator>
@@ -96,27 +90,14 @@ void RiskAnalysis::RunAnalysis(const std::string& name,
if (Analysis::settings().importance_analysis()) {
auto* ia = new ImportanceAnalyzer<Calculator>(pa);
ia->Analyze();
- importance_analyses_.emplace(name, ImportanceAnalysisPtr(ia));
+ importance_analyses_.emplace(name, ext::make_unique(ia));
}
if (Analysis::settings().uncertainty_analysis()) {
auto* ua = new UncertaintyAnalyzer<Calculator>(pa);
ua->Analyze();
- uncertainty_analyses_.emplace(name, UncertaintyAnalysisPtr(ua));
- }
- probability_analyses_.emplace(name, ProbabilityAnalysisPtr(pa));
-}
-
-void RiskAnalysis::Report(std::ostream& out) {
- Reporter rp = Reporter();
- rp.Report(*this, out);
-}
-
-void RiskAnalysis::Report(std::string output) {
- std::ofstream of(output.c_str());
- if (!of.good()) {
- throw IOError(output + " : Cannot write the output file.");
+ uncertainty_analyses_.emplace(name, ext::make_unique(ua));
}
- Report(of);
+ probability_analyses_.emplace(name, ext::make_unique(pa));
}
} // namespace core
diff --git a/src/risk_analysis.h b/src/risk_analysis.h
index ac15890..625a2ce 100644
--- a/src/risk_analysis.h
+++ b/src/risk_analysis.h
@@ -21,7 +21,6 @@
#ifndef SCRAM_SRC_RISK_ANALYSIS_H_
#define SCRAM_SRC_RISK_ANALYSIS_H_
-#include <iostream>
#include <map>
#include <memory>
#include <string>
@@ -41,16 +40,11 @@ namespace core {
/// Main system that performs analyses.
class RiskAnalysis : public Analysis {
public:
- /// Pointer aliases for convenience.
- /// @{
- using FaultTreeAnalysisPtr = std::unique_ptr<FaultTreeAnalysis>;
- using ProbabilityAnalysisPtr = std::unique_ptr<ProbabilityAnalysis>;
- using ImportanceAnalysisPtr = std::unique_ptr<ImportanceAnalysis>;
- using UncertaintyAnalysisPtr = std::unique_ptr<UncertaintyAnalysis>;
- /// @}
+ /// A storage container type for analysis kinds
+ /// with their ids as keys.
+ template <class T>
+ using AnalysisTable = std::map<std::string, std::unique_ptr<T>>;
- /// Constructs RiskAnalysis with a valid model and analysis settings.
- ///
/// @param[in] model An analysis model with fault trees, events, etc.
/// @param[in] settings Analysis settings for the given model.
RiskAnalysis(std::shared_ptr<const mef::Model> model,
@@ -59,64 +53,30 @@ class RiskAnalysis : public Analysis {
/// @returns The model under analysis.
const mef::Model& model() const { return *model_; }
- /// Performs the main analysis operations.
- /// Analyzes the fault tree and performs computations.
+ /// Analyzes the model
+ /// and performs computations specified in the settings.
///
/// @note This function must be called
- /// only after initializing the model
+ /// only after full initialization of the model
/// with or without its probabilities.
void Analyze() noexcept;
- /// Reports all results generated by all analyses
- /// into XML formatted stream.
- /// The report is appended to the stream.
- ///
- /// @param[out] out The output stream.
- ///
- /// @note This function must be called only after Analyze() function.
- void Report(std::ostream& out);
-
- /// Reports the results of analyses
- /// to a specified output destination.
- /// This function overwrites the file.
- ///
- /// @param[out] output The output destination.
- ///
- /// @throws IOError The output file is not accessible.
- ///
- /// @note This function must be called only after Analyze() function.
- void Report(std::string output);
-
- /// @returns Fault tree analyses performed on one-top-event fault trees.
- /// The top gate identifier is used as the analysis identifier.
- const std::map<std::string, FaultTreeAnalysisPtr>&
- fault_tree_analyses() const {
+ /// @returns Containers of performed analyses
+ /// identified by the top gate identifiers.
+ /// @{
+ const AnalysisTable<FaultTreeAnalysis>& fault_tree_analyses() const {
return fault_tree_analyses_;
}
-
- /// @returns Probability analysis performed on
- /// Boolean products generated by
- /// fault tree analyses.
- const std::map<std::string, ProbabilityAnalysisPtr>&
- probability_analyses() const {
+ const AnalysisTable<ProbabilityAnalysis>& probability_analyses() const {
return probability_analyses_;
}
-
- /// @returns Importance analysis performed on
- /// Boolean products generated by
- /// fault tree analyses.
- const std::map<std::string, ImportanceAnalysisPtr>&
- importance_analyses() const {
+ const AnalysisTable<ImportanceAnalysis>& importance_analyses() const {
return importance_analyses_;
}
-
- /// @returns Uncertainty analyses performed on
- /// Boolean products generated by
- /// fault tree analyses.
- const std::map<std::string, UncertaintyAnalysisPtr>&
- uncertainty_analyses() const {
+ const AnalysisTable<UncertaintyAnalysis>& uncertainty_analyses() const {
return uncertainty_analyses_;
}
+ /// @}
private:
/// Runs all possible analysis on a given target.
@@ -150,15 +110,15 @@ class RiskAnalysis : public Analysis {
void RunAnalysis(const std::string& name,
FaultTreeAnalyzer<Algorithm>* fta) noexcept;
- /// Analysis model with constructs.
+ /// The analysis model with constructs.
std::shared_ptr<const mef::Model> model_;
/// Analyses performed by this risk analysis run.
/// @{
- std::map<std::string, FaultTreeAnalysisPtr> fault_tree_analyses_;
- std::map<std::string, ProbabilityAnalysisPtr> probability_analyses_;
- std::map<std::string, ImportanceAnalysisPtr> importance_analyses_;
- std::map<std::string, UncertaintyAnalysisPtr> uncertainty_analyses_;
+ AnalysisTable<FaultTreeAnalysis> fault_tree_analyses_;
+ AnalysisTable<ProbabilityAnalysis> probability_analyses_;
+ AnalysisTable<ImportanceAnalysis> importance_analyses_;
+ AnalysisTable<UncertaintyAnalysis> uncertainty_analyses_;
/// @}
};
diff --git a/src/scram.cc b/src/scram.cc
index 6d307fa..ed2dde6 100644
--- a/src/scram.cc
+++ b/src/scram.cc
@@ -30,6 +30,7 @@
#include "error.h"
#include "initializer.h"
#include "logger.h"
+#include "reporter.h"
#include "risk_analysis.h"
#include "settings.h"
#include "version.h"
@@ -240,10 +241,11 @@ void RunScram(const po::variables_map& vm) {
if (vm.count("no-report") || vm.count("preprocessor") || vm.count("print"))
return;
#endif
+ scram::Reporter reporter;
if (output_path.empty()) {
- analysis->Report(std::cout);
+ reporter.Report(*analysis, std::cout);
} else {
- analysis->Report(output_path);
+ reporter.Report(*analysis, output_path);
}
}
@@ -252,10 +254,10 @@ void RunScram(const po::variables_map& vm) {
/// Catches an exception,
/// prints its message to the standard error,
/// and returns error code of 1 to exit from the main function.
-#define CATCH(exception_type, header) \
- catch (const exception_type& err) { \
- std::cerr << header << ":\n" << err.what() << std::endl; \
- return 1; \
+#define CATCH(exception_type) \
+ catch (const exception_type& err) { \
+ std::cerr << #exception_type << ":\n" << err.what() << std::endl; \
+ return 1; \
}
/// Command-line SCRAM entrance.
@@ -280,19 +282,19 @@ int main(int argc, char* argv[]) {
#ifdef NDEBUG
}
- CATCH(scram::IOError, "SCRAM I/O Error")
- CATCH(scram::ValidationError, "SCRAM Validation Error")
- CATCH(scram::ValueError, "SCRAM Value Error")
- CATCH(scram::LogicError, "SCRAM Logic Error")
- CATCH(scram::IllegalOperation, "SCRAM Illegal Operation")
- CATCH(scram::InvalidArgument, "SCRAM Invalid Argument Error")
- CATCH(scram::Error, "SCRAM Error")
+ CATCH(scram::IOError)
+ CATCH(scram::ValidationError)
+ CATCH(scram::ValueError)
+ CATCH(scram::LogicError)
+ CATCH(scram::IllegalOperation)
+ CATCH(scram::InvalidArgument)
+ CATCH(scram::Error)
catch (boost::exception& boost_err) {
std::cerr << "Boost Exception:\n"
<< boost::diagnostic_information(boost_err) << std::endl;
return 1;
}
- CATCH(std::exception, "Standard Exception")
+ CATCH(std::exception)
#endif
} // End of main.
#undef CATCH
diff --git a/src/settings.h b/src/settings.h
index 101a3f8..d8d9dfe 100644
--- a/src/settings.h
+++ b/src/settings.h
@@ -167,6 +167,8 @@ class Settings {
/// @param[in] time A positive number in hours by default.
///
/// @returns Reference to this object.
+ ///
+ /// @throws InvalidArgument The time value is negative.
Settings& mission_time(double time);
/// @returns true if probability analysis is requested.
diff --git a/src/uncertainty_analysis.cc b/src/uncertainty_analysis.cc
index 7d75d12..92a808d 100644
--- a/src/uncertainty_analysis.cc
+++ b/src/uncertainty_analysis.cc
@@ -29,6 +29,7 @@
#include <boost/accumulators/statistics/stats.hpp>
#include <boost/accumulators/statistics/variance.hpp>
+#include "event.h"
#include "logger.h"
namespace scram {
@@ -70,6 +71,20 @@ UncertaintyAnalysis::FilterUncertainEvents(const BooleanGraph* graph) noexcept {
return uncertain_events;
}
+void UncertaintyAnalysis::SampleEventProbabilities(
+ const std::vector<std::pair<int, mef::BasicEvent*>>& uncertain_events,
+ std::vector<double>* p_vars) noexcept {
+ // Reset distributions.
+ for (const auto& event : uncertain_events)
+ event.second->Reset();
+
+ // Sample all basic events with distributions.
+ for (const auto& event : uncertain_events) {
+ double prob = event.second->SampleProbability();
+ (*p_vars)[event.first] = prob > 1 ? 1 : prob < 0 ? 0 : prob;
+ }
+}
+
void UncertaintyAnalysis::CalculateStatistics(
const std::vector<double>& samples) noexcept {
using namespace boost; // NOLINT
diff --git a/src/uncertainty_analysis.h b/src/uncertainty_analysis.h
index 082799c..5db5f86 100644
--- a/src/uncertainty_analysis.h
+++ b/src/uncertainty_analysis.h
@@ -26,11 +26,15 @@
#include <vector>
#include "analysis.h"
-#include "event.h"
#include "probability_analysis.h"
#include "settings.h"
namespace scram {
+
+namespace mef { // Decouple from the implementation dependence.
+class BasicEvent;
+} // namespace mef
+
namespace core {
/// Uncertainty analysis and statistics
@@ -83,6 +87,18 @@ class UncertaintyAnalysis : public Analysis {
std::vector<std::pair<int, mef::BasicEvent*>> FilterUncertainEvents(
const BooleanGraph* graph) noexcept;
+ /// Samples each uncertain event probability.
+ ///
+ /// @param[in] uncertain_events A collection of uncertain events.
+ /// @param[in,out] p_vars A container for sampled event probabilities.
+ ///
+ /// @pre The container for probabilities is large enough
+ /// to have the resultant probabilities get mapped by indices.
+ /// That is, container[event.index()] never fails for any given event.
+ void SampleEventProbabilities(
+ const std::vector<std::pair<int, mef::BasicEvent*>>& uncertain_events,
+ std::vector<double>* p_vars) noexcept;
+
private:
/// Performs Monte Carlo Simulation
/// by sampling the probability distributions
@@ -118,11 +134,6 @@ class UncertaintyAnalyzer : public UncertaintyAnalysis {
/// to calculate the total probability for sampling.
///
/// @param[in] prob_analyzer Instantiated probability analyzer.
- ///
- /// @pre Probability analyzer can work with modified probability values.
- ///
- /// @post Probability analyzer's probability values are
- /// reset to the original values (event probabilities).
explicit UncertaintyAnalyzer(ProbabilityAnalyzer<Calculator>* prob_analyzer)
: UncertaintyAnalysis(prob_analyzer),
prob_analyzer_(prob_analyzer) {}
@@ -139,33 +150,16 @@ template <class Calculator>
std::vector<double> UncertaintyAnalyzer<Calculator>::Sample() noexcept {
std::vector<std::pair<int, mef::BasicEvent*>> uncertain_events =
UncertaintyAnalysis::FilterUncertainEvents(prob_analyzer_->graph());
- std::vector<double>& p_vars = prob_analyzer_->p_vars();
+ std::vector<double> p_vars = prob_analyzer_->p_vars(); // Private copy!
std::vector<double> samples;
samples.reserve(Analysis::settings().num_trials());
+
for (int i = 0; i < Analysis::settings().num_trials(); ++i) {
- // Reset distributions.
- for (const auto& event : uncertain_events)
- event.second->Reset();
-
- // Sample all basic events with distributions.
- for (const auto& event : uncertain_events) {
- double prob = event.second->SampleProbability();
- if (prob < 0) { // Adjust if out of range.
- prob = 0;
- } else if (prob > 1) {
- prob = 1;
- }
- p_vars[event.first] = prob;
- }
- double result = prob_analyzer_->CalculateTotalProbability();
- assert(result >= 0);
- if (result > 1)
- result = 1;
+ UncertaintyAnalysis::SampleEventProbabilities(uncertain_events, &p_vars);
+ double result = prob_analyzer_->CalculateTotalProbability(p_vars);
+ assert(result >= 0 && result <= 1);
samples.push_back(result);
}
- // Reset probabilities.
- for (const auto& event : uncertain_events)
- p_vars[event.first] = event.second->p();
return samples;
}
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index f76f5c4..a8c76c1 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -6,7 +6,7 @@ set(CMAKE_CXX_FLAGS_DEBUG "-g")
set(GTEST_DIR "${CMAKE_CURRENT_SOURCE_DIR}/googletest/googletest")
-add_subdirectory("${GTEST_DIR}")
+add_subdirectory("${GTEST_DIR}" EXCLUDE_FROM_ALL)
set(CMAKE_CXX_FLAGS_DEBUG "${CURRENT_DEBUG_FLAGS}") # Restore the original flags.
diff --git a/tests/bench_bscu_tests.cc b/tests/bench_bscu_tests.cc
index ae76a8f..1476910 100644
--- a/tests/bench_bscu_tests.cc
+++ b/tests/bench_bscu_tests.cc
@@ -48,12 +48,12 @@ TEST_P(RiskAnalysisTest, BSCU) {
if (settings.approximation() == "rare-event") {
EXPECT_NEAR(0.135372, p_total(), 1e-4);
- EXPECT_NEAR(0.1448961, mean(), 5e-3);
- EXPECT_NEAR(0.203192, sigma(), 5e-3);
+ EXPECT_NEAR(0.137, mean(), 5e-3);
+ EXPECT_NEAR(0.217, sigma(), 5e-3);
} else {
EXPECT_NEAR(0.1124087, p_total(), 1e-4);
- EXPECT_NEAR(0.1212541, mean(), 5e-3);
- EXPECT_NEAR(0.1646726, sigma(), 5e-3);
+ EXPECT_NEAR(0.117, mean(), 5e-3);
+ EXPECT_NEAR(0.183, sigma(), 5e-3);
}
}
diff --git a/tests/bench_core_tests.cc b/tests/bench_core_tests.cc
index 717afd6..456494a 100644
--- a/tests/bench_core_tests.cc
+++ b/tests/bench_core_tests.cc
@@ -455,9 +455,9 @@ TEST_P(RiskAnalysisTest, AlphaFactorCCF) {
ASSERT_NO_THROW(ProcessInputFile(tree_input));
ASSERT_NO_THROW(analysis->Analyze());
if (settings.approximation() == "rare-event") {
- EXPECT_NEAR(0.03234, p_total(), 1e-5);
+ EXPECT_NEAR(0.05488, p_total(), 1e-5);
} else {
- EXPECT_NEAR(0.03092, p_total(), 1e-5);
+ EXPECT_NEAR(0.05298, p_total(), 1e-5);
}
EXPECT_EQ(34, products().size());
std::vector<int> distr = {2, 24, 8};
diff --git a/tests/bench_small_tree_tests.cc b/tests/bench_small_tree_tests.cc
index 5c51082..6eb38d9 100644
--- a/tests/bench_small_tree_tests.cc
+++ b/tests/bench_small_tree_tests.cc
@@ -34,8 +34,15 @@ TEST_P(RiskAnalysisTest, SmallTree) {
std::set<std::set<std::string>> mcs = {{"e1", "e2"}, {"e3", "e4"}};
EXPECT_EQ(2, products().size());
EXPECT_EQ(mcs, products());
- EXPECT_NEAR(0.02569, mean(), 1e-3);
- EXPECT_NEAR(0.018065, sigma(), 2e-3);
+ if (settings.approximation() == "rare-event") {
+ EXPECT_NEAR(0.02696, p_total(), 1e-5);
+ EXPECT_NEAR(0.0255, mean(), 1e-3);
+ EXPECT_NEAR(0.0225, sigma(), 2e-3);
+ } else {
+ EXPECT_NEAR(0.02678, p_total(), 1e-5);
+ EXPECT_NEAR(0.0253, mean(), 1e-3);
+ EXPECT_NEAR(0.022, sigma(), 2e-3);
+ }
}
} // namespace test
diff --git a/tests/ccf_group_tests.cc b/tests/ccf_group_tests.cc
index ae9b549..f6d1570 100644
--- a/tests/ccf_group_tests.cc
+++ b/tests/ccf_group_tests.cc
@@ -20,6 +20,7 @@
#include <gtest/gtest.h>
#include "error.h"
+#include "expression/constant.h"
namespace scram {
namespace mef {
diff --git a/tests/expression_tests.cc b/tests/expression_tests.cc
index 7af0f96..67b5fd4 100644
--- a/tests/expression_tests.cc
+++ b/tests/expression_tests.cc
@@ -16,6 +16,10 @@
*/
#include "expression.h"
+#include "expression/arithmetic.h"
+#include "expression/exponential.h"
+#include "expression/random_deviate.h"
+#include "parameter.h"
#include <gtest/gtest.h>
diff --git a/tests/input/empty_attribute.xml b/tests/input/empty_attribute.xml
index bfeff69..854abbe 100644
--- a/tests/input/empty_attribute.xml
+++ b/tests/input/empty_attribute.xml
@@ -3,7 +3,7 @@
<define-fault-tree name="Ex">
<define-basic-event name="A">
<attributes>
- <attribute value=""/>
+ <attribute name="attribute" value=""/>
</attributes>
<float value="0.1"/>
</define-basic-event>
diff --git a/tests/input/fta/doubly_defined_parameter.xml b/tests/input/fta/doubly_defined_parameter.xml
index 5005073..244cc77 100644
--- a/tests/input/fta/doubly_defined_parameter.xml
+++ b/tests/input/fta/doubly_defined_parameter.xml
@@ -1,7 +1,7 @@
<?xml version="1.0"?>
<!--
This input contains a paremeter that is doubly defined.
-This input may be valid OpenPSA MEF with optional warnings.
+This input may be valid Open-PSA MEF with optional warnings.
-->
<opsa-mef>
<define-fault-tree name="TwoTrains">
diff --git a/tests/input/fta/run_inputs.py b/tests/input/fta/run_inputs.py
index 4b217b5..838c4ac 100755
--- a/tests/input/fta/run_inputs.py
+++ b/tests/input/fta/run_inputs.py
@@ -20,7 +20,6 @@
from __future__ import print_function
import subprocess
-import sys
# Input that must be analyzed with the results printed.
@@ -123,81 +122,42 @@ BLOCK_DELIM = "=" * 80
FILE_DELIM = "-" * 80
-def main():
- """Runs SCRAM with all registered inputs."""
- # Run correct inputs
- print("\nRUNNING CORRECT INPUTS WITH OUTPUT")
- print(BLOCK_DELIM)
- for i in PRINT_INPUTS:
- print("\nRUNNING : " + i)
- print(FILE_DELIM)
- args = ["scram", i]
- subprocess.call(args)
- print(FILE_DELIM)
- print(BLOCK_DELIM)
+def run_inputs(title, inputs, flags):
+ """Runs each input with scram.
- # Run correct inputs
- print("\nVALIDATING CORRECT INPUTS WITHOUT PROBABILITY CALCULATION")
+ Args:
+ title: The group title for the inputs and the run.
+ inputs: The input files.
+ flags: A list of flags to be prepended before the argument file.
+ """
+ print("\n%s" % title.upper())
print(BLOCK_DELIM)
- for i in PASS_INPUTS:
- print("\nVALIDATING : " + i)
+ for i in inputs:
+ print("\n%s : " % title.split()[0].upper() + i)
print(FILE_DELIM)
- args = ["scram", i, "--validate"]
- subprocess.call(args)
+ subprocess.call(["scram"] + flags + [i])
print(FILE_DELIM)
print(BLOCK_DELIM)
- # Run incorrect inputs
- print("\nVALIDATING INCORRECT INPUTS WITHOUT PROBABILITY CALCULATION")
- print(BLOCK_DELIM)
- for i in BAD_INPUTS:
- print("\nVALIDATING : " + i)
- print(FILE_DELIM)
- args = ["scram", i, "--validate"]
- try:
- subprocess.check_call(args)
- except subprocess.CalledProcessError:
- print(sys.exc_info()[0])
- print(FILE_DELIM)
- print(BLOCK_DELIM)
-
- # Run correct inputs with probabilities
- print("\nVALIDATING CORRECT PROBABILITY INPUTS")
- print(BLOCK_DELIM)
- for i in PASS_PROBS:
- print("\nVALIDATING : " + i)
- print(FILE_DELIM)
- args = ["scram", i, "--probability", "1", "--validate"]
- subprocess.call(args)
- print(FILE_DELIM)
- print(BLOCK_DELIM)
- # Run incorrect inputs with probability calculations
- print("\nVALIDATING INCORRECT PROBABILITY INPUTS")
- print(BLOCK_DELIM)
- for i in BAD_PROBS:
- print("\nVALIDATING : " + i)
- print(FILE_DELIM)
- args = ["scram", i, "--probability", "1", "--validate"]
- try:
- subprocess.check_call(args)
- except subprocess.CalledProcessError:
- print(sys.exc_info()[0])
- print(FILE_DELIM)
- print(BLOCK_DELIM)
+def main():
+ """Runs SCRAM with all registered inputs."""
+ # Run correct inputs
+ run_inputs("running correct inputs with output", PRINT_INPUTS, [])
+ run_inputs("validating correct inputs w/o probability calculation",
+ PASS_INPUTS, ["--validate"])
+ run_inputs("validating correct probability inputs", PASS_PROBS,
+ ["--probability", "1", "--validate"])
- print("\nVALIDATING INCORRECT CONFIGURATION FILES")
- print(BLOCK_DELIM)
- for i in BAD_CONFIG:
- print("\nVALIDATING : " + i)
- print(FILE_DELIM)
- args = ["scram", "--config-file", i, "--validate"]
- try:
- subprocess.check_call(args)
- except subprocess.CalledProcessError:
- print(sys.exc_info()[0])
- print(FILE_DELIM)
- print(BLOCK_DELIM)
+ # Run incorrect inputs
+ run_inputs("validating incorrect inputs w/o probability calculation",
+ BAD_INPUTS, ["--validate"])
+ run_inputs("validating incorrect probability inputs", BAD_PROBS,
+ ["--probability", "1", "--validate"])
+
+ # Incorrect configurations
+ run_inputs("validating incorrect configuration files", BAD_CONFIG,
+ ["--validate", "--config-file"])
if __name__ == "__main__":
main()
diff --git a/tests/input/unsupported_feature.xml b/tests/input/unsupported_feature.xml
index ac9f469..6e0ac23 100644
--- a/tests/input/unsupported_feature.xml
+++ b/tests/input/unsupported_feature.xml
@@ -1,7 +1,7 @@
<?xml version="1.0"?>
<!--
This input contains unsupported feature by SCRAM.
-However, this feature is valid in OpenPSA MEF.
+However, this feature is valid in the Open-PSA MEF.
-->
<opsa-mef>
<define-substitution name="Backup">
diff --git a/tests/performance_tests.cc b/tests/performance_tests.cc
index f872abe..be36bb5 100644
--- a/tests/performance_tests.cc
+++ b/tests/performance_tests.cc
@@ -29,7 +29,7 @@
//
// Proc Core i7-2820QM
// Ubuntu 16.04 64bit
-// GCC 5.3.1
+// GCC 5.4.0
// Boost 1.58
// TCMalloc 2.4
//
@@ -56,7 +56,6 @@ namespace test {
TEST(RegressionTest, ObjectSize) {
// x86-64 platform.
// 64-bit platform with alignment at 8-byte boundaries.
- EXPECT_EQ(16, sizeof(ControlBlock));
EXPECT_EQ(8, sizeof(WeakIntrusivePtr<Vertex<Ite>>));
EXPECT_EQ(8, sizeof(IntrusivePtr<Vertex<Ite>>));
EXPECT_EQ(16, sizeof(Vertex<Ite>));
diff --git a/tests/risk_analysis_tests.cc b/tests/risk_analysis_tests.cc
index e88606a..db1862f 100644
--- a/tests/risk_analysis_tests.cc
+++ b/tests/risk_analysis_tests.cc
@@ -17,9 +17,15 @@
#include "risk_analysis_tests.h"
+#include <sstream>
#include <utility>
+#include <libxml++/libxml++.h>
+
+#include "env.h"
#include "error.h"
+#include "initializer.h"
+#include "reporter.h"
namespace scram {
namespace core {
@@ -28,6 +34,97 @@ namespace test {
const std::set<std::set<std::string>> RiskAnalysisTest::kUnity = {
std::set<std::string>{}};
+void RiskAnalysisTest::SetUp() {
+ if (HasParam()) {
+ std::string param = GetParam();
+ if (param == "pi") {
+ settings.algorithm("bdd");
+ settings.prime_implicants(true);
+ } else {
+ settings.algorithm(GetParam());
+ }
+ }
+}
+
+void RiskAnalysisTest::ProcessInputFiles(
+ const std::vector<std::string>& input_files) {
+ mef::Initializer init(input_files, settings);
+ model = init.model();
+ analysis = std::make_unique<RiskAnalysis>(model, settings);
+ result_ = Result();
+}
+
+void RiskAnalysisTest::CheckReport(const std::string& tree_input) {
+ static xmlpp::RelaxNGValidator validator(Env::report_schema());
+
+ ASSERT_NO_THROW(ProcessInputFile(tree_input));
+ ASSERT_NO_THROW(analysis->Analyze());
+ std::stringstream output;
+ ASSERT_NO_THROW(Reporter().Report(*analysis, output));
+
+ xmlpp::DomParser parser;
+ ASSERT_NO_THROW(parser.parse_stream(output));
+ ASSERT_NO_THROW(validator.validate(parser.get_document()));
+}
+
+const std::set<std::set<std::string>>& RiskAnalysisTest::products() {
+ assert(!analysis->fault_tree_analyses().empty());
+ assert(analysis->fault_tree_analyses().size() == 1);
+ if (result_.products.empty()) {
+ const FaultTreeAnalysis* fta =
+ analysis->fault_tree_analyses().begin()->second.get();
+ for (const Product& product : fta->products()) {
+ result_.products.emplace(Convert(product));
+ }
+ }
+ return result_.products;
+}
+
+std::vector<int> RiskAnalysisTest::ProductDistribution() {
+ assert(!analysis->fault_tree_analyses().empty());
+ assert(analysis->fault_tree_analyses().size() == 1);
+ std::vector<int> distr(settings.limit_order(), 0);
+ const FaultTreeAnalysis* fta =
+ analysis->fault_tree_analyses().begin()->second.get();
+ for (const Product& product : fta->products()) {
+ distr[GetOrder(product) - 1]++;
+ }
+ while (!distr.empty() && !distr.back())
+ distr.pop_back();
+ return distr;
+}
+
+void RiskAnalysisTest::PrintProducts() {
+ assert(!analysis->fault_tree_analyses().empty());
+ assert(analysis->fault_tree_analyses().size() == 1);
+ const FaultTreeAnalysis* fta =
+ analysis->fault_tree_analyses().begin()->second.get();
+ Print(fta->products());
+}
+
+const std::map<std::set<std::string>, double>&
+RiskAnalysisTest::product_probability() {
+ assert(!analysis->fault_tree_analyses().empty());
+ assert(analysis->fault_tree_analyses().size() == 1);
+ if (result_.product_probability.empty()) {
+ const FaultTreeAnalysis* fta =
+ analysis->fault_tree_analyses().begin()->second.get();
+ for (const Product& product : fta->products()) {
+ result_.product_probability.emplace(Convert(product),
+ CalculateProbability(product));
+ }
+ }
+ return result_.product_probability;
+}
+
+std::set<std::string> RiskAnalysisTest::Convert(const Product& product) {
+ std::set<std::string> string_set;
+ for (const Literal& literal : product) {
+ string_set.insert((literal.complement ? "not " : "") + literal.event.id());
+ }
+ return string_set;
+}
+
TEST_F(RiskAnalysisTest, ProcessInput) {
std::string tree_input = "./share/scram/input/fta/correct_tree_input.xml";
ASSERT_NO_THROW(ProcessInputFile(tree_input));
@@ -281,7 +378,7 @@ TEST_F(RiskAnalysisTest, ReportIOError) {
std::string output = "abracadabra.cadabraabra/output.txt";
ASSERT_NO_THROW(ProcessInputFile(tree_input));
ASSERT_NO_THROW(analysis->Analyze());
- EXPECT_THROW(analysis->Report(output), IOError);
+ EXPECT_THROW(Reporter().Report(*analysis, output), IOError);
}
// Reporting of the default analysis for MCS only without probabilities.
diff --git a/tests/risk_analysis_tests.h b/tests/risk_analysis_tests.h
index 7318498..c427b44 100644
--- a/tests/risk_analysis_tests.h
+++ b/tests/risk_analysis_tests.h
@@ -20,19 +20,11 @@
#include "risk_analysis.h"
-#include <fstream>
-#include <map>
#include <set>
-#include <sstream>
-#include <string>
#include <vector>
#include <gtest/gtest.h>
-#include "env.h"
-#include "initializer.h"
-#include "xml.h"
-
namespace scram {
namespace core {
namespace test {
@@ -41,106 +33,44 @@ class RiskAnalysisTest : public ::testing::TestWithParam<const char*> {
protected:
static const std::set<std::set<std::string>> kUnity; ///< Special unity set.
- void SetUp() override {
- if (HasParam()) {
- std::string param = GetParam();
- if (param == "pi") {
- settings.algorithm("bdd");
- settings.prime_implicants(true);
- } else {
- settings.algorithm(GetParam());
- }
- }
- }
-
- void TearDown() override {}
+ void SetUp() override;
// Parsing multiple input files.
- void ProcessInputFiles(const std::vector<std::string>& input_files) {
- init = std::make_unique<mef::Initializer>(input_files, settings);
- ResetRiskAnalysis();
- }
-
- // Resets the risk analysis with the initialized model and settings.
- void ResetRiskAnalysis() {
- assert(init && "Missing initializer");
- analysis = std::make_unique<RiskAnalysis>(init->model(), settings);
- }
+ void ProcessInputFiles(const std::vector<std::string>& input_files);
// Parsing an input file to get the model.
void ProcessInputFile(const std::string& input_file) {
- std::vector<std::string> input_files;
- input_files.push_back(input_file);
- ProcessInputFiles(input_files);
+ ProcessInputFiles({input_file});
}
// Collection of assertions on the reporting after running analysis.
// Note that the analysis is run by this function.
- void CheckReport(const std::string& tree_input) {
- static xmlpp::RelaxNGValidator validator(Env::report_schema());
-
- ASSERT_NO_THROW(ProcessInputFile(tree_input));
- ASSERT_NO_THROW(analysis->Analyze());
- std::stringstream output;
- ASSERT_NO_THROW(analysis->Report(output));
-
- xmlpp::DomParser parser;
- ASSERT_NO_THROW(parser.parse_stream(output));
- ASSERT_NO_THROW(validator.validate(parser.get_document()));
- }
+ void CheckReport(const std::string& tree_input);
// Returns a single fault tree, assuming one fault tree with single top gate.
const mef::FaultTreePtr& fault_tree() {
- return *init->model()->fault_trees().begin();
+ return *model->fault_trees().begin();
}
- const mef::IdTable<mef::GatePtr>& gates() { return init->model()->gates(); }
+ const mef::IdTable<mef::GatePtr>& gates() { return model->gates(); }
const mef::IdTable<mef::HouseEventPtr>& house_events() {
- return init->model()->house_events();
+ return model->house_events();
}
const mef::IdTable<mef::BasicEventPtr>& basic_events() {
- return init->model()->basic_events();
+ return model->basic_events();
}
- const std::set<std::set<std::string>>& products() {
- assert(!analysis->fault_tree_analyses().empty());
- assert(analysis->fault_tree_analyses().size() == 1);
- if (products_.empty()) {
- const FaultTreeAnalysis* fta =
- analysis->fault_tree_analyses().begin()->second.get();
- for (const Product& product : fta->products()) {
- products_.emplace(Convert(product));
- }
- }
- return products_;
- }
+ /// @returns The resultant products of the fault tree analysis.
+ const std::set<std::set<std::string>>& products();
// Provides the number of products per order of sets.
// The order starts from 1.
- std::vector<int> ProductDistribution() {
- assert(!analysis->fault_tree_analyses().empty());
- assert(analysis->fault_tree_analyses().size() == 1);
- std::vector<int> distr(settings.limit_order(), 0);
- const FaultTreeAnalysis* fta =
- analysis->fault_tree_analyses().begin()->second.get();
- for (const Product& product : fta->products()) {
- distr[GetOrder(product) - 1]++;
- }
- while (!distr.empty() && !distr.back())
- distr.pop_back();
- return distr;
- }
+ std::vector<int> ProductDistribution();
/// Prints products to the standard error.
- void PrintProducts() {
- assert(!analysis->fault_tree_analyses().empty());
- assert(analysis->fault_tree_analyses().size() == 1);
- const FaultTreeAnalysis* fta =
- analysis->fault_tree_analyses().begin()->second.get();
- Print(fta->products());
- }
+ void PrintProducts();
double p_total() {
assert(!analysis->probability_analyses().empty());
@@ -148,19 +78,8 @@ class RiskAnalysisTest : public ::testing::TestWithParam<const char*> {
return analysis->probability_analyses().begin()->second->p_total();
}
- const std::map<std::set<std::string>, double>& product_probability() {
- assert(!analysis->fault_tree_analyses().empty());
- assert(analysis->fault_tree_analyses().size() == 1);
- if (product_probability_.empty()) {
- const FaultTreeAnalysis* fta =
- analysis->fault_tree_analyses().begin()->second.get();
- for (const Product& product : fta->products()) {
- product_probability_.emplace(Convert(product),
- CalculateProbability(product));
- }
- }
- return product_probability_;
- }
+ /// @returns Products and their probabilities.
+ const std::map<std::set<std::string>, double>& product_probability();
const ImportanceFactors& importance(std::string id) {
assert(!analysis->importance_analyses().empty());
@@ -181,26 +100,21 @@ class RiskAnalysisTest : public ::testing::TestWithParam<const char*> {
return analysis->uncertainty_analyses().begin()->second->sigma();
}
- /// Converts a set of pointers to events with complement flags
- /// into readable and testable strings.
- /// Complements are communicated with "not" prefix.
- std::set<std::string> Convert(const Product& product) {
- std::set<std::string> string_set;
- for (const Literal& literal : product) {
- string_set.insert((literal.complement ? "not " : "") +
- literal.event.id());
- }
- return string_set;
- }
-
// Members
std::unique_ptr<RiskAnalysis> analysis;
- std::unique_ptr<mef::Initializer> init;
+ std::shared_ptr<mef::Model> model;
Settings settings;
private:
- std::map<std::set<std::string>, double> product_probability_;
- std::set<std::set<std::string>> products_;
+ /// Converts a set of pointers to events with complement flags
+ /// into readable and testable strings.
+ /// Complements are communicated with "not" prefix.
+ std::set<std::string> Convert(const Product& product);
+
+ struct Result {
+ std::map<std::set<std::string>, double> product_probability;
+ std::set<std::set<std::string>> products;
+ } result_;
};
} // namespace test
diff --git a/tests/test_scram_call.py b/tests/test_scram_call.py
index a9dbf80..c8a04e8 100644
--- a/tests/test_scram_call.py
+++ b/tests/test_scram_call.py
@@ -18,7 +18,7 @@
import os
from subprocess import call
-from nose.tools import assert_true, assert_equal, assert_not_equal
+from nose.tools import assert_equal, assert_not_equal
def test_empty_call():
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/debian-science/packages/scram.git
More information about the debian-science-commits
mailing list