Browse Source

Merge branch 'future' into learning_engine

Former-commit-id: 801a989353
main
dehnert 9 years ago
parent
commit
aac9ba469b
  1. 2
      src/CMakeLists.txt
  2. 898
      src/builder/ExplicitPrismModelBuilder.cpp
  3. 181
      src/builder/ExplicitPrismModelBuilder.h
  4. 22
      src/builder/ExplorationOrder.cpp
  5. 17
      src/builder/ExplorationOrder.h
  6. 105
      src/generator/Choice.cpp
  7. 150
      src/generator/Choice.h
  8. 23
      src/generator/CompressedState.cpp
  9. 30
      src/generator/CompressedState.h
  10. 24
      src/generator/NextStateGenerator.h
  11. 404
      src/generator/PrismNextStateGenerator.cpp
  12. 108
      src/generator/PrismNextStateGenerator.h
  13. 50
      src/generator/PrismStateLabelingGenerator.cpp
  14. 31
      src/generator/PrismStateLabelingGenerator.h
  15. 57
      src/generator/StateBehavior.cpp
  16. 73
      src/generator/StateBehavior.h
  17. 20
      src/generator/StateLabelingGenerator.h
  18. 77
      src/generator/VariableInformation.cpp
  19. 75
      src/generator/VariableInformation.h
  20. 2
      src/modelchecker/csl/helper/SparseCtmcCslHelper.cpp
  21. 4
      src/parser/PrismParser.cpp
  22. 16
      src/settings/ArgumentValidators.h
  23. 21
      src/settings/modules/GeneralSettings.cpp
  24. 19
      src/settings/modules/GeneralSettings.h
  25. 250
      src/storage/BitVector.cpp
  26. 9
      src/storage/BitVector.h
  27. 9
      src/storage/BitVectorHashMap.cpp
  28. 9
      src/storage/BitVectorHashMap.h
  29. 62
      src/storage/Distribution.cpp
  30. 36
      src/storage/Distribution.h
  31. 279
      src/storage/SparseMatrix.cpp
  32. 61
      src/storage/SparseMatrix.h
  33. 6
      src/storage/dd/Add.cpp
  34. 8
      src/storage/prism/Program.cpp
  35. 12
      src/storage/prism/Program.h
  36. 2
      src/storage/prism/RewardModel.cpp
  37. 4
      src/utility/constants.cpp
  38. 4
      src/utility/storm.h
  39. 32
      test/functional/builder/ExplicitPrismModelBuilderTest.cpp
  40. 8
      test/functional/modelchecker/GmmxxCtmcCslModelCheckerTest.cpp
  41. 2
      test/functional/modelchecker/GmmxxDtmcPrctlModelCheckerTest.cpp
  42. 2
      test/functional/modelchecker/GmmxxMdpPrctlModelCheckerTest.cpp
  43. 8
      test/functional/modelchecker/NativeCtmcCslModelCheckerTest.cpp
  44. 2
      test/functional/permissiveschedulers/MilpPermissiveSchedulerTest.cpp
  45. 2
      test/functional/permissiveschedulers/SmtPermissiveSchedulerTest.cpp
  46. 18
      test/functional/storage/BitVectorHashMapTest.cpp
  47. 18
      test/functional/storage/BitVectorTest.cpp
  48. 2
      test/functional/storage/NondeterministicModelBisimulationDecompositionTest.cpp
  49. 4
      test/functional/storage/SparseMatrixTest.cpp
  50. 8
      test/functional/utility/GraphTest.cpp
  51. 29
      test/functional/utility/ModelInstantiatorTest.cpp

2
src/CMakeLists.txt

@ -11,6 +11,7 @@ file(GLOB_RECURSE STORM_SOURCES_CLI ${PROJECT_SOURCE_DIR}/src/cli/*.cpp)
file(GLOB_RECURSE STORM_MAIN_FILE ${PROJECT_SOURCE_DIR}/src/storm.cpp)
file(GLOB_RECURSE STORM_ADAPTERS_FILES ${PROJECT_SOURCE_DIR}/src/adapters/*.h ${PROJECT_SOURCE_DIR}/src/adapters/*.cpp)
file(GLOB_RECURSE STORM_BUILDER_FILES ${PROJECT_SOURCE_DIR}/src/builder/*.h ${PROJECT_SOURCE_DIR}/src/builder/*.cpp)
file(GLOB_RECURSE STORM_GENERATOR_FILES ${PROJECT_SOURCE_DIR}/src/generator/*.h ${PROJECT_SOURCE_DIR}/src/generator/*.cpp)
file(GLOB_RECURSE STORM_CLI_FILES ${PROJECT_SOURCE_DIR}/src/cli/*.h ${PROJECT_SOURCE_DIR}/src/cli/*.cpp)
file(GLOB_RECURSE STORM_EXCEPTIONS_FILES ${PROJECT_SOURCE_DIR}/src/exceptions/*.h ${PROJECT_SOURCE_DIR}/src/exceptions/*.cpp)
file(GLOB_RECURSE STORM_LOGIC_FILES ${PROJECT_SOURCE_DIR}/src/logic/*.h ${PROJECT_SOURCE_DIR}/src/logic/*.cpp)
@ -57,6 +58,7 @@ set(STORM_MAIN_HEADERS ${STORM_HEADERS_CLI})
source_group(main FILES ${STORM_MAIN_FILE})
source_group(adapters FILES ${STORM_ADAPTERS_FILES})
source_group(builder FILES ${STORM_BUILDER_FILES})
source_group(generator FILES ${STORM_GENERATOR_FILES})
source_group(cli FILES ${STORM_CLI_FILES})
source_group(exceptions FILES ${STORM_EXCEPTIONS_FILES})
source_group(logic FILES ${STORM_LOGIC_FILES})

898
src/builder/ExplicitPrismModelBuilder.cpp
File diff suppressed because it is too large
View File

181
src/builder/ExplicitPrismModelBuilder.h

@ -1,10 +1,10 @@
#ifndef STORM_ADAPTERS_EXPLICITPRISMMODELBUILDER_H
#define STORM_ADAPTERS_EXPLICITPRISMMODELBUILDER_H
#ifndef STORM_BUILDER_EXPLICITPRISMMODELBUILDER_H
#define STORM_BUILDER_EXPLICITPRISMMODELBUILDER_H
#include <memory>
#include <utility>
#include <vector>
#include <queue>
#include <deque>
#include <cstdint>
#include <boost/functional/hash.hpp>
#include <boost/container/flat_set.hpp>
@ -22,9 +22,13 @@
#include "src/storage/SparseMatrix.h"
#include "src/settings/SettingsManager.h"
#include "src/utility/constants.h"
#include "src/utility/prism.h"
#include "src/builder/ExplorationOrder.h"
#include "src/generator/CompressedState.h"
#include "src/generator/VariableInformation.h"
namespace storm {
namespace utility {
template<typename ValueType> class ConstantsComparator;
@ -33,30 +37,33 @@ namespace storm {
namespace builder {
using namespace storm::utility::prism;
using namespace storm::generator;
// Forward-declare classes.
template <typename ValueType> struct RewardModelBuilder;
template<typename ValueType, typename RewardModelType = storm::models::sparse::StandardRewardModel<ValueType>, typename IndexType = uint32_t>
template<typename ValueType, typename RewardModelType = storm::models::sparse::StandardRewardModel<ValueType>, typename StateType = uint32_t>
class ExplicitPrismModelBuilder {
public:
typedef storm::storage::BitVector CompressedState;
// A structure holding information about the reachable state space while building it.
struct InternalStateInformation {
// Builds an empty state information.
InternalStateInformation();
// Creates a state information structure for storing states of the given bit width.
InternalStateInformation(uint64_t bitsPerState);
// This member stores all the states and maps them to their unique indices.
storm::storage::BitVectorHashMap<IndexType> stateStorage;
storm::storage::BitVectorHashMap<StateType> stateStorage;
// A list of initial states in terms of their global indices.
std::vector<IndexType> initialStateIndices;
std::vector<StateType> initialStateIndices;
// The number of bits of each state.
uint64_t bitsPerState;
// A list of reachable states as indices in the stateToIndexMap.
std::vector<storm::storage::BitVector> reachableStates;
// The number of states that were found in the exploration so far.
uint_fast64_t numberOfStates;
};
// A structure holding information about the reachable state space that can be retrieved from the outside.
@ -74,60 +81,6 @@ namespace storm {
}
};
// A structure storing information about the used variables of the program.
struct VariableInformation {
VariableInformation(storm::expressions::ExpressionManager const& manager);
struct BooleanVariableInformation {
BooleanVariableInformation(storm::expressions::Variable const& variable, bool initialValue, uint_fast64_t bitOffset);
// The boolean variable.
storm::expressions::Variable variable;
// Its initial value.
bool initialValue;
// Its bit offset in the compressed state.
uint_fast64_t bitOffset;
};
struct IntegerVariableInformation {
IntegerVariableInformation(storm::expressions::Variable const& variable, int_fast64_t initialValue, int_fast64_t lowerBound, int_fast64_t upperBound, uint_fast64_t bitOffset, uint_fast64_t bitWidth);
// The integer variable.
storm::expressions::Variable variable;
// Its initial value.
int_fast64_t initialValue;
// The lower bound of its range.
int_fast64_t lowerBound;
// The upper bound of its range.
int_fast64_t upperBound;
// Its bit offset in the compressed state.
uint_fast64_t bitOffset;
// Its bit width in the compressed state.
uint_fast64_t bitWidth;
};
// Provide methods to access the bit offset and width of variables in the compressed state.
uint_fast64_t getBitOffset(storm::expressions::Variable const& variable) const;
uint_fast64_t getBitWidth(storm::expressions::Variable const& variable) const;
// The known boolean variables.
boost::container::flat_map<storm::expressions::Variable, uint_fast64_t> booleanVariableToIndexMap;
std::vector<BooleanVariableInformation> booleanVariables;
// The known integer variables.
boost::container::flat_map<storm::expressions::Variable, uint_fast64_t> integerVariableToIndexMap;
std::vector<IntegerVariableInformation> integerVariables;
storm::expressions::ExpressionManager const& manager;
};
// A structure holding the individual components of a model.
struct ModelComponents {
ModelComponents();
@ -151,6 +104,11 @@ namespace storm {
*/
Options();
/*!
* Copies the given set of options.
*/
Options(Options const& other) = default;
/*! Creates an object representing the suggested building options assuming that the given formula is the
* only one to check. Additional formulas may be preserved by calling <code>preserveFormula</code>.
*
@ -193,6 +151,9 @@ namespace storm {
*/
void setTerminalStatesFromFormula(storm::logic::Formula const& formula);
// The order in which to explore the model.
ExplorationOrder explorationOrder;
// A flag that indicates whether or not command labels are to be built.
bool buildCommandLabels;
@ -228,6 +189,13 @@ namespace storm {
boost::optional<boost::variant<storm::expressions::Expression, std::string>> negatedTerminalStates;
};
/*!
* Creates a builder for the given program.
*
* @param program The program to build.
*/
ExplicitPrismModelBuilder(storm::prism::Program const& program, Options const& options = Options());
/*!
* Convert the program given at construction time to an abstract model. The type of the model is the one
* specified in the program. The given reward model name selects the rewards that the model will contain.
@ -238,7 +206,7 @@ namespace storm {
* @param rewardModel The reward model that is to be built.
* @return The explicit model that was given by the probabilistic program.
*/
std::shared_ptr<storm::models::sparse::Model<ValueType, RewardModelType>> translateProgram(storm::prism::Program program, Options const& options = Options());
std::shared_ptr<storm::models::sparse::Model<ValueType, RewardModelType>> translate();
/*!
* If requested in the options, information about the variable valuations in the reachable states can be
@ -249,39 +217,14 @@ namespace storm {
StateInformation const& getStateInformation() const;
/*!
* Retrieves the program that was actually translated (i.e. including constant substitutions etc.). Note
* that this function may only be called after a succesful translation.
* Retrieves the program that was actually translated (i.e. including constant substitutions etc.).
*
* @return The translated program.
*/
storm::prism::Program const& getTranslatedProgram() const;
private:
static void unpackStateIntoEvaluator(storm::storage::BitVector const& currentState, VariableInformation const& variableInformation, storm::expressions::ExpressionEvaluator<ValueType>& evaluator);
static storm::expressions::SimpleValuation unpackStateIntoValuation(storm::storage::BitVector const& currentState, VariableInformation const& variableInformation);
/*!
* Applies an update to the given state and returns the resulting new state object. This methods does not
* modify the given state but returns a new one.
*
* @params state The state to which to apply the update.
* @params update The update to apply.
* @return The resulting state.
*/
static CompressedState applyUpdate(VariableInformation const& variableInformation, CompressedState const& state, storm::prism::Update const& update, storm::expressions::ExpressionEvaluator<ValueType> const& evaluator);
/*!
* Applies an update to the given state and returns the resulting new state object. The update is evaluated
* over the variable values of the given base state. This methods does not modify the given state but
* returns a new one.
*
* @param state The state to which to apply the update.
* @param baseState The state used for evaluating the update.
* @param update The update to apply.
* @return The resulting state.
*/
static CompressedState applyUpdate(VariableInformation const& variableInformation, CompressedState const& state, CompressedState const& baseState, storm::prism::Update const& update, storm::expressions::ExpressionEvaluator<ValueType> const& evaluator);
storm::expressions::SimpleValuation unpackStateIntoValuation(storm::storage::BitVector const& currentState);
/*!
* Retrieves the state id of the given state. If the state has not been encountered yet, it will be added to
@ -293,29 +236,8 @@ namespace storm {
* @param internalStateInformation The information about the already explored part of the reachable state space.
* @return A pair indicating whether the state was already discovered before and the state id of the state.
*/
static IndexType getOrAddStateIndex(CompressedState const& state, InternalStateInformation& internalStateInformation, std::queue<storm::storage::BitVector>& stateQueue);
StateType getOrAddStateIndex(CompressedState const& state);
/*!
* Retrieves all commands that are labeled with the given label and enabled in the given state, grouped by
* modules.
*
* This function will iterate over all modules and retrieve all commands that are labeled with the given
* action and active (i.e. enabled) in the current state. The result is a list of lists of commands in which
* the inner lists contain all commands of exactly one module. If a module does not have *any* (including
* disabled) commands, there will not be a list of commands of that module in the result. If, however, the
* module has a command with a relevant label, but no enabled one, nothing is returned to indicate that there
* is no legal transition possible.
*
* @param The program in which to search for active commands.
* @param state The current state.
* @param actionIndex The index of the action label to select.
* @return A list of lists of active commands or nothing.
*/
static boost::optional<std::vector<std::vector<std::reference_wrapper<storm::prism::Command const>>>> getActiveCommandsByActionIndex(storm::prism::Program const& program,storm::expressions::ExpressionEvaluator<ValueType> const& evaluator, uint_fast64_t const& actionIndex);
static std::vector<Choice<ValueType>> getUnlabeledTransitions(storm::prism::Program const& program, bool discreteTimeModel, InternalStateInformation& internalStateInformation, VariableInformation const& variableInformation, storm::storage::BitVector const& currentState, bool choiceLabeling, storm::expressions::ExpressionEvaluator<ValueType> const& evaluator, std::queue<storm::storage::BitVector>& stateQueue, storm::utility::ConstantsComparator<ValueType> const& comparator);
static std::vector<Choice<ValueType>> getLabeledTransitions(storm::prism::Program const& program, bool discreteTimeModel, InternalStateInformation& internalStateInformation, VariableInformation const& variableInformation, storm::storage::BitVector const& currentState, bool choiceLabeling, storm::expressions::ExpressionEvaluator<ValueType> const& evaluator, std::queue<storm::storage::BitVector>& stateQueue, storm::utility::ConstantsComparator<ValueType> const& comparator);
/*!
* Builds the transition matrix and the transition reward matrix based for the given program.
*
@ -333,7 +255,7 @@ namespace storm {
* @return A tuple containing a vector with all rows at which the nondeterministic choices of each state begin
* and a vector containing the labels associated with each choice.
*/
static boost::optional<std::vector<boost::container::flat_set<uint_fast64_t>>> buildMatrices(storm::prism::Program const& program, VariableInformation const& variableInformation, std::vector<std::reference_wrapper<storm::prism::RewardModel const>> const& selectedRewardModels, InternalStateInformation& internalStateInformation, bool commandLabels, bool deterministicModel, bool discreteTimeModel, storm::storage::SparseMatrixBuilder<ValueType>& transitionMatrixBuilder, std::vector<RewardModelBuilder<typename RewardModelType::ValueType>>& rewardModelBuilders, boost::optional<storm::expressions::Expression> const& terminalExpression);
boost::optional<std::vector<boost::container::flat_set<uint_fast64_t>>> buildMatrices(std::vector<std::reference_wrapper<storm::prism::RewardModel const>> const& selectedRewardModels, storm::storage::SparseMatrixBuilder<ValueType>& transitionMatrixBuilder, std::vector<RewardModelBuilder<typename RewardModelType::ValueType>>& rewardModelBuilders, boost::optional<storm::expressions::Expression> const& terminalExpression);
/*!
* Explores the state space of the given program and returns the components of the model as a result.
@ -343,7 +265,7 @@ namespace storm {
* @param options A set of options used to customize the building process.
* @return A structure containing the components of the resulting model.
*/
ModelComponents buildModelComponents(storm::prism::Program const& program, std::vector<std::reference_wrapper<storm::prism::RewardModel const>> const& selectedRewardModels, Options const& options);
ModelComponents buildModelComponents(std::vector<std::reference_wrapper<storm::prism::RewardModel const>> const& selectedRewardModels);
/*!
* Builds the state labeling for the given program.
@ -353,17 +275,34 @@ namespace storm {
* @param internalStateInformation Information about the state space of the program.
* @return The state labeling of the given program.
*/
static storm::models::sparse::StateLabeling buildStateLabeling(storm::prism::Program const& program, VariableInformation const& variableInformation, InternalStateInformation const& internalStateInformation);
storm::models::sparse::StateLabeling buildStateLabeling();
// The program to translate. The necessary transformations are performed upon construction of the builder.
storm::prism::Program program;
// The options to be used for translating the program.
Options options;
// The variable information.
VariableInformation variableInformation;
// Internal information about the states that were explored.
InternalStateInformation internalStateInformation;
// This member holds information about reachable states that can be retrieved from the outside after a
// successful build.
boost::optional<StateInformation> stateInformation;
// This member holds the program that was most recently translated (if any).
boost::optional<storm::prism::Program> preparedProgram;
// A set of states that still need to be explored.
std::deque<CompressedState> statesToExplore;
// An optional mapping from state indices to the row groups in which they actually reside. This needs to be
// built in case the exploration order is not BFS.
boost::optional<std::vector<uint_fast64_t>> stateRemapping;
};
} // namespace adapters
} // namespace storm
#endif /* STORM_ADAPTERS_EXPLICITPRISMMODELBUILDER_H */
#endif /* STORM_BUILDER_EXPLICITPRISMMODELBUILDER_H */

22
src/builder/ExplorationOrder.cpp

@ -0,0 +1,22 @@
#include "src/builder/ExplorationOrder.h"
namespace storm {
namespace builder {
std::ostream& operator<<(std::ostream& out, ExplorationOrder const& order) {
switch (order) {
case ExplorationOrder::Dfs:
out << "depth-first";
break;
case ExplorationOrder::Bfs:
out << "breadth-first";
break;
default:
out << "undefined";
break;
}
return out;
}
}
}

17
src/builder/ExplorationOrder.h

@ -0,0 +1,17 @@
#ifndef STORM_BUILDER_EXPLORATIONORDER_H_
#define STORM_BUILDER_EXPLORATIONORDER_H_
#include <ostream>
namespace storm {
namespace builder {
// An enum that contains all currently supported exploration orders.
enum class ExplorationOrder { Dfs, Bfs };
std::ostream& operator<<(std::ostream& out, ExplorationOrder const& order);
}
}
#endif /* STORM_BUILDER_EXPLORATIONORDER_H_ */

105
src/generator/Choice.cpp

@ -0,0 +1,105 @@
#include "src/generator/Choice.h"
#include "src/adapters/CarlAdapter.h"
#include "src/utility/constants.h"
namespace storm {
namespace generator {
template<typename ValueType, typename StateType>
Choice<ValueType, StateType>::Choice(uint_fast64_t actionIndex, bool markovian) : markovian(markovian), actionIndex(actionIndex), distribution(), totalMass(storm::utility::zero<ValueType>()), choiceRewards() {
// Intentionally left empty.
}
template<typename ValueType, typename StateType>
typename storm::storage::Distribution<ValueType, StateType>::iterator Choice<ValueType, StateType>::begin() {
return distribution.begin();
}
template<typename ValueType, typename StateType>
typename storm::storage::Distribution<ValueType, StateType>::const_iterator Choice<ValueType, StateType>::begin() const {
return distribution.cbegin();
}
template<typename ValueType, typename StateType>
typename storm::storage::Distribution<ValueType, StateType>::iterator Choice<ValueType, StateType>::end() {
return distribution.end();
}
template<typename ValueType, typename StateType>
typename storm::storage::Distribution<ValueType, StateType>::const_iterator Choice<ValueType, StateType>::end() const {
return distribution.cend();
}
template<typename ValueType, typename StateType>
void Choice<ValueType, StateType>::addChoiceLabel(uint_fast64_t label) {
if (!choiceLabels) {
choiceLabels = LabelSet();
}
choiceLabels->insert(label);
}
template<typename ValueType, typename StateType>
void Choice<ValueType, StateType>::addChoiceLabels(LabelSet const& labelSet) {
if (!choiceLabels) {
choiceLabels = LabelSet();
}
choiceLabels->insert(labelSet.begin(), labelSet.end());
}
template<typename ValueType, typename StateType>
boost::container::flat_set<uint_fast64_t> const& Choice<ValueType, StateType>::getChoiceLabels() const {
return *choiceLabels;
}
template<typename ValueType, typename StateType>
uint_fast64_t Choice<ValueType, StateType>::getActionIndex() const {
return actionIndex;
}
template<typename ValueType, typename StateType>
ValueType Choice<ValueType, StateType>::getTotalMass() const {
return totalMass;
}
template<typename ValueType, typename StateType>
void Choice<ValueType, StateType>::addProbability(StateType const& state, ValueType const& value) {
totalMass += value;
distribution.addProbability(state, value);
}
template<typename ValueType, typename StateType>
void Choice<ValueType, StateType>::addChoiceReward(ValueType const& value) {
choiceRewards.push_back(value);
}
template<typename ValueType, typename StateType>
std::vector<ValueType> const& Choice<ValueType, StateType>::getChoiceRewards() const {
return choiceRewards;
}
template<typename ValueType, typename StateType>
bool Choice<ValueType, StateType>::isMarkovian() const {
return markovian;
}
template<typename ValueType, typename StateType>
std::size_t Choice<ValueType, StateType>::size() const {
return distribution.size();
}
template<typename ValueType, typename StateType>
std::ostream& operator<<(std::ostream& out, Choice<ValueType, StateType> const& choice) {
out << "<";
for (auto const& stateProbabilityPair : choice) {
out << stateProbabilityPair.first << " : " << stateProbabilityPair.second << ", ";
}
out << ">";
return out;
}
template class Choice<double>;
template class Choice<storm::RationalFunction>;
}
}

