Browse Source

Merge branch 'dft-refactor'

tempestpy_adaptions
Matthias Volk 7 years ago
parent
commit
dc78ea9c9e
  1. 124
      src/storm-dft-cli/storm-dft.cpp
  2. 1106
      src/storm-dft/builder/ExplicitDFTModelBuilder.cpp
  3. 342
      src/storm-dft/builder/ExplicitDFTModelBuilder.h
  4. 841
      src/storm-dft/builder/ExplicitDFTModelBuilderApprox.cpp
  5. 362
      src/storm-dft/builder/ExplicitDFTModelBuilderApprox.h
  6. 4
      src/storm-dft/generator/DftNextStateGenerator.cpp
  7. 32
      src/storm-dft/modelchecker/dft/DFTModelChecker.cpp
  8. 51
      src/storm-dft/settings/DftSettings.cpp
  9. 11
      src/storm-dft/settings/DftSettings.h
  10. 189
      src/storm-dft/settings/modules/DFTSettings.cpp
  11. 123
      src/storm-dft/settings/modules/DftIOSettings.cpp
  12. 80
      src/storm-dft/settings/modules/DftIOSettings.h
  13. 93
      src/storm-dft/settings/modules/FaultTreeSettings.cpp
  14. 104
      src/storm-dft/settings/modules/FaultTreeSettings.h
  15. 12
      src/storm/models/sparse/MarkovAutomaton.cpp
  16. 4
      src/storm/models/sparse/MarkovAutomaton.h

124
src/storm-dft-cli/storm-dft.cpp