150
src/generator/Choice.h

@ -0,0 +1,150 @@
#ifndef STORM_GENERATOR_CHOICE_H_
#define STORM_GENERATOR_CHOICE_H_
#include <cstdint>
#include <functional>
#include <boost/optional.hpp>
#include <boost/container/flat_set.hpp>
#include "src/storage/Distribution.h"
namespace storm {
namespace generator {
// A structure holding information about a particular choice.
template<typename ValueType, typename StateType=uint32_t>
struct Choice {
public:
typedef boost::container::flat_set<uint_fast64_t> LabelSet;
Choice(uint_fast64_t actionIndex = 0, bool markovian = false);
Choice(Choice const& other) = default;
Choice& operator=(Choice const& other) = default;
Choice(Choice&& other) = default;
Choice& operator=(Choice&& other) = default;
/*!
* Returns an iterator to the distribution associated with this choice.
*
* @return An iterator to the first element of the distribution.
*/
typename storm::storage::Distribution<ValueType, StateType>::iterator begin();
/*!
* Returns an iterator to the distribution associated with this choice.
*
* @return An iterator to the first element of the distribution.
*/
typename storm::storage::Distribution<ValueType, StateType>::const_iterator begin() const;
/*!
* Returns an iterator past the end of the distribution associated with this choice.
*
* @return An iterator past the end of the distribution.
*/
typename storm::storage::Distribution<ValueType, StateType>::iterator end();
/*!
* Returns an iterator past the end of the distribution associated with this choice.
*
* @return An iterator past the end of the distribution.
*/
typename storm::storage::Distribution<ValueType, StateType>::const_iterator end() const;
/*!
* Inserts the contents of this object to the given output stream.
*
* @param out The stream in which to insert the contents.
*/
template<typename ValueTypePrime, typename StateTypePrime>
friend std::ostream& operator<<(std::ostream& out, Choice<ValueTypePrime, StateTypePrime> const& choice);
/*!
* Adds the given label to the labels associated with this choice.
*
* @param label The label to associate with this choice.
*/
void addChoiceLabel(uint_fast64_t label);
/*!
* Adds the given label set to the labels associated with this choice.
*
* @param labelSet The label set to associate with this choice.
*/
void addChoiceLabels(LabelSet const& labelSet);
/*!
* Retrieves the set of labels associated with this choice.
*
* @return The set of labels associated with this choice.
*/
LabelSet const& getChoiceLabels() const;
/*!
* Retrieves the index of the action of this choice.
*
* @return The index of the action of this choice.
*/
uint_fast64_t getActionIndex() const;
/*!
* Retrieves the total mass of this choice.
*
* @return The total mass.
*/
ValueType getTotalMass() const;
/*!
* Adds the given probability value to the given state in the underlying distribution.
*/
void addProbability(StateType const& state, ValueType const& value);
/*!
* Adds the given value to the reward associated with this choice.
*/
void addChoiceReward(ValueType const& value);
/*!
* Retrieves the rewards for this choice under selected reward models.
*/
std::vector<ValueType> const& getChoiceRewards() const;
/*!
* Retrieves whether the choice is Markovian.
*/
bool isMarkovian() const;
/*!
* Retrieves the size of the distribution associated with this choice.
*/
std::size_t size() const;
private:
// A flag indicating whether this choice is Markovian or not.
bool markovian;
// The action index associated with this choice.
uint_fast64_t actionIndex;
// The distribution that is associated with the choice.
storm::storage::Distribution<ValueType, StateType> distribution;
// The total probability mass (or rates) of this choice.
ValueType totalMass;
// The reward values associated with this choice.
std::vector<ValueType> choiceRewards;
// The labels that are associated with this choice.
boost::optional<LabelSet> choiceLabels;
};
template<typename ValueType, typename StateType>
std::ostream& operator<<(std::ostream& out, Choice<ValueType, StateType> const& choice);
}
}
#endif /* STORM_GENERATOR_CHOICE_H_ */

23
src/generator/CompressedState.cpp

@ -0,0 +1,23 @@
#include "src/generator/CompressedState.h"
#include "src/generator/VariableInformation.h"
#include "src/storage/expressions/ExpressionEvaluator.h"
namespace storm {
namespace generator {
template<typename ValueType>
void unpackStateIntoEvaluator(CompressedState const& state, VariableInformation const& variableInformation, storm::expressions::ExpressionEvaluator<ValueType>& evaluator) {
for (auto const& booleanVariable : variableInformation.booleanVariables) {
evaluator.setBooleanValue(booleanVariable.variable, state.get(booleanVariable.bitOffset));
}
for (auto const& integerVariable : variableInformation.integerVariables) {
evaluator.setIntegerValue(integerVariable.variable, state.getAsInt(integerVariable.bitOffset, integerVariable.bitWidth) + integerVariable.lowerBound);
}
}
template void unpackStateIntoEvaluator<double>(CompressedState const& state, VariableInformation const& variableInformation, storm::expressions::ExpressionEvaluator<double>& evaluator);
template void unpackStateIntoEvaluator<storm::RationalFunction>(CompressedState const& state, VariableInformation const& variableInformation, storm::expressions::ExpressionEvaluator<storm::RationalFunction>& evaluator);
}
}

30
src/generator/CompressedState.h

@ -0,0 +1,30 @@
#ifndef STORM_GENERATOR_COMPRESSEDSTATE_H_
#define STORM_GENERATOR_COMPRESSEDSTATE_H_
#include "src/storage/BitVector.h"
namespace storm {
namespace expressions {
template<typename ValueType> class ExpressionEvaluator;
}
namespace generator {
typedef storm::storage::BitVector CompressedState;
class VariableInformation;
/*!
* Unpacks the compressed state into the evaluator.
*
* @param state The state to unpack.
* @param variableInformation The information about how the variables are packed with the state.
* @param evaluator The evaluator into which to load the state.
*/
template<typename ValueType>
void unpackStateIntoEvaluator(CompressedState const& state, VariableInformation const& variableInformation, storm::expressions::ExpressionEvaluator<ValueType>& evaluator);
}
}
#endif /* STORM_GENERATOR_COMPRESSEDSTATE_H_ */

24
src/generator/NextStateGenerator.h

@ -0,0 +1,24 @@
#ifndef STORM_GENERATOR_NEXTSTATEGENERATOR_H_
#define STORM_GENERATOR_NEXTSTATEGENERATOR_H_
#include <vector>
#include <cstdint>
#include "src/generator/CompressedState.h"
#include "src/generator/StateBehavior.h"
namespace storm {
namespace generator {
template<typename ValueType, typename StateType = uint32_t>
class NextStateGenerator {
public:
typedef std::function<StateType (CompressedState const&)> StateToIdCallback;
virtual bool isDeterministicModel() const = 0;
virtual std::vector<StateType> getInitialStates(StateToIdCallback const& stateToIdCallback) = 0;
virtual StateBehavior<ValueType, StateType> expand(CompressedState const& state, StateToIdCallback const& stateToIdCallback) = 0;
};
}
}
#endif /* STORM_GENERATOR_NEXTSTATEGENERATOR_H_ */

404
src/generator/PrismNextStateGenerator.cpp

@ -0,0 +1,404 @@
#include "src/generator/PrismNextStateGenerator.h"
#include <boost/container/flat_map.hpp>
#include "src/utility/constants.h"
#include "src/utility/macros.h"
#include "src/exceptions/WrongFormatException.h"
namespace storm {
namespace generator {
template<typename ValueType, typename StateType>
PrismNextStateGenerator<ValueType, StateType>::PrismNextStateGenerator(storm::prism::Program const& program, VariableInformation const& variableInformation, bool buildChoiceLabeling) : program(program), selectedRewardModels(), buildChoiceLabeling(buildChoiceLabeling), variableInformation(variableInformation), evaluator(program.getManager()), comparator() {
// Intentionally left empty.
}
template<typename ValueType, typename StateType>
void PrismNextStateGenerator<ValueType, StateType>::addRewardModel(storm::prism::RewardModel const& rewardModel) {
selectedRewardModels.push_back(rewardModel);
hasStateActionRewards |= rewardModel.hasStateActionRewards();
}
template<typename ValueType, typename StateType>
void PrismNextStateGenerator<ValueType, StateType>::setTerminalExpression(storm::expressions::Expression const& terminalExpression) {
this->terminalExpression = terminalExpression;
}
template<typename ValueType, typename StateType>
bool PrismNextStateGenerator<ValueType, StateType>::isDeterministicModel() const {
return program.isDeterministicModel();
}
template<typename ValueType, typename StateType>
std::vector<StateType> PrismNextStateGenerator<ValueType, StateType>::getInitialStates(StateToIdCallback const& stateToIdCallback) {
// FIXME: This only works for models with exactly one initial state. We should make this more general.
CompressedState initialState(variableInformation.getTotalBitOffset());
// We need to initialize the values of the variables to their initial value.
for (auto const& booleanVariable : variableInformation.booleanVariables) {
initialState.set(booleanVariable.bitOffset, booleanVariable.initialValue);
}
for (auto const& integerVariable : variableInformation.integerVariables) {
initialState.setFromInt(integerVariable.bitOffset, integerVariable.bitWidth, static_cast<uint_fast64_t>(integerVariable.initialValue - integerVariable.lowerBound));
}
// Register initial state and return it.
StateType id = stateToIdCallback(initialState);
return {id};
}
template<typename ValueType, typename StateType>
StateBehavior<ValueType, StateType> PrismNextStateGenerator<ValueType, StateType>::expand(CompressedState const& state, StateToIdCallback const& stateToIdCallback) {
// Since almost all subsequent operations are based on the evaluator, we load the state into it now.
unpackStateIntoEvaluator(state, variableInformation, evaluator);
// Prepare the result, in case we return early.
StateBehavior<ValueType, StateType> result;
// First, construct the state rewards, as we may return early if there are no choices later and we already
// need the state rewards then.
for (auto const& rewardModel : selectedRewardModels) {
ValueType stateRewardValue = storm::utility::zero<ValueType>();
if (rewardModel.get().hasStateRewards()) {
for (auto const& stateReward : rewardModel.get().getStateRewards()) {
if (evaluator.asBool(stateReward.getStatePredicateExpression())) {
stateRewardValue += ValueType(evaluator.asRational(stateReward.getRewardValueExpression()));
}
}
}
result.addStateReward(stateRewardValue);
}
// If a terminal expression was set and we must not expand this state, return now.
if (terminalExpression && evaluator.asBool(terminalExpression.get())) {
return result;
}
// Get all choices for the state.
std::vector<Choice<ValueType>> allChoices = getUnlabeledChoices(state, stateToIdCallback);
std::vector<Choice<ValueType>> allLabeledChoices = getLabeledChoices(state, stateToIdCallback);
for (auto& choice : allLabeledChoices) {
allChoices.push_back(std::move(choice));
}
std::size_t totalNumberOfChoices = allChoices.size();
// If there is not a single choice, we return immediately, because the state has no behavior (other than
// the state reward).
if (totalNumberOfChoices == 0) {
return result;
}
// If the model is a deterministic model, we need to fuse the choices into one.
if (program.isDeterministicModel() && totalNumberOfChoices > 1) {
Choice<ValueType> globalChoice;
// For CTMCs, we need to keep track of the total exit rate to scale the action rewards later. For DTMCs
// this is equal to the number of choices, which is why we initialize it like this here.
ValueType totalExitRate = program.isDiscreteTimeModel() ? static_cast<ValueType>(totalNumberOfChoices) : storm::utility::zero<ValueType>();
// Iterate over all choices and combine the probabilities/rates into one choice.
for (auto const& choice : allChoices) {
for (auto const& stateProbabilityPair : choice) {
if (program.isDiscreteTimeModel()) {
globalChoice.addProbability(stateProbabilityPair.first, stateProbabilityPair.second / totalNumberOfChoices);
} else {
globalChoice.addProbability(stateProbabilityPair.first, stateProbabilityPair.second);
}
}
if (hasStateActionRewards && !program.isDiscreteTimeModel()) {
totalExitRate += choice.getTotalMass();
}
if (buildChoiceLabeling) {
globalChoice.addChoiceLabels(choice.getChoiceLabels());
}
}
// Now construct the state-action reward for all selected reward models.
for (auto const& rewardModel : selectedRewardModels) {
ValueType stateActionRewardValue = storm::utility::zero<ValueType>();
if (rewardModel.get().hasStateActionRewards()) {
for (auto const& stateActionReward : rewardModel.get().getStateActionRewards()) {
for (auto const& choice : allChoices) {
if (stateActionReward.getActionIndex() == choice.getActionIndex() && evaluator.asBool(stateActionReward.getStatePredicateExpression())) {
stateActionRewardValue += ValueType(evaluator.asRational(stateActionReward.getRewardValueExpression())) * choice.getTotalMass() / totalExitRate;
}
}
}
}
globalChoice.addChoiceReward(stateActionRewardValue);
}
// Move the newly fused choice in place.
allChoices.clear();
allChoices.push_back(std::move(globalChoice));
}
// Move all remaining choices in place.
for (auto& choice : allChoices) {
result.addChoice(std::move(choice));
}
result.setExpanded();
return result;
}
template<typename ValueType, typename StateType>
CompressedState PrismNextStateGenerator<ValueType, StateType>::applyUpdate(CompressedState const& state, storm::prism::Update const& update) {
CompressedState newState(state);
auto assignmentIt = update.getAssignments().begin();
auto assignmentIte = update.getAssignments().end();
// Iterate over all boolean assignments and carry them out.
auto boolIt = variableInformation.booleanVariables.begin();
for (; assignmentIt != assignmentIte && assignmentIt->getExpression().hasBooleanType(); ++assignmentIt) {
while (assignmentIt->getVariable() != boolIt->variable) {
++boolIt;
}
newState.set(boolIt->bitOffset, evaluator.asBool(assignmentIt->getExpression()));
}
// Iterate over all integer assignments and carry them out.
auto integerIt = variableInformation.integerVariables.begin();
for (; assignmentIt != assignmentIte && assignmentIt->getExpression().hasIntegerType(); ++assignmentIt) {
while (assignmentIt->getVariable() != integerIt->variable) {
++integerIt;
}
int_fast64_t assignedValue = evaluator.asInt(assignmentIt->getExpression());
STORM_LOG_THROW(assignedValue <= integerIt->upperBound, storm::exceptions::WrongFormatException, "The update " << update << " leads to an out-of-bounds value (" << assignedValue << ") for the variable '" << assignmentIt->getVariableName() << "'.");
newState.setFromInt(integerIt->bitOffset, integerIt->bitWidth, assignedValue - integerIt->lowerBound);
STORM_LOG_ASSERT(static_cast<int_fast64_t>(newState.getAsInt(integerIt->bitOffset, integerIt->bitWidth)) + integerIt->lowerBound == assignedValue, "Writing to the bit vector bucket failed (read " << newState.getAsInt(integerIt->bitOffset, integerIt->bitWidth) << " but wrote " << assignedValue << ").");
}
// Check that we processed all assignments.
STORM_LOG_ASSERT(assignmentIt == assignmentIte, "Not all assignments were consumed.");
return newState;
}
template<typename ValueType, typename StateType>
boost::optional<std::vector<std::vector<std::reference_wrapper<storm::prism::Command const>>>> PrismNextStateGenerator<ValueType, StateType>::getActiveCommandsByActionIndex(uint_fast64_t const& actionIndex) {
boost::optional<std::vector<std::vector<std::reference_wrapper<storm::prism::Command const>>>> result((std::vector<std::vector<std::reference_wrapper<storm::prism::Command const>>>()));
// Iterate over all modules.
for (uint_fast64_t i = 0; i < program.getNumberOfModules(); ++i) {
storm::prism::Module const& module = program.getModule(i);
// If the module has no command labeled with the given action, we can skip this module.
if (!module.hasActionIndex(actionIndex)) {
continue;
}
std::set<uint_fast64_t> const& commandIndices = module.getCommandIndicesByActionIndex(actionIndex);
// If the module contains the action, but there is no command in the module that is labeled with
// this action, we don't have any feasible command combinations.
if (commandIndices.empty()) {
return boost::optional<std::vector<std::vector<std::reference_wrapper<storm::prism::Command const>>>>();
}
std::vector<std::reference_wrapper<storm::prism::Command const>> commands;
// Look up commands by their indices and add them if the guard evaluates to true in the given state.
for (uint_fast64_t commandIndex : commandIndices) {
storm::prism::Command const& command = module.getCommand(commandIndex);
if (evaluator.asBool(command.getGuardExpression())) {
commands.push_back(command);
}
}
// If there was no enabled command although the module has some command with the required action label,
// we must not return anything.
if (commands.size() == 0) {
return boost::optional<std::vector<std::vector<std::reference_wrapper<storm::prism::Command const>>>>();
}
result.get().push_back(std::move(commands));
}
return result;
}
template<typename ValueType, typename StateType>
std::vector<Choice<ValueType>> PrismNextStateGenerator<ValueType, StateType>::getUnlabeledChoices(CompressedState const& state, StateToIdCallback stateToIdCallback) {
std::vector<Choice<ValueType>> result;
// Iterate over all modules.
for (uint_fast64_t i = 0; i < program.getNumberOfModules(); ++i) {
storm::prism::Module const& module = program.getModule(i);
// Iterate over all commands.
for (uint_fast64_t j = 0; j < module.getNumberOfCommands(); ++j) {
storm::prism::Command const& command = module.getCommand(j);
// Only consider unlabeled commands.
if (command.isLabeled()) continue;
// Skip the command, if it is not enabled.
if (!evaluator.asBool(command.getGuardExpression())) {
continue;
}
result.push_back(Choice<ValueType>(command.getActionIndex()));
Choice<ValueType>& choice = result.back();
// Remember the command labels only if we were asked to.
if (buildChoiceLabeling) {
choice.addChoiceLabel(command.getGlobalIndex());
}
// Iterate over all updates of the current command.
ValueType probabilitySum = storm::utility::zero<ValueType>();
for (uint_fast64_t k = 0; k < command.getNumberOfUpdates(); ++k) {
storm::prism::Update const& update = command.getUpdate(k);
// Obtain target state index and add it to the list of known states. If it has not yet been
// seen, we also add it to the set of states that have yet to be explored.
StateType stateIndex = stateToIdCallback(applyUpdate(state, update));
// Update the choice by adding the probability/target state to it.
ValueType probability = evaluator.asRational(update.getLikelihoodExpression());
choice.addProbability(stateIndex, probability);
probabilitySum += probability;
}
// Create the state-action reward for the newly created choice.
for (auto const& rewardModel : selectedRewardModels) {
ValueType stateActionRewardValue = storm::utility::zero<ValueType>();
if (rewardModel.get().hasStateActionRewards()) {
for (auto const& stateActionReward : rewardModel.get().getStateActionRewards()) {
if (stateActionReward.getActionIndex() == choice.getActionIndex() && evaluator.asBool(stateActionReward.getStatePredicateExpression())) {
stateActionRewardValue += ValueType(evaluator.asRational(stateActionReward.getRewardValueExpression())) * choice.getTotalMass();
}
}
}
choice.addChoiceReward(stateActionRewardValue);
}
// Check that the resulting distribution is in fact a distribution.
STORM_LOG_THROW(!program.isDiscreteTimeModel() || comparator.isOne(probabilitySum), storm::exceptions::WrongFormatException, "Probabilities do not sum to one for command '" << command << "' (actually sum to " << probabilitySum << ").");
}
}
return result;
}
template<typename ValueType, typename StateType>
std::vector<Choice<ValueType>> PrismNextStateGenerator<ValueType, StateType>::getLabeledChoices(CompressedState const& state, StateToIdCallback stateToIdCallback) {
std::vector<Choice<ValueType>> result;
for (uint_fast64_t actionIndex : program.getSynchronizingActionIndices()) {
boost::optional<std::vector<std::vector<std::reference_wrapper<storm::prism::Command const>>>> optionalActiveCommandLists = getActiveCommandsByActionIndex(actionIndex);
// Only process this action label, if there is at least one feasible solution.
if (optionalActiveCommandLists) {
std::vector<std::vector<std::reference_wrapper<storm::prism::Command const>>> const& activeCommandList = optionalActiveCommandLists.get();
std::vector<std::vector<std::reference_wrapper<storm::prism::Command const>>::const_iterator> iteratorList(activeCommandList.size());
// Initialize the list of iterators.
for (size_t i = 0; i < activeCommandList.size(); ++i) {
iteratorList[i] = activeCommandList[i].cbegin();
}
// As long as there is one feasible combination of commands, keep on expanding it.
bool done = false;
while (!done) {
boost::container::flat_map<CompressedState, ValueType>* currentTargetStates = new boost::container::flat_map<CompressedState, ValueType>();
boost::container::flat_map<CompressedState, ValueType>* newTargetStates = new boost::container::flat_map<CompressedState, ValueType>();
currentTargetStates->emplace(state, storm::utility::one<ValueType>());
for (uint_fast64_t i = 0; i < iteratorList.size(); ++i) {
storm::prism::Command const& command = *iteratorList[i];
for (uint_fast64_t j = 0; j < command.getNumberOfUpdates(); ++j) {
storm::prism::Update const& update = command.getUpdate(j);
for (auto const& stateProbabilityPair : *currentTargetStates) {
// Compute the new state under the current update and add it to the set of new target states.
CompressedState newTargetState = applyUpdate(stateProbabilityPair.first, update);
newTargetStates->emplace(newTargetState, stateProbabilityPair.second * evaluator.asRational(update.getLikelihoodExpression()));
}
}
// If there is one more command to come, shift the target states one time step back.
if (i < iteratorList.size() - 1) {
delete currentTargetStates;
currentTargetStates = newTargetStates;
newTargetStates = new boost::container::flat_map<CompressedState, ValueType>();
}
}
// At this point, we applied all commands of the current command combination and newTargetStates
// contains all target states and their respective probabilities. That means we are now ready to
// add the choice to the list of transitions.
result.push_back(Choice<ValueType>(actionIndex));
// Now create the actual distribution.
Choice<ValueType>& choice = result.back();
// Remember the command labels only if we were asked to.
if (buildChoiceLabeling) {
// Add the labels of all commands to this choice.
for (uint_fast64_t i = 0; i < iteratorList.size(); ++i) {
choice.addChoiceLabel(iteratorList[i]->get().getGlobalIndex());
}
}
// Add the probabilities/rates to the newly created choice.
ValueType probabilitySum = storm::utility::zero<ValueType>();
for (auto const& stateProbabilityPair : *newTargetStates) {
StateType actualIndex = stateToIdCallback(stateProbabilityPair.first);
choice.addProbability(actualIndex, stateProbabilityPair.second);
probabilitySum += stateProbabilityPair.second;
}
// Check that the resulting distribution is in fact a distribution.
STORM_LOG_THROW(!program.isDiscreteTimeModel() || !comparator.isConstant(probabilitySum) || comparator.isOne(probabilitySum), storm::exceptions::WrongFormatException, "Sum of update probabilities do not some to one for some command (actually sum to " << probabilitySum << ").");
// Create the state-action reward for the newly created choice.
for (auto const& rewardModel : selectedRewardModels) {
ValueType stateActionRewardValue = storm::utility::zero<ValueType>();
if (rewardModel.get().hasStateActionRewards()) {
for (auto const& stateActionReward : rewardModel.get().getStateActionRewards()) {
if (stateActionReward.getActionIndex() == choice.getActionIndex() && evaluator.asBool(stateActionReward.getStatePredicateExpression())) {
stateActionRewardValue += ValueType(evaluator.asRational(stateActionReward.getRewardValueExpression())) * choice.getTotalMass();
}
}
}
choice.addChoiceReward(stateActionRewardValue);
}
// Dispose of the temporary maps.
delete currentTargetStates;
delete newTargetStates;
// Now, check whether there is one more command combination to consider.
bool movedIterator = false;
for (int_fast64_t j = iteratorList.size() - 1; j >= 0; --j) {
++iteratorList[j];
if (iteratorList[j] != activeCommandList[j].end()) {
movedIterator = true;
} else {
// Reset the iterator to the beginning of the list.
iteratorList[j] = activeCommandList[j].begin();
}
}
done = !movedIterator;
}
}
}
return result;
}
template class PrismNextStateGenerator<double>;
template class PrismNextStateGenerator<storm::RationalFunction>;
}
}

108
src/generator/PrismNextStateGenerator.h

@ -0,0 +1,108 @@
#ifndef STORM_GENERATOR_PRISMNEXTSTATEGENERATOR_H_
#define STORM_GENERATOR_PRISMNEXTSTATEGENERATOR_H_
#include "src/generator/NextStateGenerator.h"
#include "src/generator/VariableInformation.h"
#include "src/storage/prism/Program.h"
#include "src/storage/expressions/ExpressionEvaluator.h"
#include "src/utility/ConstantsComparator.h"
namespace storm {
namespace generator {
template<typename ValueType, typename StateType = uint32_t>
class PrismNextStateGenerator : public NextStateGenerator<ValueType, StateType> {
public:
typedef typename NextStateGenerator<ValueType, StateType>::StateToIdCallback StateToIdCallback;
PrismNextStateGenerator(storm::prism::Program const& program, VariableInformation const& variableInformation, bool buildChoiceLabeling);
/*!
* Adds a reward model to the list of selected reward models ()
*/
void addRewardModel(storm::prism::RewardModel const& rewardModel);
/*!
* Sets an expression such that if it evaluates to true in a state, prevents the exploration.
*/
void setTerminalExpression(storm::expressions::Expression const& terminalExpression);
virtual bool isDeterministicModel() const override;
virtual std::vector<StateType> getInitialStates(StateToIdCallback const& stateToIdCallback) override;
virtual StateBehavior<ValueType, StateType> expand(CompressedState const& state, StateToIdCallback const& stateToIdCallback) override;
private:
/*!
* Applies an update to the state currently loaded into the evaluator and applies the resulting values to
* the given compressed state.
* @params state The state to which to apply the new values.
* @params update The update to apply.
* @return The resulting state.
*/
CompressedState applyUpdate(CompressedState const& state, storm::prism::Update const& update);
/*!
* Retrieves all commands that are labeled with the given label and enabled in the given state, grouped by
* modules.
*
* This function will iterate over all modules and retrieve all commands that are labeled with the given
* action and active (i.e. enabled) in the current state. The result is a list of lists of commands in which
* the inner lists contain all commands of exactly one module. If a module does not have *any* (including
* disabled) commands, there will not be a list of commands of that module in the result. If, however, the
* module has a command with a relevant label, but no enabled one, nothing is returned to indicate that there
* is no legal transition possible.
*
* @param The program in which to search for active commands.
* @param state The current state.
* @param actionIndex The index of the action label to select.
* @return A list of lists of active commands or nothing.
*/
boost::optional<std::vector<std::vector<std::reference_wrapper<storm::prism::Command const>>>> getActiveCommandsByActionIndex(uint_fast64_t const& actionIndex);
/*!
* Retrieves all unlabeled choices possible from the given state.
*
* @param state The state for which to retrieve the unlabeled choices.
* @return The unlabeled choices of the state.
*/
std::vector<Choice<ValueType>> getUnlabeledChoices(CompressedState const& state, StateToIdCallback stateToIdCallback);
/*!
* Retrieves all labeled choices possible from the given state.
*
* @param state The state for which to retrieve the unlabeled choices.
* @return The labeled choices of the state.
*/
std::vector<Choice<ValueType>> getLabeledChoices(CompressedState const& state, StateToIdCallback stateToIdCallback);
// The program used for the generation of next states.
storm::prism::Program const& program;
// The reward models that need to be considered.
std::vector<std::reference_wrapper<storm::prism::RewardModel const>> selectedRewardModels;
// A flag that stores whether at least one of the selected reward models has state-action rewards.
bool hasStateActionRewards;
// A flag that stores whether or not to build the choice labeling.
bool buildChoiceLabeling;
// An optional expression that governs which states must not be explored.
boost::optional<storm::expressions::Expression> terminalExpression;
// Information about how the variables are packed.
VariableInformation const& variableInformation;
// An evaluator used to evaluate expressions.
storm::expressions::ExpressionEvaluator<ValueType> evaluator;
// A comparator used to compare constants.
storm::utility::ConstantsComparator<ValueType> comparator;
};
}
}
#endif /* STORM_GENERATOR_PRISMNEXTSTATEGENERATOR_H_ */

50
src/generator/PrismStateLabelingGenerator.cpp

@ -0,0 +1,50 @@
#include "src/generator/PrismStateLabelingGenerator.h"
#include "src/generator/CompressedState.h"
#include "src/storage/expressions/ExpressionEvaluator.h"
namespace storm {
namespace generator {
template<typename ValueType, typename StateType>
PrismStateLabelingGenerator<ValueType, StateType>::PrismStateLabelingGenerator(storm::prism::Program const& program, VariableInformation const& variableInformation) : program(program), variableInformation(variableInformation) {
// Intentionally left empty.
}
template<typename ValueType, typename StateType>
storm::models::sparse::StateLabeling PrismStateLabelingGenerator<ValueType, StateType>::generate(storm::storage::BitVectorHashMap<StateType> const& states, std::vector<StateType> const& initialStateIndices) {
std::vector<storm::prism::Label> const& labels = program.getLabels();
storm::expressions::ExpressionEvaluator<ValueType> evaluator(program.getManager());
storm::models::sparse::StateLabeling result(states.size());
// Initialize labeling.
for (auto const& label : labels) {
result.addLabel(label.getName());
}
for (auto const& stateIndexPair : states) {
unpackStateIntoEvaluator(stateIndexPair.first, variableInformation, evaluator);
for (auto const& label : labels) {
// Add label to state, if the corresponding expression is true.
if (evaluator.asBool(label.getStatePredicateExpression())) {
result.addLabelToState(label.getName(), stateIndexPair.second);
}
}
}
// Also label the initial state with the special label "init".
result.addLabel("init");
for (auto index : initialStateIndices) {
result.addLabelToState("init", index);
}
return result;
}
template class PrismStateLabelingGenerator<double, uint32_t>;
template class PrismStateLabelingGenerator<storm::RationalFunction, uint32_t>;
}
}

31
src/generator/PrismStateLabelingGenerator.h

@ -0,0 +1,31 @@
#ifndef STORM_GENERATOR_PRISMSTATELABELINGGENERATOR_H_
#define STORM_GENERATOR_PRISMSTATELABELINGGENERATOR_H_
#include "src/generator/StateLabelingGenerator.h"
#include "src/generator/VariableInformation.h"
#include "src/storage/prism/Program.h"
namespace storm {
namespace generator {
template<typename ValueType, typename StateType = uint32_t>
class PrismStateLabelingGenerator : public StateLabelingGenerator<StateType> {
public:
PrismStateLabelingGenerator(storm::prism::Program const& program, VariableInformation const& variableInformation);
virtual storm::models::sparse::StateLabeling generate(storm::storage::BitVectorHashMap<StateType> const& states, std::vector<StateType> const& initialStateIndices = {}) override;
private:
// The program for which to generate the labels.
storm::prism::Program const& program;
// Information about how the variables are packed.
VariableInformation const& variableInformation;
};
}
}
#endif /* STORM_GENERATOR_PRISMSTATELABELINGGENERATOR_H_ */

57
src/generator/StateBehavior.cpp

@ -0,0 +1,57 @@
#include "src/generator/StateBehavior.h"
#include "src/adapters/CarlAdapter.h"
namespace storm {
namespace generator {
template<typename ValueType, typename StateType>
StateBehavior<ValueType, StateType>::StateBehavior() : expanded(false) {
// Intentionally left empty.
}
template<typename ValueType, typename StateType>
void StateBehavior<ValueType, StateType>::addChoice(Choice<ValueType, StateType>&& choice) {
choices.push_back(std::move(choice));
}
template<typename ValueType, typename StateType>
void StateBehavior<ValueType, StateType>::addStateReward(ValueType const& stateReward) {
stateRewards.push_back(stateReward);
}
template<typename ValueType, typename StateType>
void StateBehavior<ValueType, StateType>::setExpanded(bool newValue) {
this->expanded = newValue;
}
template<typename ValueType, typename StateType>
bool StateBehavior<ValueType, StateType>::wasExpanded() const {
return expanded;
}
template<typename ValueType, typename StateType>
bool StateBehavior<ValueType, StateType>::empty() const {
return choices.empty();
}
template<typename ValueType, typename StateType>
typename std::vector<Choice<ValueType, StateType>>::const_iterator StateBehavior<ValueType, StateType>::begin() const {
return choices.begin();
}
template<typename ValueType, typename StateType>
typename std::vector<Choice<ValueType, StateType>>::const_iterator StateBehavior<ValueType, StateType>::end() const {
return choices.end();
}
template<typename ValueType, typename StateType>
std::vector<ValueType> const& StateBehavior<ValueType, StateType>::getStateRewards() const {
return stateRewards;
}
template class StateBehavior<double>;
template class StateBehavior<storm::RationalFunction>;
}
}

73
src/generator/StateBehavior.h

@ -0,0 +1,73 @@
#ifndef STORM_GENERATOR_PRISM_STATEBEHAVIOR_H_
#define STORM_GENERATOR_PRISM_STATEBEHAVIOR_H_
#include <cstdint>
#include "src/generator/Choice.h"
namespace storm {
namespace generator {
template<typename ValueType, typename StateType = uint32_t>
class StateBehavior {
public:
/*!
* Creates an empty behavior, i.e. the state was not yet expanded.
*/
StateBehavior();
/*!
* Adds the given choice to the behavior of the state.
*/
void addChoice(Choice<ValueType, StateType>&& choice);
/*!
* Adds the given state reward to the behavior of the state.
*/
void addStateReward(ValueType const& stateReward);
/*!
* Sets whether the state was expanded.
*/
void setExpanded(bool newValue = true);
/*!
* Retrieves whether the state was expanded.
*/
bool wasExpanded() const;
/*!
* Retrieves whether the behavior is empty in the sense that there are no available choices.
*/
bool empty() const;
/*!
* Retrieves an iterator to the choices available in the behavior.
*/
typename std::vector<Choice<ValueType, StateType>>::const_iterator begin() const;
/*!
* Retrieves an iterator past the choices available in the behavior.
*/
typename std::vector<Choice<ValueType, StateType>>::const_iterator end() const;
/*!
* Retrieves the list of state rewards under selected reward models.
*/
std::vector<ValueType> const& getStateRewards() const;
private:
// The choices available in the state.
std::vector<Choice<ValueType, StateType>> choices;
// The state rewards (under the different, selected reward models) of the state.
std::vector<ValueType> stateRewards;
// A flag indicating whether the state was actually expanded.
bool expanded;
};
}
}
#endif /* STORM_GENERATOR_PRISM_STATEBEHAVIOR_H_ */

20
src/generator/StateLabelingGenerator.h

@ -0,0 +1,20 @@
#ifndef STORM_GENERATOR_STATELABELINGGENERATOR_H_
#define STORM_GENERATOR_STATELABELINGGENERATOR_H_
#include "src/models/sparse/StateLabeling.h"
#include "src/storage/BitVectorHashMap.h"
namespace storm {
namespace generator {
template<typename StateType = uint32_t>
class StateLabelingGenerator {
public:
virtual storm::models::sparse::StateLabeling generate(storm::storage::BitVectorHashMap<StateType> const& states, std::vector<StateType> const& initialStateIndices = {}) = 0;
};
}
}
#endif /* STORM_GENERATOR_STATELABELINGGENERATOR_H_ */

77
src/generator/VariableInformation.cpp

@ -0,0 +1,77 @@
#include "src/generator/VariableInformation.h"
#include "src/utility/macros.h"
#include "src/exceptions/InvalidArgumentException.h"
namespace storm {
namespace generator {
BooleanVariableInformation::BooleanVariableInformation(storm::expressions::Variable const& variable, bool initialValue, uint_fast64_t bitOffset) : variable(variable), initialValue(initialValue), bitOffset(bitOffset) {
// Intentionally left empty.
}
IntegerVariableInformation::IntegerVariableInformation(storm::expressions::Variable const& variable, int_fast64_t initialValue, int_fast64_t lowerBound, int_fast64_t upperBound, uint_fast64_t bitOffset, uint_fast64_t bitWidth) : variable(variable), initialValue(initialValue), lowerBound(lowerBound), upperBound(upperBound), bitOffset(bitOffset), bitWidth(bitWidth) {
// Intentionally left empty.
}
VariableInformation::VariableInformation(storm::prism::Program const& program) : totalBitOffset(0) {
for (auto const& booleanVariable : program.getGlobalBooleanVariables()) {
booleanVariables.emplace_back(booleanVariable.getExpressionVariable(), booleanVariable.getInitialValueExpression().evaluateAsBool(), totalBitOffset);
++totalBitOffset;
booleanVariableToIndexMap[booleanVariable.getExpressionVariable()] = booleanVariables.size() - 1;
}
for (auto const& integerVariable : program.getGlobalIntegerVariables()) {
int_fast64_t lowerBound = integerVariable.getLowerBoundExpression().evaluateAsInt();
int_fast64_t upperBound = integerVariable.getUpperBoundExpression().evaluateAsInt();
uint_fast64_t bitwidth = static_cast<uint_fast64_t>(std::ceil(std::log2(upperBound - lowerBound + 1)));
integerVariables.emplace_back(integerVariable.getExpressionVariable(), integerVariable.getInitialValueExpression().evaluateAsInt(), lowerBound, upperBound, totalBitOffset, bitwidth);
totalBitOffset += bitwidth;
integerVariableToIndexMap[integerVariable.getExpressionVariable()] = integerVariables.size() - 1;
}
for (auto const& module : program.getModules()) {
for (auto const& booleanVariable : module.getBooleanVariables()) {
booleanVariables.emplace_back(booleanVariable.getExpressionVariable(), booleanVariable.getInitialValueExpression().evaluateAsBool(), totalBitOffset);
++totalBitOffset;
booleanVariableToIndexMap[booleanVariable.getExpressionVariable()] = booleanVariables.size() - 1;
}
for (auto const& integerVariable : module.getIntegerVariables()) {
int_fast64_t lowerBound = integerVariable.getLowerBoundExpression().evaluateAsInt();
int_fast64_t upperBound = integerVariable.getUpperBoundExpression().evaluateAsInt();
uint_fast64_t bitwidth = static_cast<uint_fast64_t>(std::ceil(std::log2(upperBound - lowerBound + 1)));
integerVariables.emplace_back(integerVariable.getExpressionVariable(), integerVariable.getInitialValueExpression().evaluateAsInt(), lowerBound, upperBound, totalBitOffset, bitwidth);
totalBitOffset += bitwidth;
integerVariableToIndexMap[integerVariable.getExpressionVariable()] = integerVariables.size() - 1;
}
}
}
uint_fast64_t VariableInformation::getTotalBitOffset(bool roundTo64Bit) const {
uint_fast64_t result = totalBitOffset;
if (roundTo64Bit) {
result = ((result >> 6) + 1) << 6;
}
return result;
}
uint_fast64_t VariableInformation::getBitOffset(storm::expressions::Variable const& variable) const {
auto const& booleanIndex = booleanVariableToIndexMap.find(variable);
if (booleanIndex != booleanVariableToIndexMap.end()) {
return booleanVariables[booleanIndex->second].bitOffset;
}
auto const& integerIndex = integerVariableToIndexMap.find(variable);
if (integerIndex != integerVariableToIndexMap.end()) {
return integerVariables[integerIndex->second].bitOffset;
}
STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "Cannot look-up bit index of unknown variable.");
}
uint_fast64_t VariableInformation::getBitWidth(storm::expressions::Variable const& variable) const {
auto const& integerIndex = integerVariableToIndexMap.find(variable);
if (integerIndex != integerVariableToIndexMap.end()) {
return integerVariables[integerIndex->second].bitWidth;
}
STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "Cannot look-up bit width of unknown variable.");
}
}
}

75
src/generator/VariableInformation.h

@ -0,0 +1,75 @@
#ifndef STORM_GENERATOR_VARIABLEINFORMATION_H_
#define STORM_GENERATOR_VARIABLEINFORMATION_H_
#include <vector>
#include <boost/container/flat_map.hpp>
#include "src/storage/expressions/Variable.h"
#include "src/storage/prism/Program.h"
namespace storm {
namespace generator {
// A structure storing information about the boolean variables of the program.
struct BooleanVariableInformation {
BooleanVariableInformation(storm::expressions::Variable const& variable, bool initialValue, uint_fast64_t bitOffset);
// The boolean variable.
storm::expressions::Variable variable;
// Its initial value.
bool initialValue;
// Its bit offset in the compressed state.
uint_fast64_t bitOffset;
};
// A structure storing information about the integer variables of the program.
struct IntegerVariableInformation {
IntegerVariableInformation(storm::expressions::Variable const& variable, int_fast64_t initialValue, int_fast64_t lowerBound, int_fast64_t upperBound, uint_fast64_t bitOffset, uint_fast64_t bitWidth);
// The integer variable.
storm::expressions::Variable variable;
// Its initial value.
int_fast64_t initialValue;
// The lower bound of its range.
int_fast64_t lowerBound;
// The upper bound of its range.
int_fast64_t upperBound;
// Its bit offset in the compressed state.
uint_fast64_t bitOffset;
// Its bit width in the compressed state.
uint_fast64_t bitWidth;
};
// A structure storing information about the used variables of the program.
struct VariableInformation {
VariableInformation() = default;
VariableInformation(storm::prism::Program const& program);
uint_fast64_t getTotalBitOffset(bool roundTo64Bit = false) const;
// Provide methods to access the bit offset and width of variables in the compressed state.
uint_fast64_t getBitOffset(storm::expressions::Variable const& variable) const;
uint_fast64_t getBitWidth(storm::expressions::Variable const& variable) const;
// The total bit offset over all variables.
uint_fast64_t totalBitOffset;
// The known boolean variables.
boost::container::flat_map<storm::expressions::Variable, uint_fast64_t> booleanVariableToIndexMap;
std::vector<BooleanVariableInformation> booleanVariables;
// The known integer variables.
boost::container::flat_map<storm::expressions::Variable, uint_fast64_t> integerVariableToIndexMap;
std::vector<IntegerVariableInformation> integerVariables;
};
}
}
#endif /* STORM_GENERATOR_VARIABLEINFORMATION_H_ */

2
src/modelchecker/csl/helper/SparseCtmcCslHelper.cpp