@ -1,20 +1,14 @@
#include "storm/logic/Formula.h"
#include "storm/utility/initialize.h"
#include "storm/api/storm.h"
#include "storm-cli-utilities/cli.h"
#include "storm/exceptions/BaseException.h"
#include "storm/logic/Formula.h"
#include "storm-dft/settings/DftSettings.h"
#include "storm-dft/settings/modules/DftIOSettings.h"
#include "storm-dft/settings/modules/FaultTreeSettings.h"
#include "storm/settings/modules/IOSettings.h"
#include "storm/settings/modules/CoreSettings.h"
#include "storm/settings/modules/DebugSettings.h"
#include "storm/settings/modules/GmmxxEquationSolverSettings.h"
#include "storm/settings/modules/MinMaxEquationSolverSettings.h"
#include "storm/settings/modules/NativeEquationSolverSettings.h"
#include "storm/settings/modules/EliminationSettings.h"
#include "storm/settings/modules/ResourceSettings.h"
#include "storm/utility/initialize.h"
#include "storm/api/storm.h"
#include "storm-cli-utilities/cli.h"
#include "storm-dft/parser/DFTGalileoParser.h"
#include "storm-dft/parser/DFTJsonParser.h"
#include "storm-dft/modelchecker/dft/DFTModelChecker.h"
@ -22,12 +16,8 @@
#include "storm-dft/transformations/DftToGspnTransformator.h"
#include "storm-dft/storage/dft/DftJsonExporter.h"
#include "storm-dft/settings/modules/DFTSettings.h"
#include "storm-gspn/storage/gspn/GSPN.h"
#include "storm-gspn/storm-gspn.h"
#include "storm/settings/modules/GSPNSettings.h"
#include "storm/settings/modules/GSPNExportSettings.h"
#include <boost/lexical_cast.hpp>
#include <memory>
@ -44,18 +34,18 @@
*/
template <typename ValueType>
void analyzeDFT(std::vector<std::string> const& properties, bool symred, bool allowModularisation, bool enableDC, double approximationError) {
storm::settings::modules::DFTSettings const& dftSettings = storm::settings::getModule<storm::settings::modules::DFTSettings>();
storm::settings::modules::DftIOSettings const& dftIOSettings = storm::settings::getModule<storm::settings::modules::DftIOSettings>();
std::shared_ptr<storm::storage::DFT<ValueType>> dft;
// Build DFT from given file.
if (dftSettings.isDftJsonFileSet()) {
if (dftIOSettings.isDftJsonFileSet()) {
storm::parser::DFTJsonParser<ValueType> parser;
std::cout << "Loading DFT from file " << dftSettings.getDftJsonFilename() << std::endl;
dft = std::make_shared<storm::storage::DFT<ValueType>>(parser.parseJson(dftSettings.getDftJsonFilename()));
std::cout << "Loading DFT from file " << dftIOSettings.getDftJsonFilename() << std::endl;
dft = std::make_shared<storm::storage::DFT<ValueType>>(parser.parseJson(dftIOSettings.getDftJsonFilename()));
} else {
storm::parser::DFTGalileoParser<ValueType> parser;
std::cout << "Loading DFT from file " << dftSettings.getDftFilename() << std::endl;
dft = std::make_shared<storm::storage::DFT<ValueType>>(parser.parseDFT(dftSettings.getDftFilename()));
std::cout << "Loading DFT from file " << dftIOSettings.getDftFilename() << std::endl;
dft = std::make_shared<storm::storage::DFT<ValueType>>(parser.parseDFT(dftIOSettings.getDftFilename()));
}
// Build properties
@ -91,72 +81,39 @@ void analyzeWithSMT(std::string filename) {
//std::cout << "SMT result: " << sat << std::endl;
}
/*!
* Initialize the settings manager.
*/
void initializeSettings() {
storm::settings::mutableManager().setName("Storm-DyFTeE", "storm-dft");
// Register all known settings modules.
storm::settings::addModule<storm::settings::modules::GeneralSettings>();
storm::settings::addModule<storm::settings::modules::DFTSettings>();
storm::settings::addModule<storm::settings::modules::CoreSettings>();
storm::settings::addModule<storm::settings::modules::DebugSettings>();
storm::settings::addModule<storm::settings::modules::IOSettings>();
//storm::settings::addModule<storm::settings::modules::CounterexampleGeneratorSettings>();
//storm::settings::addModule<storm::settings::modules::CuddSettings>();
//storm::settings::addModule<storm::settings::modules::SylvanSettings>();
storm::settings::addModule<storm::settings::modules::GmmxxEquationSolverSettings>();
storm::settings::addModule<storm::settings::modules::MinMaxEquationSolverSettings>();
storm::settings::addModule<storm::settings::modules::NativeEquationSolverSettings>();
//storm::settings::addModule<storm::settings::modules::BisimulationSettings>();
//storm::settings::addModule<storm::settings::modules::GlpkSettings>();
//storm::settings::addModule<storm::settings::modules::GurobiSettings>();
//storm::settings::addModule<storm::settings::modules::TopologicalValueIterationEquationSolverSettings>();
//storm::settings::addModule<storm::settings::modules::ParametricSettings>();
storm::settings::addModule<storm::settings::modules::EliminationSettings>();
storm::settings::addModule<storm::settings::modules::ResourceSettings>();
// For translation into JANI via GSPN.
storm::settings::addModule<storm::settings::modules::GSPNSettings>();
storm::settings::addModule<storm::settings::modules::GSPNExportSettings>();
storm::settings::addModule<storm::settings::modules::JaniExportSettings>();
}
void processOptions() {
// Start by setting some urgent options (log levels, resources, etc.)
storm::cli::setUrgentOptions();
storm::cli::processOptions();
storm::settings::modules::DFTSettings const& dftSettings = storm::settings::getModule<storm::settings::modules::DFTSettings>();
storm::settings::modules::DftIOSettings const& dftIOSettings = storm::settings::getModule<storm::settings::modules::DftIOSettings>();
storm::settings::modules::FaultTreeSettings const& faultTreeSettings = storm::settings::getModule<storm::settings::modules::FaultTreeSettings>();
storm::settings::modules::GeneralSettings const& generalSettings = storm::settings::getModule<storm::settings::modules::GeneralSettings>();
storm::settings::modules::IOSettings const& ioSettings = storm::settings::getModule<storm::settings::modules::IOSettings>();
if (!dftSettings.isDftFileSet() && !dftSettings.isDftJsonFileSet()) {
if (!dftIOSettings.isDftFileSet() && !dftIOSettings.isDftJsonFileSet()) {
STORM_LOG_THROW(false, storm::exceptions::InvalidSettingsException, "No input model.");
}
if (dftSettings.isExportToJson()) {
STORM_LOG_THROW(dftSettings.isDftFileSet(), storm::exceptions::InvalidSettingsException, "No input model in Galileo format given.");
if (dftIOSettings.isExportToJson()) {
STORM_LOG_THROW(dftIOSettings.isDftFileSet(), storm::exceptions::InvalidSettingsException, "No input model in Galileo format given.");
storm::parser::DFTGalileoParser<double> parser;
storm::storage::DFT<double> dft = parser.parseDFT(dftSettings.getDftFilename());
storm::storage::DFT<double> dft = parser.parseDFT(dftIOSettings.getDftFilename());
// Export to json
storm::storage::DftJsonExporter<double>::toFile(dft, dftSettings.getExportJsonFilename());
storm::storage::DftJsonExporter<double>::toFile(dft, dftIOSettings.getExportJsonFilename());
storm::utility::cleanUp();
return;
}
if (dftSettings.isTransformToGspn()) {
if (dftIOSettings.isTransformToGspn()) {
std::shared_ptr<storm::storage::DFT<double>> dft;
if (dftSettings.isDftJsonFileSet()) {
if (dftIOSettings.isDftJsonFileSet()) {
storm::parser::DFTJsonParser<double> parser;
dft = std::make_shared<storm::storage::DFT<double>>(parser.parseJson(dftSettings.getDftJsonFilename()));
dft = std::make_shared<storm::storage::DFT<double>>(parser.parseJson(dftIOSettings.getDftJsonFilename()));
} else {
storm::parser::DFTGalileoParser<double> parser(true, false);
dft = std::make_shared<storm::storage::DFT<double>>(parser.parseDFT(dftSettings.getDftFilename()));
dft = std::make_shared<storm::storage::DFT<double>>(parser.parseDFT(dftIOSettings.getDftFilename()));
}
storm::transformations::dft::DftToGspnTransformator<double> gspnTransformator(*dft);
gspnTransformator.transform();
@ -196,12 +153,12 @@ void processOptions() {
#endif
#ifdef STORM_HAVE_Z3
if (dftSettings.solveWithSMT()) {
if (faultTreeSettings.solveWithSMT()) {
// Solve with SMT
if (parametric) {
// analyzeWithSMT<storm::RationalFunction>(dftSettings.getDftFilename());
} else {
analyzeWithSMT<double>(dftSettings.getDftFilename());
analyzeWithSMT<double>(dftIOSettings.getDftFilename());
}
storm::utility::cleanUp();
return;
@ -210,8 +167,8 @@ void processOptions() {
// Set min or max
std::string optimizationDirection = "min";
if (dftSettings.isComputeMaximalValue()) {
STORM_LOG_THROW(!dftSettings.isComputeMinimalValue(), storm::exceptions::InvalidSettingsException, "Cannot compute minimal and maximal values at the same time.");
if (dftIOSettings.isComputeMaximalValue()) {
STORM_LOG_THROW(!dftIOSettings.isComputeMinimalValue(), storm::exceptions::InvalidSettingsException, "Cannot compute minimal and maximal values at the same time.");
optimizationDirection = "max";
}
@ -221,19 +178,19 @@ void processOptions() {
if (ioSettings.isPropertySet()) {
properties.push_back(ioSettings.getProperty());
}
if (dftSettings.usePropExpectedTime()) {
if (dftIOSettings.usePropExpectedTime()) {
properties.push_back("T" + optimizationDirection + "=? [F \"failed\"]");
}
if (dftSettings.usePropProbability()) {
if (dftIOSettings.usePropProbability()) {
properties.push_back("P" + optimizationDirection + "=? [F \"failed\"]");
}
if (dftSettings.usePropTimebound()) {
if (dftIOSettings.usePropTimebound()) {
std::stringstream stream;
stream << "P" << optimizationDirection << "=? [F<=" << dftSettings.getPropTimebound() << " \"failed\"]";
stream << "P" << optimizationDirection << "=? [F<=" << dftIOSettings.getPropTimebound() << " \"failed\"]";
properties.push_back(stream.str());
}
if (dftSettings.usePropTimepoints()) {
for (double timepoint : dftSettings.getPropTimepoints()) {
if (dftIOSettings.usePropTimepoints()) {
for (double timepoint : dftIOSettings.getPropTimepoints()) {
std::stringstream stream;
stream << "P" << optimizationDirection << "=? [F<=" << timepoint << " \"failed\"]";
properties.push_back(stream.str());
@ -246,19 +203,19 @@ void processOptions() {
// Set possible approximation error
double approximationError = 0.0;
if (dftSettings.isApproximationErrorSet()) {
approximationError = dftSettings.getApproximationError();
if (faultTreeSettings.isApproximationErrorSet()) {
approximationError = faultTreeSettings.getApproximationError();
}
// From this point on we are ready to carry out the actual computations.
if (parametric) {
#ifdef STORM_HAVE_CARL
analyzeDFT<storm::RationalFunction>(properties, dftSettings.useSymmetryReduction(), dftSettings.useModularisation(), !dftSettings.isDisableDC(), approximationError);
analyzeDFT<storm::RationalFunction>(properties, faultTreeSettings.useSymmetryReduction(), faultTreeSettings.useModularisation(), !faultTreeSettings.isDisableDC(), approximationError);
#else
STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Parameters are not supported in this build.");
#endif
} else {
analyzeDFT<double>(properties, dftSettings.useSymmetryReduction(), dftSettings.useModularisation(), !dftSettings.isDisableDC(), approximationError);
analyzeDFT<double>(properties, faultTreeSettings.useSymmetryReduction(), faultTreeSettings.useModularisation(), !faultTreeSettings.isDisableDC(), approximationError);
}
}
@ -275,9 +232,8 @@ void processOptions() {
int main(const int argc, const char** argv) {
try {
storm::utility::setUp();
storm::cli::printHeader("Storm-DyFTeE", argc, argv);
//storm::settings::initializeParsSettings("Storm-pars", "storm-pars");
initializeSettings();
storm::cli::printHeader("Storm-dft", argc, argv);
storm::settings::initializeDftSettings("Storm-dft", "storm-dft");
storm::utility::Stopwatch totalTimer(true);
if (!storm::cli::parseOptions(argc, argv)) {

1106
src/storm-dft/builder/ExplicitDFTModelBuilder.cpp
File diff suppressed because it is too large
View File

342
src/storm-dft/builder/ExplicitDFTModelBuilder.h

@ -1,40 +1,42 @@
#pragma once
#pragma once
#include <boost/container/flat_set.hpp>
#include <boost/optional/optional.hpp>
#include <stack>
#include <unordered_set>
#include <limits>
#include "storm/models/sparse/StateLabeling.h"
#include "storm/models/sparse/ChoiceLabeling.h"
#include "storm/models/sparse/StandardRewardModel.h"
#include "storm/models/sparse/Model.h"
#include "storm/storage/SparseMatrix.h"
#include "storm/storage/BitVectorHashMap.h"
#include "storm/storage/sparse/StateStorage.h"
#include "storm-dft/builder/DftExplorationHeuristic.h"
#include "storm-dft/generator/DftNextStateGenerator.h"
#include "storm-dft/storage/dft/DFT.h"
#include "storm-dft/storage/dft/SymmetricUnits.h"
#include "storm-dft/storage/BucketPriorityQueue.h"
namespace storm {
namespace builder {
template<typename ValueType>
/*!
* Build a Markov chain from DFT.
*/
template<typename ValueType, typename StateType = uint32_t>
class ExplicitDFTModelBuilder {
using DFTElementPointer = std::shared_ptr<storm::storage::DFTElement<ValueType>>;
using DFTElementCPointer = std::shared_ptr<storm::storage::DFTElement<ValueType> const>;
using DFTGatePointer = std::shared_ptr<storm::storage::DFTGate<ValueType>>;
using DFTStatePointer = std::shared_ptr<storm::storage::DFTState<ValueType>>;
using DFTRestrictionPointer = std::shared_ptr<storm::storage::DFTRestriction<ValueType>>;
// TODO Matthias: make choosable
using ExplorationHeuristic = DFTExplorationHeuristicDepth<ValueType>;
using ExplorationHeuristicPointer = std::shared_ptr<ExplorationHeuristic>;
// A structure holding the individual components of a model.
struct ModelComponents {
// Constructor
ModelComponents();
// The transition matrix.
@ -51,52 +53,310 @@ namespace storm {
// A vector that stores a labeling for each choice.
boost::optional<storm::models::sparse::ChoiceLabeling> choiceLabeling;
// A flag indicating if the model is deterministic.
bool deterministicModel;
};
// A class holding the information for building the transition matrix.
class MatrixBuilder {
public:
// Constructor
MatrixBuilder(bool canHaveNondeterminism);
/*!
* Set a mapping from a state id to the index in the matrix.
*
* @param id Id of the state.
*/
void setRemapping(StateType id) {
STORM_LOG_ASSERT(id < stateRemapping.size(), "Invalid index for remapping.");
stateRemapping[id] = currentRowGroup;
}
/*!
* Create a new row group if the model is nondeterministic.
*/
void newRowGroup() {
if (canHaveNondeterminism) {
builder.newRowGroup(currentRow);
}
++currentRowGroup;
}
/*!
* Add a transition from the current row.
*
* @param index Target index
* @param value Value of transition
*/
void addTransition(StateType index, ValueType value) {
builder.addNextValue(currentRow, index, value);
}
/*!
* Finish the current row.
*/
void finishRow() {
++currentRow;
}
/*!
* Remap the columns in the matrix.
*/
void remap() {
builder.replaceColumns(stateRemapping, mappingOffset);
}
/*!
* Get the current row group.
*
* @return The current row group.
*/
StateType getCurrentRowGroup() {
return currentRowGroup;
}
/*!
* Get the remapped state for the given id.
*
* @param id State.
*
* @return Remapped index.
*/
StateType getRemapping(StateType id) {
STORM_LOG_ASSERT(id < stateRemapping.size(), "Invalid index for remapping.");
return stateRemapping[id];
}
// Matrix builder.
storm::storage::SparseMatrixBuilder<ValueType> builder;
// Offset to distinguish states which will not be remapped anymore and those which will.
size_t mappingOffset;
// A mapping from state ids to the row group indices in which they actually reside.
// TODO Matthias: avoid hack with fixed int type
std::vector<uint_fast64_t> stateRemapping;
private:
// Index of the current row group.
StateType currentRowGroup;
// Index of the current row.
StateType currentRow;
// Flag indicating if row groups are needed.
bool canHaveNondeterminism;
};
const size_t INITIAL_BUCKETSIZE = 20000;
const uint_fast64_t OFFSET_PSEUDO_STATE = UINT_FAST64_MAX / 2;
storm::storage::DFT<ValueType> const& mDft;
std::shared_ptr<storm::storage::DFTStateGenerationInfo> mStateGenerationInfo;
storm::storage::BitVectorHashMap<uint_fast64_t> mStates;
std::vector<std::pair<uint_fast64_t, storm::storage::BitVector>> mPseudoStatesMapping; // vector of (id to concrete state, bitvector)
size_t newIndex = 0;
bool mergeFailedStates = false;
bool enableDC = true;
size_t failedIndex = 0;
size_t initialStateIndex = 0;
public:
// A structure holding the labeling options.
struct LabelOptions {
bool buildFailLabel = true;
bool buildFailSafeLabel = false;
std::set<std::string> beLabels = {};
// Constructor
LabelOptions(std::vector<std::shared_ptr<storm::logic::Formula const>> properties, bool buildAllLabels = false);
// Flag indicating if the general fail label should be included.
bool buildFailLabel;
// Flag indicating if the general failsafe label should be included.
bool buildFailSafeLabel;
// Flag indicating if all possible labels should be included.
bool buildAllLabels;
// Set of element names whose fail label to include.
std::set<std::string> elementLabels;
};
/*!
* Constructor.
*
* @param dft DFT.
* @param symmetries Symmetries in the dft.
* @param enableDC Flag indicating if dont care propagation should be used.
*/
ExplicitDFTModelBuilder(storm::storage::DFT<ValueType> const& dft, storm::storage::DFTIndependentSymmetries const& symmetries, bool enableDC);
std::shared_ptr<storm::models::sparse::Model<ValueType>> buildModel(LabelOptions const& labelOpts);
/*!
* Build model from DFT.
*
* @param labelOpts Options for labeling.
* @param iteration Current number of iteration.
* @param approximationThreshold Threshold determining when to skip exploring states.
*/
void buildModel(LabelOptions const& labelOpts, size_t iteration, double approximationThreshold = 0.0);
/*!
* Get the built model.
*
* @return The model built from the DFT.
*/
std::shared_ptr<storm::models::sparse::Model<ValueType>> getModel();
/*!
* Get the built approximation model for either the lower or upper bound.
*
* @param lowerBound If true, the lower bound model is returned, else the upper bound model
* @param expectedTime If true, the bounds for expected time are computed, else the bounds for probabilities.
*
* @return The model built from the DFT.
*/
std::shared_ptr<storm::models::sparse::Model<ValueType>> getModelApproximation(bool lowerBound, bool expectedTime);
private:
std::pair<uint_fast64_t, bool> exploreStates(DFTStatePointer const& state, size_t& rowOffset, storm::storage::SparseMatrixBuilder<ValueType>& transitionMatrixBuilder, std::vector<uint_fast64_t>& markovianStates, std::vector<ValueType>& exitRates);
/*!
* Adds a state to the explored states and handles pseudo states.
* Explore state space of DFT.
*
* @param approximationThreshold Threshold to determine when to skip states.
*/
void exploreStateSpace(double approximationThreshold);
/*!
* Initialize the matrix for a refinement iteration.
*/
void initializeNextIteration();
/*!
* Build the labeling.
*
* @param labelOpts Options for labeling.
*/
void buildLabeling(LabelOptions const& labelOpts);
/*!
* Add a state to the explored states (if not already there). It also handles pseudo states.
*
* @param state The state to add.
* @return Id of added state.
*
* @return Id of state.
*/
StateType getOrAddStateIndex(DFTStatePointer const& state);
/*!
* Set markovian flag for the current state.
*
* @param markovian Flag indicating if the state is markovian.
*/
void setMarkovian(bool markovian);
/**
* Change matrix to reflect the lower or upper approximation bound.
*
* @param matrix Matrix to change. The change are reflected here.
* @param lowerBound Flag indicating if the lower bound should be used. Otherwise the upper bound is used.
*/
uint_fast64_t addState(DFTStatePointer const& state);
void changeMatrixBound(storm::storage::SparseMatrix<ValueType> & matrix, bool lowerBound) const;
/*!
* Check if state needs an exploration and remember pseudo states for later creation.
* Get lower bound approximation for state.
*
* @param state The state.
*
* @return Lower bound approximation.
*/
ValueType getLowerBound(DFTStatePointer const& state) const;
/*!
* Get upper bound approximation for state.
*
* @param state The state.
*
* @return Upper bound approximation.
*/
ValueType getUpperBound(DFTStatePointer const& state) const;
/*!
* Compute the MTTF of an AND gate via a closed formula.
* The used formula is 1/( 1/a + 1/b + 1/c + ... - 1/(a+b) - 1/(a+c) - ... + 1/(a+b+c) + ... - ...)
*
* @param rates List of rates of children of AND.
* @param size Only indices < size are considered in the vector.
* @return MTTF.
*/
ValueType computeMTTFAnd(std::vector<ValueType> const& rates, size_t size) const;
/*!
* Compares the priority of two states.
*
* @param idA Id of first state
* @param idB Id of second state
*
* @param state State which might need exploration.
* @return Pair of flag indicating whether the state needs exploration now and the state id if the state already
* exists.
* @return True if the priority of the first state is greater then the priority of the second one.
*/
std::pair<bool, uint_fast64_t> checkForExploration(DFTStatePointer const& state);
bool isPriorityGreater(StateType idA, StateType idB) const;
void printNotExplored() const;
/*!
* Create the model model from the model components.
*
* @param copy If true, all elements of the model component are copied (used for approximation). If false
* they are moved to reduce the memory overhead.
*
* @return The model built from the model components.
*/
std::shared_ptr<storm::models::sparse::Model<ValueType>> createModel(bool copy);
// Initial size of the bitvector.
const size_t INITIAL_BITVECTOR_SIZE = 20000;
// Offset used for pseudo states.
const StateType OFFSET_PSEUDO_STATE = std::numeric_limits<StateType>::max() / 2;
// Dft
storm::storage::DFT<ValueType> const& dft;
// General information for state generation
// TODO Matthias: use const reference
std::shared_ptr<storm::storage::DFTStateGenerationInfo> stateGenerationInfo;
// Flag indication if dont care propagation should be used.
bool enableDC = true;
//TODO Matthias: make changeable
const bool mergeFailedStates = true;
// Heuristic used for approximation
storm::builder::ApproximationHeuristic usedHeuristic;
// Current id for new state
size_t newIndex = 0;
// Id of failed state
size_t failedStateId = 0;
// Id of initial state
size_t initialStateIndex = 0;
// Next state generator for exploring the state space
storm::generator::DftNextStateGenerator<ValueType, StateType> generator;
// Structure for the components of the model.
ModelComponents modelComponents;
// Structure for the transition matrix builder.
MatrixBuilder matrixBuilder;
// Internal information about the states that were explored.
storm::storage::sparse::StateStorage<StateType> stateStorage;
// A priority queue of states that still need to be explored.
storm::storage::BucketPriorityQueue<ValueType> explorationQueue;
// A mapping of not yet explored states from the id to the tuple (state object, heuristic values).
std::map<StateType, std::pair<DFTStatePointer, ExplorationHeuristicPointer>> statesNotExplored;
// Holds all skipped states which were not yet expanded. More concretely it is a mapping from matrix indices
// to the corresponding skipped states.
// Notice that we need an ordered map here to easily iterate in increasing order over state ids.
// TODO remove again
std::map<StateType, std::pair<DFTStatePointer, ExplorationHeuristicPointer>> skippedStates;
// List of independent subtrees and the BEs contained in them.
std::vector<std::vector<size_t>> subtreeBEs;
};
}
}

841
src/storm-dft/builder/ExplicitDFTModelBuilderApprox.cpp

@ -1,841 +0,0 @@
#include "ExplicitDFTModelBuilderApprox.h"
#include <map>
#include "storm/models/sparse/MarkovAutomaton.h"
#include "storm/models/sparse/Ctmc.h"
#include "storm/utility/constants.h"
#include "storm/utility/vector.h"
#include "storm/utility/bitoperations.h"
#include "storm/exceptions/UnexpectedException.h"
#include "storm/settings/SettingsManager.h"
#include "storm/logic/AtomicLabelFormula.h"
#include "storm-dft/settings/modules/DFTSettings.h"
namespace storm {
namespace builder {
template<typename ValueType, typename StateType>
ExplicitDFTModelBuilderApprox<ValueType, StateType>::ModelComponents::ModelComponents() : transitionMatrix(), stateLabeling(), markovianStates(), exitRates(), choiceLabeling() {
// Intentionally left empty.
}
template<typename ValueType, typename StateType>
ExplicitDFTModelBuilderApprox<ValueType, StateType>::MatrixBuilder::MatrixBuilder(bool canHaveNondeterminism) : mappingOffset(0), stateRemapping(), currentRowGroup(0), currentRow(0), canHaveNondeterminism((canHaveNondeterminism)) {
// Create matrix builder
builder = storm::storage::SparseMatrixBuilder<ValueType>(0, 0, 0, false, canHaveNondeterminism, 0);
}
template<typename ValueType, typename StateType>
ExplicitDFTModelBuilderApprox<ValueType, StateType>::LabelOptions::LabelOptions(std::vector<std::shared_ptr<const storm::logic::Formula>> properties, bool buildAllLabels) : buildFailLabel(true), buildFailSafeLabel(false), buildAllLabels(buildAllLabels) {
// Get necessary labels from properties
std::vector<std::shared_ptr<storm::logic::AtomicLabelFormula const>> atomicLabels;
for (auto property : properties) {
property->gatherAtomicLabelFormulas(atomicLabels);
}
// Set usage of necessary labels
for (auto atomic : atomicLabels) {
std::string label = atomic->getLabel();
std::size_t foundIndex = label.find("_fail");
if (foundIndex != std::string::npos) {
elementLabels.insert(label.substr(0, foundIndex));
} else if (label.compare("failed") == 0) {
buildFailLabel = true;
} else if (label.compare("failsafe") == 0) {
buildFailSafeLabel = true;
} else {
STORM_LOG_WARN("Label '" << label << "' not known.");
}
}
}
template<typename ValueType, typename StateType>
ExplicitDFTModelBuilderApprox<ValueType, StateType>::ExplicitDFTModelBuilderApprox(storm::storage::DFT<ValueType> const& dft, storm::storage::DFTIndependentSymmetries const& symmetries, bool enableDC) :
dft(dft),
stateGenerationInfo(std::make_shared<storm::storage::DFTStateGenerationInfo>(dft.buildStateGenerationInfo(symmetries))),
enableDC(enableDC),
usedHeuristic(storm::settings::getModule<storm::settings::modules::DFTSettings>().getApproximationHeuristic()),
generator(dft, *stateGenerationInfo, enableDC, mergeFailedStates),
matrixBuilder(!generator.isDeterministicModel()),
stateStorage(((dft.stateVectorSize() / 64) + 1) * 64),
// TODO Matthias: make choosable
//explorationQueue(dft.nrElements()+1, 0, 1)
explorationQueue(200, 0, 0.9)
{
// Intentionally left empty.
// TODO Matthias: remove again
usedHeuristic = storm::builder::ApproximationHeuristic::DEPTH;
// Compute independent subtrees
if (dft.topLevelType() == storm::storage::DFTElementType::OR) {
// We only support this for approximation with top level element OR
for (auto const& child : dft.getGate(dft.getTopLevelIndex())->children()) {
// Consider all children of the top level gate
std::vector<size_t> isubdft;
if (child->nrParents() > 1 || child->hasOutgoingDependencies()) {
STORM_LOG_TRACE("child " << child->name() << "does not allow modularisation.");
isubdft.clear();
} else if (dft.isGate(child->id())) {
isubdft = dft.getGate(child->id())->independentSubDft(false);
} else {
STORM_LOG_ASSERT(dft.isBasicElement(child->id()), "Child is no BE.");
if(dft.getBasicElement(child->id())->hasIngoingDependencies()) {
STORM_LOG_TRACE("child " << child->name() << "does not allow modularisation.");
isubdft.clear();
} else {
isubdft = {child->id()};
}
}
if(isubdft.empty()) {
subtreeBEs.clear();
break;
} else {
// Add new independent subtree
std::vector<size_t> subtree;
for (size_t id : isubdft) {
if (dft.isBasicElement(id)) {
subtree.push_back(id);
}
}
subtreeBEs.push_back(subtree);
}
}
}
if (subtreeBEs.empty()) {
// Consider complete tree
std::vector<size_t> subtree;
for (size_t id = 0; id < dft.nrElements(); ++id) {
if (dft.isBasicElement(id)) {
subtree.push_back(id);
}
}
subtreeBEs.push_back(subtree);
}
for (auto tree : subtreeBEs) {
std::stringstream stream;
stream << "Subtree: ";
for (size_t id : tree) {
stream << id << ", ";
}
STORM_LOG_TRACE(stream.str());
}
}
template<typename ValueType, typename StateType>
void ExplicitDFTModelBuilderApprox<ValueType, StateType>::buildModel(LabelOptions const& labelOpts, size_t iteration, double approximationThreshold) {
STORM_LOG_TRACE("Generating DFT state space");
if (iteration < 1) {
// Initialize
modelComponents.markovianStates = storm::storage::BitVector(INITIAL_BITVECTOR_SIZE);
if(mergeFailedStates) {
// Introduce explicit fail state
storm::generator::StateBehavior<ValueType, StateType> behavior = generator.createMergeFailedState([this] (DFTStatePointer const& state) {
this->failedStateId = newIndex++;
matrixBuilder.stateRemapping.push_back(0);
return this->failedStateId;
} );
matrixBuilder.setRemapping(failedStateId);
STORM_LOG_ASSERT(!behavior.empty(), "Behavior is empty.");
matrixBuilder.newRowGroup();
setMarkovian(behavior.begin()->isMarkovian());
// Now add self loop.
// TODO Matthias: maybe use general method.
STORM_LOG_ASSERT(behavior.getNumberOfChoices() == 1, "Wrong number of choices for failed state.");
STORM_LOG_ASSERT(behavior.begin()->size() == 1, "Wrong number of transitions for failed state.");
std::pair<StateType, ValueType> stateProbabilityPair = *(behavior.begin()->begin());
STORM_LOG_ASSERT(stateProbabilityPair.first == failedStateId, "No self loop for failed state.");
STORM_LOG_ASSERT(storm::utility::isOne<ValueType>(stateProbabilityPair.second), "Probability for failed state != 1.");
matrixBuilder.addTransition(stateProbabilityPair.first, stateProbabilityPair.second);
matrixBuilder.finishRow();
}
// Build initial state
this->stateStorage.initialStateIndices = generator.getInitialStates(std::bind(&ExplicitDFTModelBuilderApprox::getOrAddStateIndex, this, std::placeholders::_1));
STORM_LOG_ASSERT(stateStorage.initialStateIndices.size() == 1, "Only one initial state assumed.");
initialStateIndex = stateStorage.initialStateIndices[0];
STORM_LOG_TRACE("Initial state: " << initialStateIndex);
// Initialize heuristic values for inital state
STORM_LOG_ASSERT(!statesNotExplored.at(initialStateIndex).second, "Heuristic for initial state is already initialized");
ExplorationHeuristicPointer heuristic = std::make_shared<ExplorationHeuristic>(initialStateIndex);
heuristic->markExpand();
statesNotExplored[initialStateIndex].second = heuristic;
explorationQueue.push(heuristic);
} else {
initializeNextIteration();
}
if (approximationThreshold > 0) {
switch (usedHeuristic) {
case storm::builder::ApproximationHeuristic::NONE:
// Do not change anything
approximationThreshold = dft.nrElements()+10;
break;
case storm::builder::ApproximationHeuristic::DEPTH:
approximationThreshold = iteration + 1;
break;
case storm::builder::ApproximationHeuristic::PROBABILITY:
case storm::builder::ApproximationHeuristic::BOUNDDIFFERENCE:
approximationThreshold = 10 * std::pow(2, iteration);
break;
}
}
exploreStateSpace(approximationThreshold);
size_t stateSize = stateStorage.getNumberOfStates() + (mergeFailedStates ? 1 : 0);
modelComponents.markovianStates.resize(stateSize);
modelComponents.deterministicModel = generator.isDeterministicModel();
// Fix the entries in the transition matrix according to the mapping of ids to row group indices
STORM_LOG_ASSERT(matrixBuilder.getRemapping(initialStateIndex) == initialStateIndex, "Initial state should not be remapped.");
// TODO Matthias: do not consider all rows?
STORM_LOG_TRACE("Remap matrix: " << matrixBuilder.stateRemapping << ", offset: " << matrixBuilder.mappingOffset);
matrixBuilder.remap();
STORM_LOG_TRACE("State remapping: " << matrixBuilder.stateRemapping);
STORM_LOG_TRACE("Markovian states: " << modelComponents.markovianStates);
STORM_LOG_DEBUG("Model has " << stateSize << " states");
STORM_LOG_DEBUG("Model is " << (generator.isDeterministicModel() ? "deterministic" : "non-deterministic"));
// Build transition matrix
modelComponents.transitionMatrix = matrixBuilder.builder.build(stateSize, stateSize);
if (stateSize <= 15) {
STORM_LOG_TRACE("Transition matrix: " << std::endl << modelComponents.transitionMatrix);
} else {
STORM_LOG_TRACE("Transition matrix: too big to print");
}
buildLabeling(labelOpts);
}
template<typename ValueType, typename StateType>
void ExplicitDFTModelBuilderApprox<ValueType, StateType>::initializeNextIteration() {
STORM_LOG_TRACE("Refining DFT state space");
// TODO Matthias: should be easier now as skipped states all are at the end of the matrix
// Push skipped states to explore queue
// TODO Matthias: remove
for (auto const& skippedState : skippedStates) {
statesNotExplored[skippedState.second.first->getId()] = skippedState.second;
explorationQueue.push(skippedState.second.second);
}
// Initialize matrix builder again
// TODO Matthias: avoid copy
std::vector<uint_fast64_t> copyRemapping = matrixBuilder.stateRemapping;
matrixBuilder = MatrixBuilder(!generator.isDeterministicModel());
matrixBuilder.stateRemapping = copyRemapping;
StateType nrStates = modelComponents.transitionMatrix.getRowGroupCount();
STORM_LOG_ASSERT(nrStates == matrixBuilder.stateRemapping.size(), "No. of states does not coincide with mapping size.");
// Start by creating a remapping from the old indices to the new indices
std::vector<StateType> indexRemapping = std::vector<StateType>(nrStates, 0);
auto iterSkipped = skippedStates.begin();
size_t skippedBefore = 0;
for (size_t i = 0; i < indexRemapping.size(); ++i) {
while (iterSkipped != skippedStates.end() && iterSkipped->first <= i) {
STORM_LOG_ASSERT(iterSkipped->first < indexRemapping.size(), "Skipped is too high.");
++skippedBefore;
++iterSkipped;
}
indexRemapping[i] = i - skippedBefore;
}
// Set remapping
size_t nrExpandedStates = nrStates - skippedBefore;
matrixBuilder.mappingOffset = nrStates;
STORM_LOG_TRACE("# expanded states: " << nrExpandedStates);
StateType skippedIndex = nrExpandedStates;
std::map<StateType, std::pair<DFTStatePointer, ExplorationHeuristicPointer>> skippedStatesNew;
for (size_t id = 0; id < matrixBuilder.stateRemapping.size(); ++id) {
StateType index = matrixBuilder.getRemapping(id);
auto itFind = skippedStates.find(index);
if (itFind != skippedStates.end()) {
// Set new mapping for skipped state
matrixBuilder.stateRemapping[id] = skippedIndex;
skippedStatesNew[skippedIndex] = itFind->second;
indexRemapping[index] = skippedIndex;
++skippedIndex;
} else {
// Set new mapping for expanded state
matrixBuilder.stateRemapping[id] = indexRemapping[index];
}
}
STORM_LOG_TRACE("New state remapping: " << matrixBuilder.stateRemapping);
std::stringstream ss;
ss << "Index remapping:" << std::endl;
for (auto tmp : indexRemapping) {
ss << tmp << " ";
}
STORM_LOG_TRACE(ss.str());
// Remap markovian states
storm::storage::BitVector markovianStatesNew = storm::storage::BitVector(modelComponents.markovianStates.size(), true);
// Iterate over all not set bits
modelComponents.markovianStates.complement();
size_t index = modelComponents.markovianStates.getNextSetIndex(0);
while (index < modelComponents.markovianStates.size()) {
markovianStatesNew.set(indexRemapping[index], false);
index = modelComponents.markovianStates.getNextSetIndex(index+1);
}
STORM_LOG_ASSERT(modelComponents.markovianStates.size() - modelComponents.markovianStates.getNumberOfSetBits() == markovianStatesNew.getNumberOfSetBits(), "Remapping of markovian states is wrong.");
STORM_LOG_ASSERT(markovianStatesNew.size() == nrStates, "No. of states does not coincide with markovian size.");
modelComponents.markovianStates = markovianStatesNew;
// Build submatrix for expanded states
// TODO Matthias: only use row groups when necessary
for (StateType oldRowGroup = 0; oldRowGroup < modelComponents.transitionMatrix.getRowGroupCount(); ++oldRowGroup) {
if (indexRemapping[oldRowGroup] < nrExpandedStates) {
// State is expanded -> copy to new matrix
matrixBuilder.newRowGroup();
for (StateType oldRow = modelComponents.transitionMatrix.getRowGroupIndices()[oldRowGroup]; oldRow < modelComponents.transitionMatrix.getRowGroupIndices()[oldRowGroup+1]; ++oldRow) {
for (typename storm::storage::SparseMatrix<ValueType>::const_iterator itEntry = modelComponents.transitionMatrix.begin(oldRow); itEntry != modelComponents.transitionMatrix.end(oldRow); ++itEntry) {
auto itFind = skippedStates.find(itEntry->getColumn());
if (itFind != skippedStates.end()) {
// Set id for skipped states as we remap it later
matrixBuilder.addTransition(matrixBuilder.mappingOffset + itFind->second.first->getId(), itEntry->getValue());
} else {
// Set newly remapped index for expanded states
matrixBuilder.addTransition(indexRemapping[itEntry->getColumn()], itEntry->getValue());
}
}
matrixBuilder.finishRow();
}
}
}
skippedStates = skippedStatesNew;
STORM_LOG_ASSERT(matrixBuilder.getCurrentRowGroup() == nrExpandedStates, "Row group size does not match.");
skippedStates.clear();
}
template<typename ValueType, typename StateType>
void ExplicitDFTModelBuilderApprox<ValueType, StateType>::exploreStateSpace(double approximationThreshold) {
size_t nrExpandedStates = 0;
size_t nrSkippedStates = 0;
// TODO Matthias: do not empty queue every time but break before
while (!explorationQueue.empty()) {
// Get the first state in the queue
ExplorationHeuristicPointer currentExplorationHeuristic = explorationQueue.popTop();
StateType currentId = currentExplorationHeuristic->getId();
auto itFind = statesNotExplored.find(currentId);
STORM_LOG_ASSERT(itFind != statesNotExplored.end(), "Id " << currentId << " not found");
DFTStatePointer currentState = itFind->second.first;
STORM_LOG_ASSERT(currentExplorationHeuristic == itFind->second.second, "Exploration heuristics do not match");
STORM_LOG_ASSERT(currentState->getId() == currentId, "Ids do not match");
// Remove it from the list of not explored states
statesNotExplored.erase(itFind);
STORM_LOG_ASSERT(stateStorage.stateToId.contains(currentState->status()), "State is not contained in state storage.");
STORM_LOG_ASSERT(stateStorage.stateToId.getValue(currentState->status()) == currentId, "Ids of states do not coincide.");
// Get concrete state if necessary
if (currentState->isPseudoState()) {
// Create concrete state from pseudo state
currentState->construct();
}
STORM_LOG_ASSERT(!currentState->isPseudoState(), "State is pseudo state.");
// Remember that the current row group was actually filled with the transitions of a different state
matrixBuilder.setRemapping(currentId);
matrixBuilder.newRowGroup();
// Try to explore the next state
generator.load(currentState);
//if (approximationThreshold > 0.0 && nrExpandedStates > approximationThreshold && !currentExplorationHeuristic->isExpand()) {
if (approximationThreshold > 0.0 && currentExplorationHeuristic->isSkip(approximationThreshold)) {
// Skip the current state
++nrSkippedStates;
STORM_LOG_TRACE("Skip expansion of state: " << dft.getStateString(currentState));
setMarkovian(true);
// Add transition to target state with temporary value 0
// TODO Matthias: what to do when there is no unique target state?
matrixBuilder.addTransition(failedStateId, storm::utility::zero<ValueType>());
// Remember skipped state
skippedStates[matrixBuilder.getCurrentRowGroup() - 1] = std::make_pair(currentState, currentExplorationHeuristic);
matrixBuilder.finishRow();
} else {
// Explore the current state
++nrExpandedStates;
storm::generator::StateBehavior<ValueType, StateType> behavior = generator.expand(std::bind(&ExplicitDFTModelBuilderApprox::getOrAddStateIndex, this, std::placeholders::_1));
STORM_LOG_ASSERT(!behavior.empty(), "Behavior is empty.");
setMarkovian(behavior.begin()->isMarkovian());
// Now add all choices.
for (auto const& choice : behavior) {
// Add the probabilistic behavior to the matrix.
for (auto const& stateProbabilityPair : choice) {
STORM_LOG_ASSERT(!storm::utility::isZero(stateProbabilityPair.second), "Probability zero.");
// Set transition to state id + offset. This helps in only remapping all previously skipped states.
matrixBuilder.addTransition(matrixBuilder.mappingOffset + stateProbabilityPair.first, stateProbabilityPair.second);
// Set heuristic values for reached states
auto iter = statesNotExplored.find(stateProbabilityPair.first);
if (iter != statesNotExplored.end()) {
// Update heuristic values
DFTStatePointer state = iter->second.first;
if (!iter->second.second) {
// Initialize heuristic values
ExplorationHeuristicPointer heuristic = std::make_shared<ExplorationHeuristic>(stateProbabilityPair.first, *currentExplorationHeuristic, stateProbabilityPair.second, choice.getTotalMass());
iter->second.second = heuristic;
if (state->hasFailed(dft.getTopLevelIndex()) || state->isFailsafe(dft.getTopLevelIndex()) || state->nrFailableDependencies() > 0 || (state->nrFailableDependencies() == 0 && state->nrFailableBEs() == 0)) {
// Do not skip absorbing state or if reached by dependencies
iter->second.second->markExpand();
}
if (usedHeuristic == storm::builder::ApproximationHeuristic::BOUNDDIFFERENCE) {
// Compute bounds for heuristic now
if (state->isPseudoState()) {
// Create concrete state from pseudo state
state->construct();
}
STORM_LOG_ASSERT(!currentState->isPseudoState(), "State is pseudo state.");
// Initialize bounds
// TODO Mathias: avoid hack
ValueType lowerBound = getLowerBound(state);
ValueType upperBound = getUpperBound(state);
heuristic->setBounds(lowerBound, upperBound);
}
explorationQueue.push(heuristic);
} else if (!iter->second.second->isExpand()) {
double oldPriority = iter->second.second->getPriority();
if (iter->second.second->updateHeuristicValues(*currentExplorationHeuristic, stateProbabilityPair.second, choice.getTotalMass())) {
// Update priority queue
explorationQueue.update(iter->second.second, oldPriority);
}
}
}
}
matrixBuilder.finishRow();
}
}
} // end exploration
STORM_LOG_INFO("Expanded " << nrExpandedStates << " states");
STORM_LOG_INFO("Skipped " << nrSkippedStates << " states");
STORM_LOG_ASSERT(nrSkippedStates == skippedStates.size(), "Nr skipped states is wrong");
}
template<typename ValueType, typename StateType>
void ExplicitDFTModelBuilderApprox<ValueType, StateType>::buildLabeling(LabelOptions const& labelOpts) {
// Build state labeling
modelComponents.stateLabeling = storm::models::sparse::StateLabeling(modelComponents.transitionMatrix.getRowGroupCount());
// Initial state
modelComponents.stateLabeling.addLabel("init");
STORM_LOG_ASSERT(matrixBuilder.getRemapping(initialStateIndex) == initialStateIndex, "Initial state should not be remapped.");
modelComponents.stateLabeling.addLabelToState("init", initialStateIndex);
// Label all states corresponding to their status (failed, failsafe, failed BE)
if(labelOpts.buildFailLabel) {
modelComponents.stateLabeling.addLabel("failed");
}
if(labelOpts.buildFailSafeLabel) {
modelComponents.stateLabeling.addLabel("failsafe");
}
// Collect labels for all necessary elements
for (size_t id = 0; id < dft.nrElements(); ++id) {
std::shared_ptr<storage::DFTElement<ValueType> const> element = dft.getElement(id);
if (labelOpts.buildAllLabels || labelOpts.elementLabels.count(element->name()) > 0) {
modelComponents.stateLabeling.addLabel(element->name() + "_fail");
}
}
// Set labels to states
if (mergeFailedStates) {
modelComponents.stateLabeling.addLabelToState("failed", failedStateId);
}
for (auto const& stateIdPair : stateStorage.stateToId) {
storm::storage::BitVector state = stateIdPair.first;
size_t stateId = matrixBuilder.getRemapping(stateIdPair.second);
if (!mergeFailedStates && labelOpts.buildFailLabel && dft.hasFailed(state, *stateGenerationInfo)) {
modelComponents.stateLabeling.addLabelToState("failed", stateId);
}
if (labelOpts.buildFailSafeLabel && dft.isFailsafe(state, *stateGenerationInfo)) {
modelComponents.stateLabeling.addLabelToState("failsafe", stateId);
}
// Set fail status for each necessary element
for (size_t id = 0; id < dft.nrElements(); ++id) {
std::shared_ptr<storage::DFTElement<ValueType> const> element = dft.getElement(id);
if ((labelOpts.buildAllLabels || labelOpts.elementLabels.count(element->name()) > 0) && storm::storage::DFTState<ValueType>::hasFailed(state, stateGenerationInfo->getStateIndex(element->id()))) {
modelComponents.stateLabeling.addLabelToState(element->name() + "_fail", stateId);
}
}
}
STORM_LOG_TRACE(modelComponents.stateLabeling);
}
template<typename ValueType, typename StateType>
std::shared_ptr<storm::models::sparse::Model<ValueType>> ExplicitDFTModelBuilderApprox<ValueType, StateType>::getModel() {
STORM_LOG_ASSERT(skippedStates.size() == 0, "Concrete model has skipped states");
return createModel(false);
}
template<typename ValueType, typename StateType>
std::shared_ptr<storm::models::sparse::Model<ValueType>> ExplicitDFTModelBuilderApprox<ValueType, StateType>::getModelApproximation(bool lowerBound, bool expectedTime) {
if (expectedTime) {
// TODO Matthias: handle case with no skipped states
changeMatrixBound(modelComponents.transitionMatrix, lowerBound);
return createModel(true);
} else {
// Change model for probabilities
// TODO Matthias: make nicer
storm::storage::SparseMatrix<ValueType> matrix = modelComponents.transitionMatrix;
storm::models::sparse::StateLabeling labeling = modelComponents.stateLabeling;
if (lowerBound) {
// Set self loop for lower bound
for (auto it = skippedStates.begin(); it != skippedStates.end(); ++it) {
auto matrixEntry = matrix.getRow(it->first, 0).begin();
STORM_LOG_ASSERT(matrixEntry->getColumn() == failedStateId, "Transition has wrong target state.");
STORM_LOG_ASSERT(!it->second.first->isPseudoState(), "State is still pseudo state.");
matrixEntry->setValue(storm::utility::one<ValueType>());
matrixEntry->setColumn(it->first);
}
} else {
// Make skipped states failed states for upper bound
storm::storage::BitVector failedStates = modelComponents.stateLabeling.getStates("failed");
for (auto it = skippedStates.begin(); it != skippedStates.end(); ++it) {
failedStates.set(it->first);
}
labeling.setStates("failed", failedStates);
}
std::shared_ptr<storm::models::sparse::Model<ValueType>> model;
if (modelComponents.deterministicModel) {
model = std::make_shared<storm::models::sparse::Ctmc<ValueType>>(std::move(matrix), std::move(labeling));
} else {
// Build MA
// Compute exit rates
// TODO Matthias: avoid computing multiple times
modelComponents.exitRates = std::vector<ValueType>(modelComponents.markovianStates.size());
std::vector<typename storm::storage::SparseMatrix<ValueType>::index_type> indices = matrix.getRowGroupIndices();
for (StateType stateIndex = 0; stateIndex < modelComponents.markovianStates.size(); ++stateIndex) {
if (modelComponents.markovianStates[stateIndex]) {
modelComponents.exitRates[stateIndex] = matrix.getRowSum(indices[stateIndex]);
} else {
modelComponents.exitRates[stateIndex] = storm::utility::zero<ValueType>();
}
}
STORM_LOG_TRACE("Exit rates: " << modelComponents.exitRates);
storm::storage::sparse::ModelComponents<ValueType> maComponents(std::move(matrix), std::move(labeling));
maComponents.rateTransitions = true;
maComponents.markovianStates = modelComponents.markovianStates;
maComponents.exitRates = modelComponents.exitRates;
std::shared_ptr<storm::models::sparse::MarkovAutomaton<ValueType>> ma = std::make_shared<storm::models::sparse::MarkovAutomaton<ValueType>>(std::move(maComponents));
if (ma->hasOnlyTrivialNondeterminism()) {
// Markov automaton can be converted into CTMC
// TODO Matthias: change components which were not moved accordingly
model = ma->convertToCTMC();
} else {
model = ma;
}
}
if (model->getNumberOfStates() <= 15) {
STORM_LOG_TRACE("Transition matrix: " << std::endl << model->getTransitionMatrix());
} else {
STORM_LOG_TRACE("Transition matrix: too big to print");
}
return model;
}
}
template<typename ValueType, typename StateType>
std::shared_ptr<storm::models::sparse::Model<ValueType>> ExplicitDFTModelBuilderApprox<ValueType, StateType>::createModel(bool copy) {
std::shared_ptr<storm::models::sparse::Model<ValueType>> model;
if (modelComponents.deterministicModel) {
// Build CTMC
if (copy) {
model = std::make_shared<storm::models::sparse::Ctmc<ValueType>>(modelComponents.transitionMatrix, modelComponents.stateLabeling);
} else {
model = std::make_shared<storm::models::sparse::Ctmc<ValueType>>(std::move(modelComponents.transitionMatrix), std::move(modelComponents.stateLabeling));
}
} else {
// Build MA
// Compute exit rates
// TODO Matthias: avoid computing multiple times
modelComponents.exitRates = std::vector<ValueType>(modelComponents.markovianStates.size());
std::vector<typename storm::storage::SparseMatrix<ValueType>::index_type> indices = modelComponents.transitionMatrix.getRowGroupIndices();
for (StateType stateIndex = 0; stateIndex < modelComponents.markovianStates.size(); ++stateIndex) {
if (modelComponents.markovianStates[stateIndex]) {
modelComponents.exitRates[stateIndex] = modelComponents.transitionMatrix.getRowSum(indices[stateIndex]);
} else {
modelComponents.exitRates[stateIndex] = storm::utility::zero<ValueType>();
}
}
STORM_LOG_TRACE("Exit rates: " << modelComponents.exitRates);
std::shared_ptr<storm::models::sparse::MarkovAutomaton<ValueType>> ma;
if (copy) {
storm::storage::sparse::ModelComponents<ValueType> maComponents(modelComponents.transitionMatrix, modelComponents.stateLabeling);
maComponents.rateTransitions = true;
maComponents.markovianStates = modelComponents.markovianStates;
maComponents.exitRates = modelComponents.exitRates;
std::shared_ptr<storm::models::sparse::MarkovAutomaton<ValueType>> ma = std::make_shared<storm::models::sparse::MarkovAutomaton<ValueType>>(std::move(maComponents));
} else {
storm::storage::sparse::ModelComponents<ValueType> maComponents(std::move(modelComponents.transitionMatrix), std::move(modelComponents.stateLabeling));
maComponents.rateTransitions = true;
maComponents.markovianStates = std::move(modelComponents.markovianStates);
maComponents.exitRates = std::move(modelComponents.exitRates);
std::shared_ptr<storm::models::sparse::MarkovAutomaton<ValueType>> ma = std::make_shared<storm::models::sparse::MarkovAutomaton<ValueType>>(std::move(maComponents));
}
if (ma->hasOnlyTrivialNondeterminism()) {
// Markov automaton can be converted into CTMC
// TODO Matthias: change components which were not moved accordingly
model = ma->convertToCTMC();
} else {
model = ma;
}
}
if (model->getNumberOfStates() <= 15) {
STORM_LOG_TRACE("Transition matrix: " << std::endl << model->getTransitionMatrix());
} else {
STORM_LOG_TRACE("Transition matrix: too big to print");
}
return model;
}
template<typename ValueType, typename StateType>
void ExplicitDFTModelBuilderApprox<ValueType, StateType>::changeMatrixBound(storm::storage::SparseMatrix<ValueType> & matrix, bool lowerBound) const {
// Set lower bound for skipped states
for (auto it = skippedStates.begin(); it != skippedStates.end(); ++it) {
auto matrixEntry = matrix.getRow(it->first, 0).begin();
STORM_LOG_ASSERT(matrixEntry->getColumn() == failedStateId, "Transition has wrong target state.");
STORM_LOG_ASSERT(!it->second.first->isPseudoState(), "State is still pseudo state.");
ExplorationHeuristicPointer heuristic = it->second.second;
if (storm::utility::isZero(heuristic->getUpperBound())) {
// Initialize bounds
ValueType lowerBound = getLowerBound(it->second.first);
ValueType upperBound = getUpperBound(it->second.first);
heuristic->setBounds(lowerBound, upperBound);
}
// Change bound
if (lowerBound) {
matrixEntry->setValue(it->second.second->getLowerBound());
} else {
matrixEntry->setValue(it->second.second->getUpperBound());
}
}
}
template<typename ValueType, typename StateType>
ValueType ExplicitDFTModelBuilderApprox<ValueType, StateType>::getLowerBound(DFTStatePointer const& state) const {
// Get the lower bound by considering the failure of all possible BEs
ValueType lowerBound = storm::utility::zero<ValueType>();
for (size_t index = 0; index < state->nrFailableBEs(); ++index) {
lowerBound += state->getFailableBERate(index);
}
return lowerBound;
}
template<typename ValueType, typename StateType>
ValueType ExplicitDFTModelBuilderApprox<ValueType, StateType>::getUpperBound(DFTStatePointer const& state) const {
if (state->hasFailed(dft.getTopLevelIndex())) {
return storm::utility::zero<ValueType>();
}
// Get the upper bound by considering the failure of all BEs
ValueType upperBound = storm::utility::one<ValueType>();
ValueType rateSum = storm::utility::zero<ValueType>();
// Compute for each independent subtree
for (std::vector<size_t> const& subtree : subtreeBEs) {
// Get all possible rates
std::vector<ValueType> rates;
storm::storage::BitVector coldBEs(subtree.size(), false);
for (size_t i = 0; i < subtree.size(); ++i) {
size_t id = subtree[i];
if (state->isOperational(id)) {
// Get BE rate
ValueType rate = state->getBERate(id);
if (storm::utility::isZero<ValueType>(rate)) {
// Get active failure rate for cold BE
rate = dft.getBasicElement(id)->activeFailureRate();
if (storm::utility::isZero<ValueType>(rate)) {
// Ignore BE which cannot fail
continue;
}
// Mark BE as cold
coldBEs.set(i, true);
}
rates.push_back(rate);
rateSum += rate;
}
}
STORM_LOG_ASSERT(rates.size() > 0, "No rates failable");
// Sort rates
std::sort(rates.begin(), rates.end());
std::vector<size_t> rateCount(rates.size(), 0);
size_t lastIndex = 0;
for (size_t i = 0; i < rates.size(); ++i) {
if (rates[lastIndex] != rates[i]) {
lastIndex = i;
}
++rateCount[lastIndex];
}
for (size_t i = 0; i < rates.size(); ++i) {
// Cold BEs cannot fail in the first step
if (!coldBEs.get(i) && rateCount[i] > 0) {
std::iter_swap(rates.begin() + i, rates.end() - 1);
// Compute AND MTTF of subtree without current rate and scale with current rate
upperBound += rates.back() * rateCount[i] * computeMTTFAnd(rates, rates.size() - 1);
// Swap back
// TODO try to avoid swapping back
std::iter_swap(rates.begin() + i, rates.end() - 1);
}
}
}
STORM_LOG_TRACE("Upper bound is " << (rateSum / upperBound) << " for state " << state->getId());
STORM_LOG_ASSERT(!storm::utility::isZero(upperBound), "Upper bound is 0");
STORM_LOG_ASSERT(!storm::utility::isZero(rateSum), "State is absorbing");
return rateSum / upperBound;
}
template<typename ValueType, typename StateType>
ValueType ExplicitDFTModelBuilderApprox<ValueType, StateType>::computeMTTFAnd(std::vector<ValueType> const& rates, size_t size) const {
ValueType result = storm::utility::zero<ValueType>();
if (size == 0) {
return result;
}
// TODO Matthias: works only for <64 BEs!
// WARNING: this code produces wrong results for more than 32 BEs
/*for (size_t i = 1; i < 4 && i <= rates.size(); ++i) {
size_t permutation = smallestIntWithNBitsSet(static_cast<size_t>(i));
ValueType sum = storm::utility::zero<ValueType>();
do {
ValueType permResult = storm::utility::zero<ValueType>();
for(size_t j = 0; j < rates.size(); ++j) {
if(permutation & static_cast<size_t>(1 << static_cast<size_t>(j))) {
// WARNING: if the first bit is set, it also recognizes the 32nd bit as set
// TODO: fix
permResult += rates[j];
}
}
permutation = nextBitPermutation(permutation);
STORM_LOG_ASSERT(!storm::utility::isZero(permResult), "PermResult is 0");
sum += storm::utility::one<ValueType>() / permResult;
} while(permutation < (static_cast<size_t>(1) << rates.size()) && permutation != 0);
if (i % 2 == 0) {
result -= sum;
} else {
result += sum;
}
}*/
// Compute result with permutations of size <= 3
ValueType one = storm::utility::one<ValueType>();
for (size_t i1 = 0; i1 < size; ++i1) {
// + 1/a
ValueType sum = rates[i1];
result += one / sum;
for (size_t i2 = 0; i2 < i1; ++i2) {
// - 1/(a+b)
ValueType sum2 = sum + rates[i2];
result -= one / sum2;
for (size_t i3 = 0; i3 < i2; ++i3) {
// + 1/(a+b+c)
result += one / (sum2 + rates[i3]);
}
}
}
STORM_LOG_ASSERT(!storm::utility::isZero(result), "UpperBound is 0");
return result;
}
template<typename ValueType, typename StateType>
StateType ExplicitDFTModelBuilderApprox<ValueType, StateType>::getOrAddStateIndex(DFTStatePointer const& state) {
StateType stateId;
bool changed = false;
if (stateGenerationInfo->hasSymmetries()) {
// Order state by symmetry
STORM_LOG_TRACE("Check for symmetry: " << dft.getStateString(state));
changed = state->orderBySymmetry();
STORM_LOG_TRACE("State " << (changed ? "changed to " : "did not change") << (changed ? dft.getStateString(state) : ""));
}
if (stateStorage.stateToId.contains(state->status())) {
// State already exists
stateId = stateStorage.stateToId.getValue(state->status());
STORM_LOG_TRACE("State " << dft.getStateString(state) << " with id " << stateId << " already exists");
if (!changed) {
// Check if state is pseudo state
// If state is explored already the possible pseudo state was already constructed
auto iter = statesNotExplored.find(stateId);
if (iter != statesNotExplored.end() && iter->second.first->isPseudoState()) {
// Create pseudo state now
STORM_LOG_ASSERT(iter->second.first->getId() == stateId, "Ids do not match.");
STORM_LOG_ASSERT(iter->second.first->status() == state->status(), "Pseudo states do not coincide.");
state->setId(stateId);
// Update mapping to map to concrete state now
// TODO Matthias: just change pointer?
statesNotExplored[stateId] = std::make_pair(state, iter->second.second);
// We do not push the new state on the exploration queue as the pseudo state was already pushed
STORM_LOG_TRACE("Created pseudo state " << dft.getStateString(state));
}
}
} else {
// State does not exist yet
STORM_LOG_ASSERT(state->isPseudoState() == changed, "State type (pseudo/concrete) wrong.");
// Create new state
state->setId(newIndex++);
stateId = stateStorage.stateToId.findOrAdd(state->status(), state->getId());
STORM_LOG_ASSERT(stateId == state->getId(), "Ids do not match.");
// Insert state as not yet explored
ExplorationHeuristicPointer nullHeuristic;
statesNotExplored[stateId] = std::make_pair(state, nullHeuristic);
// Reserve one slot for the new state in the remapping
matrixBuilder.stateRemapping.push_back(0);
STORM_LOG_TRACE("New " << (state->isPseudoState() ? "pseudo" : "concrete") << " state: " << dft.getStateString(state));
}
return stateId;
}
template<typename ValueType, typename StateType>
void ExplicitDFTModelBuilderApprox<ValueType, StateType>::setMarkovian(bool markovian) {
if (matrixBuilder.getCurrentRowGroup() > modelComponents.markovianStates.size()) {
// Resize BitVector
modelComponents.markovianStates.resize(modelComponents.markovianStates.size() + INITIAL_BITVECTOR_SIZE);
}
modelComponents.markovianStates.set(matrixBuilder.getCurrentRowGroup() - 1, markovian);
}
template<typename ValueType, typename StateType>
void ExplicitDFTModelBuilderApprox<ValueType, StateType>::printNotExplored() const {
std::cout << "states not explored:" << std::endl;
for (auto it : statesNotExplored) {
std::cout << it.first << " -> " << dft.getStateString(it.second.first) << std::endl;
}
}
// Explicitly instantiate the class.
template class ExplicitDFTModelBuilderApprox<double>;
#ifdef STORM_HAVE_CARL
template class ExplicitDFTModelBuilderApprox<storm::RationalFunction>;
#endif
} // namespace builder
} // namespace storm

362
src/storm-dft/builder/ExplicitDFTModelBuilderApprox.h

@ -1,362 +0,0 @@
#pragma once
#include <boost/container/flat_set.hpp>
#include <boost/optional/optional.hpp>
#include <stack>
#include <unordered_set>
#include <limits>
#include "storm/models/sparse/StateLabeling.h"
#include "storm/models/sparse/ChoiceLabeling.h"
#include "storm/models/sparse/StandardRewardModel.h"
#include "storm/models/sparse/Model.h"
#include "storm/storage/SparseMatrix.h"
#include "storm/storage/sparse/StateStorage.h"
#include "storm-dft/builder/DftExplorationHeuristic.h"
#include "storm-dft/generator/DftNextStateGenerator.h"
#include "storm-dft/storage/dft/DFT.h"
#include "storm-dft/storage/dft/SymmetricUnits.h"
#include "storm-dft/storage/BucketPriorityQueue.h"
namespace storm {
namespace builder {
/*!
* Build a Markov chain from DFT.
*/
template<typename ValueType, typename StateType = uint32_t>
class ExplicitDFTModelBuilderApprox {
using DFTStatePointer = std::shared_ptr<storm::storage::DFTState<ValueType>>;
// TODO Matthias: make choosable
using ExplorationHeuristic = DFTExplorationHeuristicDepth<ValueType>;
using ExplorationHeuristicPointer = std::shared_ptr<ExplorationHeuristic>;
// A structure holding the individual components of a model.
struct ModelComponents {
// Constructor
ModelComponents();
// The transition matrix.
storm::storage::SparseMatrix<ValueType> transitionMatrix;
// The state labeling.
storm::models::sparse::StateLabeling stateLabeling;
// The Markovian states.
storm::storage::BitVector markovianStates;
// The exit rates.
std::vector<ValueType> exitRates;
// A vector that stores a labeling for each choice.
boost::optional<storm::models::sparse::ChoiceLabeling> choiceLabeling;
// A flag indicating if the model is deterministic.
bool deterministicModel;
};
// A class holding the information for building the transition matrix.
class MatrixBuilder {
public:
// Constructor
MatrixBuilder(bool canHaveNondeterminism);
/*!
* Set a mapping from a state id to the index in the matrix.
*
* @param id Id of the state.
*/
void setRemapping(StateType id) {
STORM_LOG_ASSERT(id < stateRemapping.size(), "Invalid index for remapping.");
stateRemapping[id] = currentRowGroup;
}
/*!
* Create a new row group if the model is nondeterministic.
*/
void newRowGroup() {
if (canHaveNondeterminism) {
builder.newRowGroup(currentRow);
}
++currentRowGroup;
}
/*!
* Add a transition from the current row.
*
* @param index Target index
* @param value Value of transition
*/
void addTransition(StateType index, ValueType value) {
builder.addNextValue(currentRow, index, value);
}
/*!
* Finish the current row.
*/
void finishRow() {
++currentRow;
}
/*!
* Remap the columns in the matrix.
*/
void remap() {
builder.replaceColumns(stateRemapping, mappingOffset);
}
/*!
* Get the current row group.
*
* @return The current row group.
*/
StateType getCurrentRowGroup() {
return currentRowGroup;
}
/*!
* Get the remapped state for the given id.
*
* @param id State.
*
* @return Remapped index.
*/
StateType getRemapping(StateType id) {
STORM_LOG_ASSERT(id < stateRemapping.size(), "Invalid index for remapping.");
return stateRemapping[id];
}
// Matrix builder.
storm::storage::SparseMatrixBuilder<ValueType> builder;
// Offset to distinguish states which will not be remapped anymore and those which will.
size_t mappingOffset;
// A mapping from state ids to the row group indices in which they actually reside.
// TODO Matthias: avoid hack with fixed int type
std::vector<uint_fast64_t> stateRemapping;
private:
// Index of the current row group.
StateType currentRowGroup;
// Index of the current row.
StateType currentRow;
// Flag indicating if row groups are needed.
bool canHaveNondeterminism;
};
public:
// A structure holding the labeling options.
struct LabelOptions {
// Constructor
LabelOptions(std::vector<std::shared_ptr<storm::logic::Formula const>> properties, bool buildAllLabels = false);
// Flag indicating if the general fail label should be included.
bool buildFailLabel;
// Flag indicating if the general failsafe label should be included.
bool buildFailSafeLabel;
// Flag indicating if all possible labels should be included.
bool buildAllLabels;
// Set of element names whose fail label to include.
std::set<std::string> elementLabels;
};
/*!
* Constructor.
*
* @param dft DFT.
* @param symmetries Symmetries in the dft.
* @param enableDC Flag indicating if dont care propagation should be used.
*/
ExplicitDFTModelBuilderApprox(storm::storage::DFT<ValueType> const& dft, storm::storage::DFTIndependentSymmetries const& symmetries, bool enableDC);
/*!
* Build model from DFT.
*
* @param labelOpts Options for labeling.
* @param iteration Current number of iteration.
* @param approximationThreshold Threshold determining when to skip exploring states.
*/
void buildModel(LabelOptions const& labelOpts, size_t iteration, double approximationThreshold = 0.0);
/*!
* Get the built model.
*
* @return The model built from the DFT.
*/
std::shared_ptr<storm::models::sparse::Model<ValueType>> getModel();
/*!
* Get the built approximation model for either the lower or upper bound.
*
* @param lowerBound If true, the lower bound model is returned, else the upper bound model
* @param expectedTime If true, the bounds for expected time are computed, else the bounds for probabilities.
*
* @return The model built from the DFT.
*/
std::shared_ptr<storm::models::sparse::Model<ValueType>> getModelApproximation(bool lowerBound, bool expectedTime);
private:
/*!
* Explore state space of DFT.
*
* @param approximationThreshold Threshold to determine when to skip states.
*/
void exploreStateSpace(double approximationThreshold);
/*!
* Initialize the matrix for a refinement iteration.
*/
void initializeNextIteration();
/*!
* Build the labeling.
*
* @param labelOpts Options for labeling.
*/
void buildLabeling(LabelOptions const& labelOpts);
/*!
* Add a state to the explored states (if not already there). It also handles pseudo states.
*
* @param state The state to add.
*
* @return Id of state.
*/
StateType getOrAddStateIndex(DFTStatePointer const& state);
/*!
* Set markovian flag for the current state.
*
* @param markovian Flag indicating if the state is markovian.
*/
void setMarkovian(bool markovian);
/**
* Change matrix to reflect the lower or upper approximation bound.
*
* @param matrix Matrix to change. The change are reflected here.
* @param lowerBound Flag indicating if the lower bound should be used. Otherwise the upper bound is used.
*/
void changeMatrixBound(storm::storage::SparseMatrix<ValueType> & matrix, bool lowerBound) const;
/*!
* Get lower bound approximation for state.
*
* @param state The state.
*
* @return Lower bound approximation.
*/
ValueType getLowerBound(DFTStatePointer const& state) const;
/*!
* Get upper bound approximation for state.
*
* @param state The state.
*
* @return Upper bound approximation.
*/
ValueType getUpperBound(DFTStatePointer const& state) const;
/*!
* Compute the MTTF of an AND gate via a closed formula.
* The used formula is 1/( 1/a + 1/b + 1/c + ... - 1/(a+b) - 1/(a+c) - ... + 1/(a+b+c) + ... - ...)
*
* @param rates List of rates of children of AND.
* @param size Only indices < size are considered in the vector.
* @return MTTF.
*/
ValueType computeMTTFAnd(std::vector<ValueType> const& rates, size_t size) const;
/*!
* Compares the priority of two states.
*
* @param idA Id of first state
* @param idB Id of second state
*
* @return True if the priority of the first state is greater then the priority of the second one.
*/
bool isPriorityGreater(StateType idA, StateType idB) const;
void printNotExplored() const;
/*!
* Create the model model from the model components.
*
* @param copy If true, all elements of the model component are copied (used for approximation). If false
* they are moved to reduce the memory overhead.
*
* @return The model built from the model components.
*/
std::shared_ptr<storm::models::sparse::Model<ValueType>> createModel(bool copy);
// Initial size of the bitvector.
const size_t INITIAL_BITVECTOR_SIZE = 20000;
// Offset used for pseudo states.
const StateType OFFSET_PSEUDO_STATE = std::numeric_limits<StateType>::max() / 2;
// Dft
storm::storage::DFT<ValueType> const& dft;
// General information for state generation
// TODO Matthias: use const reference
std::shared_ptr<storm::storage::DFTStateGenerationInfo> stateGenerationInfo;
// Flag indication if dont care propagation should be used.
bool enableDC = true;
//TODO Matthias: make changeable
const bool mergeFailedStates = true;
// Heuristic used for approximation
storm::builder::ApproximationHeuristic usedHeuristic;
// Current id for new state
size_t newIndex = 0;
// Id of failed state
size_t failedStateId = 0;
// Id of initial state
size_t initialStateIndex = 0;
// Next state generator for exploring the state space
storm::generator::DftNextStateGenerator<ValueType, StateType> generator;
// Structure for the components of the model.
ModelComponents modelComponents;
// Structure for the transition matrix builder.
MatrixBuilder matrixBuilder;
// Internal information about the states that were explored.
storm::storage::sparse::StateStorage<StateType> stateStorage;
// A priority queue of states that still need to be explored.
storm::storage::BucketPriorityQueue<ValueType> explorationQueue;
// A mapping of not yet explored states from the id to the tuple (state object, heuristic values).
std::map<StateType, std::pair<DFTStatePointer, ExplorationHeuristicPointer>> statesNotExplored;
// Holds all skipped states which were not yet expanded. More concretely it is a mapping from matrix indices
// to the corresponding skipped states.
// Notice that we need an ordered map here to easily iterate in increasing order over state ids.
// TODO remove again
std::map<StateType, std::pair<DFTStatePointer, ExplorationHeuristicPointer>> skippedStates;
// List of independent subtrees and the BEs contained in them.
std::vector<std::vector<size_t>> subtreeBEs;
};
}
}

4
src/storm-dft/generator/DftNextStateGenerator.cpp

@ -4,7 +4,7 @@
#include "storm/utility/macros.h"
#include "storm/exceptions/NotImplementedException.h"
#include "storm/settings/SettingsManager.h"
#include "storm-dft/settings/modules/DFTSettings.h"
#include "storm-dft/settings/modules/FaultTreeSettings.h"
namespace storm {
namespace generator {
@ -71,7 +71,7 @@ namespace storm {
// Let BE fail
while (currentFailable < failableCount) {
if (storm::settings::getModule<storm::settings::modules::DFTSettings>().isTakeFirstDependency() && hasDependencies && currentFailable > 0) {
if (storm::settings::getModule<storm::settings::modules::FaultTreeSettings>().isTakeFirstDependency() && hasDependencies && currentFailable > 0) {
// We discard further exploration as we already chose one dependent event
break;
}

32
src/storm-dft/modelchecker/dft/DFTModelChecker.cpp

@ -6,9 +6,8 @@
#include "storm/utility/DirectEncodingExporter.h"
#include "storm-dft/builder/ExplicitDFTModelBuilder.h"
#include "storm-dft/builder/ExplicitDFTModelBuilderApprox.h"
#include "storm-dft/storage/dft/DFTIsomorphism.h"
#include "storm-dft/settings/modules/DFTSettings.h"
#include "storm-dft/settings/modules/FaultTreeSettings.h"
namespace storm {
@ -192,8 +191,8 @@ namespace storm {
// Build a single CTMC
STORM_LOG_INFO("Building Model...");
storm::builder::ExplicitDFTModelBuilderApprox<ValueType> builder(ft, symmetries, enableDC);
typename storm::builder::ExplicitDFTModelBuilderApprox<ValueType>::LabelOptions labeloptions(properties);
storm::builder::ExplicitDFTModelBuilder<ValueType> builder(ft, symmetries, enableDC);
typename storm::builder::ExplicitDFTModelBuilder<ValueType>::LabelOptions labeloptions(properties);
builder.buildModel(labeloptions, 0, 0.0);
std::shared_ptr<storm::models::sparse::Model<ValueType>> model = builder.getModel();
explorationTimer.stop();
@ -244,9 +243,8 @@ namespace storm {
// Build a single CTMC
STORM_LOG_INFO("Building Model...");
storm::builder::ExplicitDFTModelBuilderApprox<ValueType> builder(dft, symmetries, enableDC);
typename storm::builder::ExplicitDFTModelBuilderApprox<ValueType>::LabelOptions labeloptions(properties);
storm::builder::ExplicitDFTModelBuilder<ValueType> builder(dft, symmetries, enableDC);
typename storm::builder::ExplicitDFTModelBuilder<ValueType>::LabelOptions labeloptions(properties);
builder.buildModel(labeloptions, 0, 0.0);
std::shared_ptr<storm::models::sparse::Model<ValueType>> model = builder.getModel();
model->printModelInformationToStream(std::cout);
@ -277,8 +275,8 @@ namespace storm {
approximation_result approxResult = std::make_pair(storm::utility::zero<ValueType>(), storm::utility::zero<ValueType>());
std::shared_ptr<storm::models::sparse::Model<ValueType>> model;
std::vector<ValueType> newResult;
storm::builder::ExplicitDFTModelBuilderApprox<ValueType> builder(dft, symmetries, enableDC);
typename storm::builder::ExplicitDFTModelBuilderApprox<ValueType>::LabelOptions labeloptions(properties);
storm::builder::ExplicitDFTModelBuilder<ValueType> builder(dft, symmetries, enableDC);
typename storm::builder::ExplicitDFTModelBuilder<ValueType>::LabelOptions labeloptions(properties);
// TODO Matthias: compute approximation for all properties simultaneously?
std::shared_ptr<const storm::logic::Formula> property = properties[0];
@ -342,18 +340,10 @@ namespace storm {
} else {
// Build a single Markov Automaton
STORM_LOG_INFO("Building Model...");
std::shared_ptr<storm::models::sparse::Model<ValueType>> model;
// TODO Matthias: use only one builder if everything works again
if (storm::settings::getModule<storm::settings::modules::DFTSettings>().isApproximationErrorSet()) {
storm::builder::ExplicitDFTModelBuilderApprox<ValueType> builder(dft, symmetries, enableDC);
typename storm::builder::ExplicitDFTModelBuilderApprox<ValueType>::LabelOptions labeloptions(properties, storm::settings::getModule<storm::settings::modules::IOSettings>().isExportExplicitSet());
builder.buildModel(labeloptions, 0, 0.0);
model = builder.getModel();
} else {
storm::builder::ExplicitDFTModelBuilder<ValueType> builder(dft, symmetries, enableDC);
typename storm::builder::ExplicitDFTModelBuilder<ValueType>::LabelOptions labeloptions;
model = builder.buildModel(labeloptions);
}
storm::builder::ExplicitDFTModelBuilder<ValueType> builder(dft, symmetries, enableDC);
typename storm::builder::ExplicitDFTModelBuilder<ValueType>::LabelOptions labeloptions(properties, storm::settings::getModule<storm::settings::modules::IOSettings>().isExportExplicitSet());
builder.buildModel(labeloptions, 0, 0.0);
std::shared_ptr<storm::models::sparse::Model<ValueType>> model = builder.getModel();
model->printModelInformationToStream(std::cout);
explorationTimer.stop();

51
src/storm-dft/settings/DftSettings.cpp

@ -0,0 +1,51 @@
#include "storm-dft/settings/DftSettings.h"
#include "storm-dft/settings/modules/DftIOSettings.h"
#include "storm-dft/settings/modules/FaultTreeSettings.h"
#include "storm/settings/SettingsManager.h"
#include "storm/settings/modules/GeneralSettings.h"
#include "storm/settings/modules/CoreSettings.h"
#include "storm/settings/modules/IOSettings.h"
#include "storm/settings/modules/DebugSettings.h"
#include "storm/settings/modules/EigenEquationSolverSettings.h"
#include "storm/settings/modules/GmmxxEquationSolverSettings.h"
#include "storm/settings/modules/NativeEquationSolverSettings.h"
#include "storm/settings/modules/EliminationSettings.h"
#include "storm/settings/modules/MinMaxEquationSolverSettings.h"
#include "storm/settings/modules/BisimulationSettings.h"
#include "storm/settings/modules/ResourceSettings.h"
#include "storm/settings/modules/JaniExportSettings.h"
#include "storm/settings/modules/GSPNSettings.h"
#include "storm/settings/modules/GSPNExportSettings.h"
namespace storm {
namespace settings {
void initializeDftSettings(std::string const& name, std::string const& executableName) {
storm::settings::mutableManager().setName(name, executableName);
// Register relevant settings modules.
storm::settings::addModule<storm::settings::modules::GeneralSettings>();
storm::settings::addModule<storm::settings::modules::DftIOSettings>();
storm::settings::addModule<storm::settings::modules::FaultTreeSettings>();
storm::settings::addModule<storm::settings::modules::IOSettings>();
storm::settings::addModule<storm::settings::modules::CoreSettings>();
storm::settings::addModule<storm::settings::modules::DebugSettings>();
storm::settings::addModule<storm::settings::modules::NativeEquationSolverSettings>();
storm::settings::addModule<storm::settings::modules::GmmxxEquationSolverSettings>();
storm::settings::addModule<storm::settings::modules::EigenEquationSolverSettings>();
storm::settings::addModule<storm::settings::modules::EliminationSettings>();
storm::settings::addModule<storm::settings::modules::MinMaxEquationSolverSettings>();
// storm::settings::addModule<storm::settings::modules::BisimulationSettings>();
storm::settings::addModule<storm::settings::modules::ResourceSettings>();
// For translation into JANI via GSPN.
storm::settings::addModule<storm::settings::modules::JaniExportSettings>();
storm::settings::addModule<storm::settings::modules::GSPNSettings>();
storm::settings::addModule<storm::settings::modules::GSPNExportSettings>();
}
}
}

11
src/storm-dft/settings/DftSettings.h

@ -0,0 +1,11 @@
#pragma once
#include <string>
namespace storm {
namespace settings {
void initializeDftSettings(std::string const& name, std::string const& executableName);
}
}

189
src/storm-dft/settings/modules/DFTSettings.cpp

@ -1,189 +0,0 @@
#include "DFTSettings.h"
#include "storm/settings/SettingsManager.h"
#include "storm/settings/SettingMemento.h"
#include "storm/settings/Option.h"
#include "storm/settings/OptionBuilder.h"
#include "storm/settings/ArgumentBuilder.h"
#include "storm/settings/Argument.h"
#include "storm/exceptions/InvalidSettingsException.h"
#include "storm/exceptions/IllegalArgumentValueException.h"
namespace storm {
namespace settings {
namespace modules {
const std::string DFTSettings::moduleName = "dft";
const std::string DFTSettings::dftFileOptionName = "dftfile";
const std::string DFTSettings::dftFileOptionShortName = "dft";
const std::string DFTSettings::dftJsonFileOptionName = "dftfile-json";
const std::string DFTSettings::dftJsonFileOptionShortName = "dftjson";
const std::string DFTSettings::symmetryReductionOptionName = "symmetryreduction";
const std::string DFTSettings::symmetryReductionOptionShortName = "symred";
const std::string DFTSettings::modularisationOptionName = "modularisation";
const std::string DFTSettings::disableDCOptionName = "disabledc";
const std::string DFTSettings::approximationErrorOptionName = "approximation";
const std::string DFTSettings::approximationErrorOptionShortName = "approx";
const std::string DFTSettings::approximationHeuristicOptionName = "approximationheuristic";
const std::string DFTSettings::propExpectedTimeOptionName = "expectedtime";
const std::string DFTSettings::propExpectedTimeOptionShortName = "mttf";
const std::string DFTSettings::propProbabilityOptionName = "probability";
const std::string DFTSettings::propTimeboundOptionName = "timebound";
const std::string DFTSettings::propTimepointsOptionName = "timepoints";
const std::string DFTSettings::minValueOptionName = "min";
const std::string DFTSettings::maxValueOptionName = "max";
const std::string DFTSettings::firstDependencyOptionName = "firstdep";
const std::string DFTSettings::transformToGspnOptionName = "gspn";
const std::string DFTSettings::exportToJsonOptionName = "export-json";
#ifdef STORM_HAVE_Z3
const std::string DFTSettings::solveWithSmtOptionName = "smt";
#endif
DFTSettings::DFTSettings() : ModuleSettings(moduleName) {
this->addOption(storm::settings::OptionBuilder(moduleName, dftFileOptionName, false, "Parses the model given in the Galileo format.").setShortName(dftFileOptionShortName)
.addArgument(storm::settings::ArgumentBuilder::createStringArgument("filename", "The name of the file from which to read the DFT model.").addValidatorString(ArgumentValidatorFactory::createExistingFileValidator()).build()).build());
this->addOption(storm::settings::OptionBuilder(moduleName, dftJsonFileOptionName, false, "Parses the model given in the Cytoscape JSON format.").setShortName(dftJsonFileOptionShortName)
.addArgument(storm::settings::ArgumentBuilder::createStringArgument("filename", "The name of the JSON file from which to read the DFT model.").addValidatorString(ArgumentValidatorFactory::createExistingFileValidator()).build()).build());
this->addOption(storm::settings::OptionBuilder(moduleName, symmetryReductionOptionName, false, "Exploit symmetric structure of model.").setShortName(symmetryReductionOptionShortName).build());
this->addOption(storm::settings::OptionBuilder(moduleName, modularisationOptionName, false, "Use modularisation (not applicable for expected time).").build());
this->addOption(storm::settings::OptionBuilder(moduleName, disableDCOptionName, false, "Disable Dont Care propagation.").build());
this->addOption(storm::settings::OptionBuilder(moduleName, firstDependencyOptionName, false, "Avoid non-determinism by always taking the first possible dependency.").build());
this->addOption(storm::settings::OptionBuilder(moduleName, approximationErrorOptionName, false, "Approximation error allowed.").setShortName(approximationErrorOptionShortName).addArgument(storm::settings::ArgumentBuilder::createDoubleArgument("error", "The relative approximation error to use.").addValidatorDouble(ArgumentValidatorFactory::createDoubleGreaterEqualValidator(0.0)).build()).build());
this->addOption(storm::settings::OptionBuilder(moduleName, approximationHeuristicOptionName, false, "Set the heuristic used for approximation.").addArgument(storm::settings::ArgumentBuilder::createStringArgument("heuristic", "Sets which heuristic is used for approximation. Must be in {depth, probability}. Default is").setDefaultValueString("depth").addValidatorString(ArgumentValidatorFactory::createMultipleChoiceValidator({"depth", "rateratio"})).build()).build());
this->addOption(storm::settings::OptionBuilder(moduleName, propExpectedTimeOptionName, false, "Compute expected time of system failure.").setShortName(propExpectedTimeOptionShortName).build());
this->addOption(storm::settings::OptionBuilder(moduleName, propProbabilityOptionName, false, "Compute probability of system failure.").build());
this->addOption(storm::settings::OptionBuilder(moduleName, propTimeboundOptionName, false, "Compute probability of system failure up to given timebound.").addArgument(storm::settings::ArgumentBuilder::createDoubleArgument("time", "The timebound to use.").addValidatorDouble(ArgumentValidatorFactory::createDoubleGreaterValidator(0.0)).build()).build());
this->addOption(storm::settings::OptionBuilder(moduleName, propTimepointsOptionName, false, "Compute probability of system failure up to given timebound for a set of given timepoints [starttime, starttime+inc, starttime+2inc, ... ,endtime]").addArgument(storm::settings::ArgumentBuilder::createDoubleArgument("starttime", "The timebound to start from.").addValidatorDouble(ArgumentValidatorFactory::createDoubleGreaterEqualValidator(0.0)).build()).addArgument(storm::settings::ArgumentBuilder::createDoubleArgument("endtime", "The timebound to end with.").addValidatorDouble(ArgumentValidatorFactory::createDoubleGreaterEqualValidator(0.0)).build()).addArgument(storm::settings::ArgumentBuilder::createDoubleArgument("inc", "The value to increment with to get the next timepoint.").addValidatorDouble(ArgumentValidatorFactory::createDoubleGreaterEqualValidator(0.0)).build()).build());
this->addOption(storm::settings::OptionBuilder(moduleName, minValueOptionName, false, "Compute minimal value in case of non-determinism.").build());
this->addOption(storm::settings::OptionBuilder(moduleName, maxValueOptionName, false, "Compute maximal value in case of non-determinism.").build());
#ifdef STORM_HAVE_Z3
this->addOption(storm::settings::OptionBuilder(moduleName, solveWithSmtOptionName, true, "Solve the DFT with SMT.").build());
#endif
this->addOption(storm::settings::OptionBuilder(moduleName, transformToGspnOptionName, false, "Transform DFT to GSPN.").build());
this->addOption(storm::settings::OptionBuilder(moduleName, exportToJsonOptionName, false, "Export the model to the Cytoscape JSON format.").addArgument(storm::settings::ArgumentBuilder::createStringArgument("filename", "The name of the JSON file to export to.").build()).build());
}
bool DFTSettings::isDftFileSet() const {
return this->getOption(dftFileOptionName).getHasOptionBeenSet();
}
std::string DFTSettings::getDftFilename() const {
return this->getOption(dftFileOptionName).getArgumentByName("filename").getValueAsString();
}
bool DFTSettings::isDftJsonFileSet() const {
return this->getOption(dftJsonFileOptionName).getHasOptionBeenSet();
}
std::string DFTSettings::getDftJsonFilename() const {
return this->getOption(dftJsonFileOptionName).getArgumentByName("filename").getValueAsString();
}
bool DFTSettings::useSymmetryReduction() const {
return this->getOption(symmetryReductionOptionName).getHasOptionBeenSet();
}
bool DFTSettings::useModularisation() const {
return this->getOption(modularisationOptionName).getHasOptionBeenSet();
}
bool DFTSettings::isDisableDC() const {
return this->getOption(disableDCOptionName).getHasOptionBeenSet();
}
bool DFTSettings::isApproximationErrorSet() const {
return this->getOption(approximationErrorOptionName).getHasOptionBeenSet();
}
double DFTSettings::getApproximationError() const {
return this->getOption(approximationErrorOptionName).getArgumentByName("error").getValueAsDouble();
}
storm::builder::ApproximationHeuristic DFTSettings::getApproximationHeuristic() const {
if (!isApproximationErrorSet() || getApproximationError() == 0.0) {
// No approximation is done
return storm::builder::ApproximationHeuristic::NONE;
}
std::string heuristicAsString = this->getOption(approximationHeuristicOptionName).getArgumentByName("heuristic").getValueAsString();
if (heuristicAsString == "depth") {
return storm::builder::ApproximationHeuristic::DEPTH;
} else if (heuristicAsString == "probability") {
return storm::builder::ApproximationHeuristic::PROBABILITY;
}
STORM_LOG_THROW(false, storm::exceptions::IllegalArgumentValueException, "Illegal value '" << heuristicAsString << "' set as heuristic for approximation.");
}
bool DFTSettings::usePropExpectedTime() const {
return this->getOption(propExpectedTimeOptionName).getHasOptionBeenSet();
}
bool DFTSettings::usePropProbability() const {
return this->getOption(propProbabilityOptionName).getHasOptionBeenSet();
}
bool DFTSettings::usePropTimebound() const {
return this->getOption(propTimeboundOptionName).getHasOptionBeenSet();
}
double DFTSettings::getPropTimebound() const {
return this->getOption(propTimeboundOptionName).getArgumentByName("time").getValueAsDouble();
}
bool DFTSettings::usePropTimepoints() const {
return this->getOption(propTimepointsOptionName).getHasOptionBeenSet();
}
std::vector<double> DFTSettings::getPropTimepoints() const {
double starttime = this->getOption(propTimepointsOptionName).getArgumentByName("starttime").getValueAsDouble();
double endtime = this->getOption(propTimepointsOptionName).getArgumentByName("endtime").getValueAsDouble();
double inc = this->getOption(propTimepointsOptionName).getArgumentByName("inc").getValueAsDouble();
std::vector<double> timepoints;
for (double time = starttime; time <= endtime; time += inc) {
timepoints.push_back(time);
}
return timepoints;
}
bool DFTSettings::isComputeMinimalValue() const {
return this->getOption(minValueOptionName).getHasOptionBeenSet();
}
bool DFTSettings::isComputeMaximalValue() const {
return this->getOption(maxValueOptionName).getHasOptionBeenSet();
}
bool DFTSettings::isTakeFirstDependency() const {
return this->getOption(firstDependencyOptionName).getHasOptionBeenSet();
}
#ifdef STORM_HAVE_Z3
bool DFTSettings::solveWithSMT() const {
return this->getOption(solveWithSmtOptionName).getHasOptionBeenSet();
}
#endif
bool DFTSettings::isTransformToGspn() const {
return this->getOption(transformToGspnOptionName).getHasOptionBeenSet();
}
bool DFTSettings::isExportToJson() const {
return this->getOption(exportToJsonOptionName).getHasOptionBeenSet();
}
std::string DFTSettings::getExportJsonFilename() const {
return this->getOption(exportToJsonOptionName).getArgumentByName("filename").getValueAsString();
}
void DFTSettings::finalize() {
}
bool DFTSettings::check() const {
// Ensure that at most one of min or max is set
STORM_LOG_THROW(!isComputeMinimalValue() || !isComputeMaximalValue(), storm::exceptions::InvalidSettingsException, "Min and max can not both be set.");
return true;
}
} // namespace modules
} // namespace settings
} // namespace storm

123
src/storm-dft/settings/modules/DftIOSettings.cpp

@ -0,0 +1,123 @@
#include "DftIOSettings.h"
#include "storm/settings/SettingsManager.h"
#include "storm/settings/SettingMemento.h"
#include "storm/settings/Option.h"
#include "storm/settings/OptionBuilder.h"
#include "storm/settings/ArgumentBuilder.h"
#include "storm/settings/Argument.h"
#include "storm/exceptions/InvalidSettingsException.h"
namespace storm {
namespace settings {
namespace modules {
const std::string DftIOSettings::moduleName = "dftIO";
const std::string DftIOSettings::dftFileOptionName = "dftfile";
const std::string DftIOSettings::dftFileOptionShortName = "dft";
const std::string DftIOSettings::dftJsonFileOptionName = "dftfile-json";
const std::string DftIOSettings::dftJsonFileOptionShortName = "dftjson";
const std::string DftIOSettings::propExpectedTimeOptionName = "expectedtime";
const std::string DftIOSettings::propExpectedTimeOptionShortName = "mttf";
const std::string DftIOSettings::propProbabilityOptionName = "probability";
const std::string DftIOSettings::propTimeboundOptionName = "timebound";
const std::string DftIOSettings::propTimepointsOptionName = "timepoints";
const std::string DftIOSettings::minValueOptionName = "min";
const std::string DftIOSettings::maxValueOptionName = "max";
const std::string DftIOSettings::transformToGspnOptionName = "gspn";
const std::string DftIOSettings::exportToJsonOptionName = "export-json";
DftIOSettings::DftIOSettings() : ModuleSettings(moduleName) {
this->addOption(storm::settings::OptionBuilder(moduleName, dftFileOptionName, false, "Parses the model given in the Galileo format.").setShortName(dftFileOptionShortName)
.addArgument(storm::settings::ArgumentBuilder::createStringArgument("filename", "The name of the file from which to read the DFT model.").addValidatorString(ArgumentValidatorFactory::createExistingFileValidator()).build()).build());
this->addOption(storm::settings::OptionBuilder(moduleName, dftJsonFileOptionName, false, "Parses the model given in the Cytoscape JSON format.").setShortName(dftJsonFileOptionShortName)
.addArgument(storm::settings::ArgumentBuilder::createStringArgument("filename", "The name of the JSON file from which to read the DFT model.").addValidatorString(ArgumentValidatorFactory::createExistingFileValidator()).build()).build());
this->addOption(storm::settings::OptionBuilder(moduleName, propExpectedTimeOptionName, false, "Compute expected time of system failure.").setShortName(propExpectedTimeOptionShortName).build());
this->addOption(storm::settings::OptionBuilder(moduleName, propProbabilityOptionName, false, "Compute probability of system failure.").build());
this->addOption(storm::settings::OptionBuilder(moduleName, propTimeboundOptionName, false, "Compute probability of system failure up to given timebound.").addArgument(storm::settings::ArgumentBuilder::createDoubleArgument("time", "The timebound to use.").addValidatorDouble(ArgumentValidatorFactory::createDoubleGreaterValidator(0.0)).build()).build());
this->addOption(storm::settings::OptionBuilder(moduleName, propTimepointsOptionName, false, "Compute probability of system failure up to given timebound for a set of given timepoints [starttime, starttime+inc, starttime+2inc, ... ,endtime]").addArgument(storm::settings::ArgumentBuilder::createDoubleArgument("starttime", "The timebound to start from.").addValidatorDouble(ArgumentValidatorFactory::createDoubleGreaterEqualValidator(0.0)).build()).addArgument(storm::settings::ArgumentBuilder::createDoubleArgument("endtime", "The timebound to end with.").addValidatorDouble(ArgumentValidatorFactory::createDoubleGreaterEqualValidator(0.0)).build()).addArgument(storm::settings::ArgumentBuilder::createDoubleArgument("inc", "The value to increment with to get the next timepoint.").addValidatorDouble(ArgumentValidatorFactory::createDoubleGreaterEqualValidator(0.0)).build()).build());
this->addOption(storm::settings::OptionBuilder(moduleName, minValueOptionName, false, "Compute minimal value in case of non-determinism.").build());
this->addOption(storm::settings::OptionBuilder(moduleName, maxValueOptionName, false, "Compute maximal value in case of non-determinism.").build());
this->addOption(storm::settings::OptionBuilder(moduleName, transformToGspnOptionName, false, "Transform DFT to GSPN.").build());
this->addOption(storm::settings::OptionBuilder(moduleName, exportToJsonOptionName, false, "Export the model to the Cytoscape JSON format.").addArgument(storm::settings::ArgumentBuilder::createStringArgument("filename", "The name of the JSON file to export to.").build()).build());
}
bool DftIOSettings::isDftFileSet() const {
return this->getOption(dftFileOptionName).getHasOptionBeenSet();
}
std::string DftIOSettings::getDftFilename() const {
return this->getOption(dftFileOptionName).getArgumentByName("filename").getValueAsString();
}
bool DftIOSettings::isDftJsonFileSet() const {
return this->getOption(dftJsonFileOptionName).getHasOptionBeenSet();
}
std::string DftIOSettings::getDftJsonFilename() const {
return this->getOption(dftJsonFileOptionName).getArgumentByName("filename").getValueAsString();
}
bool DftIOSettings::usePropExpectedTime() const {
return this->getOption(propExpectedTimeOptionName).getHasOptionBeenSet();
}
bool DftIOSettings::usePropProbability() const {
return this->getOption(propProbabilityOptionName).getHasOptionBeenSet();
}
bool DftIOSettings::usePropTimebound() const {
return this->getOption(propTimeboundOptionName).getHasOptionBeenSet();
}
double DftIOSettings::getPropTimebound() const {
return this->getOption(propTimeboundOptionName).getArgumentByName("time").getValueAsDouble();
}
bool DftIOSettings::usePropTimepoints() const {
return this->getOption(propTimepointsOptionName).getHasOptionBeenSet();
}
std::vector<double> DftIOSettings::getPropTimepoints() const {
double starttime = this->getOption(propTimepointsOptionName).getArgumentByName("starttime").getValueAsDouble();
double endtime = this->getOption(propTimepointsOptionName).getArgumentByName("endtime").getValueAsDouble();
double inc = this->getOption(propTimepointsOptionName).getArgumentByName("inc").getValueAsDouble();
std::vector<double> timepoints;
for (double time = starttime; time <= endtime; time += inc) {
timepoints.push_back(time);
}
return timepoints;
}
bool DftIOSettings::isComputeMinimalValue() const {
return this->getOption(minValueOptionName).getHasOptionBeenSet();
}
bool DftIOSettings::isComputeMaximalValue() const {
return this->getOption(maxValueOptionName).getHasOptionBeenSet();
}
bool DftIOSettings::isTransformToGspn() const {
return this->getOption(transformToGspnOptionName).getHasOptionBeenSet();
}
bool DftIOSettings::isExportToJson() const {
return this->getOption(exportToJsonOptionName).getHasOptionBeenSet();
}
std::string DftIOSettings::getExportJsonFilename() const {
return this->getOption(exportToJsonOptionName).getArgumentByName("filename").getValueAsString();
}
void DftIOSettings::finalize() {
}
bool DftIOSettings::check() const {
// Ensure that at most one of min or max is set
STORM_LOG_THROW(!isComputeMinimalValue() || !isComputeMaximalValue(), storm::exceptions::InvalidSettingsException, "Min and max can not both be set.");
return true;
}
} // namespace modules
} // namespace settings
} // namespace storm

80
src/storm-dft/settings/modules/DFTSettings.h → src/storm-dft/settings/modules/DftIOSettings.h

@ -1,24 +1,21 @@
#pragma once
#include "storm-config.h"
#include "storm/settings/modules/ModuleSettings.h"
#include "storm-dft/builder/DftExplorationHeuristic.h"
namespace storm {
namespace settings {
namespace modules {
/*!
* This class represents the settings for DFT model checking.
* This class represents the settings for IO operations concerning DFTs.
*/
class DFTSettings : public ModuleSettings {
class DftIOSettings : public ModuleSettings {
public:
/*!
* Creates a new set of DFT settings.
* Creates a new set of IO settings for DFTs.
*/
DFTSettings();
DftIOSettings();
/*!
* Retrieves whether the dft file option was set.
@ -48,48 +45,6 @@ namespace storm {
*/
std::string getDftJsonFilename() const;
/*!
* Retrieves whether the option to use symmetry reduction is set.
*
* @return True iff the option was set.
*/
bool useSymmetryReduction() const;
/*!
* Retrieves whether the option to use modularisation is set.
*
* @return True iff the option was set.
*/
bool useModularisation() const;
/*!
* Retrieves whether the option to disable Dont Care propagation is set.
*
* @return True iff the option was set.
*/
bool isDisableDC() const;
/*!
* Retrieves whether the option to compute an approximation is set.
*
* @return True iff the option was set.
*/
bool isApproximationErrorSet() const;
/*!
* Retrieves the relative error allowed for approximating the model checking result.
*
* @return The allowed errorbound.
*/
double getApproximationError() const;
/*!
* Retrieves the heuristic used for approximation.
*
* @return The heuristic to use.
*/
storm::builder::ApproximationHeuristic getApproximationHeuristic() const;
/*!
* Retrieves whether the property expected time should be used.
*
@ -146,13 +101,6 @@ namespace storm {
*/
bool isComputeMaximalValue() const;
/*!
* Retrieves whether the non-determinism should be avoided by always taking the first possible dependency.
*
* @return True iff the option was set.
*/
bool isTakeFirstDependency() const;
/*!
* Retrieves whether the DFT should be transformed into a GSPN.
*
@ -174,15 +122,6 @@ namespace storm {
*/
std::string getExportJsonFilename() const;
#ifdef STORM_HAVE_Z3
/*!
* Retrieves whether the DFT should be checked via SMT.
*
* @return True iff the option was set.
*/
bool solveWithSMT() const;
#endif
bool check() const override;
void finalize() override;
@ -195,13 +134,6 @@ namespace storm {
static const std::string dftFileOptionShortName;
static const std::string dftJsonFileOptionName;
static const std::string dftJsonFileOptionShortName;
static const std::string symmetryReductionOptionName;
static const std::string symmetryReductionOptionShortName;
static const std::string modularisationOptionName;
static const std::string disableDCOptionName;
static const std::string approximationErrorOptionName;
static const std::string approximationErrorOptionShortName;
static const std::string approximationHeuristicOptionName;
static const std::string propExpectedTimeOptionName;
static const std::string propExpectedTimeOptionShortName;
static const std::string propProbabilityOptionName;
@ -209,10 +141,6 @@ namespace storm {
static const std::string propTimepointsOptionName;
static const std::string minValueOptionName;
static const std::string maxValueOptionName;
static const std::string firstDependencyOptionName;
#ifdef STORM_HAVE_Z3
static const std::string solveWithSmtOptionName;
#endif
static const std::string transformToGspnOptionName;
static const std::string exportToJsonOptionName;

93
src/storm-dft/settings/modules/FaultTreeSettings.cpp

@ -0,0 +1,93 @@
#include "FaultTreeSettings.h"
#include "storm/settings/SettingsManager.h"
#include "storm/settings/SettingMemento.h"
#include "storm/settings/Option.h"
#include "storm/settings/OptionBuilder.h"
#include "storm/settings/ArgumentBuilder.h"
#include "storm/settings/Argument.h"
#include "storm/exceptions/IllegalArgumentValueException.h"
namespace storm {
namespace settings {
namespace modules {
const std::string FaultTreeSettings::moduleName = "dft";
const std::string FaultTreeSettings::symmetryReductionOptionName = "symmetryreduction";
const std::string FaultTreeSettings::symmetryReductionOptionShortName = "symred";
const std::string FaultTreeSettings::modularisationOptionName = "modularisation";
const std::string FaultTreeSettings::disableDCOptionName = "disabledc";
const std::string FaultTreeSettings::approximationErrorOptionName = "approximation";
const std::string FaultTreeSettings::approximationErrorOptionShortName = "approx";
const std::string FaultTreeSettings::approximationHeuristicOptionName = "approximationheuristic";
const std::string FaultTreeSettings::firstDependencyOptionName = "firstdep";
#ifdef STORM_HAVE_Z3
const std::string FaultTreeSettings::solveWithSmtOptionName = "smt";
#endif
FaultTreeSettings::FaultTreeSettings() : ModuleSettings(moduleName) {
this->addOption(storm::settings::OptionBuilder(moduleName, symmetryReductionOptionName, false, "Exploit symmetric structure of model.").setShortName(symmetryReductionOptionShortName).build());
this->addOption(storm::settings::OptionBuilder(moduleName, modularisationOptionName, false, "Use modularisation (not applicable for expected time).").build());
this->addOption(storm::settings::OptionBuilder(moduleName, disableDCOptionName, false, "Disable Dont Care propagation.").build());
this->addOption(storm::settings::OptionBuilder(moduleName, firstDependencyOptionName, false, "Avoid non-determinism by always taking the first possible dependency.").build());
this->addOption(storm::settings::OptionBuilder(moduleName, approximationErrorOptionName, false, "Approximation error allowed.").setShortName(approximationErrorOptionShortName).addArgument(storm::settings::ArgumentBuilder::createDoubleArgument("error", "The relative approximation error to use.").addValidatorDouble(ArgumentValidatorFactory::createDoubleGreaterEqualValidator(0.0)).build()).build());
this->addOption(storm::settings::OptionBuilder(moduleName, approximationHeuristicOptionName, false, "Set the heuristic used for approximation.").addArgument(storm::settings::ArgumentBuilder::createStringArgument("heuristic", "Sets which heuristic is used for approximation. Must be in {depth, probability}. Default is").setDefaultValueString("depth").addValidatorString(ArgumentValidatorFactory::createMultipleChoiceValidator({"depth", "rateratio"})).build()).build());
#ifdef STORM_HAVE_Z3
this->addOption(storm::settings::OptionBuilder(moduleName, solveWithSmtOptionName, true, "Solve the DFT with SMT.").build());
#endif
}
bool FaultTreeSettings::useSymmetryReduction() const {
return this->getOption(symmetryReductionOptionName).getHasOptionBeenSet();
}
bool FaultTreeSettings::useModularisation() const {
return this->getOption(modularisationOptionName).getHasOptionBeenSet();
}
bool FaultTreeSettings::isDisableDC() const {
return this->getOption(disableDCOptionName).getHasOptionBeenSet();
}
bool FaultTreeSettings::isApproximationErrorSet() const {
return this->getOption(approximationErrorOptionName).getHasOptionBeenSet();
}
double FaultTreeSettings::getApproximationError() const {
return this->getOption(approximationErrorOptionName).getArgumentByName("error").getValueAsDouble();
}
storm::builder::ApproximationHeuristic FaultTreeSettings::getApproximationHeuristic() const {
if (!isApproximationErrorSet() || getApproximationError() == 0.0) {
// No approximation is done
return storm::builder::ApproximationHeuristic::NONE;
}
std::string heuristicAsString = this->getOption(approximationHeuristicOptionName).getArgumentByName("heuristic").getValueAsString();
if (heuristicAsString == "depth") {
return storm::builder::ApproximationHeuristic::DEPTH;
} else if (heuristicAsString == "probability") {
return storm::builder::ApproximationHeuristic::PROBABILITY;
}
STORM_LOG_THROW(false, storm::exceptions::IllegalArgumentValueException, "Illegal value '" << heuristicAsString << "' set as heuristic for approximation.");
}
bool FaultTreeSettings::isTakeFirstDependency() const {
return this->getOption(firstDependencyOptionName).getHasOptionBeenSet();
}
#ifdef STORM_HAVE_Z3
bool FaultTreeSettings::solveWithSMT() const {
return this->getOption(solveWithSmtOptionName).getHasOptionBeenSet();
}
#endif
void FaultTreeSettings::finalize() {
}
bool FaultTreeSettings::check() const {
return true;
}
} // namespace modules
} // namespace settings
} // namespace storm

104
src/storm-dft/settings/modules/FaultTreeSettings.h

@ -0,0 +1,104 @@
#pragma once
#include "storm/settings/modules/ModuleSettings.h"
#include "storm-dft/builder/DftExplorationHeuristic.h"
#include "storm-config.h"
namespace storm {
namespace settings {
namespace modules {
/*!
* This class represents the settings for DFT model checking.
*/
class FaultTreeSettings : public ModuleSettings {
public:
/*!
* Creates a new set of DFT settings.
*/
FaultTreeSettings();
/*!
* Retrieves whether the option to use symmetry reduction is set.
*
* @return True iff the option was set.
*/
bool useSymmetryReduction() const;
/*!
* Retrieves whether the option to use modularisation is set.
*
* @return True iff the option was set.
*/
bool useModularisation() const;
/*!
* Retrieves whether the option to disable Dont Care propagation is set.
*
* @return True iff the option was set.
*/
bool isDisableDC() const;
/*!
* Retrieves whether the option to compute an approximation is set.
*
* @return True iff the option was set.
*/
bool isApproximationErrorSet() const;
/*!
* Retrieves the relative error allowed for approximating the model checking result.
*
* @return The allowed errorbound.
*/
double getApproximationError() const;
/*!
* Retrieves the heuristic used for approximation.
*
* @return The heuristic to use.
*/
storm::builder::ApproximationHeuristic getApproximationHeuristic() const;
/*!
* Retrieves whether the non-determinism should be avoided by always taking the first possible dependency.
*
* @return True iff the option was set.
*/
bool isTakeFirstDependency() const;
#ifdef STORM_HAVE_Z3
/*!
* Retrieves whether the DFT should be checked via SMT.
*
* @return True iff the option was set.
*/
bool solveWithSMT() const;
#endif
bool check() const override;
void finalize() override;
// The name of the module.
static const std::string moduleName;
private:
// Define the string names of the options as constants.
static const std::string symmetryReductionOptionName;
static const std::string symmetryReductionOptionShortName;
static const std::string modularisationOptionName;
static const std::string disableDCOptionName;
static const std::string approximationErrorOptionName;
static const std::string approximationErrorOptionShortName;
static const std::string approximationHeuristicOptionName;
static const std::string firstDependencyOptionName;
#ifdef STORM_HAVE_Z3
static const std::string solveWithSmtOptionName;
#endif
};
} // namespace modules
} // namespace settings
} // namespace storm

12
src/storm/models/sparse/MarkovAutomaton.cpp

@ -50,7 +50,9 @@ namespace storm {
if (components.exitRates) {
exitRates = std::move(components.exitRates.get());
} else {
}
if (components.rateTransitions) {
this->turnRatesToProbabilities();
}
closed = this->checkIsClosed();
@ -150,7 +152,7 @@ namespace storm {
uint_fast64_t row = this->getTransitionMatrix().getRowGroupIndices()[state];
if (this->markovianStates.get(state)) {
if (assertRates) {
STORM_LOG_THROW(this->exitRates[state] == this->getTransitionMatrix().getRowSum(row), storm::exceptions::InvalidArgumentException, "The specified exit rate is inconsistent with the rate matrix. Difference is " << (this->exitRates[state] - this->getTransitionMatrix().getRowSum(row)) << ".");
STORM_LOG_THROW(this->exitRates[state] == this->getTransitionMatrix().getRowSum(row), storm::exceptions::InvalidArgumentException, "The specified exit rate is inconsistent with the rate matrix. Difference is " << (this->exitRates[state] - this->getTransitionMatrix().getRowSum(row)) << ".");
} else {
this->exitRates.push_back(this->getTransitionMatrix().getRowSum(row));
}
@ -159,7 +161,11 @@ namespace storm {
}
++row;
} else {
this->exitRates.push_back(storm::utility::zero<ValueType>());
if (assertRates) {
STORM_LOG_THROW(storm::utility::isZero<ValueType>(this->exitRates[state]), storm::exceptions::InvalidArgumentException, "The specified exit rate for (non-Markovian) choice should be 0.");
} else {
this->exitRates.push_back(storm::utility::zero<ValueType>());
}
}
for (; row < this->getTransitionMatrix().getRowGroupIndices()[state+1]; ++row) {
STORM_LOG_THROW(storm::utility::isOne(this->getTransitionMatrix().getRowSum(row)), storm::exceptions::InvalidArgumentException, "Entries of transition matrix do not sum up to one for (non-Markovian) choice " << row << " of state " << state << " (sum is " << this->getTransitionMatrix().getRowSum(row) << ").");

4
src/storm/models/sparse/MarkovAutomaton.h

@ -22,7 +22,7 @@ namespace storm {
* For hybrid states (i.e., states with Markovian and probabilistic transitions), it is assumed that the first
* choice corresponds to the markovian transitions.
*
* @param transitionMatrix The matrix representing the transitions in the model in terms of rates (markocian choices) and probabilities (probabilistic choices).
* @param transitionMatrix The matrix representing the transitions in the model in terms of rates (Markovian choices) and probabilities (probabilistic choices).
* @param stateLabeling The labeling of the states.
* @param markovianStates A bit vector indicating the Markovian states of the automaton (i.e., states with at least one markovian transition).
* @param rewardModels A mapping of reward model names to reward models.
@ -38,7 +38,7 @@ namespace storm {
* For hybrid states (i.e., states with Markovian and probabilistic transitions), it is assumed that the first
* choice corresponds to the markovian transitions.
*
* @param transitionMatrix The matrix representing the transitions in the model in terms of rates (markocian choices) and probabilities (probabilistic choices).
* @param transitionMatrix The matrix representing the transitions in the model in terms of rates (Markovian choices) and probabilities (probabilistic choices).
* @param stateLabeling The labeling of the states.
* @param markovianStates A bit vector indicating the Markovian states of the automaton (i.e., states with at least one markovian transition).
* @param rewardModels A mapping of reward model names to reward models.
Loading…
Cancel
Save