@ -354,7 +354,7 @@ namespace storm {
STORM_LOG_THROW(uniformizationRate > 0, storm::exceptions::InvalidStateException, "The uniformization rate must be positive.");
storm::storage::SparseMatrix<ValueType> uniformizedMatrix = computeUniformizedMatrix(rateMatrix, storm::storage::BitVector(numberOfStates, true), uniformizationRate, exitRateVector);
// Compute the total state reward vector.
std::vector<ValueType> totalRewardVector = rewardModel.getTotalRewardVector(rateMatrix, exitRateVector);

4
src/parser/PrismParser.cpp

@ -11,7 +11,7 @@ namespace storm {
namespace parser {
storm::prism::Program PrismParser::parse(std::string const& filename) {
// Open file and initialize result.
std::ifstream inputFileStream(filename, std::ios::in);
std::ifstream inputFileStream(filename);
STORM_LOG_THROW(inputFileStream.good(), storm::exceptions::WrongFormatException, "Unable to read from file '" << filename << "'.");
storm::prism::Program result;
@ -35,7 +35,7 @@ namespace storm {
PositionIteratorType first(input.begin());
PositionIteratorType iter = first;
PositionIteratorType last(input.end());
assert(first != last);
STORM_LOG_ASSERT(first != last, "Illegal input to PRISM parser.");
// Create empty result;
storm::prism::Program result;

16
src/settings/ArgumentValidators.h

@ -18,6 +18,7 @@
#include "src/exceptions/IllegalArgumentValueException.h"
#include "src/exceptions/IllegalFunctionCallException.h"
#include <sys/stat.h>
namespace storm {
namespace settings {
@ -97,11 +98,16 @@ namespace storm {
*/
static std::function<bool (std::string const&)> existingReadableFileValidator() {
return [] (std::string const fileName) -> bool {
std::ifstream targetFile(fileName);
bool isFileGood = targetFile.good();
STORM_LOG_THROW(isFileGood, storm::exceptions::IllegalArgumentValueException, "The file " << fileName << " does not exist or is not readable.");
return isFileGood;
// First check existence as ifstream::good apparently als returns true for directories.
struct stat info;
stat(fileName.c_str(), &info);
STORM_LOG_THROW(info.st_mode & S_IFREG, storm::exceptions::IllegalArgumentValueException, "Unable to read from non-existing file '" << fileName << "'.");
// Now that we know it's a file, we can check its readability.
std::ifstream istream(fileName);
STORM_LOG_THROW(istream.good(), storm::exceptions::IllegalArgumentValueException, "Unable to read from file '" << fileName << "'.");
return true;
};
}

21
src/settings/modules/GeneralSettings.cpp

@ -32,6 +32,8 @@ namespace storm {
const std::string GeneralSettings::explicitOptionShortName = "exp";
const std::string GeneralSettings::symbolicOptionName = "symbolic";
const std::string GeneralSettings::symbolicOptionShortName = "s";
const std::string GeneralSettings::explorationOrderOptionName = "explorder";
const std::string GeneralSettings::explorationOrderOptionShortName = "eo";
const std::string GeneralSettings::propertyOptionName = "prop";
const std::string GeneralSettings::propertyOptionShortName = "prop";
const std::string GeneralSettings::transitionRewardsOptionName = "transrew";
@ -83,6 +85,11 @@ namespace storm {
.addArgument(storm::settings::ArgumentBuilder::createStringArgument("labeling filename", "The name of the file from which to read the state labeling.").addValidationFunctionString(storm::settings::ArgumentValidators::existingReadableFileValidator()).build()).build());
this->addOption(storm::settings::OptionBuilder(moduleName, symbolicOptionName, false, "Parses the model given in a symbolic representation.").setShortName(symbolicOptionShortName)
.addArgument(storm::settings::ArgumentBuilder::createStringArgument("filename", "The name of the file from which to read the symbolic model.").addValidationFunctionString(storm::settings::ArgumentValidators::existingReadableFileValidator()).build()).build());
std::vector<std::string> explorationOrders = {"dfs", "bfs"};
this->addOption(storm::settings::OptionBuilder(moduleName, explorationOrderOptionName, false, "Sets which exploration order to use.").setShortName(explorationOrderOptionShortName)
.addArgument(storm::settings::ArgumentBuilder::createStringArgument("name", "The name of the exploration order to choose. Available are: dfs and bfs.").addValidationFunctionString(storm::settings::ArgumentValidators::stringInListValidator(explorationOrders)).setDefaultValueString("bfs").build()).build());
this->addOption(storm::settings::OptionBuilder(moduleName, propertyOptionName, false, "Specifies the formulas to be checked on the model.").setShortName(propertyOptionShortName)
.addArgument(storm::settings::ArgumentBuilder::createStringArgument("formula or filename", "The formula or the file containing the formulas.").build()).build());
this->addOption(storm::settings::OptionBuilder(moduleName, counterexampleOptionName, false, "Generates a counterexample for the given PRCTL formulas if not satisfied by the model")
@ -186,6 +193,20 @@ namespace storm {
return this->getOption(symbolicOptionName).getArgumentByName("filename").getValueAsString();
}
bool GeneralSettings::isExplorationOrderSet() const {
return this->getOption(explorationOrderOptionName).getHasOptionBeenSet();
}
storm::builder::ExplorationOrder GeneralSettings::getExplorationOrder() const {
std::string explorationOrderAsString = this->getOption(explorationOrderOptionName).getArgumentByName("name").getValueAsString();
if (explorationOrderAsString == "dfs") {
return storm::builder::ExplorationOrder::Dfs;
} else if (explorationOrderAsString == "bfs") {
return storm::builder::ExplorationOrder::Bfs;
}
STORM_LOG_THROW(false, storm::exceptions::IllegalArgumentValueException, "Unknown exploration order '" << explorationOrderAsString << "'.");
}
bool GeneralSettings::isPropertySet() const {
return this->getOption(propertyOptionName).getHasOptionBeenSet();
}

19
src/settings/modules/GeneralSettings.h

@ -4,6 +4,8 @@
#include "storm-config.h"
#include "src/settings/modules/ModuleSettings.h"
#include "src/builder/ExplorationOrder.h"
namespace storm {
namespace solver {
enum class EquationSolverType;
@ -25,7 +27,6 @@ namespace storm {
class GeneralSettings : public ModuleSettings {
public:
// An enumeration of all engines.
enum class Engine {
Sparse, Hybrid, Dd, Learning, AbstractionRefinement
};
@ -138,6 +139,20 @@ namespace storm {
* @return The name of the file that contains the symbolic model specification.
*/
std::string getSymbolicModelFilename() const;
/*!
* Retrieves whether the model exploration order was set.
*
* @return True if the model exploration option was set.
*/
bool isExplorationOrderSet() const;
/*!
* Retrieves the exploration order if it was set.
*
* @return The chosen exploration order.
*/
storm::builder::ExplorationOrder getExplorationOrder() const;
/*!
* Retrieves whether the property option was set.
@ -389,6 +404,8 @@ namespace storm {
static const std::string explicitOptionShortName;
static const std::string symbolicOptionName;
static const std::string symbolicOptionShortName;
static const std::string explorationOrderOptionName;
static const std::string explorationOrderOptionShortName;
static const std::string propertyOptionName;
static const std::string propertyOptionShortName;
static const std::string transitionRewardsOptionName;

250
src/storage/BitVector.cpp

@ -60,11 +60,11 @@ namespace storm {
return currentIndex == other.currentIndex;
}
BitVector::BitVector() : bitCount(0), bucketVector() {
BitVector::BitVector() : bitCount(0), buckets(nullptr) {
// Intentionally left empty.
}
BitVector::BitVector(uint_fast64_t length, bool init) : bitCount(length) {
BitVector::BitVector(uint_fast64_t length, bool init) : bitCount(length), buckets(nullptr) {
// Compute the correct number of buckets needed to store the given number of bits.
uint_fast64_t bucketCount = length >> 6;
if ((length & mod64mask) != 0) {
@ -73,10 +73,17 @@ namespace storm {
// Initialize the storage with the required values.
if (init) {
bucketVector = std::vector<uint64_t>(bucketCount, -1ll);
buckets = new uint64_t[bucketCount];
std::fill_n(buckets, bucketCount, -1ull);
truncateLastBucket();
} else {
bucketVector = std::vector<uint64_t>(bucketCount, 0);
buckets = new uint64_t[bucketCount]();
}
}
BitVector::~BitVector() {
if (buckets != nullptr) {
delete buckets;
}
}
@ -89,23 +96,22 @@ namespace storm {
// Intentionally left empty.
}
BitVector::BitVector(uint_fast64_t bucketCount, uint_fast64_t bitCount) : bitCount(bitCount), bucketVector(bucketCount) {
BitVector::BitVector(uint_fast64_t bucketCount, uint_fast64_t bitCount) : bitCount(bitCount), buckets(nullptr) {
STORM_LOG_ASSERT((bucketCount << 6) == bitCount, "Bit count does not match number of buckets.");
buckets = new uint64_t[bucketCount]();
}
BitVector::BitVector(BitVector const& other) : bitCount(other.bitCount), bucketVector(other.bucketVector) {
// Intentionally left empty.
BitVector::BitVector(BitVector const& other) : bitCount(other.bitCount), buckets(nullptr) {
buckets = new uint64_t[other.bucketCount()];
std::copy_n(other.buckets, other.bucketCount(), buckets);
}
//BitVector::BitVector(BitVector&& other) : bitCount(other.bitCount), bucketVector(std::move(other.bucketVector)) {
// Intentionally left empty.
//}
BitVector& BitVector::operator=(BitVector const& other) {
// Only perform the assignment if the source and target are not identical.
if (this != &other) {
bitCount = other.bitCount;
bucketVector = std::vector<uint64_t>(other.bucketVector);
buckets = new uint64_t[other.bucketCount()];
std::copy_n(other.buckets, other.bucketCount(), buckets);
}
return *this;
}
@ -117,9 +123,9 @@ namespace storm {
return false;
}
std::vector<uint64_t>::const_iterator first1 = this->bucketVector.begin();
std::vector<uint64_t>::const_iterator last1 = this->bucketVector.end();
std::vector<uint64_t>::const_iterator first2 = other.bucketVector.begin();
uint64_t* first1 = this->buckets;
uint64_t* last1 = this->buckets + this->bucketCount();
uint64_t* first2 = other.buckets;
for (; first1 != last1; ++first1, ++first2) {
if (*first1 < *first2) {
@ -130,12 +136,18 @@ namespace storm {
}
return false;
}
BitVector::BitVector(BitVector&& other) : bitCount(other.bitCount), buckets(other.buckets) {
other.bitCount = 0;
other.buckets = nullptr;
}
BitVector& BitVector::operator=(BitVector&& other) {
// Only perform the assignment if the source and target are not identical.
if (this != &other) {
bitCount = other.bitCount;
bucketVector = std::move(other.bucketVector);
this->buckets = other.buckets;
other.buckets = nullptr;
}
return *this;
@ -146,14 +158,7 @@ namespace storm {
if (this->bitCount != other.bitCount) return false;
// If the lengths match, we compare the buckets one by one.
for (std::vector<uint64_t>::const_iterator it1 = bucketVector.begin(), it2 = other.bucketVector.begin(); it1 != bucketVector.end(); ++it1, ++it2) {
if (*it1 != *it2) {
return false;
}
}
// All buckets were equal, so the bit vectors are equal.
return true;
return std::equal(this->buckets, this->buckets + this->bucketCount(), other.buckets);
}
bool BitVector::operator!=(BitVector const& other) const {
@ -166,9 +171,9 @@ namespace storm {
uint64_t mask = 1ull << (63 - (index & mod64mask));
if (value) {
bucketVector[bucket] |= mask;
buckets[bucket] |= mask;
} else {
bucketVector[bucket] &= ~mask;
buckets[bucket] &= ~mask;
}
}
@ -182,7 +187,7 @@ namespace storm {
bool BitVector::operator[](uint_fast64_t index) const {
uint64_t bucket = index >> 6;
uint64_t mask = 1ull << (63 - (index & mod64mask));
return (this->bucketVector[bucket] & mask) == mask;
return (this->buckets[bucket] & mask) == mask;
}
bool BitVector::get(uint_fast64_t index) const {
@ -197,89 +202,80 @@ namespace storm {
++newBucketCount;
}
if (newBucketCount > bucketVector.size()) {
if (newBucketCount > this->bucketCount()) {
uint64_t* newBuckets = new uint64_t[newBucketCount];
std::copy_n(buckets, this->bucketCount(), newBuckets);
if (init) {
bucketVector.back() |= ((1ull << (64 - (bitCount & mod64mask))) - 1ull);
bucketVector.resize(newBucketCount, -1ull);
newBuckets[this->bucketCount() - 1] |= ((1ull << (64 - (bitCount & mod64mask))) - 1ull);
std::fill_n(newBuckets + this->bucketCount(), newBucketCount - this->bucketCount(), -1ull);
} else {
bucketVector.resize(newBucketCount, 0);
std::fill_n(newBuckets + this->bucketCount(), newBucketCount - this->bucketCount(), 0);
}
if (buckets != nullptr) {
delete buckets;
}
buckets = newBuckets;
bitCount = newLength;
} else {
// If the underlying storage does not need to grow, we have to insert the missing bits.
if (init) {
bucketVector.back() |= ((1ull << (64 - (bitCount & mod64mask))) - 1ull);
buckets[this->bucketCount() - 1] |= ((1ull << (64 - (bitCount & mod64mask))) - 1ull);
}
bitCount = newLength;
}
truncateLastBucket();
} else {
bitCount = newLength;
uint_fast64_t newBucketCount = newLength >> 6;
if ((newLength & mod64mask) != 0) {
++newBucketCount;
}
bucketVector.resize(newBucketCount);
// If the number of buckets needs to be reduced, we resize it now. Otherwise, we can just truncate the
// last bucket.
if (newBucketCount < this->bucketCount()) {
uint64_t* newBuckets = new uint64_t[newBucketCount];
std::copy_n(buckets, newBucketCount, newBuckets);
if (buckets != nullptr) {
delete buckets;
}
buckets = newBuckets;
bitCount = newLength;
}
bitCount = newLength;
truncateLastBucket();
}
}
BitVector BitVector::operator&(BitVector const& other) const {
STORM_LOG_ASSERT(bitCount == other.bitCount, "Length of the bit vectors does not match.");
BitVector result(bitCount);
std::vector<uint64_t>::iterator it = result.bucketVector.begin();
for (std::vector<uint64_t>::const_iterator it1 = bucketVector.begin(), it2 = other.bucketVector.begin(); it != result.bucketVector.end(); ++it1, ++it2, ++it) {
*it = *it1 & *it2;
}
std::transform(this->buckets, this->buckets + this->bucketCount(), other.buckets, result.buckets, [] (uint64_t const& a, uint64_t const& b) { return a & b; });
return result;
}
BitVector& BitVector::operator&=(BitVector const& other) {
STORM_LOG_ASSERT(bitCount == other.bitCount, "Length of the bit vectors does not match.");
std::vector<uint64_t>::iterator it = bucketVector.begin();
for (std::vector<uint64_t>::const_iterator otherIt = other.bucketVector.begin(); it != bucketVector.end() && otherIt != other.bucketVector.end(); ++it, ++otherIt) {
*it &= *otherIt;
}
std::transform(this->buckets, this->buckets + this->bucketCount(), other.buckets, this->buckets, [] (uint64_t const& a, uint64_t const& b) { return a & b; });
return *this;
}
BitVector BitVector::operator|(BitVector const& other) const {
STORM_LOG_ASSERT(bitCount == other.bitCount, "Length of the bit vectors does not match.");
BitVector result(bitCount);
std::vector<uint64_t>::iterator it = result.bucketVector.begin();
for (std::vector<uint64_t>::const_iterator it1 = bucketVector.begin(), it2 = other.bucketVector.begin(); it != result.bucketVector.end(); ++it1, ++it2, ++it) {
*it = *it1 | *it2;
}
std::transform(this->buckets, this->buckets + this->bucketCount(), other.buckets, result.buckets, [] (uint64_t const& a, uint64_t const& b) { return a | b; });
return result;
}
BitVector& BitVector::operator|=(BitVector const& other) {
STORM_LOG_ASSERT(bitCount == other.bitCount, "Length of the bit vectors does not match.");
std::vector<uint64_t>::iterator it = bucketVector.begin();
for (std::vector<uint64_t>::const_iterator otherIt = other.bucketVector.begin(); it != bucketVector.end() && otherIt != other.bucketVector.end(); ++it, ++otherIt) {
*it |= *otherIt;
}
std::transform(this->buckets, this->buckets + this->bucketCount(), other.buckets, this->buckets, [] (uint64_t const& a, uint64_t const& b) { return a | b; });
return *this;
}
BitVector BitVector::operator^(BitVector const& other) const {
STORM_LOG_ASSERT(bitCount == other.bitCount, "Length of the bit vectors does not match.");
BitVector result(bitCount);
std::vector<uint64_t>::iterator it = result.bucketVector.begin();
for (std::vector<uint64_t>::const_iterator it1 = bucketVector.begin(), it2 = other.bucketVector.begin(); it != result.bucketVector.end(); ++it1, ++it2, ++it) {
*it = *it1 ^ *it2;
}
std::transform(this->buckets, this->buckets + this->bucketCount(), other.buckets, result.buckets, [] (uint64_t const& a, uint64_t const& b) { return a ^ b; });
result.truncateLastBucket();
return result;
}
@ -314,19 +310,13 @@ namespace storm {
BitVector BitVector::operator~() const {
BitVector result(this->bitCount);
std::vector<uint64_t>::iterator it = result.bucketVector.begin();
for (std::vector<uint64_t>::const_iterator it1 = bucketVector.begin(); it != result.bucketVector.end(); ++it1, ++it) {
*it = ~(*it1);
}
std::transform(this->buckets, this->buckets + this->bucketCount(), result.buckets, [] (uint64_t const& a) { return ~a; });
result.truncateLastBucket();
return result;
}
void BitVector::complement() {
for (auto& element : bucketVector) {
element = ~element;
}
std::transform(this->buckets, this->buckets + this->bucketCount(), this->buckets, [] (uint64_t const& a) { return ~a; });
truncateLastBucket();
}
@ -334,11 +324,7 @@ namespace storm {
STORM_LOG_ASSERT(bitCount == other.bitCount, "Length of the bit vectors does not match.");
BitVector result(bitCount);
std::vector<uint64_t>::iterator it = result.bucketVector.begin();
for (std::vector<uint64_t>::const_iterator it1 = bucketVector.begin(), it2 = other.bucketVector.begin(); it != result.bucketVector.end(); ++it1, ++it2, ++it) {
*it = ~(*it1) | *it2;
}
std::transform(this->buckets, this->buckets + this->bucketCount(), other.buckets, result.buckets, [] (uint64_t const& a, uint64_t const& b) { return (~a | b); });
result.truncateLastBucket();
return result;
}
@ -346,7 +332,11 @@ namespace storm {
bool BitVector::isSubsetOf(BitVector const& other) const {
STORM_LOG_ASSERT(bitCount == other.bitCount, "Length of the bit vectors does not match.");
for (std::vector<uint64_t>::const_iterator it1 = bucketVector.begin(), it2 = other.bucketVector.begin(); it1 != bucketVector.end(); ++it1, ++it2) {
uint64_t const* it1 = buckets;
uint64_t const* ite1 = buckets + bucketCount();
uint64_t const* it2 = other.buckets;
for (; it1 != ite1; ++it1, ++it2) {
if ((*it1 & *it2) != *it1) {
return false;
}
@ -357,7 +347,11 @@ namespace storm {
bool BitVector::isDisjointFrom(BitVector const& other) const {
STORM_LOG_ASSERT(bitCount == other.bitCount, "Length of the bit vectors does not match.");
for (std::vector<uint64_t>::const_iterator it1 = bucketVector.begin(), it2 = other.bucketVector.begin(); it1 != bucketVector.end(); ++it1, ++it2) {
uint64_t const* it1 = buckets;
uint64_t const* ite1 = buckets + bucketCount();
uint64_t const* it2 = other.buckets;
for (; it1 != ite1; ++it1, ++it2) {
if ((*it1 & *it2) != 0) {
return false;
}
@ -372,9 +366,9 @@ namespace storm {
// Compute the first bucket that needs to be checked and the number of buckets.
uint64_t index = bitIndex >> 6;
std::vector<uint64_t>::const_iterator first1 = bucketVector.begin() + index;
std::vector<uint64_t>::const_iterator first2 = other.bucketVector.begin();
std::vector<uint64_t>::const_iterator last2 = other.bucketVector.end();
uint64_t const* first1 = buckets + index;
uint64_t const* first2 = other.buckets;
uint64_t const* last2 = other.buckets + other.bucketCount();
for (; first2 != last2; ++first1, ++first2) {
if (*first1 != *first2) {
@ -391,10 +385,10 @@ namespace storm {
// Compute the first bucket that needs to be checked and the number of buckets.
uint64_t index = bitIndex >> 6;
std::vector<uint64_t>::iterator first1 = bucketVector.begin() + index;
std::vector<uint64_t>::const_iterator first2 = other.bucketVector.begin();
std::vector<uint64_t>::const_iterator last2 = other.bucketVector.end();
uint64_t* first1 = buckets + index;
uint64_t const* first2 = other.buckets;
uint64_t const* last2 = other.buckets + other.bucketCount();
for (; first2 != last2; ++first1, ++first2) {
*first1 = *first2;
}
@ -406,8 +400,8 @@ namespace storm {
STORM_LOG_ASSERT(index + numberOfBuckets <= this->bucketCount(), "Argument is out-of-range.");
storm::storage::BitVector result(numberOfBuckets, numberOfBits);
std::copy(this->bucketVector.begin() + index, this->bucketVector.begin() + index + numberOfBuckets, result.bucketVector.begin());
std::copy(this->buckets + index, this->buckets + index + numberOfBuckets, result.buckets);
result.truncateLastBucket();
return result;
}
@ -426,10 +420,10 @@ namespace storm {
if (bitIndexInBucket + numberOfBits < 64) {
// If the value stops before the end of the bucket, we need to erase some lower bits.
mask &= ~((1ull << (64 - (bitIndexInBucket + numberOfBits))) - 1ull);
return (bucketVector[bucket] & mask) >> (64 - (bitIndexInBucket + numberOfBits));
return (buckets[bucket] & mask) >> (64 - (bitIndexInBucket + numberOfBits));
} else if (bitIndexInBucket + numberOfBits > 64) {
// In this case, the integer "crosses" the bucket line.
uint64_t result = (bucketVector[bucket] & mask);
uint64_t result = (buckets[bucket] & mask);
++bucket;
// Compute the remaining number of bits.
@ -441,13 +435,13 @@ namespace storm {
// Strip away everything from the second bucket that is beyond the final index and add it to the
// intermediate result.
mask = ~((1ull << (64 - numberOfBits)) - 1ull);
uint64_t lowerBits = bucketVector[bucket] & mask;
uint64_t lowerBits = buckets[bucket] & mask;
result |= (lowerBits >> (64 - numberOfBits));
return result;
} else {
// In this case, it suffices to take the current mask.
return bucketVector[bucket] & mask;
return buckets[bucket] & mask;
}
}
@ -468,10 +462,10 @@ namespace storm {
if (bitIndexInBucket + numberOfBits < 64) {
// If the value stops before the end of the bucket, we need to erase some lower bits.
mask &= ~((1ull << (64 - (bitIndexInBucket + numberOfBits))) - 1ull);
bucketVector[bucket] = (bucketVector[bucket] & ~mask) | (value << (64 - (bitIndexInBucket + numberOfBits)));
buckets[bucket] = (buckets[bucket] & ~mask) | (value << (64 - (bitIndexInBucket + numberOfBits)));
} else if (bitIndexInBucket + numberOfBits > 64) {
// Write the part of the value that falls into the first bucket.
bucketVector[bucket] = (bucketVector[bucket] & ~mask) | (value >> (numberOfBits + (bitIndexInBucket - 64)));
buckets[bucket] = (buckets[bucket] & ~mask) | (value >> (numberOfBits + (bitIndexInBucket - 64)));
++bucket;
// Compute the remaining number of bits.
@ -482,45 +476,41 @@ namespace storm {
// Put the remaining bits in their place.
mask = ((1ull << (64 - numberOfBits)) - 1ull);
bucketVector[bucket] = (bucketVector[bucket] & mask) | value;
buckets[bucket] = (buckets[bucket] & mask) | value;
} else {
bucketVector[bucket] = (bucketVector[bucket] & ~mask) | value;
buckets[bucket] = (buckets[bucket] & ~mask) | value;
}
}
bool BitVector::empty() const {
for (auto& element : bucketVector) {
if (element != 0) {
return false;
}
}
return true;
uint64_t* last = buckets + bucketCount();
uint64_t* it = std::find_if(buckets, last, [] (uint64_t const& a) { return a != 0; });
return it == last;
}
bool BitVector::full() const {
// Check that all buckets except the last one have all bits set.
for (uint_fast64_t index = 0; index < bucketVector.size() - 1; ++index) {
if (bucketVector[index] != -1ull) {
uint64_t* last = buckets + bucketCount() - 1;
for (uint64_t const* it = buckets; it < last; ++it) {
if (*it != -1ull) {
return false;
}
}
// Now check whether the relevant bits are set in the last bucket.
uint64_t mask = ~((1ull << (64 - (bitCount & mod64mask))) - 1ull);
if ((bucketVector.back() & mask) != mask) {
if ((*last & mask) != mask) {
return false;
}
return true;
}
void BitVector::clear() {
for (auto& element : bucketVector) {
element = 0;
}
std::fill_n(buckets, this->bucketCount(), 0);
}
uint_fast64_t BitVector::getNumberOfSetBits() const {
return getNumberOfSetBitsBeforeIndex(bucketVector.size() << 6);
return getNumberOfSetBitsBeforeIndex(bitCount);
}
uint_fast64_t BitVector::getNumberOfSetBitsBeforeIndex(uint_fast64_t index) const {
@ -531,14 +521,14 @@ namespace storm {
for (uint_fast64_t i = 0; i < bucket; ++i) {
// Check if we are using g++ or clang++ and, if so, use the built-in function
#if (defined (__GNUG__) || defined(__clang__))
result += __builtin_popcountll(bucketVector[i]);
result += __builtin_popcountll(buckets[i]);
#elif defined WINDOWS
#include <nmmintrin.h>
// If the target machine does not support SSE4, this will fail.
result += _mm_popcnt_u64(bucketVector[i]);
#else
uint_fast32_t cnt;
uint_fast64_t bitset = bucketVector[i];
uint_fast64_t bitset = buckets[i];
for (cnt = 0; bitset; cnt++) {
bitset &= bitset - 1;
}
@ -550,7 +540,7 @@ namespace storm {
uint64_t tmp = index & mod64mask;
if (tmp != 0) {
tmp = ~((1ll << (64 - (tmp & mod64mask))) - 1ll);
tmp &= bucketVector[bucket];
tmp &= buckets[bucket];
// Check if we are using g++ or clang++ and, if so, use the built-in function
#if (defined (__GNUG__) || defined(__clang__))
result += __builtin_popcountll(tmp);
@ -587,19 +577,19 @@ namespace storm {
}
std::size_t BitVector::getSizeInBytes() const {
return sizeof (*this) + sizeof (uint64_t) * bucketVector.size();
return sizeof (*this) + sizeof (uint64_t) * bucketCount();
}
BitVector::const_iterator BitVector::begin() const {
return const_iterator(bucketVector.data(), 0, bitCount);
return const_iterator(buckets, 0, bitCount);
}
BitVector::const_iterator BitVector::end() const {
return const_iterator(bucketVector.data(), bitCount, bitCount, false);
return const_iterator(buckets, bitCount, bitCount, false);
}
uint_fast64_t BitVector::getNextSetIndex(uint_fast64_t startingIndex) const {
return getNextSetIndex(bucketVector.data(), startingIndex, bitCount);
return getNextSetIndex(buckets, startingIndex, bitCount);
}
uint_fast64_t BitVector::getNextSetIndex(uint64_t const* dataPtr, uint_fast64_t startingIndex, uint_fast64_t endIndex) {
@ -643,17 +633,21 @@ namespace storm {
void BitVector::truncateLastBucket() {
if ((bitCount & mod64mask) != 0) {
bucketVector.back() &= ~((1ll << (64 - (bitCount & mod64mask))) - 1ll);
buckets[bucketCount() - 1] &= ~((1ll << (64 - (bitCount & mod64mask))) - 1ll);
}
}
size_t BitVector::bucketCount() const {
return bucketVector.size();
size_t result = (bitCount >> 6);
if ((bitCount & mod64mask) != 0) {
++result;
}
return result;
}
std::ostream& operator<<(std::ostream& out, BitVector const& bitVector) {
out << "bit vector(" << bitVector.getNumberOfSetBits() << "/" << bitVector.bitCount << ") [";
for (auto index : bitVector) {
std::ostream& operator<<(std::ostream& out, BitVector const& bitvector) {
out << "bit vector(" << bitvector.getNumberOfSetBits() << "/" << bitvector.bitCount << ") [";
for (auto index : bitvector) {
out << index << " ";
}
out << "]";
@ -661,13 +655,13 @@ namespace storm {
return out;
}
std::size_t NonZeroBitVectorHash::operator()(storm::storage::BitVector const& bv) const {
STORM_LOG_ASSERT(bv.size() > 0, "Cannot hash bit vector of zero size.");
std::size_t NonZeroBitVectorHash::operator()(storm::storage::BitVector const& bitvector) const {
STORM_LOG_ASSERT(bitvector.size() > 0, "Cannot hash bit vector of zero size.");
std::size_t result = 0;
for (uint_fast64_t index = 0; index < bv.bucketVector.size(); ++index) {
for (uint_fast64_t index = 0; index < bitvector.bucketCount(); ++index) {
result ^= result << 3;
result ^= result >> bv.getAsInt(index << 6, 5);
result ^= result >> bitvector.getAsInt(index << 6, 5);
}
// Erase the last bit and add one to definitely make this hash value non-zero.
@ -691,7 +685,7 @@ namespace storm {
namespace std {
std::size_t hash<storm::storage::BitVector>::operator()(storm::storage::BitVector const& bv) const {
return boost::hash_range(bv.bucketVector.begin(), bv.bucketVector.end());
std::size_t hash<storm::storage::BitVector>::operator()(storm::storage::BitVector const& bitvector) const {
return boost::hash_range(bitvector.buckets, bitvector.buckets + bitvector.bucketCount());
}
}

9
src/storage/BitVector.h

@ -104,6 +104,11 @@ namespace storm {
*/
BitVector();
/*
* Deconstructs a bit vector by deleting the underlying storage.
*/
~BitVector();
/*!
* Constructs a bit vector which can hold the given number of bits and initializes all bits with the
* provided truth value.
@ -141,7 +146,7 @@ namespace storm {
*
* @param other The bit vector from which to move-construct.
*/
BitVector(BitVector&& other) = default;
BitVector(BitVector&& other);
/*!
* Compares the given bit vector with the current one.
@ -494,7 +499,7 @@ namespace storm {
uint_fast64_t bitCount;
// The underlying storage of 64-bit buckets for all bits of this bit vector.
std::vector<uint64_t> bucketVector;
uint64_t* buckets;
// A bit mask that can be used to reduce a modulo 64 operation to a logical "and".
static const uint_fast64_t mod64mask = (1 << 6) - 1;

9
src/storage/BitVectorHashMap.cpp

@ -41,7 +41,7 @@ namespace storm {
std::pair<storm::storage::BitVector, ValueType> BitVectorHashMap<ValueType, Hash1, Hash2>::BitVectorHashMapIterator::operator*() const {
return map.getBucketAndValue(*indexIt);
}
template<class ValueType, class Hash1, class Hash2>
BitVectorHashMap<ValueType, Hash1, Hash2>::BitVectorHashMap(uint64_t bucketSize, uint64_t initialSize, double loadFactor) : loadFactor(loadFactor), bucketSize(bucketSize), numberOfElements(0) {
STORM_LOG_ASSERT(bucketSize % 64 == 0, "Bucket size must be a multiple of 64.");
@ -234,6 +234,13 @@ namespace storm {
return std::make_pair(buckets.get(bucket * bucketSize, bucketSize), values[bucket]);
}
template<class ValueType, class Hash1, class Hash2>
void BitVectorHashMap<ValueType, Hash1, Hash2>::remap(std::function<ValueType(ValueType const&)> const& remapping) {
for (auto pos : occupied) {
values[pos] = remapping(values[pos]);
}
}
template class BitVectorHashMap<uint_fast64_t>;
template class BitVectorHashMap<uint32_t>;
}

9
src/storage/BitVectorHashMap.h

@ -55,7 +55,7 @@ namespace storm {
* @param loadFactor The load factor that determines at which point the size of the underlying storage is
* increased.
*/
BitVectorHashMap(uint64_t bucketSize, uint64_t initialSize, double loadFactor = 0.75);
BitVectorHashMap(uint64_t bucketSize = 64, uint64_t initialSize = 1000, double loadFactor = 0.75);
/*!
* Searches for the given key in the map. If it is found, the mapped-to value is returned. Otherwise, the
@ -123,6 +123,13 @@ namespace storm {
*/
std::size_t capacity() const;
/*!
* Performs a remapping of all values stored by applying the given remapping.
*
* @param remapping The remapping to apply.
*/
void remap(std::function<ValueType(ValueType const&)> const& remapping);
private:
/*!
* Retrieves whether the given bucket holds a value.

62
src/storage/Distribution.cpp

@ -14,13 +14,13 @@
namespace storm {
namespace storage {
template<typename ValueType>
Distribution<ValueType>::Distribution() {
template<typename ValueType, typename StateType>
Distribution<ValueType, StateType>::Distribution() {
// Intentionally left empty.
}
template<typename ValueType>
bool Distribution<ValueType>::equals(Distribution<ValueType> const& other, storm::utility::ConstantsComparator<ValueType> const& comparator) const {
template<typename ValueType, typename StateType>
bool Distribution<ValueType, StateType>::equals(Distribution<ValueType, StateType> const& other, storm::utility::ConstantsComparator<ValueType> const& comparator) const {
// We need to check equality by ourselves, because we need to account for epsilon differences.
if (this->distribution.size() != other.distribution.size()) {
return false;
@ -42,8 +42,8 @@ namespace storm {
return true;
}
template<typename ValueType>
void Distribution<ValueType>::addProbability(storm::storage::sparse::state_type const& state, ValueType const& probability) {
template<typename ValueType, typename StateType>
void Distribution<ValueType, StateType>::addProbability(StateType const& state, ValueType const& probability) {
auto it = this->distribution.find(state);
if (it == this->distribution.end()) {
this->distribution.emplace_hint(it, state, probability);
@ -52,8 +52,8 @@ namespace storm {
}
}
template<typename ValueType>
void Distribution<ValueType>::removeProbability(storm::storage::sparse::state_type const& state, ValueType const& probability, storm::utility::ConstantsComparator<ValueType> const& comparator) {
template<typename ValueType, typename StateType>
void Distribution<ValueType, StateType>::removeProbability(StateType const& state, ValueType const& probability, storm::utility::ConstantsComparator<ValueType> const& comparator) {
auto it = this->distribution.find(state);
STORM_LOG_ASSERT(it != this->distribution.end(), "Cannot remove probability, because the state is not in the support of the distribution.");
it->second -= probability;
@ -62,34 +62,44 @@ namespace storm {
}
}
template<typename ValueType>
void Distribution<ValueType>::shiftProbability(storm::storage::sparse::state_type const& fromState, storm::storage::sparse::state_type const& toState, ValueType const& probability, storm::utility::ConstantsComparator<ValueType> const& comparator) {
template<typename ValueType, typename StateType>
void Distribution<ValueType, StateType>::shiftProbability(StateType const& fromState, StateType const& toState, ValueType const& probability, storm::utility::ConstantsComparator<ValueType> const& comparator) {
removeProbability(fromState, probability, comparator);
addProbability(toState, probability);
}
template<typename ValueType>
typename Distribution<ValueType>::iterator Distribution<ValueType>::begin() {
template<typename ValueType, typename StateType>
typename Distribution<ValueType, StateType>::iterator Distribution<ValueType, StateType>::begin() {
return this->distribution.begin();
}
template<typename ValueType>
typename Distribution<ValueType>::const_iterator Distribution<ValueType>::begin() const {
template<typename ValueType, typename StateType>
typename Distribution<ValueType, StateType>::const_iterator Distribution<ValueType, StateType>::begin() const {
return this->distribution.begin();
}
template<typename ValueType>
typename Distribution<ValueType>::iterator Distribution<ValueType>::end() {
template<typename ValueType, typename StateType>
typename Distribution<ValueType, StateType>::const_iterator Distribution<ValueType, StateType>::cbegin() const {
return this->begin();
}
template<typename ValueType, typename StateType>
typename Distribution<ValueType, StateType>::iterator Distribution<ValueType, StateType>::end() {
return this->distribution.end();
}
template<typename ValueType>
typename Distribution<ValueType>::const_iterator Distribution<ValueType>::end() const {
template<typename ValueType, typename StateType>
typename Distribution<ValueType, StateType>::const_iterator Distribution<ValueType, StateType>::end() const {
return this->distribution.end();
}
template<typename ValueType, typename StateType>
typename Distribution<ValueType, StateType>::const_iterator Distribution<ValueType, StateType>::cend() const {
return this->end();
}
template<typename ValueType>
void Distribution<ValueType>::scale(storm::storage::sparse::state_type const& state) {
template<typename ValueType, typename StateType>
void Distribution<ValueType, StateType>::scale(StateType const& state) {
auto probabilityIterator = this->distribution.find(state);
if (probabilityIterator != this->distribution.end()) {
ValueType scaleValue = storm::utility::one<ValueType>() / probabilityIterator->second;
@ -101,13 +111,13 @@ namespace storm {
}
}
template<typename ValueType>
std::size_t Distribution<ValueType>::size() const {
template<typename ValueType, typename StateType>
std::size_t Distribution<ValueType, StateType>::size() const {
return this->distribution.size();
}
template<typename ValueType>
std::ostream& operator<<(std::ostream& out, Distribution<ValueType> const& distribution) {
template<typename ValueType, typename StateType>
std::ostream& operator<<(std::ostream& out, Distribution<ValueType, StateType> const& distribution) {
out << "{";
for (auto const& entry : distribution) {
out << "[" << entry.second << ": " << entry.first << "], ";
@ -117,8 +127,8 @@ namespace storm {
return out;
}
template<typename ValueType>
bool Distribution<ValueType>::less(Distribution<ValueType> const& other, storm::utility::ConstantsComparator<ValueType> const& comparator) const {
template<typename ValueType, typename StateType>
bool Distribution<ValueType, StateType>::less(Distribution<ValueType, StateType> const& other, storm::utility::ConstantsComparator<ValueType> const& comparator) const {
if (this->size() != other.size()) {
return this->size() < other.size();
}

36
src/storage/Distribution.h

@ -17,10 +17,10 @@ namespace storm {
namespace storage {
template<typename ValueType>
template<typename ValueType, typename StateType = uint32_t>
class Distribution {
public:
typedef boost::container::flat_map<storm::storage::sparse::state_type, ValueType> container_type;
typedef boost::container::flat_map<StateType, ValueType> container_type;
typedef typename container_type::iterator iterator;
typedef typename container_type::const_iterator const_iterator;
@ -43,7 +43,7 @@ namespace storm {
* @param other The distribution with which the current distribution is to be compared.
* @return True iff the two distributions are equal.
*/
bool equals(Distribution<ValueType> const& other, storm::utility::ConstantsComparator<ValueType> const& comparator = storm::utility::ConstantsComparator<ValueType>()) const;
bool equals(Distribution<ValueType, StateType> const& other, storm::utility::ConstantsComparator<ValueType> const& comparator = storm::utility::ConstantsComparator<ValueType>()) const;
/*!
* Assigns the given state the given probability under this distribution.
@ -51,7 +51,7 @@ namespace storm {
* @param state The state to which to assign the probability.
* @param probability The probability to assign.
*/
void addProbability(storm::storage::sparse::state_type const& state, ValueType const& probability);
void addProbability(StateType const& state, ValueType const& probability);
/*!
* Removes the given probability mass of going to the given state.
@ -61,7 +61,7 @@ namespace storm {
* @param comparator A comparator that is used to determine if the remaining probability is zero. If so, the
* entry is removed.
*/
void removeProbability(storm::storage::sparse::state_type const& state, ValueType const& probability, storm::utility::ConstantsComparator<ValueType> const& comparator = storm::utility::ConstantsComparator<ValueType>());
void removeProbability(StateType const& state, ValueType const& probability, storm::utility::ConstantsComparator<ValueType> const& comparator = storm::utility::ConstantsComparator<ValueType>());
/*!
* Removes the probability mass from one state and adds it to another.
@ -72,8 +72,8 @@ namespace storm {
* @param comparator A comparator that is used to determine if the remaining probability is zero. If so, the
* entry is removed.
*/
void shiftProbability(storm::storage::sparse::state_type const& fromState, storm::storage::sparse::state_type const& toState, ValueType const& probability, storm::utility::ConstantsComparator<ValueType> const& comparator = storm::utility::ConstantsComparator<ValueType>());
void shiftProbability(StateType const& fromState, StateType const& toState, ValueType const& probability, storm::utility::ConstantsComparator<ValueType> const& comparator = storm::utility::ConstantsComparator<ValueType>());
/*!
* Retrieves an iterator to the elements in this distribution.
*
@ -88,6 +88,13 @@ namespace storm {
*/
const_iterator begin() const;
/*!
* Retrieves an iterator to the elements in this distribution.
*
* @return The iterator to the elements in this distribution.
*/
const_iterator cbegin() const;
/*!
* Retrieves an iterator past the elements in this distribution.
*
@ -102,6 +109,13 @@ namespace storm {
*/
const_iterator end() const;
/*!
* Retrieves an iterator past the elements in this distribution.
*
* @return The iterator past the elements in this distribution.
*/
const_iterator cend() const;
/*!
* Scales the distribution by multiplying all the probabilities with 1/p where p is the probability of moving
* to the given state and sets the probability of moving to the given state to zero. If the probability is
@ -109,22 +123,22 @@ namespace storm {
*
* @param state The state whose associated probability is used to scale the distribution.
*/
void scale(storm::storage::sparse::state_type const& state);
void scale(StateType const& state);
/*!
* Retrieves the size of the distribution, i.e. the size of the support set.
*/
std::size_t size() const;
bool less(Distribution<ValueType> const& other, storm::utility::ConstantsComparator<ValueType> const& comparator) const;
bool less(Distribution<ValueType, StateType> const& other, storm::utility::ConstantsComparator<ValueType> const& comparator) const;
private:
// A list of states and the probabilities that are assigned to them.
container_type distribution;
};
template<typename ValueType>
std::ostream& operator<<(std::ostream& out, Distribution<ValueType> const& distribution);
template<typename ValueType, typename StateType = uint32_t>
std::ostream& operator<<(std::ostream& out, Distribution<ValueType, StateType> const& distribution);
}
}

279
src/storage/SparseMatrix.cpp

@ -80,20 +80,23 @@ namespace storm {
if (initialEntryCountSet) {
columnsAndValues.reserve(initialEntryCount);
}
if (initialRowGroupCountSet) {
rowGroupIndices.reserve(initialRowGroupCount + 1);
if (hasCustomRowGrouping) {
rowGroupIndices = std::vector<index_type>();
}
if (initialRowGroupCountSet && hasCustomRowGrouping) {
rowGroupIndices.get().reserve(initialRowGroupCount + 1);
}
rowIndications.push_back(0);
}
template<typename ValueType>
SparseMatrixBuilder<ValueType>::SparseMatrixBuilder(SparseMatrix<ValueType>&& matrix) : initialRowCountSet(false), initialRowCount(0), initialColumnCountSet(false), initialColumnCount(0), initialEntryCountSet(false), initialEntryCount(0), forceInitialDimensions(false), hasCustomRowGrouping(matrix.nontrivialRowGrouping), initialRowGroupCountSet(false), initialRowGroupCount(0), rowGroupIndices(), columnsAndValues(std::move(matrix.columnsAndValues)), rowIndications(std::move(matrix.rowIndications)), currentEntryCount(matrix.entryCount), lastRow(matrix.rowCount - 1), lastColumn(columnsAndValues.back().getColumn()), highestColumn(matrix.getColumnCount() - 1), currentRowGroup() {
SparseMatrixBuilder<ValueType>::SparseMatrixBuilder(SparseMatrix<ValueType>&& matrix) : initialRowCountSet(false), initialRowCount(0), initialColumnCountSet(false), initialColumnCount(0), initialEntryCountSet(false), initialEntryCount(0), forceInitialDimensions(false), hasCustomRowGrouping(!matrix.trivialRowGrouping), initialRowGroupCountSet(false), initialRowGroupCount(0), rowGroupIndices(), columnsAndValues(std::move(matrix.columnsAndValues)), rowIndications(std::move(matrix.rowIndications)), currentEntryCount(matrix.entryCount), lastRow(matrix.rowCount - 1), lastColumn(columnsAndValues.back().getColumn()), highestColumn(matrix.getColumnCount() - 1), currentRowGroup() {
// If the matrix has a custom row grouping, we move it and remove the last element to make it 'open' again.
if (hasCustomRowGrouping) {
rowGroupIndices = std::move(matrix.rowGroupIndices);
rowGroupIndices.pop_back();
currentRowGroup = rowGroupIndices.size() - 1;
rowGroupIndices.get().pop_back();
currentRowGroup = rowGroupIndices.get().size() - 1;
}
// Likewise, we need to 'open' the row indications again.
@ -141,14 +144,14 @@ namespace storm {
void SparseMatrixBuilder<ValueType>::newRowGroup(index_type startingRow) {
STORM_LOG_THROW(hasCustomRowGrouping, storm::exceptions::InvalidStateException, "Matrix was not created to have a custom row grouping.");
STORM_LOG_THROW(startingRow >= lastRow, storm::exceptions::InvalidStateException, "Illegal row group with negative size.");
rowGroupIndices.push_back(startingRow);
rowGroupIndices.get().push_back(startingRow);
++currentRowGroup;
// Close all rows from the most recent one to the starting row.
for (index_type i = lastRow + 1; i <= startingRow; ++i) {
rowIndications.push_back(currentEntryCount);
}
// Reset the most recently seen row/column to allow for proper insertion of the following elements.
lastRow = startingRow;
lastColumn = 0;
@ -162,7 +165,7 @@ namespace storm {
rowCount = std::max(rowCount, initialRowCount);
}
rowCount = std::max(rowCount, overriddenRowCount);
// If the current row count was overridden, we may need to add empty rows.
for (index_type i = lastRow + 1; i < rowCount; ++i) {
rowIndications.push_back(currentEntryCount);
@ -186,11 +189,7 @@ namespace storm {
}
// Check whether row groups are missing some entries.
if (!hasCustomRowGrouping) {
for (index_type i = 0; i <= rowCount; ++i) {
rowGroupIndices.push_back(i);
}
} else {
if (hasCustomRowGrouping) {
uint_fast64_t rowGroupCount = currentRowGroup;
if (initialRowGroupCountSet && forceInitialDimensions) {
STORM_LOG_THROW(rowGroupCount <= initialRowGroupCount, storm::exceptions::InvalidStateException, "Expected not more than " << initialRowGroupCount << " row groups, but got " << rowGroupCount << ".");
@ -199,11 +198,11 @@ namespace storm {
rowGroupCount = std::max(rowGroupCount, overriddenRowGroupCount);
for (index_type i = currentRowGroup; i <= rowGroupCount; ++i) {
rowGroupIndices.push_back(rowCount);
rowGroupIndices.get().push_back(rowCount);
}
}
return SparseMatrix<ValueType>(columnCount, std::move(rowIndications), std::move(columnsAndValues), std::move(rowGroupIndices), hasCustomRowGrouping);
return SparseMatrix<ValueType>(columnCount, std::move(rowIndications), std::move(columnsAndValues), std::move(rowGroupIndices));
}
template<typename ValueType>
@ -216,6 +215,44 @@ namespace storm {
return lastColumn;
}
template<typename ValueType>
bool SparseMatrixBuilder<ValueType>::replaceColumns(std::vector<index_type> const& replacements, index_type offset) {
bool matrixChanged = false;
// Walk through all rows.
for (index_type row = 0; row < rowIndications.size(); ++row) {
bool rowChanged = false;
index_type rowEnd = row < rowIndications.size()-1 ? rowIndications[row+1] : columnsAndValues.size();
for (auto it = columnsAndValues.begin() + rowIndications[row], ite = columnsAndValues.begin() + rowEnd; it != ite; ++it) {
if (it->getColumn() >= offset && it->getColumn() != replacements[it->getColumn() - offset]) {
it->setColumn(replacements[it->getColumn() - offset]);
rowChanged = true;
}
// Update highest column in a way that only works if the highest appearing index does not become
// lower during performing the replacement.
highestColumn = std::max(highestColumn, it->getColumn());
}
if (rowChanged) {
matrixChanged = true;
// Sort the row.
std::sort(columnsAndValues.begin() + rowIndications[row], columnsAndValues.begin() + rowEnd,
[](MatrixEntry<index_type, value_type> const& a, MatrixEntry<index_type, value_type> const& b) {
return a.getColumn() < b.getColumn();
});
// Assert no equal elements
STORM_LOG_ASSERT(std::is_sorted(columnsAndValues.begin() + rowIndications[row], columnsAndValues.begin() + rowEnd,
[](MatrixEntry<index_type, value_type> const& a, MatrixEntry<index_type, value_type> const& b) {
return a.getColumn() <= b.getColumn();
}), "Must not have different elements with the same column in a row.");
}
}
return matrixChanged;
}
template<typename ValueType>
SparseMatrix<ValueType>::rows::rows(iterator begin, index_type entryCount) : beginIterator(begin), entryCount(entryCount) {
// Intentionally left empty.
@ -257,12 +294,12 @@ namespace storm {
}
template<typename ValueType>
SparseMatrix<ValueType>::SparseMatrix() : rowCount(0), columnCount(0), entryCount(0), nonzeroEntryCount(0), columnsAndValues(), rowIndications(), nontrivialRowGrouping(false), rowGroupIndices() {
SparseMatrix<ValueType>::SparseMatrix() : rowCount(0), columnCount(0), entryCount(0), nonzeroEntryCount(0), columnsAndValues(), rowIndications(), rowGroupIndices() {
// Intentionally left empty.
}
template<typename ValueType>
SparseMatrix<ValueType>::SparseMatrix(SparseMatrix<ValueType> const& other) : rowCount(other.rowCount), columnCount(other.columnCount), entryCount(other.entryCount), nonzeroEntryCount(other.nonzeroEntryCount), columnsAndValues(other.columnsAndValues), rowIndications(other.rowIndications), nontrivialRowGrouping(other.nontrivialRowGrouping), rowGroupIndices(other.rowGroupIndices) {
SparseMatrix<ValueType>::SparseMatrix(SparseMatrix<ValueType> const& other) : rowCount(other.rowCount), columnCount(other.columnCount), entryCount(other.entryCount), nonzeroEntryCount(other.nonzeroEntryCount), columnsAndValues(other.columnsAndValues), rowIndications(other.rowIndications), trivialRowGrouping(other.trivialRowGrouping), rowGroupIndices(other.rowGroupIndices) {
// Intentionally left empty.
}
@ -274,7 +311,7 @@ namespace storm {
}
template<typename ValueType>
SparseMatrix<ValueType>::SparseMatrix(SparseMatrix<ValueType>&& other) : rowCount(other.rowCount), columnCount(other.columnCount), entryCount(other.entryCount), nonzeroEntryCount(other.nonzeroEntryCount), columnsAndValues(std::move(other.columnsAndValues)), rowIndications(std::move(other.rowIndications)), nontrivialRowGrouping(other.nontrivialRowGrouping), rowGroupIndices(std::move(other.rowGroupIndices)) {
SparseMatrix<ValueType>::SparseMatrix(SparseMatrix<ValueType>&& other) : rowCount(other.rowCount), columnCount(other.columnCount), entryCount(other.entryCount), nonzeroEntryCount(other.nonzeroEntryCount), columnsAndValues(std::move(other.columnsAndValues)), rowIndications(std::move(other.rowIndications)), trivialRowGrouping(other.trivialRowGrouping), rowGroupIndices(std::move(other.rowGroupIndices)) {
// Now update the source matrix
other.rowCount = 0;
other.columnCount = 0;
@ -282,12 +319,12 @@ namespace storm {
}
template<typename ValueType>
SparseMatrix<ValueType>::SparseMatrix(index_type columnCount, std::vector<index_type> const& rowIndications, std::vector<MatrixEntry<index_type, ValueType>> const& columnsAndValues, std::vector<index_type> const& rowGroupIndices, bool nontrivialRowGrouping) : rowCount(rowIndications.size() - 1), columnCount(columnCount), entryCount(columnsAndValues.size()), nonzeroEntryCount(0), columnsAndValues(columnsAndValues), rowIndications(rowIndications), nontrivialRowGrouping(nontrivialRowGrouping), rowGroupIndices(rowGroupIndices) {
SparseMatrix<ValueType>::SparseMatrix(index_type columnCount, std::vector<index_type> const& rowIndications, std::vector<MatrixEntry<index_type, ValueType>> const& columnsAndValues, boost::optional<std::vector<index_type>> const& rowGroupIndices) : rowCount(rowIndications.size() - 1), columnCount(columnCount), entryCount(columnsAndValues.size()), nonzeroEntryCount(0), columnsAndValues(columnsAndValues), rowIndications(rowIndications), trivialRowGrouping(!rowGroupIndices), rowGroupIndices(rowGroupIndices) {
this->updateNonzeroEntryCount();
}
template<typename ValueType>
SparseMatrix<ValueType>::SparseMatrix(index_type columnCount, std::vector<index_type>&& rowIndications, std::vector<MatrixEntry<index_type, ValueType>>&& columnsAndValues, std::vector<index_type>&& rowGroupIndices, bool nontrivialRowGrouping) : rowCount(rowIndications.size() - 1), columnCount(columnCount), entryCount(columnsAndValues.size()), nonzeroEntryCount(0), columnsAndValues(std::move(columnsAndValues)), rowIndications(std::move(rowIndications)), nontrivialRowGrouping(nontrivialRowGrouping), rowGroupIndices(std::move(rowGroupIndices)) {
SparseMatrix<ValueType>::SparseMatrix(index_type columnCount, std::vector<index_type>&& rowIndications, std::vector<MatrixEntry<index_type, ValueType>>&& columnsAndValues, boost::optional<std::vector<index_type>>&& rowGroupIndices) : rowCount(rowIndications.size() - 1), columnCount(columnCount), entryCount(columnsAndValues.size()), nonzeroEntryCount(0), columnsAndValues(std::move(columnsAndValues)), rowIndications(std::move(rowIndications)), trivialRowGrouping(!rowGroupIndices), rowGroupIndices(std::move(rowGroupIndices)) {
this->updateNonzeroEntryCount();
}
@ -303,7 +340,7 @@ namespace storm {
columnsAndValues = other.columnsAndValues;
rowIndications = other.rowIndications;
rowGroupIndices = other.rowGroupIndices;
nontrivialRowGrouping = other.nontrivialRowGrouping;
trivialRowGrouping = other.trivialRowGrouping;
}
return *this;
@ -321,7 +358,7 @@ namespace storm {
columnsAndValues = std::move(other.columnsAndValues);
rowIndications = std::move(other.rowIndications);
rowGroupIndices = std::move(other.rowGroupIndices);
nontrivialRowGrouping = other.nontrivialRowGrouping;
trivialRowGrouping = other.trivialRowGrouping;
}
return *this;
@ -343,7 +380,11 @@ namespace storm {
if (!equalityResult) {
return false;
}
equalityResult &= this->getRowGroupIndices() == other.getRowGroupIndices();
if (!this->hasTrivialRowGrouping() && !other.hasTrivialRowGrouping()) {
equalityResult &= this->getRowGroupIndices() == other.getRowGroupIndices();
} else {
equalityResult &= this->hasTrivialRowGrouping() && other.hasTrivialRowGrouping();
}
if (!equalityResult) {
return false;
}
@ -395,8 +436,12 @@ namespace storm {
template<typename T>
uint_fast64_t SparseMatrix<T>::getRowGroupEntryCount(uint_fast64_t const group) const {
uint_fast64_t result = 0;
for (uint_fast64_t row = this->getRowGroupIndices()[group]; row < this->getRowGroupIndices()[group + 1]; ++row) {
result += (this->rowIndications[row + 1] - this->rowIndications[row]);
if (!this->hasTrivialRowGrouping()) {
for (uint_fast64_t row = this->getRowGroupIndices()[group]; row < this->getRowGroupIndices()[group + 1]; ++row) {
result += (this->rowIndications[row + 1] - this->rowIndications[row]);
}
} else {
result += (this->rowIndications[group + 1] - this->rowIndications[group]);
}
return result;
}
@ -435,7 +480,11 @@ namespace storm {
template<typename ValueType>
typename SparseMatrix<ValueType>::index_type SparseMatrix<ValueType>::getRowGroupCount() const {
return rowGroupIndices.size() - 1;
if (!this->hasTrivialRowGrouping()) {
return rowGroupIndices.get().size() - 1;
} else {
return rowCount;
}
}
template<typename ValueType>
@ -445,7 +494,15 @@ namespace storm {
template<typename ValueType>
std::vector<typename SparseMatrix<ValueType>::index_type> const& SparseMatrix<ValueType>::getRowGroupIndices() const {
return rowGroupIndices;
// If there is no current row grouping, we need to create it.
if (!this->rowGroupIndices) {
STORM_LOG_ASSERT(trivialRowGrouping, "Only trivial row-groupings can be constructed on-the-fly.");
this->rowGroupIndices = std::vector<index_type>(this->getRowCount() + 1);
for (uint_fast64_t group = 0; group <= this->getRowCount(); ++group) {
this->rowGroupIndices.get()[group] = group;
}
}
return rowGroupIndices.get();
}
template<typename ValueType>
@ -457,9 +514,15 @@ namespace storm {
template<typename ValueType>
void SparseMatrix<ValueType>::makeRowGroupsAbsorbing(storm::storage::BitVector const& rowGroupConstraint) {
for (auto rowGroup : rowGroupConstraint) {
for (index_type row = this->getRowGroupIndices()[rowGroup]; row < this->getRowGroupIndices()[rowGroup + 1]; ++row) {
makeRowDirac(row, rowGroup);
if (!this->hasTrivialRowGrouping()) {
for (auto rowGroup : rowGroupConstraint) {
for (index_type row = this->getRowGroupIndices()[rowGroup]; row < this->getRowGroupIndices()[rowGroup + 1]; ++row) {
makeRowDirac(row, rowGroup);
}
}
} else {
for (auto rowGroup : rowGroupConstraint) {
makeRowDirac(rowGroup, rowGroup);
}
}
}
@ -512,9 +575,15 @@ namespace storm {
std::vector<ValueType> SparseMatrix<ValueType>::getConstrainedRowGroupSumVector(storm::storage::BitVector const& rowGroupConstraint, storm::storage::BitVector const& columnConstraint) const {
std::vector<ValueType> result;
result.reserve(rowGroupConstraint.getNumberOfSetBits());
for (auto rowGroup : rowGroupConstraint) {
for (index_type row = this->getRowGroupIndices()[rowGroup]; row < this->getRowGroupIndices()[rowGroup + 1]; ++row) {
result.push_back(getConstrainedRowSum(row, columnConstraint));
if (!this->hasTrivialRowGrouping()) {
for (auto rowGroup : rowGroupConstraint) {
for (index_type row = this->getRowGroupIndices()[rowGroup]; row < this->getRowGroupIndices()[rowGroup + 1]; ++row) {
result.push_back(getConstrainedRowSum(row, columnConstraint));
}
}
} else {
for (auto rowGroup : rowGroupConstraint) {
result.push_back(getConstrainedRowSum(rowGroup, columnConstraint));
}
}
return result;
@ -532,25 +601,30 @@ namespace storm {
*it = i;
}
auto res = getSubmatrix(rowConstraint, columnConstraint, fakeRowGroupIndices, insertDiagonalElements);
// Create a new row grouping that reflects the new sizes of the row groups.
std::vector<uint_fast64_t> newRowGroupIndices;
newRowGroupIndices.push_back(0);
auto selectedRowIt = rowConstraint.begin();
// For this, we need to count how many rows were preserved in every group.
for (uint_fast64_t group = 0; group < this->getRowGroupCount(); ++group) {
uint_fast64_t newRowCount = 0;
while (*selectedRowIt < this->getRowGroupIndices()[group + 1]) {
++selectedRowIt;
++newRowCount;
}
if (newRowCount > 0) {
newRowGroupIndices.push_back(newRowGroupIndices.back() + newRowCount);
// Create a new row grouping that reflects the new sizes of the row groups if the current matrix has a
// non trivial row-grouping.
if (!this->hasTrivialRowGrouping()) {
std::vector<uint_fast64_t> newRowGroupIndices;
newRowGroupIndices.push_back(0);
auto selectedRowIt = rowConstraint.begin();
// For this, we need to count how many rows were preserved in every group.
for (uint_fast64_t group = 0; group < this->getRowGroupCount(); ++group) {
uint_fast64_t newRowCount = 0;
while (*selectedRowIt < this->getRowGroupIndices()[group + 1]) {
++selectedRowIt;
++newRowCount;
}
if (newRowCount > 0) {
newRowGroupIndices.push_back(newRowGroupIndices.back() + newRowCount);
}
}
res.trivialRowGrouping = false;
res.rowGroupIndices = newRowGroupIndices;
}
res.rowGroupIndices = newRowGroupIndices;
return res;
}
}
@ -597,13 +671,13 @@ namespace storm {
}
// Create and initialize resulting matrix.
SparseMatrixBuilder<ValueType> matrixBuilder(subRows, submatrixColumnCount, subEntries, true, this->hasNontrivialRowGrouping());
SparseMatrixBuilder<ValueType> matrixBuilder(subRows, submatrixColumnCount, subEntries, true, !this->hasTrivialRowGrouping());
// Copy over selected entries.
rowGroupCount = 0;
index_type rowCount = 0;
for (auto index : rowGroupConstraint) {
if (this->hasNontrivialRowGrouping()) {
if (!this->hasTrivialRowGrouping()) {
matrixBuilder.newRowGroup(rowCount);
}
for (index_type i = rowGroupIndices[index]; i < rowGroupIndices[index + 1]; ++i) {
@ -639,12 +713,12 @@ namespace storm {
template<typename ValueType>
SparseMatrix<ValueType> SparseMatrix<ValueType>::restrictRows(storm::storage::BitVector const& rowsToKeep) const {
// For now, we use the expensive call to submatrix.
assert(rowsToKeep.size() == getRowCount());
assert(rowsToKeep.getNumberOfSetBits() >= getRowGroupCount());
STORM_LOG_ASSERT(rowsToKeep.size() == this->getRowCount(), "Dimensions mismatch.");
STORM_LOG_ASSERT(rowsToKeep.getNumberOfSetBits() >= this->getRowGroupCount(), "Invalid dimensions.");
SparseMatrix<ValueType> res(getSubmatrix(false, rowsToKeep, storm::storage::BitVector(getColumnCount(), true), false));
assert(res.getRowCount() == rowsToKeep.getNumberOfSetBits());
assert(res.getColumnCount() == getColumnCount());
assert(getRowGroupCount() == res.getRowGroupCount());
STORM_LOG_ASSERT(res.getRowCount() == rowsToKeep.getNumberOfSetBits(), "Invalid dimensions");
STORM_LOG_ASSERT(res.getColumnCount() == this->getColumnCount(), "Invalid dimensions");
STORM_LOG_ASSERT(this->getRowGroupCount() == res.getRowGroupCount(), "Invalid dimensions");
return res;
}
@ -655,7 +729,7 @@ namespace storm {
index_type subEntries = 0;
for (index_type rowGroupIndex = 0, rowGroupIndexEnd = rowGroupToRowIndexMapping.size(); rowGroupIndex < rowGroupIndexEnd; ++rowGroupIndex) {
// Determine which row we need to select from the current row group.
index_type rowToCopy = rowGroupIndices[rowGroupIndex] + rowGroupToRowIndexMapping[rowGroupIndex];
index_type rowToCopy = this->getRowGroupIndices()[rowGroupIndex] + rowGroupToRowIndexMapping[rowGroupIndex];
// Iterate through that row and count the number of slots we have to reserve for copying.
bool foundDiagonalElement = false;
@ -671,12 +745,12 @@ namespace storm {
}
// Now create the matrix to be returned with the appropriate size.
SparseMatrixBuilder<ValueType> matrixBuilder(rowGroupIndices.size() - 1, columnCount, subEntries);
SparseMatrixBuilder<ValueType> matrixBuilder(rowGroupIndices.get().size() - 1, columnCount, subEntries);
// Copy over the selected lines from the source matrix.
for (index_type rowGroupIndex = 0, rowGroupIndexEnd = rowGroupToRowIndexMapping.size(); rowGroupIndex < rowGroupIndexEnd; ++rowGroupIndex) {
// Determine which row we need to select from the current row group.
index_type rowToCopy = rowGroupIndices[rowGroupIndex] + rowGroupToRowIndexMapping[rowGroupIndex];
index_type rowToCopy = this->getRowGroupIndices()[rowGroupIndex] + rowGroupToRowIndexMapping[rowGroupIndex];
// Iterate through that row and copy the entries. This also inserts a zero element on the diagonal if
// there is no entry yet.
@ -743,12 +817,7 @@ namespace storm {
}
}
std::vector<index_type> rowGroupIndices(rowCount + 1);
for (index_type i = 0; i <= rowCount; ++i) {
rowGroupIndices[i] = i;
}
storm::storage::SparseMatrix<ValueType> transposedMatrix(columnCount, std::move(rowIndications), std::move(columnsAndValues), std::move(rowGroupIndices), false);
storm::storage::SparseMatrix<ValueType> transposedMatrix(columnCount, std::move(rowIndications), std::move(columnsAndValues), boost::none);
return transposedMatrix;
}
@ -998,50 +1067,66 @@ namespace storm {
template<typename ValueType>
typename SparseMatrix<ValueType>::const_rows SparseMatrix<ValueType>::getRows(index_type startRow, index_type endRow) const {
return const_rows(this->columnsAndValues.begin() + this->rowIndications[startRow], this->rowIndications[endRow + 1] - this->rowIndications[startRow]);
return const_rows(this->columnsAndValues.begin() + this->rowIndications[startRow], this->rowIndications[endRow] - this->rowIndications[startRow]);
}
template<typename ValueType>
typename SparseMatrix<ValueType>::rows SparseMatrix<ValueType>::getRows(index_type startRow, index_type endRow) {
return rows(this->columnsAndValues.begin() + this->rowIndications[startRow], this->rowIndications[endRow + 1] - this->rowIndications[startRow]);
return rows(this->columnsAndValues.begin() + this->rowIndications[startRow], this->rowIndications[endRow] - this->rowIndications[startRow]);
}
template<typename ValueType>
typename SparseMatrix<ValueType>::const_rows SparseMatrix<ValueType>::getRow(index_type row) const {
return getRows(row, row);
return getRows(row, row + 1);
}
template<typename ValueType>
typename SparseMatrix<ValueType>::rows SparseMatrix<ValueType>::getRow(index_type row) {
return getRows(row, row);
return getRows(row, row + 1);
}
template<typename ValueType>
typename SparseMatrix<ValueType>::const_rows SparseMatrix<ValueType>::getRow(index_type rowGroup, index_type offset) const {
assert(rowGroup < this->getRowGroupCount());
assert(offset < this->getRowGroupEntryCount(rowGroup));
return getRow(rowGroupIndices[rowGroup] + offset);
STORM_LOG_ASSERT(rowGroup < this->getRowGroupCount(), "Row group is out-of-bounds.");
STORM_LOG_ASSERT(offset < this->getRowGroupEntryCount(rowGroup), "Row offset in row-group is out-of-bounds.");
if (!this->hasTrivialRowGrouping()) {
return getRow(this->getRowGroupIndices()[rowGroup] + offset);
} else {
return getRow(this->getRowGroupIndices()[rowGroup] + offset);
}
}
template<typename ValueType>
typename SparseMatrix<ValueType>::rows SparseMatrix<ValueType>::getRow(index_type rowGroup, index_type offset) {
assert(rowGroup < this->getRowGroupCount());
assert(offset < this->getRowGroupEntryCount(rowGroup));
return getRow(rowGroupIndices[rowGroup] + offset);
STORM_LOG_ASSERT(rowGroup < this->getRowGroupCount(), "Row group is out-of-bounds.");
STORM_LOG_ASSERT(offset < this->getRowGroupEntryCount(rowGroup), "Row offset in row-group is out-of-bounds.");
if (!this->hasTrivialRowGrouping()) {
return getRow(this->getRowGroupIndices()[rowGroup] + offset);
} else {
STORM_LOG_ASSERT(offset == 0, "Invalid offset.");
return getRow(rowGroup + offset);
}
}
template<typename ValueType>
typename SparseMatrix<ValueType>::const_rows SparseMatrix<ValueType>::getRowGroup(index_type rowGroup) const {
assert(rowGroup < this->getRowGroupCount());
return getRows(rowGroupIndices[rowGroup], rowGroupIndices[rowGroup + 1] - 1);
STORM_LOG_ASSERT(rowGroup < this->getRowGroupCount(), "Row group is out-of-bounds.");
if (!this->hasTrivialRowGrouping()) {
return getRows(this->getRowGroupIndices()[rowGroup], this->getRowGroupIndices()[rowGroup + 1]);
} else {
return getRows(rowGroup, rowGroup + 1);
}
}
template<typename ValueType>
typename SparseMatrix<ValueType>::rows SparseMatrix<ValueType>::getRowGroup(index_type rowGroup) {
assert(rowGroup < this->getRowGroupCount());
return getRows(rowGroupIndices[rowGroup], rowGroupIndices[rowGroup + 1] - 1);
STORM_LOG_ASSERT(rowGroup < this->getRowGroupCount(), "Row group is out-of-bounds.");
if (!this->hasTrivialRowGrouping()) {
return getRows(this->getRowGroupIndices()[rowGroup], this->getRowGroupIndices()[rowGroup + 1]);
} else {
return getRows(rowGroup, rowGroup + 1);
}
}
template<typename ValueType>
@ -1075,8 +1160,8 @@ namespace storm {
}
template<typename ValueType>
bool SparseMatrix<ValueType>::hasNontrivialRowGrouping() const {
return nontrivialRowGrouping;
bool SparseMatrix<ValueType>::hasTrivialRowGrouping() const {
return trivialRowGrouping;
}
template<typename ValueType>
@ -1105,6 +1190,9 @@ namespace storm {
// Check for matching sizes.
if (this->getRowCount() != matrix.getRowCount()) return false;
if (this->getColumnCount() != matrix.getColumnCount()) return false;
if (this->hasTrivialRowGrouping() && !matrix.hasTrivialRowGrouping()) return false;
if (!this->hasTrivialRowGrouping() && matrix.hasTrivialRowGrouping()) return false;
if (!this->hasTrivialRowGrouping() && !matrix.hasTrivialRowGrouping() && this->getRowGroupIndices() != matrix.getRowGroupIndices()) return false;
if (this->getRowGroupIndices() != matrix.getRowGroupIndices()) return false;
// Check the subset property for all rows individually.
@ -1136,7 +1224,10 @@ namespace storm {
// Iterate over all row groups.
for (typename SparseMatrix<ValueType>::index_type group = 0; group < matrix.getRowGroupCount(); ++group) {
out << "\t---- group " << group << "/" << (matrix.getRowGroupCount() - 1) << " ---- " << std::endl;
for (typename SparseMatrix<ValueType>::index_type i = matrix.getRowGroupIndices()[group]; i < matrix.getRowGroupIndices()[group + 1]; ++i) {
typename SparseMatrix<ValueType>::index_type start = matrix.hasTrivialRowGrouping() ? group : matrix.getRowGroupIndices()[group];
typename SparseMatrix<ValueType>::index_type end = matrix.hasTrivialRowGrouping() ? group + 1 : matrix.getRowGroupIndices()[group + 1];
for (typename SparseMatrix<ValueType>::index_type i = start; i < end; ++i) {
typename SparseMatrix<ValueType>::index_type nextIndex = matrix.rowIndications[i];
// Print the actual row.
@ -1172,7 +1263,7 @@ namespace storm {
assert(this->getRowGroupSize(group) == 1);
for (typename SparseMatrix<ValueType>::index_type i = this->getRowGroupIndices()[group]; i < this->getRowGroupIndices()[group + 1]; ++i) {
typename SparseMatrix<ValueType>::index_type nextIndex = this->rowIndications[i];
// Print the actual row.
out << i << "\t(";
typename SparseMatrix<ValueType>::index_type currentRealIndex = 0;
@ -1199,7 +1290,9 @@ namespace storm {
boost::hash_combine(result, this->getEntryCount());
boost::hash_combine(result, boost::hash_range(columnsAndValues.begin(), columnsAndValues.end()));
boost::hash_combine(result, boost::hash_range(rowIndications.begin(), rowIndications.end()));
boost::hash_combine(result, boost::hash_range(rowGroupIndices.begin(), rowGroupIndices.end()));
if (!this->hasTrivialRowGrouping()) {
boost::hash_combine(result, boost::hash_range(rowGroupIndices.get().begin(), rowGroupIndices.get().end()));
}
return result;
}
@ -1226,7 +1319,7 @@ namespace storm {
template std::ostream& operator<<(std::ostream& out, SparseMatrix<double> const& matrix);
template std::vector<double> SparseMatrix<double>::getPointwiseProductRowSumVector(storm::storage::SparseMatrix<double> const& otherMatrix) const;
template bool SparseMatrix<double>::isSubmatrixOf(SparseMatrix<double> const& matrix) const;
// float
template class MatrixEntry<typename SparseMatrix<float>::index_type, float>;
template std::ostream& operator<<(std::ostream& out, MatrixEntry<typename SparseMatrix<float>::index_type, float> const& entry);
@ -1235,7 +1328,7 @@ namespace storm {
template std::ostream& operator<<(std::ostream& out, SparseMatrix<float> const& matrix);
template std::vector<float> SparseMatrix<float>::getPointwiseProductRowSumVector(storm::storage::SparseMatrix<float> const& otherMatrix) const;
template bool SparseMatrix<float>::isSubmatrixOf(SparseMatrix<float> const& matrix) const;
// int
template class MatrixEntry<typename SparseMatrix<int>::index_type, int>;
template std::ostream& operator<<(std::ostream& out, MatrixEntry<typename SparseMatrix<int>::index_type, int> const& entry);
@ -1243,7 +1336,7 @@ namespace storm {
template class SparseMatrix<int>;
template std::ostream& operator<<(std::ostream& out, SparseMatrix<int> const& matrix);
template bool SparseMatrix<int>::isSubmatrixOf(SparseMatrix<int> const& matrix) const;
// state_type
template class MatrixEntry<typename SparseMatrix<storm::storage::sparse::state_type>::index_type, storm::storage::sparse::state_type>;
template std::ostream& operator<<(std::ostream& out, MatrixEntry<typename SparseMatrix<storm::storage::sparse::state_type>::index_type, storm::storage::sparse::state_type> const& entry);
@ -1251,7 +1344,7 @@ namespace storm {
template class SparseMatrix<storm::storage::sparse::state_type>;
template std::ostream& operator<<(std::ostream& out, SparseMatrix<storm::storage::sparse::state_type> const& matrix);
template bool SparseMatrix<int>::isSubmatrixOf(SparseMatrix<storm::storage::sparse::state_type> const& matrix) const;
#ifdef STORM_HAVE_CARL
// Rat Function
template class MatrixEntry<typename SparseMatrix<RationalFunction>::index_type, RationalFunction>;
@ -1264,7 +1357,7 @@ namespace storm {
template std::vector<storm::RationalFunction> SparseMatrix<float>::getPointwiseProductRowSumVector(storm::storage::SparseMatrix<storm::RationalFunction> const& otherMatrix) const;
template std::vector<storm::RationalFunction> SparseMatrix<int>::getPointwiseProductRowSumVector(storm::storage::SparseMatrix<storm::RationalFunction> const& otherMatrix) const;
template bool SparseMatrix<storm::RationalFunction>::isSubmatrixOf(SparseMatrix<storm::RationalFunction> const& matrix) const;
// Intervals
template std::vector<storm::Interval> SparseMatrix<double>::getPointwiseProductRowSumVector(storm::storage::SparseMatrix<storm::Interval> const& otherMatrix) const;
template class MatrixEntry<typename SparseMatrix<Interval>::index_type, Interval>;
@ -1274,7 +1367,7 @@ namespace storm {
template std::ostream& operator<<(std::ostream& out, SparseMatrix<Interval> const& matrix);
template std::vector<storm::Interval> SparseMatrix<Interval>::getPointwiseProductRowSumVector(storm::storage::SparseMatrix<storm::Interval> const& otherMatrix) const;
template bool SparseMatrix<storm::Interval>::isSubmatrixOf(SparseMatrix<storm::Interval> const& matrix) const;
template bool SparseMatrix<storm::Interval>::isSubmatrixOf(SparseMatrix<double> const& matrix) const;
#endif

61
src/storage/SparseMatrix.h

@ -7,9 +7,11 @@
#include <vector>
#include <iterator>
#include <boost/functional/hash.hpp>
#include <boost/optional.hpp>
#include "src/utility/OsDetection.h"
#include "src/adapters/CarlAdapter.h"
#include <boost/functional/hash.hpp>
// Forward declaration for adapter classes.
namespace storm {
@ -217,6 +219,17 @@ namespace storm {
*/
index_type getLastColumn() const;
/*!
* Replaces all columns with id > offset according to replacements.
* Every state with id offset+i is replaced by the id in replacements[i].
* Afterwards the columns are sorted.
*
* @param replacements Mapping indicating the replacements from offset+i -> value of i.
* @param offset Offset to add to each id in vector index.
* @return True if replacement took place, False if nothing changed.
*/
bool replaceColumns(std::vector<index_type> const& replacements, index_type offset);
private:
// A flag indicating whether a row count was set upon construction.
bool initialRowCountSet;
@ -248,7 +261,8 @@ namespace storm {
// The number of row groups in the matrix.
index_type initialRowGroupCount;
std::vector<index_type> rowGroupIndices;
// The vector that stores the row-group indices (if they are non-trivial).
boost::optional<std::vector<index_type>> rowGroupIndices;
// The storage for the columns and values of all entries in the matrix.
std::vector<MatrixEntry<index_type, value_type>> columnsAndValues;
@ -436,9 +450,8 @@ namespace storm {
* @param rowIndications The row indications vector of the matrix to be constructed.
* @param columnsAndValues The vector containing the columns and values of the entries in the matrix.
* @param rowGroupIndices The vector representing the row groups in the matrix.
* @param hasNontrivialRowGrouping If set to true, this indicates that the row grouping is non-trivial.
*/
SparseMatrix(index_type columnCount, std::vector<index_type> const& rowIndications, std::vector<MatrixEntry<index_type, value_type>> const& columnsAndValues, std::vector<index_type> const& rowGroupIndices, bool hasNontrivialRowGrouping);
SparseMatrix(index_type columnCount, std::vector<index_type> const& rowIndications, std::vector<MatrixEntry<index_type, value_type>> const& columnsAndValues, boost::optional<std::vector<index_type>> const& rowGroupIndices);
/*!
* Constructs a sparse matrix by moving the given contents.
@ -447,9 +460,8 @@ namespace storm {
* @param rowIndications The row indications vector of the matrix to be constructed.
* @param columnsAndValues The vector containing the columns and values of the entries in the matrix.
* @param rowGroupIndices The vector representing the row groups in the matrix.
* @param hasNontrivialRowGrouping If set to true, this indicates that the row grouping is non-trivial.
*/
SparseMatrix(index_type columnCount, std::vector<index_type>&& rowIndications, std::vector<MatrixEntry<index_type, value_type>>&& columnsAndValues, std::vector<index_type>&& rowGroupIndices, bool hasNontrivialRowGrouping);
SparseMatrix(index_type columnCount, std::vector<index_type>&& rowIndications, std::vector<MatrixEntry<index_type, value_type>>&& columnsAndValues, boost::optional<std::vector<index_type>>&& rowGroupIndices);
/*!
* Assigns the contents of the given matrix to the current one by deep-copying its contents.
@ -793,7 +805,7 @@ namespace storm {
* Returns an object representing the consecutive rows given by the parameters.
*
* @param startRow The starting row.
* @param endRow The ending row (which is included in the result).
* @param endRow The ending row (which is *not* included in the result).
* @return An object representing the consecutive rows given by the parameters.
*/
const_rows getRows(index_type startRow, index_type endRow) const;
@ -802,7 +814,7 @@ namespace storm {
* Returns an object representing the consecutive rows given by the parameters.
*
* @param startRow The starting row.
* @param endRow The ending row (which is included in the result).
* @param endRow The ending row (which is *not* included in the result).
* @return An object representing the consecutive rows given by the parameters.
*/
rows getRows(index_type startRow, index_type endRow);
@ -902,27 +914,28 @@ namespace storm {
iterator end();
/*!
* Retrieves whether the matrix has a (possibly) non-trivial row grouping.
* Retrieves whether the matrix has a trivial row grouping.
*
* @return True iff the matrix has a (possibly) non-trivial row grouping.
* @return True iff the matrix has a trivial row grouping.
*/
bool hasNontrivialRowGrouping() const;
bool hasTrivialRowGrouping() const;
/*!
* Returns a copy of the matrix with the chosen internal data type
*/
template<typename NewValueType>
SparseMatrix<NewValueType> toValueType() const {
std::vector<MatrixEntry<SparseMatrix::index_type, NewValueType>> new_columnsAndValues;
std::vector<SparseMatrix::index_type> new_rowIndications(rowIndications);
std::vector<SparseMatrix::index_type> new_rowGroupIndices(rowGroupIndices);
std::vector<MatrixEntry<SparseMatrix::index_type, NewValueType>> newColumnsAndValues;
std::vector<SparseMatrix::index_type> newRowIndications(rowIndications);
boost::optional<std::vector<SparseMatrix::index_type>> newRowGroupIndices(rowGroupIndices);
new_columnsAndValues.resize(columnsAndValues.size());
for (size_t i = 0, size = columnsAndValues.size(); i < size; ++i) {
new_columnsAndValues.at(i) = MatrixEntry<SparseMatrix::index_type, NewValueType>(columnsAndValues.at(i).getColumn(), static_cast<NewValueType>(columnsAndValues.at(i).getValue()));
}
newColumnsAndValues.resize(columnsAndValues.size());
std::transform(columnsAndValues.begin(), columnsAndValues.end(), newColumnsAndValues.begin(),
[] (MatrixEntry<SparseMatrix::index_type, ValueType> const& a) {
return MatrixEntry<SparseMatrix::index_type, NewValueType>(a.getColumn(), static_cast<NewValueType>(a.getValue()));
});
return SparseMatrix<NewValueType>(columnCount, std::move(new_rowIndications), std::move(new_columnsAndValues), std::move(new_rowGroupIndices), nontrivialRowGrouping);
return SparseMatrix<NewValueType>(columnCount, std::move(newRowIndications), std::move(newColumnsAndValues), std::move(newRowGroupIndices));
}
private:
@ -961,12 +974,12 @@ namespace storm {
// entry is not included anymore.
std::vector<index_type> rowIndications;
// A flag that indicates whether the matrix has a non-trivial row-grouping, i.e. (possibly) more than one
// row per row group.
bool nontrivialRowGrouping;
// A flag indicating whether the matrix has a trivial row grouping. Note that this may be true and yet
// there may be row group indices, because they were requested from the outside.
bool trivialRowGrouping;
// A vector indicating the row groups of the matrix.
std::vector<index_type> rowGroupIndices;
// A vector indicating the row groups of the matrix. This needs to be mutible in case we create it on-the-fly.
mutable boost::optional<std::vector<index_type>> rowGroupIndices;
};

6
src/storage/dd/Add.cpp

@ -459,7 +459,7 @@ namespace storm {
rowIndications[0] = 0;
// Construct matrix and return result.
return storm::storage::SparseMatrix<ValueType>(columnOdd.getTotalOffset(), std::move(rowIndications), std::move(columnsAndValues), std::move(trivialRowGroupIndices), false);
return storm::storage::SparseMatrix<ValueType>(columnOdd.getTotalOffset(), std::move(rowIndications), std::move(columnsAndValues), boost::none);
}
template<DdType LibraryType, typename ValueType>
@ -583,7 +583,7 @@ namespace storm {
}
rowIndications[0] = 0;
return storm::storage::SparseMatrix<ValueType>(columnOdd.getTotalOffset(), std::move(rowIndications), std::move(columnsAndValues), std::move(rowGroupIndices), true);
return storm::storage::SparseMatrix<ValueType>(columnOdd.getTotalOffset(), std::move(rowIndications), std::move(columnsAndValues), std::move(rowGroupIndices));
}
template<DdType LibraryType, typename ValueType>
@ -708,7 +708,7 @@ namespace storm {
}
rowIndications[0] = 0;
return std::make_pair(storm::storage::SparseMatrix<ValueType>(columnOdd.getTotalOffset(), std::move(rowIndications), std::move(columnsAndValues), std::move(rowGroupIndices), true), std::move(explicitVector));
return std::make_pair(storm::storage::SparseMatrix<ValueType>(columnOdd.getTotalOffset(), std::move(rowIndications), std::move(columnsAndValues), std::move(rowGroupIndices)), std::move(explicitVector));
}
template<DdType LibraryType, typename ValueType>

8
src/storage/prism/Program.cpp

@ -77,6 +77,14 @@ namespace storm {
return modelType;
}
bool Program::isDiscreteTimeModel() const {
return modelType == ModelType::DTMC || modelType == ModelType::MDP;
}
bool Program::isDeterministicModel() const {
return modelType == ModelType::DTMC || modelType == ModelType::CTMC;
}
bool Program::hasUndefinedConstants() const {
for (auto const& constant : this->getConstants()) {
if (!constant.isDefined()) {

12
src/storage/prism/Program.h

@ -66,6 +66,18 @@ namespace storm {
* @return The type of the model.
*/
ModelType getModelType() const;
/*!
* Retrieves whether the model is a discrete-time model, i.e. a DTMC or an MDP.
*
* @return True iff the model is a discrete-time model.
*/
bool isDiscreteTimeModel() const;
/*!
* Retrieves whether the model is one without nondeterministic choices, i.e. a DTMC or a CTMC.
*/
bool isDeterministicModel() const;
/*!
* Retrieves whether there are undefined constants of any type in the program.

2
src/storage/prism/RewardModel.cpp

@ -84,7 +84,7 @@ namespace storm {
std::ostream& operator<<(std::ostream& stream, RewardModel const& rewardModel) {
stream << "rewards";
if (rewardModel.getName() != "") {
std::cout << " \"" << rewardModel.getName() << "\"";
stream << " \"" << rewardModel.getName() << "\"";
}
stream << std::endl;
for (auto const& reward : rewardModel.getStateRewards()) {

4
src/utility/constants.cpp

@ -204,6 +204,10 @@ namespace storm {
template bool isZero(storm::storage::sparse::state_type const& value);
template bool isConstant(storm::storage::sparse::state_type const& value);
template uint32_t one();
template uint32_t zero();
template uint32_t infinity();
template storm::storage::sparse::state_type one();
template storm::storage::sparse::state_type zero();
template storm::storage::sparse::state_type infinity();

4
src/utility/storm.h

@ -106,8 +106,8 @@ namespace storm {
options.buildCommandLabels = true;
}
storm::builder::ExplicitPrismModelBuilder<ValueType> builder;
result.model = builder.translateProgram(program, options);
storm::builder::ExplicitPrismModelBuilder<ValueType> builder(program, options);
result.model = builder.translate();
translatedProgram = builder.getTranslatedProgram();
} else if (settings.getEngine() == storm::settings::modules::GeneralSettings::Engine::Dd || settings.getEngine() == storm::settings::modules::GeneralSettings::Engine::Hybrid) {
typename storm::builder::DdPrismModelBuilder<LibraryType>::Options options;

32
test/functional/builder/ExplicitPrismModelBuilderTest.cpp

@ -10,27 +10,27 @@
TEST(ExplicitPrismModelBuilderTest, Dtmc) {
storm::prism::Program program = storm::parser::PrismParser::parse(STORM_CPP_TESTS_BASE_PATH "/functional/builder/die.pm");
std::shared_ptr<storm::models::sparse::Model<double>> model = storm::builder::ExplicitPrismModelBuilder<double>().translateProgram(program);
std::shared_ptr<storm::models::sparse::Model<double>> model = storm::builder::ExplicitPrismModelBuilder<double>(program).translate();
EXPECT_EQ(13ul, model->getNumberOfStates());
EXPECT_EQ(20ul, model->getNumberOfTransitions());
program = storm::parser::PrismParser::parse(STORM_CPP_TESTS_BASE_PATH "/functional/builder/brp-16-2.pm");
model = storm::builder::ExplicitPrismModelBuilder<double>().translateProgram(program);
model = storm::builder::ExplicitPrismModelBuilder<double>(program).translate();
EXPECT_EQ(677ul, model->getNumberOfStates());
EXPECT_EQ(867ul, model->getNumberOfTransitions());
program = storm::parser::PrismParser::parse(STORM_CPP_TESTS_BASE_PATH "/functional/builder/crowds-5-5.pm");
model = storm::builder::ExplicitPrismModelBuilder<double>().translateProgram(program);
model = storm::builder::ExplicitPrismModelBuilder<double>(program).translate();
EXPECT_EQ(8607ul, model->getNumberOfStates());
EXPECT_EQ(15113ul, model->getNumberOfTransitions());
program = storm::parser::PrismParser::parse(STORM_CPP_TESTS_BASE_PATH "/functional/builder/leader-3-5.pm");
model = storm::builder::ExplicitPrismModelBuilder<double>().translateProgram(program);
model = storm::builder::ExplicitPrismModelBuilder<double>(program).translate();
EXPECT_EQ(273ul, model->getNumberOfStates());
EXPECT_EQ(397ul, model->getNumberOfTransitions());
program = storm::parser::PrismParser::parse(STORM_CPP_TESTS_BASE_PATH "/functional/builder/nand-5-2.pm");
model = storm::builder::ExplicitPrismModelBuilder<double>().translateProgram(program);
model = storm::builder::ExplicitPrismModelBuilder<double>(program).translate();
EXPECT_EQ(1728ul, model->getNumberOfStates());
EXPECT_EQ(2505ul, model->getNumberOfTransitions());
}
@ -41,27 +41,27 @@ TEST(ExplicitPrismModelBuilderTest, Ctmc) {
storm::prism::Program program = storm::parser::PrismParser::parse(STORM_CPP_TESTS_BASE_PATH "/functional/builder/cluster2.sm");
std::shared_ptr<storm::models::sparse::Model<double>> model = storm::builder::ExplicitPrismModelBuilder<double>().translateProgram(program);
std::shared_ptr<storm::models::sparse::Model<double>> model = storm::builder::ExplicitPrismModelBuilder<double>(program).translate();
EXPECT_EQ(276ul, model->getNumberOfStates());
EXPECT_EQ(1120ul, model->getNumberOfTransitions());
program = storm::parser::PrismParser::parse(STORM_CPP_TESTS_BASE_PATH "/functional/builder/embedded2.sm");
model = storm::builder::ExplicitPrismModelBuilder<double>().translateProgram(program);
model = storm::builder::ExplicitPrismModelBuilder<double>(program).translate();
EXPECT_EQ(3478ul, model->getNumberOfStates());
EXPECT_EQ(14639ul, model->getNumberOfTransitions());
program = storm::parser::PrismParser::parse(STORM_CPP_TESTS_BASE_PATH "/functional/builder/polling2.sm");
model = storm::builder::ExplicitPrismModelBuilder<double>().translateProgram(program);
model = storm::builder::ExplicitPrismModelBuilder<double>(program).translate();
EXPECT_EQ(12ul, model->getNumberOfStates());
EXPECT_EQ(22ul, model->getNumberOfTransitions());
program = storm::parser::PrismParser::parse(STORM_CPP_TESTS_BASE_PATH "/functional/builder/fms2.sm");
model = storm::builder::ExplicitPrismModelBuilder<double>().translateProgram(program);
model = storm::builder::ExplicitPrismModelBuilder<double>(program).translate();
EXPECT_EQ(810ul, model->getNumberOfStates());
EXPECT_EQ(3699ul, model->getNumberOfTransitions());
program = storm::parser::PrismParser::parse(STORM_CPP_TESTS_BASE_PATH "/functional/builder/tandem5.sm");
model = storm::builder::ExplicitPrismModelBuilder<double>().translateProgram(program);
model = storm::builder::ExplicitPrismModelBuilder<double>(program).translate();
EXPECT_EQ(66ul, model->getNumberOfStates());
EXPECT_EQ(189ul, model->getNumberOfTransitions());
}
@ -69,32 +69,32 @@ TEST(ExplicitPrismModelBuilderTest, Ctmc) {
TEST(ExplicitPrismModelBuilderTest, Mdp) {
storm::prism::Program program = storm::parser::PrismParser::parse(STORM_CPP_TESTS_BASE_PATH "/functional/builder/two_dice.nm");
std::shared_ptr<storm::models::sparse::Model<double>> model = storm::builder::ExplicitPrismModelBuilder<double>().translateProgram(program);
std::shared_ptr<storm::models::sparse::Model<double>> model = storm::builder::ExplicitPrismModelBuilder<double>(program).translate();
EXPECT_EQ(169ul, model->getNumberOfStates());
EXPECT_EQ(436ul, model->getNumberOfTransitions());
program = storm::parser::PrismParser::parse(STORM_CPP_TESTS_BASE_PATH "/functional/builder/leader3.nm");
model = storm::builder::ExplicitPrismModelBuilder<double>().translateProgram(program);
model = storm::builder::ExplicitPrismModelBuilder<double>(program).translate();
EXPECT_EQ(364ul, model->getNumberOfStates());
EXPECT_EQ(654ul, model->getNumberOfTransitions());
program = storm::parser::PrismParser::parse(STORM_CPP_TESTS_BASE_PATH "/functional/builder/coin2-2.nm");
model = storm::builder::ExplicitPrismModelBuilder<double>().translateProgram(program);
model = storm::builder::ExplicitPrismModelBuilder<double>(program).translate();
EXPECT_EQ(272ul, model->getNumberOfStates());
EXPECT_EQ(492ul, model->getNumberOfTransitions());
program = storm::parser::PrismParser::parse(STORM_CPP_TESTS_BASE_PATH "/functional/builder/csma2-2.nm");
model = storm::builder::ExplicitPrismModelBuilder<double>().translateProgram(program);
model = storm::builder::ExplicitPrismModelBuilder<double>(program).translate();
EXPECT_EQ(1038ul, model->getNumberOfStates());
EXPECT_EQ(1282ul, model->getNumberOfTransitions());
program = storm::parser::PrismParser::parse(STORM_CPP_TESTS_BASE_PATH "/functional/builder/firewire3-0.5.nm");
model = storm::builder::ExplicitPrismModelBuilder<double>().translateProgram(program);
model = storm::builder::ExplicitPrismModelBuilder<double>(program).translate();
EXPECT_EQ(4093ul, model->getNumberOfStates());
EXPECT_EQ(5585ul, model->getNumberOfTransitions());
program = storm::parser::PrismParser::parse(STORM_CPP_TESTS_BASE_PATH "/functional/builder/wlan0-2-2.nm");
model = storm::builder::ExplicitPrismModelBuilder<double>().translateProgram(program);
model = storm::builder::ExplicitPrismModelBuilder<double>(program).translate();
EXPECT_EQ(37ul, model->getNumberOfStates());
EXPECT_EQ(59ul, model->getNumberOfTransitions());
}

8
test/functional/modelchecker/GmmxxCtmcCslModelCheckerTest.cpp

@ -34,7 +34,7 @@ TEST(GmmxxCtmcCslModelCheckerTest, Cluster) {
#endif
options.buildAllRewardModels = false;
options.rewardModelsToBuild.insert("num_repairs");
std::shared_ptr<storm::models::sparse::Model<double>> model = storm::builder::ExplicitPrismModelBuilder<double>().translateProgram(program, options);
std::shared_ptr<storm::models::sparse::Model<double>> model = storm::builder::ExplicitPrismModelBuilder<double>(program, options).translate();
ASSERT_EQ(storm::models::ModelType::Ctmc, model->getType());
std::shared_ptr<storm::models::sparse::Ctmc<double>> ctmc = model->as<storm::models::sparse::Ctmc<double>>();
uint_fast64_t initialState = *ctmc->getInitialStates().begin();
@ -117,7 +117,7 @@ TEST(GmmxxCtmcCslModelCheckerTest, Embedded) {
#endif
options.buildAllRewardModels = false;
options.rewardModelsToBuild.insert("up");
std::shared_ptr<storm::models::sparse::Model<double>> model = storm::builder::ExplicitPrismModelBuilder<double>().translateProgram(program, options);
std::shared_ptr<storm::models::sparse::Model<double>> model = storm::builder::ExplicitPrismModelBuilder<double>(program, options).translate();
ASSERT_EQ(storm::models::ModelType::Ctmc, model->getType());
std::shared_ptr<storm::models::sparse::Ctmc<double>> ctmc = model->as<storm::models::sparse::Ctmc<double>>();
uint_fast64_t initialState = *ctmc->getInitialStates().begin();
@ -179,7 +179,7 @@ TEST(GmmxxCtmcCslModelCheckerTest, Polling) {
std::shared_ptr<const storm::logic::Formula> formula(nullptr);
// Build the model.
std::shared_ptr<storm::models::sparse::Model<double>> model = storm::builder::ExplicitPrismModelBuilder<double>().translateProgram(program);
std::shared_ptr<storm::models::sparse::Model<double>> model = storm::builder::ExplicitPrismModelBuilder<double>(program).translate();
ASSERT_EQ(storm::models::ModelType::Ctmc, model->getType());
std::shared_ptr<storm::models::sparse::Ctmc<double>> ctmc = model->as<storm::models::sparse::Ctmc<double>>();
uint_fast64_t initialState = *ctmc->getInitialStates().begin();
@ -226,7 +226,7 @@ TEST(GmmxxCtmcCslModelCheckerTest, Tandem) {
typename storm::builder::ExplicitPrismModelBuilder<double>::Options options;
#endif
options.rewardModelsToBuild.insert("customers");
std::shared_ptr<storm::models::sparse::Model<double>> model = storm::builder::ExplicitPrismModelBuilder<double>().translateProgram(program, options);
std::shared_ptr<storm::models::sparse::Model<double>> model = storm::builder::ExplicitPrismModelBuilder<double>(program, options).translate();
ASSERT_EQ(storm::models::ModelType::Ctmc, model->getType());
std::shared_ptr<storm::models::sparse::Ctmc<double>> ctmc = model->as<storm::models::sparse::Ctmc<double>>();
uint_fast64_t initialState = *ctmc->getInitialStates().begin();

2
test/functional/modelchecker/GmmxxDtmcPrctlModelCheckerTest.cpp

@ -284,7 +284,7 @@ TEST(GmmxxDtmcPrctlModelCheckerTest, LRA) {
TEST(GmmxxDtmcPrctlModelCheckerTest, Conditional) {
storm::prism::Program program = storm::parser::PrismParser::parse(STORM_CPP_TESTS_BASE_PATH "/functional/modelchecker/test_conditional.pm");
std::shared_ptr<storm::models::sparse::Model<double>> model = storm::builder::ExplicitPrismModelBuilder<double>().translateProgram(program);
std::shared_ptr<storm::models::sparse::Model<double>> model = storm::builder::ExplicitPrismModelBuilder<double>(program).translate();
ASSERT_TRUE(model->getType() == storm::models::ModelType::Dtmc);
ASSERT_EQ(4ul, model->getNumberOfStates());
ASSERT_EQ(5ul, model->getNumberOfTransitions());

2
test/functional/modelchecker/GmmxxMdpPrctlModelCheckerTest.cpp

@ -197,7 +197,7 @@ TEST(GmmxxMdpPrctlModelCheckerTest, SchedulerGeneration) {
// A parser that we use for conveniently constructing the formulas.
storm::parser::FormulaParser formulaParser;
std::shared_ptr<storm::models::sparse::Model<double>> model = storm::builder::ExplicitPrismModelBuilder<double>().translateProgram(program);
std::shared_ptr<storm::models::sparse::Model<double>> model = storm::builder::ExplicitPrismModelBuilder<double>(program).translate();
EXPECT_EQ(4ul, model->getNumberOfStates());
EXPECT_EQ(11ul, model->getNumberOfTransitions());

8
test/functional/modelchecker/NativeCtmcCslModelCheckerTest.cpp

@ -32,7 +32,7 @@ TEST(NativeCtmcCslModelCheckerTest, Cluster) {
#endif
options.buildAllRewardModels = false;
options.rewardModelsToBuild.insert("num_repairs");
std::shared_ptr<storm::models::sparse::Model<double>> model = storm::builder::ExplicitPrismModelBuilder<double>().translateProgram(program, options);
std::shared_ptr<storm::models::sparse::Model<double>> model = storm::builder::ExplicitPrismModelBuilder<double>(program, options).translate();
ASSERT_EQ(storm::models::ModelType::Ctmc, model->getType());
std::shared_ptr<storm::models::sparse::Ctmc<double>> ctmc = model->as<storm::models::sparse::Ctmc<double>>();
uint_fast64_t initialState = *ctmc->getInitialStates().begin();
@ -108,7 +108,7 @@ TEST(NativeCtmcCslModelCheckerTest, Embedded) {
#endif
options.buildAllRewardModels = false;
options.rewardModelsToBuild.insert("up");
std::shared_ptr<storm::models::sparse::Model<double>> model = storm::builder::ExplicitPrismModelBuilder<double>().translateProgram(program, options);
std::shared_ptr<storm::models::sparse::Model<double>> model = storm::builder::ExplicitPrismModelBuilder<double>(program, options).translate();
ASSERT_EQ(storm::models::ModelType::Ctmc, model->getType());
std::shared_ptr<storm::models::sparse::Ctmc<double>> ctmc = model->as<storm::models::sparse::Ctmc<double>>();
uint_fast64_t initialState = *ctmc->getInitialStates().begin();
@ -163,7 +163,7 @@ TEST(NativeCtmcCslModelCheckerTest, Polling) {
std::shared_ptr<const storm::logic::Formula> formula(nullptr);
// Build the model.
std::shared_ptr<storm::models::sparse::Model<double>> model = storm::builder::ExplicitPrismModelBuilder<double>().translateProgram(program);
std::shared_ptr<storm::models::sparse::Model<double>> model = storm::builder::ExplicitPrismModelBuilder<double>(program).translate();
ASSERT_EQ(storm::models::ModelType::Ctmc, model->getType());
std::shared_ptr<storm::models::sparse::Ctmc<double>> ctmc = model->as<storm::models::sparse::Ctmc<double>>();
uint_fast64_t initialState = *ctmc->getInitialStates().begin();
@ -204,7 +204,7 @@ TEST(NativeCtmcCslModelCheckerTest, Tandem) {
#endif
options.buildAllRewardModels = false;
options.rewardModelsToBuild.insert("customers");
std::shared_ptr<storm::models::sparse::Model<double>> model = storm::builder::ExplicitPrismModelBuilder<double>().translateProgram(program, options);
std::shared_ptr<storm::models::sparse::Model<double>> model = storm::builder::ExplicitPrismModelBuilder<double>(program, options).translate();
ASSERT_EQ(storm::models::ModelType::Ctmc, model->getType());
std::shared_ptr<storm::models::sparse::Ctmc<double>> ctmc = model->as<storm::models::sparse::Ctmc<double>>();
uint_fast64_t initialState = *ctmc->getInitialStates().begin();

2
test/functional/permissiveschedulers/MilpPermissiveSchedulerTest.cpp

@ -28,7 +28,7 @@ TEST(MilpPermissiveSchedulerTest, DieSelection) {
options.addConstantDefinitionsFromString(program, "");
options.buildCommandLabels = true;
std::shared_ptr<storm::models::sparse::Mdp<double>> mdp = storm::builder::ExplicitPrismModelBuilder<double>().translateProgram(program, options)->as<storm::models::sparse::Mdp<double>>();
std::shared_ptr<storm::models::sparse::Mdp<double>> mdp = storm::builder::ExplicitPrismModelBuilder<double>(program, options).translate()->as<storm::models::sparse::Mdp<double>>();
boost::optional<storm::ps::SubMDPPermissiveScheduler<>> perms = storm::ps::computePermissiveSchedulerViaMILP<>(*mdp, formula02);
EXPECT_NE(perms, boost::none);

2
test/functional/permissiveschedulers/SmtPermissiveSchedulerTest.cpp

@ -31,7 +31,7 @@ TEST(SmtPermissiveSchedulerTest, DieSelection) {
options.addConstantDefinitionsFromString(program, "");
options.buildCommandLabels = true;
std::shared_ptr<storm::models::sparse::Mdp<double>> mdp = storm::builder::ExplicitPrismModelBuilder<double>().translateProgram(program, options)->as<storm::models::sparse::Mdp<double>>();
std::shared_ptr<storm::models::sparse::Mdp<double>> mdp = storm::builder::ExplicitPrismModelBuilder<double>(program, options).translate()->as<storm::models::sparse::Mdp<double>>();
// boost::optional<storm::ps::SubMDPPermissiveScheduler<>> perms = storm::ps::computePermissiveSchedulerViaSMT<>(*mdp, formula02);
// EXPECT_NE(perms, boost::none);

18
test/functional/storage/BitVectorHashMapTest.cpp

@ -19,25 +19,41 @@ TEST(BitVectorHashMapTest, FindOrAdd) {
ASSERT_NO_THROW(map.findOrAdd(second, 2));
EXPECT_EQ(1ul, map.findOrAdd(first, 3));
EXPECT_EQ(2ul, map.findOrAdd(second, 3));
storm::storage::BitVector third(64);
third.set(10);
third.set(63);
ASSERT_NO_THROW(map.findOrAdd(third, 3));
EXPECT_EQ(1ul, map.findOrAdd(first, 2));
EXPECT_EQ(2ul, map.findOrAdd(second, 1));
EXPECT_EQ(3ul, map.findOrAdd(third, 1));
storm::storage::BitVector fourth(64);
fourth.set(12);
fourth.set(14);
ASSERT_NO_THROW(map.findOrAdd(fourth, 4));
EXPECT_EQ(1ul, map.findOrAdd(first, 2));
EXPECT_EQ(2ul, map.findOrAdd(second, 1));
EXPECT_EQ(3ul, map.findOrAdd(third, 1));
EXPECT_EQ(4ul, map.findOrAdd(fourth, 1));
storm::storage::BitVector fifth(64);
fifth.set(44);
fifth.set(55);
ASSERT_NO_THROW(map.findOrAdd(fifth, 5));
EXPECT_EQ(1ul, map.findOrAdd(first, 2));
EXPECT_EQ(2ul, map.findOrAdd(second, 1));
EXPECT_EQ(3ul, map.findOrAdd(third, 1));
EXPECT_EQ(4ul, map.findOrAdd(fourth, 1));
EXPECT_EQ(5ul, map.findOrAdd(fifth, 1));
storm::storage::BitVector sixth(64);
sixth.set(45);
sixth.set(55);

18
test/functional/storage/BitVectorTest.cpp

@ -321,24 +321,6 @@ TEST(BitVectorTest, OperatorModulo) {
ASSERT_FALSE(moduloResult.get(i));
}
}
storm::storage::BitVector vector3(31);
for (uint_fast64_t i = 0; i < 15; ++i) {
vector3.set(i, i % 2 == 0);
}
#ifndef NDEBUG
#ifdef WINDOWS
EXPECT_EXIT(vector1 % vector3, ::testing::ExitedWithCode(0), ".*");
#else
EXPECT_DEATH_IF_SUPPORTED(vector1 % vector3, "");
#endif
#else
std::cerr << "WARNING: Not testing OperatorModulo size check, as assertions are disabled in release mode." << std::endl;
SUCCEED();
#endif
}
TEST(BitVectorTest, OperatorNot) {

2
test/functional/storage/NondeterministicModelBisimulationDecompositionTest.cpp

@ -14,7 +14,7 @@ TEST(NondeterministicModelBisimulationDecomposition, TwoDice) {
storm::prism::Program program = storm::parser::PrismParser::parse(STORM_CPP_TESTS_BASE_PATH "/functional/builder/two_dice.nm");
// Build the die model without its reward model.
std::shared_ptr<storm::models::sparse::Model<double>> model = storm::builder::ExplicitPrismModelBuilder<double>().translateProgram(program);
std::shared_ptr<storm::models::sparse::Model<double>> model = storm::builder::ExplicitPrismModelBuilder<double>(program).translate();
ASSERT_EQ(model->getType(), storm::models::ModelType::Mdp);
std::shared_ptr<storm::models::sparse::Mdp<double>> mdp = model->as<storm::models::sparse::Mdp<double>>();

4
test/functional/storage/SparseMatrixTest.cpp

@ -155,8 +155,8 @@ TEST(SparseMatrix, CreationWithMovingContents) {
columnsAndValues.emplace_back(1, 0.7);
columnsAndValues.emplace_back(3, 0.2);
ASSERT_NO_THROW(storm::storage::SparseMatrix<double> matrix(4, {0, 2, 5, 5}, columnsAndValues, {0, 1, 2, 3}, false));
storm::storage::SparseMatrix<double> matrix(4, {0, 2, 5, 5}, columnsAndValues, {0, 1, 2, 3}, false);
ASSERT_NO_THROW(storm::storage::SparseMatrix<double> matrix(4, {0, 2, 5, 5}, columnsAndValues, boost::optional<std::vector<uint_fast64_t>>({0, 1, 2, 3})));
storm::storage::SparseMatrix<double> matrix(4, {0, 2, 5, 5}, columnsAndValues, boost::optional<std::vector<uint_fast64_t>>({0, 1, 2, 3}));
ASSERT_EQ(3ul, matrix.getRowCount());
ASSERT_EQ(4ul, matrix.getColumnCount());
ASSERT_EQ(5ul, matrix.getEntryCount());

8
test/functional/utility/GraphTest.cpp

@ -181,7 +181,7 @@ TEST(GraphTest, SymbolicProb01MinMax_Sylvan) {
TEST(GraphTest, ExplicitProb01) {
storm::prism::Program program = storm::parser::PrismParser::parse(STORM_CPP_TESTS_BASE_PATH "/functional/builder/crowds-5-5.pm");
std::shared_ptr<storm::models::sparse::Model<double>> model = storm::builder::ExplicitPrismModelBuilder<double>().translateProgram(program);
std::shared_ptr<storm::models::sparse::Model<double>> model = storm::builder::ExplicitPrismModelBuilder<double>(program).translate();
ASSERT_TRUE(model->getType() == storm::models::ModelType::Dtmc);
@ -202,7 +202,7 @@ TEST(GraphTest, ExplicitProb01) {
TEST(GraphTest, ExplicitProb01MinMax) {
storm::prism::Program program = storm::parser::PrismParser::parse(STORM_CPP_TESTS_BASE_PATH "/functional/builder/leader3.nm");
std::shared_ptr<storm::models::sparse::Model<double>> model = storm::builder::ExplicitPrismModelBuilder<double>().translateProgram(program);
std::shared_ptr<storm::models::sparse::Model<double>> model = storm::builder::ExplicitPrismModelBuilder<double>(program).translate();
ASSERT_TRUE(model->getType() == storm::models::ModelType::Mdp);
@ -217,7 +217,7 @@ TEST(GraphTest, ExplicitProb01MinMax) {
EXPECT_EQ(364ul, statesWithProbability01.second.getNumberOfSetBits());
program = storm::parser::PrismParser::parse(STORM_CPP_TESTS_BASE_PATH "/functional/builder/coin2-2.nm");
model = storm::builder::ExplicitPrismModelBuilder<double>().translateProgram(program);
model = storm::builder::ExplicitPrismModelBuilder<double>(program).translate();
ASSERT_TRUE(model->getType() == storm::models::ModelType::Mdp);
@ -238,7 +238,7 @@ TEST(GraphTest, ExplicitProb01MinMax) {
EXPECT_EQ(35ul, statesWithProbability01.second.getNumberOfSetBits());
program = storm::parser::PrismParser::parse(STORM_CPP_TESTS_BASE_PATH "/functional/builder/csma2-2.nm");
model = storm::builder::ExplicitPrismModelBuilder<double>().translateProgram(program);
model = storm::builder::ExplicitPrismModelBuilder<double>(program).translate();
ASSERT_TRUE(model->getType() == storm::models::ModelType::Mdp);

29
test/functional/utility/ModelInstantiatorTest.cpp

@ -17,12 +17,12 @@
#include "src/models/sparse/Dtmc.h"
#include "src/models/sparse/Mdp.h"
TEST(ModelInstantiatorTest, Brp_Prob) {
TEST(ModelInstantiatorTest, BrpProb) {
carl::VariablePool::getInstance().clear();
std::string const& programFile = STORM_CPP_TESTS_BASE_PATH "/functional/utility/brp16_2.pm";
std::string const& formulaAsString = "P=? [F s=5 ]";
std::string const& constantsAsString = ""; //e.g. pL=0.9,TOACK=0.5
std::string programFile = STORM_CPP_TESTS_BASE_PATH "/functional/utility/brp16_2.pm";
std::string formulaAsString = "P=? [F s=5 ]";
std::string constantsAsString = ""; //e.g. pL=0.9,TOACK=0.5
// Program and formula
storm::prism::Program program = storm::parseProgram(programFile);
@ -33,7 +33,7 @@ TEST(ModelInstantiatorTest, Brp_Prob) {
typename storm::builder::ExplicitPrismModelBuilder<storm::RationalFunction>::Options options = storm::builder::ExplicitPrismModelBuilder<storm::RationalFunction>::Options(*formulas[0]);
options.addConstantDefinitionsFromString(program, constantsAsString);
options.preserveFormula(*formulas[0]);
std::shared_ptr<storm::models::sparse::Dtmc<storm::RationalFunction>> dtmc = storm::builder::ExplicitPrismModelBuilder<storm::RationalFunction>().translateProgram(program, options)->as<storm::models::sparse::Dtmc<storm::RationalFunction>>();
std::shared_ptr<storm::models::sparse::Dtmc<storm::RationalFunction>> dtmc = storm::builder::ExplicitPrismModelBuilder<storm::RationalFunction>(program, options).translate()->as<storm::models::sparse::Dtmc<storm::RationalFunction>>();
storm::utility::ModelInstantiator<storm::models::sparse::Dtmc<storm::RationalFunction>, storm::models::sparse::Dtmc<double>> modelInstantiator(*dtmc);
EXPECT_FALSE(dtmc->hasRewardModel());
@ -141,9 +141,9 @@ TEST(ModelInstantiatorTest, Brp_Prob) {
TEST(ModelInstantiatorTest, Brp_Rew) {
carl::VariablePool::getInstance().clear();
std::string const& programFile = STORM_CPP_TESTS_BASE_PATH "/functional/utility/brp16_2.pm";
std::string const& formulaAsString = "R=? [F ((s=5) | (s=0&srep=3)) ]";
std::string const& constantsAsString = ""; //e.g. pL=0.9,TOACK=0.5
std::string programFile = STORM_CPP_TESTS_BASE_PATH "/functional/utility/brp16_2.pm";
std::string formulaAsString = "R=? [F ((s=5) | (s=0&srep=3)) ]";
std::string constantsAsString = ""; //e.g. pL=0.9,TOACK=0.5
// Program and formula
storm::prism::Program program = storm::parseProgram(programFile);
@ -154,7 +154,7 @@ TEST(ModelInstantiatorTest, Brp_Rew) {
typename storm::builder::ExplicitPrismModelBuilder<storm::RationalFunction>::Options options = storm::builder::ExplicitPrismModelBuilder<storm::RationalFunction>::Options(*formulas[0]);
options.addConstantDefinitionsFromString(program, constantsAsString);
options.preserveFormula(*formulas[0]);
std::shared_ptr<storm::models::sparse::Dtmc<storm::RationalFunction>> dtmc = storm::builder::ExplicitPrismModelBuilder<storm::RationalFunction>().translateProgram(program, options)->as<storm::models::sparse::Dtmc<storm::RationalFunction>>();
std::shared_ptr<storm::models::sparse::Dtmc<storm::RationalFunction>> dtmc = storm::builder::ExplicitPrismModelBuilder<storm::RationalFunction>(program, options).translate()->as<storm::models::sparse::Dtmc<storm::RationalFunction>>();
storm::utility::ModelInstantiator<storm::models::sparse::Dtmc<storm::RationalFunction>, storm::models::sparse::Dtmc<double>> modelInstantiator(*dtmc);
@ -211,12 +211,12 @@ TEST(ModelInstantiatorTest, Brp_Rew) {
}
TEST(ModelInstantiatorTest, consensus) {
TEST(ModelInstantiatorTest, Consensus) {
carl::VariablePool::getInstance().clear();
std::string const& programFile = STORM_CPP_TESTS_BASE_PATH "/functional/utility/coin2_2.pm";
std::string const& formulaAsString = "Pmin=? [F \"finished\"&\"all_coins_equal_1\" ]";
std::string const& constantsAsString = ""; //e.g. pL=0.9,TOACK=0.5
std::string programFile = STORM_CPP_TESTS_BASE_PATH "/functional/utility/coin2_2.pm";
std::string formulaAsString = "Pmin=? [F \"finished\"&\"all_coins_equal_1\" ]";
std::string constantsAsString = ""; //e.g. pL=0.9,TOACK=0.5
// Program and formula
storm::prism::Program program = storm::parseProgram(programFile);
@ -227,7 +227,7 @@ TEST(ModelInstantiatorTest, consensus) {
typename storm::builder::ExplicitPrismModelBuilder<storm::RationalFunction>::Options options = storm::builder::ExplicitPrismModelBuilder<storm::RationalFunction>::Options(*formulas[0]);
options.addConstantDefinitionsFromString(program, constantsAsString);
options.preserveFormula(*formulas[0]);
std::shared_ptr<storm::models::sparse::Mdp<storm::RationalFunction>> mdp = storm::builder::ExplicitPrismModelBuilder<storm::RationalFunction>().translateProgram(program, options)->as<storm::models::sparse::Mdp<storm::RationalFunction>>();
std::shared_ptr<storm::models::sparse::Mdp<storm::RationalFunction>> mdp = storm::builder::ExplicitPrismModelBuilder<storm::RationalFunction>(program, options).translate()->as<storm::models::sparse::Mdp<storm::RationalFunction>>();
storm::utility::ModelInstantiator<storm::models::sparse::Mdp<storm::RationalFunction>, storm::models::sparse::Mdp<double>> modelInstantiator(*mdp);
@ -260,7 +260,6 @@ TEST(ModelInstantiatorTest, consensus) {
std::unique_ptr<storm::modelchecker::CheckResult> chkResult = modelchecker.check(*formulas[0]);
storm::modelchecker::ExplicitQuantitativeCheckResult<double>& quantitativeChkResult = chkResult->asExplicitQuantitativeCheckResult<double>();
EXPECT_NEAR(0.3526577219, quantitativeChkResult[*instantiated.getInitialStates().begin()], storm::settings::generalSettings().getPrecision());
}
#endif
|||||||
100:0
Loading…
Cancel
Save