Browse Source

Merge branch 'master' into SmtSolvers

Conflicts:
	src/storage/expressions/Expression.cpp

Former-commit-id: 151d48f807
main
David_Korzeniewski 11 years ago
parent
commit
c3a71d5915
  1. 4
      src/adapters/GmmxxAdapter.h
  2. 345
      src/counterexamples/MILPMinimalLabelSetGenerator.h
  3. 144
      src/counterexamples/PathBasedSubsystemGenerator.h
  4. 2
      src/modelchecker/csl/SparseMarkovAutomatonCslModelChecker.cpp
  5. 78
      src/modelchecker/csl/SparseMarkovAutomatonCslModelChecker.h
  6. 6
      src/models/AbstractDeterministicModel.h
  7. 2
      src/models/AbstractModel.h
  8. 4
      src/models/AbstractNondeterministicModel.h
  9. 12
      src/models/Dtmc.h
  10. 12
      src/models/MarkovAutomaton.h
  11. 273
      src/solver/GlpkLpSolver.cpp
  12. 97
      src/solver/GlpkLpSolver.h
  13. 386
      src/solver/GurobiLpSolver.cpp
  14. 94
      src/solver/GurobiLpSolver.h
  15. 170
      src/solver/LpSolver.h
  16. 8
      src/storage/MaximalEndComponentDecomposition.cpp
  17. 158
      src/storage/SparseMatrix.cpp
  18. 100
      src/storage/SparseMatrix.h
  19. 20
      src/storage/StronglyConnectedComponentDecomposition.cpp
  20. 8
      src/storage/dd/CuddDd.cpp
  21. 8
      src/storage/dd/CuddDd.h
  22. 48
      src/storage/dd/CuddDdForwardIterator.cpp
  23. 10
      src/storage/dd/CuddDdForwardIterator.h
  24. 23
      src/storage/dd/CuddDdManager.cpp
  25. 26
      src/storage/dd/CuddDdManager.h
  26. 18
      src/storage/expressions/BaseExpression.cpp
  27. 26
      src/storage/expressions/BaseExpression.h
  28. 10
      src/storage/expressions/BinaryBooleanFunctionExpression.cpp
  29. 1
      src/storage/expressions/BinaryBooleanFunctionExpression.h
  30. 6
      src/storage/expressions/BinaryExpression.cpp
  31. 1
      src/storage/expressions/BinaryExpression.h
  32. 11
      src/storage/expressions/BinaryNumericalFunctionExpression.cpp
  33. 1
      src/storage/expressions/BinaryNumericalFunctionExpression.h
  34. 13
      src/storage/expressions/BinaryRelationExpression.cpp
  35. 1
      src/storage/expressions/BinaryRelationExpression.h
  36. 39
      src/storage/expressions/Expression.cpp
  37. 38
      src/storage/expressions/Expression.h
  38. 15
      src/storage/expressions/ExpressionReturnType.cpp
  39. 17
      src/storage/expressions/ExpressionReturnType.h
  40. 4
      src/storage/expressions/IdentifierSubstitutionVisitor.cpp
  41. 2
      src/storage/expressions/IdentifierSubstitutionVisitor.h
  42. 30
      src/storage/expressions/IfThenElseExpression.cpp
  43. 5
      src/storage/expressions/IfThenElseExpression.h
  44. 151
      src/storage/expressions/LinearCoefficientVisitor.cpp
  45. 46
      src/storage/expressions/LinearCoefficientVisitor.h
  46. 112
      src/storage/expressions/LinearityCheckVisitor.cpp
  47. 45
      src/storage/expressions/LinearityCheckVisitor.h
  48. 33
      src/storage/expressions/OperatorType.h
  49. 184
      src/storage/expressions/SimpleValuation.cpp
  50. 52
      src/storage/expressions/SimpleValuation.h
  51. 4
      src/storage/expressions/SubstitutionVisitor.cpp
  52. 2
      src/storage/expressions/SubstitutionVisitor.h
  53. 4
      src/storage/expressions/TypeCheckVisitor.cpp
  54. 2
      src/storage/expressions/TypeCheckVisitor.h
  55. 6
      src/storage/expressions/UnaryBooleanFunctionExpression.cpp
  56. 1
      src/storage/expressions/UnaryBooleanFunctionExpression.h
  57. 4
      src/storage/expressions/UnaryExpression.cpp
  58. 1
      src/storage/expressions/UnaryExpression.h
  59. 8
      src/storage/expressions/UnaryNumericalFunctionExpression.cpp
  60. 1
      src/storage/expressions/UnaryNumericalFunctionExpression.h
  61. 61
      src/storage/expressions/Valuation.h
  62. 2
      src/storage/prism/Program.cpp
  63. 28
      src/utility/counterexamples.h
  64. 60
      src/utility/graph.h
  65. 2
      src/utility/matrix.h
  66. 6
      test/functional/modelchecker/GmmxxDtmcPrctlModelCheckerTest.cpp
  67. 12
      test/functional/parser/AutoParserTest.cpp
  68. 4
      test/functional/parser/DeterministicModelParserTest.cpp
  69. 168
      test/functional/parser/DeterministicSparseTransitionParserTest.cpp
  70. 48
      test/functional/parser/MarkovAutomatonSparseTransitionParserTest.cpp
  71. 184
      test/functional/parser/NondeterministicSparseTransitionParserTest.cpp
  72. 243
      test/functional/solver/GlpkLpSolverTest.cpp
  73. 240
      test/functional/solver/GurobiLpSolverTest.cpp
  74. 22
      test/functional/storage/CuddDdTest.cpp
  75. 17
      test/functional/storage/ExpressionTest.cpp
  76. 26
      test/functional/storage/SparseMatrixTest.cpp
  77. 4
      test/performance/modelchecker/GmmxxDtmcPrctModelCheckerTest.cpp
  78. 2
      test/performance/storage/SparseMatrixTest.cpp

4
src/adapters/GmmxxAdapter.h

@ -51,8 +51,8 @@ public:
columns.reserve(matrix.getEntryCount()); columns.reserve(matrix.getEntryCount());
for (auto const& entry : matrix) { for (auto const& entry : matrix) {
columns.emplace_back(entry.first); columns.emplace_back(entry.getColumn());
values.emplace_back(entry.second); values.emplace_back(entry.getValue());
} }
std::swap(result->ir, columns); std::swap(result->ir, columns);

345
src/counterexamples/MILPMinimalLabelSetGenerator.h

@ -65,13 +65,13 @@ namespace storm {
* A helper struct capturing information about the variables of the MILP formulation. * A helper struct capturing information about the variables of the MILP formulation.
*/ */
struct VariableInformation { struct VariableInformation {
std::unordered_map<uint_fast64_t, uint_fast64_t> labelToVariableIndexMap; std::unordered_map<uint_fast64_t, std::string> labelToVariableMap;
std::unordered_map<uint_fast64_t, std::list<uint_fast64_t>> stateToChoiceVariablesIndexMap; std::unordered_map<uint_fast64_t, std::list<std::string>> stateToChoiceVariablesMap;
std::unordered_map<uint_fast64_t, uint_fast64_t> initialStateToChoiceVariableIndexMap; std::unordered_map<uint_fast64_t, std::string> initialStateToChoiceVariableMap;
std::unordered_map<uint_fast64_t, uint_fast64_t> stateToProbabilityVariableIndexMap; std::unordered_map<uint_fast64_t, std::string> stateToProbabilityVariableMap;
uint_fast64_t virtualInitialStateVariableIndex; std::string virtualInitialStateVariable;
std::unordered_map<uint_fast64_t, uint_fast64_t> problematicStateToVariableIndexMap; std::unordered_map<uint_fast64_t, std::string> problematicStateToVariableMap;
std::unordered_map<std::pair<uint_fast64_t, uint_fast64_t>, uint_fast64_t, PairHash> problematicTransitionToVariableIndexMap; std::unordered_map<std::pair<uint_fast64_t, uint_fast64_t>, std::string, PairHash> problematicTransitionToVariableMap;
uint_fast64_t numberOfVariables; uint_fast64_t numberOfVariables;
VariableInformation() : numberOfVariables(0) {} VariableInformation() : numberOfVariables(0) {}
@ -130,7 +130,7 @@ namespace storm {
bool allSuccessorsProblematic = true; bool allSuccessorsProblematic = true;
for (auto const& successorEntry : transitionMatrix.getRow(row)) { for (auto const& successorEntry : transitionMatrix.getRow(row)) {
// If there is a relevant successor, we need to add the labels of the current choice. // If there is a relevant successor, we need to add the labels of the current choice.
if (stateInformation.relevantStates.get(successorEntry.first) || psiStates.get(successorEntry.first)) { if (stateInformation.relevantStates.get(successorEntry.getColumn()) || psiStates.get(successorEntry.getColumn())) {
for (auto const& label : choiceLabeling[row]) { for (auto const& label : choiceLabeling[row]) {
result.allRelevantLabels.insert(label); result.allRelevantLabels.insert(label);
} }
@ -139,7 +139,7 @@ namespace storm {
result.relevantChoicesForRelevantStates[state].push_back(row); result.relevantChoicesForRelevantStates[state].push_back(row);
} }
} }
if (!stateInformation.problematicStates.get(successorEntry.first)) { if (!stateInformation.problematicStates.get(successorEntry.getColumn())) {
allSuccessorsProblematic = false; allSuccessorsProblematic = false;
} }
} }
@ -167,14 +167,15 @@ namespace storm {
* @param relevantLabels The set of relevant labels of the model. * @param relevantLabels The set of relevant labels of the model.
* @return A mapping from labels to variable indices. * @return A mapping from labels to variable indices.
*/ */
static std::pair<std::unordered_map<uint_fast64_t, uint_fast64_t>, uint_fast64_t> createLabelVariables(storm::solver::LpSolver& solver, boost::container::flat_set<uint_fast64_t> const& relevantLabels) { static std::pair<std::unordered_map<uint_fast64_t, std::string>, uint_fast64_t> createLabelVariables(storm::solver::LpSolver& solver, boost::container::flat_set<uint_fast64_t> const& relevantLabels) {
std::stringstream variableNameBuffer; std::stringstream variableNameBuffer;
std::unordered_map<uint_fast64_t, uint_fast64_t> resultingMap; std::unordered_map<uint_fast64_t, std::string> resultingMap;
for (auto const& label : relevantLabels) { for (auto const& label : relevantLabels) {
variableNameBuffer.str(""); variableNameBuffer.str("");
variableNameBuffer.clear(); variableNameBuffer.clear();
variableNameBuffer << "label" << label; variableNameBuffer << "label" << label;
resultingMap[label] = solver.createBinaryVariable(variableNameBuffer.str(), 1); resultingMap[label] = variableNameBuffer.str();
solver.addBinaryVariable(resultingMap[label], 1);
} }
return std::make_pair(resultingMap, relevantLabels.size()); return std::make_pair(resultingMap, relevantLabels.size());
} }
@ -187,19 +188,20 @@ namespace storm {
* @param choiceInformation The information about the choices of the model. * @param choiceInformation The information about the choices of the model.
* @return A mapping from states to a list of choice variable indices. * @return A mapping from states to a list of choice variable indices.
*/ */
static std::pair<std::unordered_map<uint_fast64_t, std::list<uint_fast64_t>>, uint_fast64_t> createSchedulerVariables(storm::solver::LpSolver& solver, StateInformation const& stateInformation, ChoiceInformation const& choiceInformation) { static std::pair<std::unordered_map<uint_fast64_t, std::list<std::string>>, uint_fast64_t> createSchedulerVariables(storm::solver::LpSolver& solver, StateInformation const& stateInformation, ChoiceInformation const& choiceInformation) {
std::stringstream variableNameBuffer; std::stringstream variableNameBuffer;
uint_fast64_t numberOfVariablesCreated = 0; uint_fast64_t numberOfVariablesCreated = 0;
std::unordered_map<uint_fast64_t, std::list<uint_fast64_t>> resultingMap; std::unordered_map<uint_fast64_t, std::list<std::string>> resultingMap;
for (auto state : stateInformation.relevantStates) { for (auto state : stateInformation.relevantStates) {
resultingMap.emplace(state, std::list<uint_fast64_t>()); resultingMap.emplace(state, std::list<std::string>());
std::list<uint_fast64_t> const& relevantChoicesForState = choiceInformation.relevantChoicesForRelevantStates.at(state); std::list<uint_fast64_t> const& relevantChoicesForState = choiceInformation.relevantChoicesForRelevantStates.at(state);
for (uint_fast64_t row : relevantChoicesForState) { for (uint_fast64_t row : relevantChoicesForState) {
variableNameBuffer.str(""); variableNameBuffer.str("");
variableNameBuffer.clear(); variableNameBuffer.clear();
variableNameBuffer << "choice" << row << "in" << state; variableNameBuffer << "choice" << row << "in" << state;
resultingMap[state].push_back(solver.createBinaryVariable(variableNameBuffer.str(), 0)); resultingMap[state].push_back(variableNameBuffer.str());
solver.addBinaryVariable(resultingMap[state].back());
++numberOfVariablesCreated; ++numberOfVariablesCreated;
} }
} }
@ -215,10 +217,10 @@ namespace storm {
* @param stateInformation The information about the states of the model. * @param stateInformation The information about the states of the model.
* @return A mapping from initial states to choice variable indices. * @return A mapping from initial states to choice variable indices.
*/ */
static std::pair<std::unordered_map<uint_fast64_t, uint_fast64_t>, uint_fast64_t> createInitialChoiceVariables(storm::solver::LpSolver& solver, storm::models::Mdp<T> const& labeledMdp, StateInformation const& stateInformation) { static std::pair<std::unordered_map<uint_fast64_t, std::string>, uint_fast64_t> createInitialChoiceVariables(storm::solver::LpSolver& solver, storm::models::Mdp<T> const& labeledMdp, StateInformation const& stateInformation) {
std::stringstream variableNameBuffer; std::stringstream variableNameBuffer;
uint_fast64_t numberOfVariablesCreated = 0; uint_fast64_t numberOfVariablesCreated = 0;
std::unordered_map<uint_fast64_t, uint_fast64_t> resultingMap; std::unordered_map<uint_fast64_t, std::string> resultingMap;
for (auto initialState : labeledMdp.getLabeledStates("init")) { for (auto initialState : labeledMdp.getLabeledStates("init")) {
// Only consider this initial state if it is relevant. // Only consider this initial state if it is relevant.
@ -226,7 +228,8 @@ namespace storm {
variableNameBuffer.str(""); variableNameBuffer.str("");
variableNameBuffer.clear(); variableNameBuffer.clear();
variableNameBuffer << "init" << initialState; variableNameBuffer << "init" << initialState;
resultingMap[initialState] = solver.createBinaryVariable(variableNameBuffer.str(), 0); resultingMap[initialState] = variableNameBuffer.str();
solver.addBinaryVariable(resultingMap[initialState]);
++numberOfVariablesCreated; ++numberOfVariablesCreated;
} }
} }
@ -240,34 +243,36 @@ namespace storm {
* @param stateInformation The information about the states in the model. * @param stateInformation The information about the states in the model.
* @return A mapping from states to the index of the corresponding probability variables. * @return A mapping from states to the index of the corresponding probability variables.
*/ */
static std::pair<std::unordered_map<uint_fast64_t, uint_fast64_t>, uint_fast64_t> createProbabilityVariables(storm::solver::LpSolver& solver, StateInformation const& stateInformation) { static std::pair<std::unordered_map<uint_fast64_t, std::string>, uint_fast64_t> createProbabilityVariables(storm::solver::LpSolver& solver, StateInformation const& stateInformation) {
std::stringstream variableNameBuffer; std::stringstream variableNameBuffer;
uint_fast64_t numberOfVariablesCreated = 0; uint_fast64_t numberOfVariablesCreated = 0;
std::unordered_map<uint_fast64_t, uint_fast64_t> resultingMap; std::unordered_map<uint_fast64_t, std::string> resultingMap;
for (auto state : stateInformation.relevantStates) { for (auto state : stateInformation.relevantStates) {
variableNameBuffer.str(""); variableNameBuffer.str("");
variableNameBuffer.clear(); variableNameBuffer.clear();
variableNameBuffer << "p" << state; variableNameBuffer << "p" << state;
resultingMap[state] = solver.createContinuousVariable(variableNameBuffer.str(), storm::solver::LpSolver::BOUNDED, 0, 1, 0); resultingMap[state] = variableNameBuffer.str();
solver.addBoundedContinuousVariable(resultingMap[state], 0, 1);
++numberOfVariablesCreated; ++numberOfVariablesCreated;
} }
return std::make_pair(resultingMap, numberOfVariablesCreated); return std::make_pair(resultingMap, numberOfVariablesCreated);
} }
/*! /*!
* Creates the variables for the probabilities in the model. * Creates the variable for the probability of the virtual initial state.
* *
* @param solver The MILP solver. * @param solver The MILP solver.
* @param maximizeProbability If set to true, the objective function is constructed in a way that a * @param maximizeProbability If set to true, the objective function is constructed in a way that a
* label-minimal subsystem of maximal probability is computed. * label-minimal subsystem of maximal probability is computed.
* @return The index of the variable for the probability of the virtual initial state. * @return The index of the variable for the probability of the virtual initial state.
*/ */
static std::pair<uint_fast64_t, uint_fast64_t> createVirtualInitialStateVariable(storm::solver::LpSolver& solver, bool maximizeProbability = false) { static std::pair<std::string, uint_fast64_t> createVirtualInitialStateVariable(storm::solver::LpSolver& solver, bool maximizeProbability = false) {
std::stringstream variableNameBuffer; std::stringstream variableNameBuffer;
variableNameBuffer << "pinit"; variableNameBuffer << "pinit";
std::string variableName = variableNameBuffer.str();
return std::make_pair(solver.createContinuousVariable(variableNameBuffer.str(), storm::solver::LpSolver::BOUNDED, 0, 1, 0), 1); solver.addBoundedContinuousVariable(variableName, 0, 1);
return std::make_pair(variableName, 1);
} }
/*! /*!
@ -278,10 +283,10 @@ namespace storm {
* @param stateInformation The information about the states in the model. * @param stateInformation The information about the states in the model.
* @return A mapping from problematic states to the index of the corresponding variables. * @return A mapping from problematic states to the index of the corresponding variables.
*/ */
static std::pair<std::unordered_map<uint_fast64_t, uint_fast64_t>, uint_fast64_t> createProblematicStateVariables(storm::solver::LpSolver& solver, storm::models::Mdp<T> const& labeledMdp, StateInformation const& stateInformation, ChoiceInformation const& choiceInformation) { static std::pair<std::unordered_map<uint_fast64_t, std::string>, uint_fast64_t> createProblematicStateVariables(storm::solver::LpSolver& solver, storm::models::Mdp<T> const& labeledMdp, StateInformation const& stateInformation, ChoiceInformation const& choiceInformation) {
std::stringstream variableNameBuffer; std::stringstream variableNameBuffer;
uint_fast64_t numberOfVariablesCreated = 0; uint_fast64_t numberOfVariablesCreated = 0;
std::unordered_map<uint_fast64_t, uint_fast64_t> resultingMap; std::unordered_map<uint_fast64_t, std::string> resultingMap;
for (auto state : stateInformation.problematicStates) { for (auto state : stateInformation.problematicStates) {
// First check whether there is not already a variable for this state and advance to the next state // First check whether there is not already a variable for this state and advance to the next state
@ -290,19 +295,21 @@ namespace storm {
variableNameBuffer.str(""); variableNameBuffer.str("");
variableNameBuffer.clear(); variableNameBuffer.clear();
variableNameBuffer << "r" << state; variableNameBuffer << "r" << state;
resultingMap[state] = solver.createContinuousVariable(variableNameBuffer.str(), storm::solver::LpSolver::BOUNDED, 0, 1, 0); resultingMap[state] = variableNameBuffer.str();
solver.addBoundedContinuousVariable(resultingMap[state], 0, 1);
++numberOfVariablesCreated; ++numberOfVariablesCreated;
} }
std::list<uint_fast64_t> const& relevantChoicesForState = choiceInformation.relevantChoicesForRelevantStates.at(state); std::list<uint_fast64_t> const& relevantChoicesForState = choiceInformation.relevantChoicesForRelevantStates.at(state);
for (uint_fast64_t row : relevantChoicesForState) { for (uint_fast64_t row : relevantChoicesForState) {
for (auto const& successorEntry : labeledMdp.getTransitionMatrix().getRow(row)) { for (auto const& successorEntry : labeledMdp.getTransitionMatrix().getRow(row)) {
if (stateInformation.relevantStates.get(successorEntry.first)) { if (stateInformation.relevantStates.get(successorEntry.getColumn())) {
if (resultingMap.find(successorEntry.first) == resultingMap.end()) { if (resultingMap.find(successorEntry.getColumn()) == resultingMap.end()) {
variableNameBuffer.str(""); variableNameBuffer.str("");
variableNameBuffer.clear(); variableNameBuffer.clear();
variableNameBuffer << "r" << successorEntry.first; variableNameBuffer << "r" << successorEntry.getColumn();
resultingMap[state] = solver.createContinuousVariable(variableNameBuffer.str(), storm::solver::LpSolver::BOUNDED, 0, 1, 0); resultingMap[successorEntry.getColumn()] = variableNameBuffer.str();
solver.addBoundedContinuousVariable(resultingMap[successorEntry.getColumn()], 0, 1);
++numberOfVariablesCreated; ++numberOfVariablesCreated;
} }
} }
@ -321,20 +328,21 @@ namespace storm {
* @param choiceInformation The information about the choices in the model. * @param choiceInformation The information about the choices in the model.
* @return A mapping from problematic choices to the index of the corresponding variables. * @return A mapping from problematic choices to the index of the corresponding variables.
*/ */
static std::pair<std::unordered_map<std::pair<uint_fast64_t, uint_fast64_t>, uint_fast64_t, PairHash>, uint_fast64_t> createProblematicChoiceVariables(storm::solver::LpSolver& solver, storm::models::Mdp<T> const& labeledMdp, StateInformation const& stateInformation, ChoiceInformation const& choiceInformation) { static std::pair<std::unordered_map<std::pair<uint_fast64_t, uint_fast64_t>, std::string, PairHash>, uint_fast64_t> createProblematicChoiceVariables(storm::solver::LpSolver& solver, storm::models::Mdp<T> const& labeledMdp, StateInformation const& stateInformation, ChoiceInformation const& choiceInformation) {
std::stringstream variableNameBuffer; std::stringstream variableNameBuffer;
uint_fast64_t numberOfVariablesCreated = 0; uint_fast64_t numberOfVariablesCreated = 0;
std::unordered_map<std::pair<uint_fast64_t, uint_fast64_t>, uint_fast64_t, PairHash> resultingMap; std::unordered_map<std::pair<uint_fast64_t, uint_fast64_t>, std::string, PairHash> resultingMap;
for (auto state : stateInformation.problematicStates) { for (auto state : stateInformation.problematicStates) {
std::list<uint_fast64_t> const& relevantChoicesForState = choiceInformation.relevantChoicesForRelevantStates.at(state); std::list<uint_fast64_t> const& relevantChoicesForState = choiceInformation.relevantChoicesForRelevantStates.at(state);
for (uint_fast64_t row : relevantChoicesForState) { for (uint_fast64_t row : relevantChoicesForState) {
for (auto const& successorEntry : labeledMdp.getTransitionMatrix().getRow(row)) { for (auto const& successorEntry : labeledMdp.getTransitionMatrix().getRow(row)) {
if (stateInformation.relevantStates.get(successorEntry.first)) { if (stateInformation.relevantStates.get(successorEntry.getColumn())) {
variableNameBuffer.str(""); variableNameBuffer.str("");
variableNameBuffer.clear(); variableNameBuffer.clear();
variableNameBuffer << "t" << state << "to" << successorEntry.first; variableNameBuffer << "t" << state << "to" << successorEntry.getColumn();
resultingMap[std::make_pair(state, successorEntry.first)] = solver.createBinaryVariable(variableNameBuffer.str(), 0); resultingMap[std::make_pair(state, successorEntry.getColumn())] = variableNameBuffer.str();
solver.addBinaryVariable(resultingMap[std::make_pair(state, successorEntry.getColumn())]);
++numberOfVariablesCreated; ++numberOfVariablesCreated;
} }
} }
@ -358,44 +366,44 @@ namespace storm {
VariableInformation result; VariableInformation result;
// Create variables for involved labels. // Create variables for involved labels.
std::pair<std::unordered_map<uint_fast64_t, uint_fast64_t>, uint_fast64_t> labelVariableResult = createLabelVariables(solver, choiceInformation.allRelevantLabels); std::pair<std::unordered_map<uint_fast64_t, std::string>, uint_fast64_t> labelVariableResult = createLabelVariables(solver, choiceInformation.allRelevantLabels);
result.labelToVariableIndexMap = std::move(labelVariableResult.first); result.labelToVariableMap = std::move(labelVariableResult.first);
result.numberOfVariables += labelVariableResult.second; result.numberOfVariables += labelVariableResult.second;
LOG4CPLUS_DEBUG(logger, "Created variables for labels."); LOG4CPLUS_DEBUG(logger, "Created variables for labels.");
// Create scheduler variables for relevant states and their actions. // Create scheduler variables for relevant states and their actions.
std::pair<std::unordered_map<uint_fast64_t, std::list<uint_fast64_t>>, uint_fast64_t> schedulerVariableResult = createSchedulerVariables(solver, stateInformation, choiceInformation); std::pair<std::unordered_map<uint_fast64_t, std::list<std::string>>, uint_fast64_t> schedulerVariableResult = createSchedulerVariables(solver, stateInformation, choiceInformation);
result.stateToChoiceVariablesIndexMap = std::move(schedulerVariableResult.first); result.stateToChoiceVariablesMap = std::move(schedulerVariableResult.first);
result.numberOfVariables += schedulerVariableResult.second; result.numberOfVariables += schedulerVariableResult.second;
LOG4CPLUS_DEBUG(logger, "Created variables for nondeterministic choices."); LOG4CPLUS_DEBUG(logger, "Created variables for nondeterministic choices.");
// Create scheduler variables for nondeterministically choosing an initial state. // Create scheduler variables for nondeterministically choosing an initial state.
std::pair<std::unordered_map<uint_fast64_t, uint_fast64_t>, uint_fast64_t> initialChoiceVariableResult = createInitialChoiceVariables(solver, labeledMdp, stateInformation); std::pair<std::unordered_map<uint_fast64_t, std::string>, uint_fast64_t> initialChoiceVariableResult = createInitialChoiceVariables(solver, labeledMdp, stateInformation);
result.initialStateToChoiceVariableIndexMap = std::move(initialChoiceVariableResult.first); result.initialStateToChoiceVariableMap = std::move(initialChoiceVariableResult.first);
result.numberOfVariables += initialChoiceVariableResult.second; result.numberOfVariables += initialChoiceVariableResult.second;
LOG4CPLUS_DEBUG(logger, "Created variables for the nondeterministic choice of the initial state."); LOG4CPLUS_DEBUG(logger, "Created variables for the nondeterministic choice of the initial state.");
// Create variables for probabilities for all relevant states. // Create variables for probabilities for all relevant states.
std::pair<std::unordered_map<uint_fast64_t, uint_fast64_t>, uint_fast64_t> probabilityVariableResult = createProbabilityVariables(solver, stateInformation); std::pair<std::unordered_map<uint_fast64_t, std::string>, uint_fast64_t> probabilityVariableResult = createProbabilityVariables(solver, stateInformation);
result.stateToProbabilityVariableIndexMap = std::move(probabilityVariableResult.first); result.stateToProbabilityVariableMap = std::move(probabilityVariableResult.first);
result.numberOfVariables += probabilityVariableResult.second; result.numberOfVariables += probabilityVariableResult.second;
LOG4CPLUS_DEBUG(logger, "Created variables for the reachability probabilities."); LOG4CPLUS_DEBUG(logger, "Created variables for the reachability probabilities.");
// Create a probability variable for a virtual initial state that nondeterministically chooses one of the system's real initial states as its target state. // Create a probability variable for a virtual initial state that nondeterministically chooses one of the system's real initial states as its target state.
std::pair<uint_fast64_t, uint_fast64_t> virtualInitialStateVariableResult = createVirtualInitialStateVariable(solver); std::pair<std::string, uint_fast64_t> virtualInitialStateVariableResult = createVirtualInitialStateVariable(solver);
result.virtualInitialStateVariableIndex = virtualInitialStateVariableResult.first; result.virtualInitialStateVariable = virtualInitialStateVariableResult.first;
result.numberOfVariables += virtualInitialStateVariableResult.second; result.numberOfVariables += virtualInitialStateVariableResult.second;
LOG4CPLUS_DEBUG(logger, "Created variables for the virtual initial state."); LOG4CPLUS_DEBUG(logger, "Created variables for the virtual initial state.");
// Create variables for problematic states. // Create variables for problematic states.
std::pair<std::unordered_map<uint_fast64_t, uint_fast64_t>, uint_fast64_t> problematicStateVariableResult = createProblematicStateVariables(solver, labeledMdp, stateInformation, choiceInformation); std::pair<std::unordered_map<uint_fast64_t, std::string>, uint_fast64_t> problematicStateVariableResult = createProblematicStateVariables(solver, labeledMdp, stateInformation, choiceInformation);
result.problematicStateToVariableIndexMap = std::move(problematicStateVariableResult.first); result.problematicStateToVariableMap = std::move(problematicStateVariableResult.first);
result.numberOfVariables += problematicStateVariableResult.second; result.numberOfVariables += problematicStateVariableResult.second;
LOG4CPLUS_DEBUG(logger, "Created variables for the problematic states."); LOG4CPLUS_DEBUG(logger, "Created variables for the problematic states.");
// Create variables for problematic choices. // Create variables for problematic choices.
std::pair<std::unordered_map<std::pair<uint_fast64_t, uint_fast64_t>, uint_fast64_t, PairHash>, uint_fast64_t> problematicTransitionVariableResult = createProblematicChoiceVariables(solver, labeledMdp, stateInformation, choiceInformation); std::pair<std::unordered_map<std::pair<uint_fast64_t, uint_fast64_t>, std::string, PairHash>, uint_fast64_t> problematicTransitionVariableResult = createProblematicChoiceVariables(solver, labeledMdp, stateInformation, choiceInformation);
result.problematicTransitionToVariableIndexMap = problematicTransitionVariableResult.first; result.problematicTransitionToVariableMap = problematicTransitionVariableResult.first;
result.numberOfVariables += problematicTransitionVariableResult.second; result.numberOfVariables += problematicTransitionVariableResult.second;
LOG4CPLUS_DEBUG(logger, "Created variables for the problematic choices."); LOG4CPLUS_DEBUG(logger, "Created variables for the problematic choices.");
@ -419,7 +427,13 @@ namespace storm {
* @return The total number of constraints that were created. * @return The total number of constraints that were created.
*/ */
static uint_fast64_t assertProbabilityGreaterThanThreshold(storm::solver::LpSolver& solver, storm::models::Mdp<T> const& labeledMdp, VariableInformation const& variableInformation, double probabilityThreshold, bool strictBound) { static uint_fast64_t assertProbabilityGreaterThanThreshold(storm::solver::LpSolver& solver, storm::models::Mdp<T> const& labeledMdp, VariableInformation const& variableInformation, double probabilityThreshold, bool strictBound) {
solver.addConstraint("ProbGreaterThreshold", {variableInformation.virtualInitialStateVariableIndex}, {1}, strictBound ? storm::solver::LpSolver::GREATER : storm::solver::LpSolver::GREATER_EQUAL, probabilityThreshold); storm::expressions::Expression constraint;
if (strictBound) {
constraint = storm::expressions::Expression::createDoubleVariable(variableInformation.virtualInitialStateVariable) > storm::expressions::Expression::createDoubleLiteral(probabilityThreshold);
} else {
constraint = storm::expressions::Expression::createDoubleVariable(variableInformation.virtualInitialStateVariable) >= storm::expressions::Expression::createDoubleLiteral(probabilityThreshold);
}
solver.addConstraint("ProbGreaterThreshold", constraint);
return 1; return 1;
} }
@ -435,28 +449,28 @@ namespace storm {
// Assert that the policy chooses at most one action in each state of the system. // Assert that the policy chooses at most one action in each state of the system.
uint_fast64_t numberOfConstraintsCreated = 0; uint_fast64_t numberOfConstraintsCreated = 0;
for (auto state : stateInformation.relevantStates) { for (auto state : stateInformation.relevantStates) {
std::list<uint_fast64_t> const& choiceVariableIndices = variableInformation.stateToChoiceVariablesIndexMap.at(state); std::list<std::string> const& choiceVariableIndices = variableInformation.stateToChoiceVariablesMap.at(state);
std::vector<uint_fast64_t> variables; storm::expressions::Expression constraint = storm::expressions::Expression::createDoubleLiteral(0);
std::vector<double> coefficients(choiceVariableIndices.size(), 1); for (auto const& choiceVariable : choiceVariableIndices) {
variables.reserve(choiceVariableIndices.size()); constraint = constraint + storm::expressions::Expression::createIntegerVariable(choiceVariable);
for (auto choiceVariableIndex : choiceVariableIndices) {
variables.push_back(choiceVariableIndex);
} }
solver.addConstraint("ValidPolicy" + std::to_string(numberOfConstraintsCreated), variables, coefficients, storm::solver::LpSolver::LESS_EQUAL, 1); constraint = constraint <= storm::expressions::Expression::createDoubleLiteral(1);
solver.addConstraint("ValidPolicy" + std::to_string(numberOfConstraintsCreated), constraint);
++numberOfConstraintsCreated; ++numberOfConstraintsCreated;
} }
// Now assert that the virtual initial state picks exactly one initial state from the system as its // Now assert that the virtual initial state picks exactly one initial state from the system as its
// successor state. // successor state.
std::vector<uint_fast64_t> variables; storm::expressions::Expression constraint = storm::expressions::Expression::createDoubleLiteral(0);
variables.reserve(variableInformation.initialStateToChoiceVariableIndexMap.size()); for (auto const& initialStateVariablePair : variableInformation.initialStateToChoiceVariableMap) {
std::vector<double> coefficients(variableInformation.initialStateToChoiceVariableIndexMap.size(), 1); constraint = constraint + storm::expressions::Expression::createIntegerVariable(initialStateVariablePair.second);
for (auto initialStateVariableIndexPair : variableInformation.initialStateToChoiceVariableIndexMap) {
variables.push_back(initialStateVariableIndexPair.second);
} }
constraint = constraint == storm::expressions::Expression::createDoubleLiteral(1);
solver.addConstraint("VirtualInitialStateChoosesOneInitialState", variables, coefficients, storm::solver::LpSolver::EQUAL, 1); solver.addConstraint("VirtualInitialStateChoosesOneInitialState", constraint);
++numberOfConstraintsCreated; ++numberOfConstraintsCreated;
return numberOfConstraintsCreated; return numberOfConstraintsCreated;
@ -478,13 +492,14 @@ namespace storm {
std::vector<boost::container::flat_set<uint_fast64_t>> const& choiceLabeling = labeledMdp.getChoiceLabeling(); std::vector<boost::container::flat_set<uint_fast64_t>> const& choiceLabeling = labeledMdp.getChoiceLabeling();
for (auto state : stateInformation.relevantStates) { for (auto state : stateInformation.relevantStates) {
std::list<uint_fast64_t>::const_iterator choiceVariableIndicesIterator = variableInformation.stateToChoiceVariablesIndexMap.at(state).begin(); std::list<std::string>::const_iterator choiceVariableIterator = variableInformation.stateToChoiceVariablesMap.at(state).begin();
for (auto choice : choiceInformation.relevantChoicesForRelevantStates.at(state)) { for (auto choice : choiceInformation.relevantChoicesForRelevantStates.at(state)) {
for (auto label : choiceLabeling[choice]) { for (auto label : choiceLabeling[choice]) {
solver.addConstraint("ChoicesImplyLabels" + std::to_string(numberOfConstraintsCreated), {variableInformation.labelToVariableIndexMap.at(label), *choiceVariableIndicesIterator}, {1, -1}, storm::solver::LpSolver::GREATER_EQUAL, 0); storm::expressions::Expression constraint = storm::expressions::Expression::createIntegerVariable(variableInformation.labelToVariableMap.at(label)) - storm::expressions::Expression::createIntegerVariable(*choiceVariableIterator) >= storm::expressions::Expression::createDoubleLiteral(0);
solver.addConstraint("ChoicesImplyLabels" + std::to_string(numberOfConstraintsCreated), constraint);
++numberOfConstraintsCreated; ++numberOfConstraintsCreated;
} }
++choiceVariableIndicesIterator; ++choiceVariableIterator;
} }
} }
return numberOfConstraintsCreated; return numberOfConstraintsCreated;
@ -503,16 +518,12 @@ namespace storm {
static uint_fast64_t assertZeroProbabilityWithoutChoice(storm::solver::LpSolver& solver, StateInformation const& stateInformation, ChoiceInformation const& choiceInformation, VariableInformation const& variableInformation) { static uint_fast64_t assertZeroProbabilityWithoutChoice(storm::solver::LpSolver& solver, StateInformation const& stateInformation, ChoiceInformation const& choiceInformation, VariableInformation const& variableInformation) {
uint_fast64_t numberOfConstraintsCreated = 0; uint_fast64_t numberOfConstraintsCreated = 0;
for (auto state : stateInformation.relevantStates) { for (auto state : stateInformation.relevantStates) {
std::list<uint_fast64_t> const& choiceVariableIndices = variableInformation.stateToChoiceVariablesIndexMap.at(state); storm::expressions::Expression constraint = storm::expressions::Expression::createDoubleVariable(variableInformation.stateToProbabilityVariableMap.at(state));
for (auto const& choiceVariable : variableInformation.stateToChoiceVariablesMap.at(state)) {
std::vector<double> coefficients(choiceVariableIndices.size() + 1, -1); constraint = constraint - storm::expressions::Expression::createIntegerVariable(choiceVariable);
coefficients[0] = 1; }
std::vector<uint_fast64_t> variables; constraint = constraint <= storm::expressions::Expression::createDoubleLiteral(0);
variables.reserve(variableInformation.stateToChoiceVariablesIndexMap.at(state).size() + 1); solver.addConstraint("ProbabilityIsZeroIfNoAction" + std::to_string(numberOfConstraintsCreated), constraint);
variables.push_back(variableInformation.stateToProbabilityVariableIndexMap.at(state));
variables.insert(variables.end(), choiceVariableIndices.begin(), choiceVariableIndices.end());
solver.addConstraint("ProbabilityIsZeroIfNoAction" + std::to_string(numberOfConstraintsCreated), variables, coefficients, storm::solver::LpSolver::LESS_EQUAL, 0);
++numberOfConstraintsCreated; ++numberOfConstraintsCreated;
} }
return numberOfConstraintsCreated; return numberOfConstraintsCreated;
@ -532,40 +543,32 @@ namespace storm {
static uint_fast64_t assertReachabilityProbabilities(storm::solver::LpSolver& solver, storm::models::Mdp<T> const& labeledMdp, storm::storage::BitVector const& psiStates, StateInformation const& stateInformation, ChoiceInformation const& choiceInformation, VariableInformation const& variableInformation) { static uint_fast64_t assertReachabilityProbabilities(storm::solver::LpSolver& solver, storm::models::Mdp<T> const& labeledMdp, storm::storage::BitVector const& psiStates, StateInformation const& stateInformation, ChoiceInformation const& choiceInformation, VariableInformation const& variableInformation) {
uint_fast64_t numberOfConstraintsCreated = 0; uint_fast64_t numberOfConstraintsCreated = 0;
for (auto state : stateInformation.relevantStates) { for (auto state : stateInformation.relevantStates) {
std::vector<double> coefficients; std::list<std::string>::const_iterator choiceVariableIterator = variableInformation.stateToChoiceVariablesMap.at(state).begin();
std::vector<uint_fast64_t> variables;
std::list<uint_fast64_t>::const_iterator choiceVariableIndicesIterator = variableInformation.stateToChoiceVariablesIndexMap.at(state).begin();
for (auto choice : choiceInformation.relevantChoicesForRelevantStates.at(state)) { for (auto choice : choiceInformation.relevantChoicesForRelevantStates.at(state)) {
variables.clear(); storm::expressions::Expression constraint = storm::expressions::Expression::createDoubleVariable(variableInformation.stateToProbabilityVariableMap.at(state));
coefficients.clear();
variables.push_back(variableInformation.stateToProbabilityVariableIndexMap.at(state));
coefficients.push_back(1.0);
double rightHandSide = 1; double rightHandSide = 1;
for (auto const& successorEntry : labeledMdp.getTransitionMatrix().getRow(choice)) { for (auto const& successorEntry : labeledMdp.getTransitionMatrix().getRow(choice)) {
if (stateInformation.relevantStates.get(successorEntry.first)) { if (stateInformation.relevantStates.get(successorEntry.getColumn())) {
variables.push_back(static_cast<int>(variableInformation.stateToProbabilityVariableIndexMap.at(successorEntry.first))); constraint = constraint - storm::expressions::Expression::createDoubleLiteral(successorEntry.getValue()) * storm::expressions::Expression::createDoubleVariable(variableInformation.stateToProbabilityVariableMap.at(successorEntry.getColumn()));
coefficients.push_back(-successorEntry.second); } else if (psiStates.get(successorEntry.getColumn())) {
} else if (psiStates.get(successorEntry.first)) { rightHandSide += successorEntry.getValue();
rightHandSide += successorEntry.second;
} }
} }
coefficients.push_back(1); constraint = constraint + storm::expressions::Expression::createIntegerVariable(*choiceVariableIterator) <= storm::expressions::Expression::createDoubleLiteral(rightHandSide);
variables.push_back(*choiceVariableIndicesIterator); solver.addConstraint("ReachabilityProbabilities" + std::to_string(numberOfConstraintsCreated), constraint);
solver.addConstraint("ReachabilityProbabilities" + std::to_string(numberOfConstraintsCreated), variables, coefficients, storm::solver::LpSolver::LESS_EQUAL, rightHandSide);
++numberOfConstraintsCreated; ++numberOfConstraintsCreated;
++choiceVariableIndicesIterator; ++choiceVariableIterator;
} }
} }
// Make sure that the virtual initial state is being assigned the probability from the initial state // Make sure that the virtual initial state is being assigned the probability from the initial state
// that it selected as a successor state. // that it selected as a successor state.
for (auto initialStateVariableIndexPair : variableInformation.initialStateToChoiceVariableIndexMap) { for (auto const& initialStateVariablePair : variableInformation.initialStateToChoiceVariableMap) {
solver.addConstraint("VirtualInitialStateHasCorrectProbability" + std::to_string(numberOfConstraintsCreated), {variableInformation.virtualInitialStateVariableIndex, variableInformation.stateToProbabilityVariableIndexMap.at(initialStateVariableIndexPair.first), initialStateVariableIndexPair.second}, {1, -1, 1}, storm::solver::LpSolver::LESS_EQUAL, 1); storm::expressions::Expression constraint = storm::expressions::Expression::createDoubleVariable(variableInformation.virtualInitialStateVariable) - storm::expressions::Expression::createDoubleVariable(variableInformation.stateToProbabilityVariableMap.at(initialStateVariablePair.first)) + storm::expressions::Expression::createDoubleVariable(initialStateVariablePair.second) <= storm::expressions::Expression::createDoubleLiteral(1);
solver.addConstraint("VirtualInitialStateHasCorrectProbability" + std::to_string(numberOfConstraintsCreated), constraint);
++numberOfConstraintsCreated; ++numberOfConstraintsCreated;
} }
@ -587,44 +590,34 @@ namespace storm {
for (auto stateListPair : choiceInformation.problematicChoicesForProblematicStates) { for (auto stateListPair : choiceInformation.problematicChoicesForProblematicStates) {
for (auto problematicChoice : stateListPair.second) { for (auto problematicChoice : stateListPair.second) {
std::list<uint_fast64_t>::const_iterator choiceVariableIndicesIterator = variableInformation.stateToChoiceVariablesIndexMap.at(stateListPair.first).begin(); std::list<std::string>::const_iterator choiceVariableIterator = variableInformation.stateToChoiceVariablesMap.at(stateListPair.first).begin();
for (auto relevantChoice : choiceInformation.relevantChoicesForRelevantStates.at(stateListPair.first)) { for (auto relevantChoice : choiceInformation.relevantChoicesForRelevantStates.at(stateListPair.first)) {
if (relevantChoice == problematicChoice) { if (relevantChoice == problematicChoice) {
break; break;
} }
++choiceVariableIndicesIterator; ++choiceVariableIterator;
} }
std::vector<uint_fast64_t> variables; storm::expressions::Expression constraint = storm::expressions::Expression::createDoubleVariable(*choiceVariableIterator);
std::vector<double> coefficients;
variables.push_back(*choiceVariableIndicesIterator);
coefficients.push_back(1);
for (auto const& successorEntry : labeledMdp.getTransitionMatrix().getRow(problematicChoice)) { for (auto const& successorEntry : labeledMdp.getTransitionMatrix().getRow(problematicChoice)) {
variables.push_back(variableInformation.problematicTransitionToVariableIndexMap.at(std::make_pair(stateListPair.first, successorEntry.first))); constraint = constraint - storm::expressions::Expression::createDoubleVariable(variableInformation.problematicTransitionToVariableMap.at(std::make_pair(stateListPair.first, successorEntry.getColumn())));
coefficients.push_back(-1);
} }
constraint = constraint <= storm::expressions::Expression::createDoubleLiteral(0);
solver.addConstraint("UnproblematicStateReachable" + std::to_string(numberOfConstraintsCreated), variables, coefficients, storm::solver::LpSolver::LESS_EQUAL, 0); solver.addConstraint("UnproblematicStateReachable" + std::to_string(numberOfConstraintsCreated), constraint);
++numberOfConstraintsCreated; ++numberOfConstraintsCreated;
} }
} }
for (auto state : stateInformation.problematicStates) { for (auto state : stateInformation.problematicStates) {
for (auto problematicChoice : choiceInformation.problematicChoicesForProblematicStates.at(state)) { for (auto problematicChoice : choiceInformation.problematicChoicesForProblematicStates.at(state)) {
for (auto const& successorEntry : labeledMdp.getTransitionMatrix().getRow(state)) { for (auto const& successorEntry : labeledMdp.getTransitionMatrix().getRow(problematicChoice)) {
std::vector<uint_fast64_t> variables; storm::expressions::Expression constraint = storm::expressions::Expression::createDoubleVariable(variableInformation.problematicStateToVariableMap.at(state));
std::vector<double> coefficients; constraint = constraint - storm::expressions::Expression::createDoubleVariable(variableInformation.problematicStateToVariableMap.at(successorEntry.getColumn()));
constraint = constraint + storm::expressions::Expression::createDoubleVariable(variableInformation.problematicTransitionToVariableMap.at(std::make_pair(state, successorEntry.getColumn())));
variables.push_back(variableInformation.problematicStateToVariableIndexMap.at(state)); constraint = constraint < storm::expressions::Expression::createDoubleLiteral(1);
coefficients.push_back(1);
variables.push_back(variableInformation.problematicStateToVariableIndexMap.at(successorEntry.first));
coefficients.push_back(-1);
variables.push_back(variableInformation.problematicTransitionToVariableIndexMap.at(std::make_pair(state, successorEntry.first)));
coefficients.push_back(1);
solver.addConstraint("UnproblematicStateReachable" + std::to_string(numberOfConstraintsCreated), variables, coefficients, storm::solver::LpSolver::LESS, 1); solver.addConstraint("UnproblematicStateReachable" + std::to_string(numberOfConstraintsCreated), constraint);
++numberOfConstraintsCreated; ++numberOfConstraintsCreated;
} }
} }
@ -646,7 +639,8 @@ namespace storm {
uint_fast64_t numberOfConstraintsCreated = 0; uint_fast64_t numberOfConstraintsCreated = 0;
for (auto label : choiceInformation.knownLabels) { for (auto label : choiceInformation.knownLabels) {
solver.addConstraint("KnownLabels" + std::to_string(numberOfConstraintsCreated), {variableInformation.labelToVariableIndexMap.at(label)}, {1}, storm::solver::LpSolver::EQUAL, 1); storm::expressions::Expression constraint = storm::expressions::Expression::createDoubleVariable(variableInformation.labelToVariableMap.at(label)) == storm::expressions::Expression::createDoubleLiteral(1);
solver.addConstraint("KnownLabels" + std::to_string(numberOfConstraintsCreated), constraint);
++numberOfConstraintsCreated; ++numberOfConstraintsCreated;
} }
@ -667,61 +661,52 @@ namespace storm {
static uint_fast64_t assertSchedulerCuts(storm::solver::LpSolver& solver, storm::models::Mdp<T> const& labeledMdp, storm::storage::BitVector const& psiStates, StateInformation const& stateInformation, ChoiceInformation const& choiceInformation, VariableInformation const& variableInformation) { static uint_fast64_t assertSchedulerCuts(storm::solver::LpSolver& solver, storm::models::Mdp<T> const& labeledMdp, storm::storage::BitVector const& psiStates, StateInformation const& stateInformation, ChoiceInformation const& choiceInformation, VariableInformation const& variableInformation) {
storm::storage::SparseMatrix<T> backwardTransitions = labeledMdp.getBackwardTransitions(); storm::storage::SparseMatrix<T> backwardTransitions = labeledMdp.getBackwardTransitions();
uint_fast64_t numberOfConstraintsCreated = 0; uint_fast64_t numberOfConstraintsCreated = 0;
std::vector<uint_fast64_t> variables;
std::vector<double> coefficients;
for (auto state : stateInformation.relevantStates) { for (auto state : stateInformation.relevantStates) {
// Assert that all states, that select an action, this action either has a non-zero probability to // Assert that all states, that select an action, this action either has a non-zero probability to
// go to a psi state directly, or in the successor states, at least one action is selected as well. // go to a psi state directly, or in the successor states, at least one action is selected as well.
std::list<uint_fast64_t>::const_iterator choiceVariableIndicesIterator = variableInformation.stateToChoiceVariablesIndexMap.at(state).begin(); std::list<std::string>::const_iterator choiceVariableIterator = variableInformation.stateToChoiceVariablesMap.at(state).begin();
for (auto choice : choiceInformation.relevantChoicesForRelevantStates.at(state)) { for (auto choice : choiceInformation.relevantChoicesForRelevantStates.at(state)) {
bool psiStateReachableInOneStep = false; bool psiStateReachableInOneStep = false;
for (auto const& successorEntry : labeledMdp.getTransitionMatrix().getRow(choice)) { for (auto const& successorEntry : labeledMdp.getTransitionMatrix().getRow(choice)) {
if (psiStates.get(successorEntry.first)) { if (psiStates.get(successorEntry.getColumn())) {
psiStateReachableInOneStep = true; psiStateReachableInOneStep = true;
} }
} }
if (!psiStateReachableInOneStep) { if (!psiStateReachableInOneStep) {
variables.clear(); storm::expressions::Expression constraint = storm::expressions::Expression::createDoubleVariable(*choiceVariableIterator);
coefficients.clear();
variables.push_back(static_cast<int>(*choiceVariableIndicesIterator));
coefficients.push_back(1);
for (auto const& successorEntry : labeledMdp.getTransitionMatrix().getRow(choice)) { for (auto const& successorEntry : labeledMdp.getTransitionMatrix().getRow(choice)) {
if (state != successorEntry.first && stateInformation.relevantStates.get(successorEntry.first)) { if (state != successorEntry.getColumn() && stateInformation.relevantStates.get(successorEntry.getColumn())) {
std::list<uint_fast64_t> const& successorChoiceVariableIndices = variableInformation.stateToChoiceVariablesIndexMap.at(successorEntry.first); std::list<std::string> const& successorChoiceVariableIndices = variableInformation.stateToChoiceVariablesMap.at(successorEntry.getColumn());
for (auto choiceVariableIndex : successorChoiceVariableIndices) { for (auto const& choiceVariable : successorChoiceVariableIndices) {
variables.push_back(choiceVariableIndex); constraint = constraint - storm::expressions::Expression::createDoubleVariable(choiceVariable);
coefficients.push_back(-1);
} }
} }
} }
constraint = constraint <= storm::expressions::Expression::createDoubleLiteral(1);
solver.addConstraint("SchedulerCuts" + std::to_string(numberOfConstraintsCreated), variables, coefficients, storm::solver::LpSolver::LESS_EQUAL, 1); solver.addConstraint("SchedulerCuts" + std::to_string(numberOfConstraintsCreated), constraint);
++numberOfConstraintsCreated; ++numberOfConstraintsCreated;
} }
++choiceVariableIndicesIterator; ++choiceVariableIterator;
} }
// For all states assert that there is either a selected incoming transition in the subsystem or the // For all states assert that there is either a selected incoming transition in the subsystem or the
// state is the chosen initial state if there is one selected action in the current state. // state is the chosen initial state if there is one selected action in the current state.
variables.clear(); storm::expressions::Expression constraint = storm::expressions::Expression::createDoubleLiteral(0);
coefficients.clear(); for (auto const& choiceVariable : variableInformation.stateToChoiceVariablesMap.at(state)) {
constraint = constraint + storm::expressions::Expression::createDoubleVariable(choiceVariable);
for (auto choiceVariableIndex : variableInformation.stateToChoiceVariablesIndexMap.at(state)) {
variables.push_back(choiceVariableIndex);
coefficients.push_back(1);
} }
// Compute the set of predecessors. // Compute the set of predecessors.
std::unordered_set<uint_fast64_t> predecessors; std::unordered_set<uint_fast64_t> predecessors;
for (auto const& predecessorEntry : backwardTransitions.getRow(state)) { for (auto const& predecessorEntry : backwardTransitions.getRow(state)) {
if (state != predecessorEntry.first) { if (state != predecessorEntry.getColumn()) {
predecessors.insert(predecessorEntry.first); predecessors.insert(predecessorEntry.getColumn());
} }
} }
@ -731,13 +716,13 @@ namespace storm {
continue; continue;
} }
std::list<uint_fast64_t>::const_iterator choiceVariableIndicesIterator = variableInformation.stateToChoiceVariablesIndexMap.at(predecessor).begin(); std::list<std::string>::const_iterator choiceVariableIterator = variableInformation.stateToChoiceVariablesMap.at(predecessor).begin();
for (auto relevantChoice : choiceInformation.relevantChoicesForRelevantStates.at(predecessor)) { for (auto relevantChoice : choiceInformation.relevantChoicesForRelevantStates.at(predecessor)) {
bool choiceTargetsCurrentState = false; bool choiceTargetsCurrentState = false;
// Check if the current choice targets the current state. // Check if the current choice targets the current state.
for (auto const& successorEntry : labeledMdp.getTransitionMatrix().getRow(relevantChoice)) { for (auto const& successorEntry : labeledMdp.getTransitionMatrix().getRow(relevantChoice)) {
if (state == successorEntry.first) { if (state == successorEntry.getColumn()) {
choiceTargetsCurrentState = true; choiceTargetsCurrentState = true;
break; break;
} }
@ -745,45 +730,42 @@ namespace storm {
// If it does, we can add the choice to the sum. // If it does, we can add the choice to the sum.
if (choiceTargetsCurrentState) { if (choiceTargetsCurrentState) {
variables.push_back(static_cast<int>(*choiceVariableIndicesIterator)); constraint = constraint - storm::expressions::Expression::createDoubleVariable(*choiceVariableIterator);
coefficients.push_back(-1);
} }
++choiceVariableIndicesIterator; ++choiceVariableIterator;
} }
} }
// If the current state is an initial state and is selected as a successor state by the virtual // If the current state is an initial state and is selected as a successor state by the virtual
// initial state, then this also justifies making a choice in the current state. // initial state, then this also justifies making a choice in the current state.
if (labeledMdp.getLabeledStates("init").get(state)) { if (labeledMdp.getLabeledStates("init").get(state)) {
variables.push_back(variableInformation.initialStateToChoiceVariableIndexMap.at(state)); constraint = constraint - storm::expressions::Expression::createDoubleVariable(variableInformation.initialStateToChoiceVariableMap.at(state));
coefficients.push_back(-1);
} }
constraint = constraint <= storm::expressions::Expression::createDoubleLiteral(0);
solver.addConstraint("SchedulerCuts" + std::to_string(numberOfConstraintsCreated), variables, coefficients, storm::solver::LpSolver::LESS_EQUAL, 0); solver.addConstraint("SchedulerCuts" + std::to_string(numberOfConstraintsCreated), constraint);
++numberOfConstraintsCreated; ++numberOfConstraintsCreated;
} }
// Assert that at least one initial state selects at least one action. // Assert that at least one initial state selects at least one action.
variables.clear(); storm::expressions::Expression constraint = storm::expressions::Expression::createDoubleLiteral(0);
coefficients.clear();
for (auto initialState : labeledMdp.getLabeledStates("init")) { for (auto initialState : labeledMdp.getLabeledStates("init")) {
for (auto choiceVariableIndex : variableInformation.stateToChoiceVariablesIndexMap.at(initialState)) { for (auto const& choiceVariable : variableInformation.stateToChoiceVariablesMap.at(initialState)) {
variables.push_back(choiceVariableIndex); constraint = constraint + storm::expressions::Expression::createDoubleVariable(choiceVariable);
coefficients.push_back(1);
} }
} }
solver.addConstraint("SchedulerCuts" + std::to_string(numberOfConstraintsCreated), variables, coefficients, storm::solver::LpSolver::GREATER_EQUAL, 1); constraint = constraint >= storm::expressions::Expression::createDoubleLiteral(1);
solver.addConstraint("SchedulerCuts" + std::to_string(numberOfConstraintsCreated), constraint);
++numberOfConstraintsCreated; ++numberOfConstraintsCreated;
// Add constraints that ensure at least one choice is selected that targets a psi state. // Add constraints that ensure at least one choice is selected that targets a psi state.
variables.clear(); constraint = storm::expressions::Expression::createDoubleLiteral(0);
coefficients.clear();
std::unordered_set<uint_fast64_t> predecessors; std::unordered_set<uint_fast64_t> predecessors;
for (auto psiState : psiStates) { for (auto psiState : psiStates) {
// Compute the set of predecessors. // Compute the set of predecessors.
for (auto const& predecessorEntry : backwardTransitions.getRow(psiState)) { for (auto const& predecessorEntry : backwardTransitions.getRow(psiState)) {
if (psiState != predecessorEntry.first) { if (psiState != predecessorEntry.getColumn()) {
predecessors.insert(predecessorEntry.first); predecessors.insert(predecessorEntry.getColumn());
} }
} }
} }
@ -794,13 +776,13 @@ namespace storm {
continue; continue;
} }
std::list<uint_fast64_t>::const_iterator choiceVariableIndicesIterator = variableInformation.stateToChoiceVariablesIndexMap.at(predecessor).begin(); std::list<std::string>::const_iterator choiceVariableIterator = variableInformation.stateToChoiceVariablesMap.at(predecessor).begin();
for (auto relevantChoice : choiceInformation.relevantChoicesForRelevantStates.at(predecessor)) { for (auto relevantChoice : choiceInformation.relevantChoicesForRelevantStates.at(predecessor)) {
bool choiceTargetsPsiState = false; bool choiceTargetsPsiState = false;
// Check if the current choice targets the current state. // Check if the current choice targets the current state.
for (auto const& successorEntry : labeledMdp.getTransitionMatrix().getRow(relevantChoice)) { for (auto const& successorEntry : labeledMdp.getTransitionMatrix().getRow(relevantChoice)) {
if (psiStates.get(successorEntry.first)) { if (psiStates.get(successorEntry.getColumn())) {
choiceTargetsPsiState = true; choiceTargetsPsiState = true;
break; break;
} }
@ -808,14 +790,14 @@ namespace storm {
// If it does, we can add the choice to the sum. // If it does, we can add the choice to the sum.
if (choiceTargetsPsiState) { if (choiceTargetsPsiState) {
variables.push_back(*choiceVariableIndicesIterator); constraint = constraint + storm::expressions::Expression::createDoubleVariable(*choiceVariableIterator);
coefficients.push_back(1);
} }
++choiceVariableIndicesIterator; ++choiceVariableIterator;
} }
} }
constraint = constraint >= storm::expressions::Expression::createDoubleLiteral(1);
solver.addConstraint("SchedulerCuts" + std::to_string(numberOfConstraintsCreated), variables, coefficients, storm::solver::LpSolver::GREATER_EQUAL, 1); solver.addConstraint("SchedulerCuts" + std::to_string(numberOfConstraintsCreated), constraint);
++numberOfConstraintsCreated; ++numberOfConstraintsCreated;
return numberOfConstraintsCreated; return numberOfConstraintsCreated;
@ -872,6 +854,9 @@ namespace storm {
LOG4CPLUS_DEBUG(logger, "Asserted scheduler cuts."); LOG4CPLUS_DEBUG(logger, "Asserted scheduler cuts.");
} }
// Finally, we can tell the solver to incorporate the latest changes.
solver.update();
LOG4CPLUS_INFO(logger, "Successfully created " << numberOfConstraints << " MILP constraints."); LOG4CPLUS_INFO(logger, "Successfully created " << numberOfConstraints << " MILP constraints.");
} }
@ -884,7 +869,7 @@ namespace storm {
static boost::container::flat_set<uint_fast64_t> getUsedLabelsInSolution(storm::solver::LpSolver const& solver, VariableInformation const& variableInformation) { static boost::container::flat_set<uint_fast64_t> getUsedLabelsInSolution(storm::solver::LpSolver const& solver, VariableInformation const& variableInformation) {
boost::container::flat_set<uint_fast64_t> result; boost::container::flat_set<uint_fast64_t> result;
for (auto labelVariablePair : variableInformation.labelToVariableIndexMap) { for (auto const& labelVariablePair : variableInformation.labelToVariableMap) {
bool labelTaken = solver.getBinaryValue(labelVariablePair.second); bool labelTaken = solver.getBinaryValue(labelVariablePair.second);
if (labelTaken) { if (labelTaken) {
@ -908,10 +893,10 @@ namespace storm {
std::map<uint_fast64_t, uint_fast64_t> result; std::map<uint_fast64_t, uint_fast64_t> result;
for (auto state : stateInformation.relevantStates) { for (auto state : stateInformation.relevantStates) {
std::list<uint_fast64_t>::const_iterator choiceVariableIndicesIterator = variableInformation.stateToChoiceVariablesIndexMap.at(state).begin(); std::list<std::string>::const_iterator choiceVariableIterator = variableInformation.stateToChoiceVariablesIndexMap.at(state).begin();
for (auto choice : choiceInformation.relevantChoicesForRelevantStates.at(state)) { for (auto choice : choiceInformation.relevantChoicesForRelevantStates.at(state)) {
bool choiceTaken = solver.getBinaryValue(*choiceVariableIndicesIterator); bool choiceTaken = solver.getBinaryValue(*choiceVariableIterator);
++choiceVariableIndicesIterator; ++choiceVariableIterator;
if (choiceTaken) { if (choiceTaken) {
result.emplace_hint(result.end(), state, choice); result.emplace_hint(result.end(), state, choice);
} }
@ -930,20 +915,20 @@ namespace storm {
*/ */
static std::pair<uint_fast64_t, double> getReachabilityProbability(storm::solver::LpSolver const& solver, storm::models::Mdp<T> const& labeledMdp, VariableInformation const& variableInformation) { static std::pair<uint_fast64_t, double> getReachabilityProbability(storm::solver::LpSolver const& solver, storm::models::Mdp<T> const& labeledMdp, VariableInformation const& variableInformation) {
uint_fast64_t selectedInitialState = 0; uint_fast64_t selectedInitialState = 0;
for (auto initialStateVariableIndexPair : variableInformation.initialStateToChoiceVariableIndexMap) { for (auto const& initialStateVariablePair : variableInformation.initialStateToChoiceVariableMap) {
bool initialStateChosen = solver.getBinaryValue(initialStateVariableIndexPair.second); bool initialStateChosen = solver.getBinaryValue(initialStateVariablePair.second);
if (initialStateChosen) { if (initialStateChosen) {
selectedInitialState = initialStateVariableIndexPair.first; selectedInitialState = initialStateVariablePair.first;
break; break;
} }
} }
double reachabilityProbability = solver.getContinuousValue(variableInformation.virtualInitialStateVariableIndex); double reachabilityProbability = solver.getContinuousValue(variableInformation.virtualInitialStateVariable);
return std::make_pair(selectedInitialState, reachabilityProbability); return std::make_pair(selectedInitialState, reachabilityProbability);
} }
public: public:
static boost::container::flat_set<uint_fast64_t> getMinimalLabelSet(storm::models::Mdp<T> const& labeledMdp, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, double probabilityThreshold, bool strictBound, bool checkThresholdFeasible = false, bool includeSchedulerCuts = false) { static boost::container::flat_set<uint_fast64_t> getMinimalLabelSet(storm::models::Mdp<T> const& labeledMdp, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, double probabilityThreshold, bool strictBound, bool checkThresholdFeasible = false, bool includeSchedulerCuts = false) {
// (0) Check whether the MDP is indeed labeled. // (0) Check whether the MDP is indeed labeled.
if (!labeledMdp.hasChoiceLabeling()) { if (!labeledMdp.hasChoiceLabeling()) {

144
src/counterexamples/PathBasedSubsystemGenerator.h

@ -69,31 +69,31 @@ public:
for(auto const& trans : transMat.getRow(init)) { for(auto const& trans : transMat.getRow(init)) {
//save transition only if it's no 'virtual transition of prob 0 and it doesn't go from init state to init state. //save transition only if it's no 'virtual transition of prob 0 and it doesn't go from init state to init state.
if(trans.second != (T) 0 && !subSysStates.get(trans.first)) { if(trans.getValue() != (T) 0 && !subSysStates.get(trans.getColumn())) {
//new state? //new state?
if(distances[trans.first].second == (T) -1) { if(distances[trans.getColumn()].second == (T) -1) {
distances[trans.first].first = init; distances[trans.getColumn()].first = init;
distances[trans.first].second = trans.second; distances[trans.getColumn()].second = trans.getValue();
activeSet.insert(std::pair<uint_fast64_t, T>(trans.first, distances[trans.first].second)); activeSet.insert(std::pair<uint_fast64_t, T>(trans.getColumn(), distances[trans.getColumn()].second));
} }
else if(distances[trans.first].second < trans.second){ else if(distances[trans.getColumn()].second < trans.getValue()){
//This state has already been discovered //This state has already been discovered
//And the distance can be improved by using this transition. //And the distance can be improved by using this transition.
//find state in set, remove it, reenter it with new and correct values. //find state in set, remove it, reenter it with new and correct values.
auto range = activeSet.equal_range(std::pair<uint_fast64_t, T>(trans.first, distances[trans.first].second)); auto range = activeSet.equal_range(std::pair<uint_fast64_t, T>(trans.getColumn(), distances[trans.getColumn()].second));
for(;range.first != range.second; range.first++) { for(;range.first != range.second; range.first++) {
if(trans.first == range.first->first) { if(trans.getColumn() == range.first->first) {
activeSet.erase(range.first); activeSet.erase(range.first);
break; break;
} }
} }
distances[trans.first].first = init; distances[trans.getColumn()].first = init;
distances[trans.first].second = trans.second; distances[trans.getColumn()].second = trans.getValue();
activeSet.insert(std::pair<uint_fast64_t, T>(trans.first, trans.second)); activeSet.insert(std::pair<uint_fast64_t, T>(trans.getColumn(), trans.getValue()));
} }
} }
} }
@ -115,36 +115,36 @@ public:
// Look at all neighbors // Look at all neighbors
for(auto const& trans : transMat.getRow(activeState.first)) { for(auto const& trans : transMat.getRow(activeState.first)) {
// Only consider the transition if it's not virtual // Only consider the transition if it's not virtual
if(trans.second != (T) 0) { if(trans.getValue() != (T) 0) {
T distance = activeState.second * trans.second; T distance = activeState.second * trans.getValue();
//not discovered or initial terminal state //not discovered or initial terminal state
if(distances[trans.first].second == (T)-1) { if(distances[trans.getColumn()].second == (T)-1) {
//New state discovered -> save it //New state discovered -> save it
distances[trans.first].first = activeState.first; distances[trans.getColumn()].first = activeState.first;
distances[trans.first].second = distance; distances[trans.getColumn()].second = distance;
// push newly discovered state into activeSet // push newly discovered state into activeSet
activeSet.insert(std::pair<uint_fast64_t, T>(trans.first, distance)); activeSet.insert(std::pair<uint_fast64_t, T>(trans.getColumn(), distance));
} }
else if(distances[trans.first].second < distance ){ else if(distances[trans.getColumn()].second < distance) {
//This state has already been discovered //This state has already been discovered
//And the distance can be improved by using this transition. //And the distance can be improved by using this transition.
//find state in set, remove it, reenter it with new and correct values. //find state in set, remove it, reenter it with new and correct values.
auto range = activeSet.equal_range(std::pair<uint_fast64_t, T>(trans.first, distances[trans.first].second)); auto range = activeSet.equal_range(std::pair<uint_fast64_t, T>(trans.getColumn(), distances[trans.getColumn()].second));
for(;range.first != range.second; range.first++) { for(;range.first != range.second; range.first++) {
if(trans.first == range.first->first) { if(trans.getColumn() == range.first->first) {
activeSet.erase(range.first); activeSet.erase(range.first);
break; break;
} }
} }
distances[trans.first].first = activeState.first; distances[trans.getColumn()].first = activeState.first;
distances[trans.first].second = distance; distances[trans.getColumn()].second = distance;
activeSet.insert(std::pair<uint_fast64_t, T>(trans.first, distance)); activeSet.insert(std::pair<uint_fast64_t, T>(trans.getColumn(), distance));
} }
} }
} }
@ -182,33 +182,33 @@ public:
for(auto const& trans : transMat.getRow(init)) { for(auto const& trans : transMat.getRow(init)) {
//save transition only if it's no 'virtual transition of prob 0 and it doesn't go from init state to init state. //save transition only if it's no 'virtual transition of prob 0 and it doesn't go from init state to init state.
if(trans.second != (T) 0 && !subSysStates.get(trans.first)) { if(trans.getValue() != (T) 0 && !subSysStates.get(trans.getColumn())) {
//new state? //new state?
if(distances[trans.first].second == (T) -1) { if(distances[trans.getColumn()].second == (T) -1) {
//for initialization of subsys -> subsys search use prob (init -> subsys state -> found state) instead of prob(subsys state -> found state) //for initialization of subsys -> subsys search use prob (init -> subsys state -> found state) instead of prob(subsys state -> found state)
distances[trans.first].first = init; distances[trans.getColumn()].first = init;
distances[trans.first].second = trans.second * (itDistances[init].second == -1 ? 1 : itDistances[init].second); distances[trans.getColumn()].second = trans.getValue() * (itDistances[init].second == -1 ? 1 : itDistances[init].second);
activeSet.insert(std::pair<uint_fast64_t, T>(trans.first, distances[trans.first].second)); activeSet.insert(std::pair<uint_fast64_t, T>(trans.getColumn(), distances[trans.getColumn()].second));
} }
else if(distances[trans.first].second < trans.second * itDistances[init].second){ else if(distances[trans.getColumn()].second < trans.getValue() * itDistances[init].second){
//This state has already been discovered //This state has already been discovered
//And the distance can be improved by using this transition. //And the distance can be improved by using this transition.
//find state in set, remove it, reenter it with new and correct values. //find state in set, remove it, reenter it with new and correct values.
auto range = activeSet.equal_range(std::pair<uint_fast64_t, T>(trans.first, distances[trans.first].second)); auto range = activeSet.equal_range(std::pair<uint_fast64_t, T>(trans.getColumn(), distances[trans.getColumn()].second));
for(;range.first != range.second; range.first++) { for(;range.first != range.second; range.first++) {
if(trans.first == range.first->first) { if(trans.getColumn() == range.first->first) {
activeSet.erase(range.first); activeSet.erase(range.first);
break; break;
} }
} }
//for initialization of subsys -> subsys search use prob (init -> subsys state -> found state) instead of prob(subsys state -> found state) //for initialization of subsys -> subsys search use prob (init -> subsys state -> found state) instead of prob(subsys state -> found state)
distances[trans.first].first = init; distances[trans.getColumn()].first = init;
distances[trans.first].second = trans.second * (itDistances[init].second == -1 ? 1 : itDistances[init].second); distances[trans.getColumn()].second = trans.getValue() * (itDistances[init].second == -1 ? 1 : itDistances[init].second);
activeSet.insert(std::pair<uint_fast64_t, T>(trans.first, trans.second)); activeSet.insert(std::pair<uint_fast64_t, T>(trans.getColumn(), trans.getValue()));
} }
} }
} }
@ -225,7 +225,7 @@ public:
activeSet.erase(--activeSet.end()); activeSet.erase(--activeSet.end());
// Always stop at first target/terminal state // Always stop at first target/terminal state
//if(terminalStates.get(activeState.first) || subSysStates.get(activeState.first)) break; //if(terminalStates.get(activeState.getColumn()) || subSysStates.get(activeState.getColumn())) break;
// If this is an initial state, do not consider its outgoing transitions, since all relevant ones have already been considered // If this is an initial state, do not consider its outgoing transitions, since all relevant ones have already been considered
// Same goes for forbidden states since they may not be used on a path, except as last node. // Same goes for forbidden states since they may not be used on a path, except as last node.
@ -233,36 +233,36 @@ public:
// Look at all neighbors // Look at all neighbors
for(auto const& trans : transMat.getRow(activeState.first)) { for(auto const& trans : transMat.getRow(activeState.first)) {
// Only consider the transition if it's not virtual // Only consider the transition if it's not virtual
if(trans.second != (T) 0) { if(trans.getValue() != (T) 0) {
T distance = activeState.second * trans.second; T distance = activeState.second * trans.getValue();
//not discovered or initial terminal state //not discovered or initial terminal state
if(distances[trans.first].second == (T)-1) { if(distances[trans.getColumn()].second == (T)-1) {
//New state discovered -> save it //New state discovered -> save it
distances[trans.first].first = activeState.first; distances[trans.getColumn()].first = activeState.first;
distances[trans.first].second = distance; distances[trans.getColumn()].second = distance;
// push newly discovered state into activeSet // push newly discovered state into activeSet
activeSet.insert(std::pair<uint_fast64_t, T>(trans.first, distance)); activeSet.insert(std::pair<uint_fast64_t, T>(trans.getColumn(), distance));
} }
else if(distances[trans.first].second < distance ){ else if(distances[trans.getColumn()].second < distance) {
//This state has already been discovered //This state has already been discovered
//And the distance can be improved by using this transition. //And the distance can be improved by using this transition.
//find state in set, remove it, reenter it with new and correct values. //find state in set, remove it, reenter it with new and correct values.
auto range = activeSet.equal_range(std::pair<uint_fast64_t, T>(trans.first, distances[trans.first].second)); auto range = activeSet.equal_range(std::pair<uint_fast64_t, T>(trans.getColumn(), distances[trans.getColumn()].second));
for(;range.first != range.second; range.first++) { for(;range.first != range.second; range.first++) {
if(trans.first == range.first->first) { if(trans.getColumn() == range.first->first) {
activeSet.erase(range.first); activeSet.erase(range.first);
break; break;
} }
} }
distances[trans.first].first = activeState.first; distances[trans.getColumn()].first = activeState.first;
distances[trans.first].second = distance; distances[trans.getColumn()].second = distance;
activeSet.insert(std::pair<uint_fast64_t, T>(trans.first, distance)); activeSet.insert(std::pair<uint_fast64_t, T>(trans.getColumn(), distance));
} }
} }
} }
@ -292,8 +292,8 @@ public:
// if there is a terminal state that is an initial state then prob == 1 and return // if there is a terminal state that is an initial state then prob == 1 and return
if(initStates.get(*target)){ if(initStates.get(*target)){
distances[*target].first = *target; distances[*target].getColumn() = *target;
distances[*target].second = (T) 1; distances[*target].getValue() = (T) 1;
return; return;
} }
@ -302,19 +302,19 @@ public:
//only use if allowed and not in subsys and not terminal //only use if allowed and not in subsys and not terminal
if(allowedStates.get(*iter) && !subSysStates.get(*iter) && !terminalStates.get(*iter)) { if(allowedStates.get(*iter) && !subSysStates.get(*iter) && !terminalStates.get(*iter)) {
//new state? //new state?
if(distances[*iter].second == (T) -1) { if(distances[*iter].getValue() == (T) -1) {
// save as discovered and push into active set // save as discovered and push into active set
distances[*iter].first = *target; //successor distances[*iter].getColumn() = *target; //successor
distances[*iter].second = transMat.getValue(*iter, *target); //prob of shortest path distances[*iter].getValue() = transMat.getValue(*iter, *target); //prob of shortest path
activeSet.insert(std::pair<uint_fast64_t, T>(*iter, probabilities[*iter])); //prob of reaching some terminal state from pred. activeSet.insert(std::pair<uint_fast64_t, T>(*iter, probabilities[*iter])); //prob of reaching some terminal state from pred.
} }
else { else {
// state was already discovered // state was already discovered
// is this the better transition? // is this the better transition?
if(distances[*iter].second > transMat.getValue(*iter, *target)) { if(distances[*iter].getValue() > transMat.getValue(*iter, *target)) {
distances[*iter].first = *target; distances[*iter].getColumn() = *target;
distances[*iter].second = transMat.getValue(*iter, *target); distances[*iter].getValue() = transMat.getValue(*iter, *target);
} }
} }
} }
@ -328,19 +328,19 @@ public:
//only use if allowed and not in subsys and not terminal //only use if allowed and not in subsys and not terminal
if(allowedStates.get(*iter) && !subSysStates.get(*iter) && !terminalStates.get(*iter)) { if(allowedStates.get(*iter) && !subSysStates.get(*iter) && !terminalStates.get(*iter)) {
//new state? //new state?
if(distances[*iter].second == (T) -1) { if(distances[*iter].getValue() == (T) -1) {
// save as discovered and push into active set // save as discovered and push into active set
distances[*iter].first = *sysState; //successor distances[*iter].getColumn() = *sysState; //successor
distances[*iter].second = transMat.getValue(*iter, *sysState); //prob of shortest path distances[*iter].getValue() = transMat.getValue(*iter, *sysState); //prob of shortest path
activeSet.insert(std::pair<uint_fast64_t, T>(*iter, probabilities[*iter])); //prob of reaching some terminal state from pred. activeSet.insert(std::pair<uint_fast64_t, T>(*iter, probabilities[*iter])); //prob of reaching some terminal state from pred.
} }
else { else {
// state was already discovered // state was already discovered
// is this the better transition? // is this the better transition?
if(distances[*iter].second > transMat.getValue(*iter, *sysState)) { if(distances[*iter].getValue() > transMat.getValue(*iter, *sysState)) {
distances[*iter].first = *sysState; distances[*iter].getColumn() = *sysState;
distances[*iter].second = transMat.getValue(*iter, *sysState); distances[*iter].getValue() = transMat.getValue(*iter, *sysState);
} }
} }
} }
@ -355,7 +355,7 @@ public:
while(!activeSet.empty()) { while(!activeSet.empty()) {
// copy here since using a reference leads to segfault // copy here since using a reference leads to segfault
state = *(--activeSet.end()); state = *(--activeSet.end());
activeState = state.first; activeState = state.getColumn();
activeSet.erase(--activeSet.end()); activeSet.erase(--activeSet.end());
//stop on the first subsys/init state //stop on the first subsys/init state
@ -368,19 +368,19 @@ public:
//only if transition is not "virtual" and no selfloop //only if transition is not "virtual" and no selfloop
if(*iter != activeState && transMat.getValue(*iter, activeState) != (T) 0) { if(*iter != activeState && transMat.getValue(*iter, activeState) != (T) 0) {
//new state? //new state?
if(distances[*iter].second == (T) -1) { if(distances[*iter].getValue() == (T) -1) {
// save as discovered and push into active set // save as discovered and push into active set
distances[*iter].first = activeState; distances[*iter].getColumn() = activeState;
distances[*iter].second = transMat.getValue(*iter, activeState) * distances[activeState].second; distances[*iter].getValue() = transMat.getValue(*iter, activeState) * distances[activeState].getValue();
activeSet.insert(std::pair<uint_fast64_t, T>(*iter, probabilities[*iter])); activeSet.insert(std::pair<uint_fast64_t, T>(*iter, probabilities[*iter]));
} }
else { else {
// state was already discovered // state was already discovered
// is this the better transition? // is this the better transition?
if(distances[*iter].second < transMat.getValue(*iter, activeState) * distances[activeState].second) { if(distances[*iter].getValue() < transMat.getValue(*iter, activeState) * distances[activeState].getValue()) {
distances[*iter].first = activeState; distances[*iter].getColumn() = activeState;
distances[*iter].second = transMat.getValue(*iter, activeState) * distances[activeState].second; distances[*iter].getValue() = transMat.getValue(*iter, activeState) * distances[activeState].getValue();
} }
} }
} }
@ -389,15 +389,15 @@ public:
} }
//get path probability //get path probability
probability = distances[activeState].second; probability = distances[activeState].getValue();
if(probability == (T) -1) probability = 1; if(probability == (T) -1) probability = 1;
// iterate over the successors until reaching the end of the finite path // iterate over the successors until reaching the end of the finite path
shortestPath.push_back(activeState); shortestPath.push_back(activeState);
activeState = distances[activeState].first; activeState = distances[activeState].getColumn();
while(!terminalStates.get(activeState) && !subSysStates.get(activeState)) { while(!terminalStates.get(activeState) && !subSysStates.get(activeState)) {
shortestPath.push_back(activeState); shortestPath.push_back(activeState);
activeState = distances[activeState].first; activeState = distances[activeState].getColumn();
} }
shortestPath.push_back(activeState); shortestPath.push_back(activeState);
} }
@ -482,7 +482,7 @@ public:
shortestPath.push_back(bestIndex); shortestPath.push_back(bestIndex);
//At last compensate for the distance between init and source state //At last compensate for the distance between init and source state
probability = itSearch ? probability : probability / itDistances[bestIndex].second; probability = itSearch ? probability : probability / itDistances[bestIndex].first;
} }
private: private:

2
src/modelchecker/csl/SparseMarkovAutomatonCslModelChecker.cpp

@ -5,4 +5,4 @@ bool SparseMarkovAutomatonCslModelCheckerOptionsRegistered = storm::settings::Se
instance->addOption(storm::settings::OptionBuilder("GmmxxLinearEquationSolver", "digiprecision", "", "Precision used for iterative solving of linear equation systems").addArgument(storm::settings::ArgumentBuilder::createDoubleArgument("precision value", "Precision").setDefaultValueDouble(1e-4).addValidationFunctionDouble(storm::settings::ArgumentValidators::doubleRangeValidatorExcluding(0.0, 1.0)).build()).build()); instance->addOption(storm::settings::OptionBuilder("GmmxxLinearEquationSolver", "digiprecision", "", "Precision used for iterative solving of linear equation systems").addArgument(storm::settings::ArgumentBuilder::createDoubleArgument("precision value", "Precision").setDefaultValueDouble(1e-4).addValidationFunctionDouble(storm::settings::ArgumentValidators::doubleRangeValidatorExcluding(0.0, 1.0)).build()).build());
return true; return true;
}); });

78
src/modelchecker/csl/SparseMarkovAutomatonCslModelChecker.h

@ -103,10 +103,10 @@ namespace storm {
for (auto state : markovianNonGoalStates) { for (auto state : markovianNonGoalStates) {
for (auto& element : aMarkovian.getRow(rowIndex)) { for (auto& element : aMarkovian.getRow(rowIndex)) {
ValueType eTerm = std::exp(-exitRates[state] * delta); ValueType eTerm = std::exp(-exitRates[state] * delta);
if (element.first == rowIndex) { if (element.getColumn() == rowIndex) {
element.second = (storm::utility::constantOne<ValueType>() - eTerm) * element.second + eTerm; element.getValue() = (storm::utility::constantOne<ValueType>() - eTerm) * element.getValue() + eTerm;
} else { } else {
element.second = (storm::utility::constantOne<ValueType>() - eTerm) * element.second; element.getValue() = (storm::utility::constantOne<ValueType>() - eTerm) * element.getValue();
} }
} }
++rowIndex; ++rowIndex;
@ -116,7 +116,7 @@ namespace storm {
rowIndex = 0; rowIndex = 0;
for (auto state : markovianNonGoalStates) { for (auto state : markovianNonGoalStates) {
for (auto& element : aMarkovianToProbabilistic.getRow(rowIndex)) { for (auto& element : aMarkovianToProbabilistic.getRow(rowIndex)) {
element.second = (1 - std::exp(-exitRates[state] * delta)) * element.second; element.getValue() = (1 - std::exp(-exitRates[state] * delta)) * element.getValue();
} }
++rowIndex; ++rowIndex;
} }
@ -133,8 +133,8 @@ namespace storm {
bMarkovianFixed.push_back(storm::utility::constantZero<ValueType>()); bMarkovianFixed.push_back(storm::utility::constantZero<ValueType>());
for (auto& element : transitionMatrix.getRowGroup(state)) { for (auto& element : transitionMatrix.getRowGroup(state)) {
if (goalStates.get(element.first)) { if (goalStates.get(element.getColumn())) {
bMarkovianFixed.back() += (1 - std::exp(-exitRates[state] * delta)) * element.second; bMarkovianFixed.back() += (1 - std::exp(-exitRates[state] * delta)) * element.getValue();
} }
} }
} }
@ -314,13 +314,13 @@ namespace storm {
b.push_back(storm::utility::constantZero<ValueType>()); b.push_back(storm::utility::constantZero<ValueType>());
for (auto element : transitionMatrix.getRow(choice)) { for (auto element : transitionMatrix.getRow(choice)) {
if (statesNotContainedInAnyMec.get(element.first)) { if (statesNotContainedInAnyMec.get(element.getColumn())) {
// If the target state is not contained in an MEC, we can copy over the entry. // If the target state is not contained in an MEC, we can copy over the entry.
sspMatrixBuilder.addNextValue(currentChoice, statesNotInMecsBeforeIndex[element.first], element.second); sspMatrixBuilder.addNextValue(currentChoice, statesNotInMecsBeforeIndex[element.getColumn()], element.getValue());
} else { } else {
// If the target state is contained in MEC i, we need to add the probability to the corresponding field in the vector // If the target state is contained in MEC i, we need to add the probability to the corresponding field in the vector
// so that we are able to write the cumulative probability to the MEC into the matrix. // so that we are able to write the cumulative probability to the MEC into the matrix.
auxiliaryStateToProbabilityMap[stateToMecIndexMap[element.first]] += element.second; auxiliaryStateToProbabilityMap[stateToMecIndexMap[element.getColumn()]] += element.getValue();
} }
} }
@ -350,13 +350,13 @@ namespace storm {
b.push_back(storm::utility::constantZero<ValueType>()); b.push_back(storm::utility::constantZero<ValueType>());
for (auto element : transitionMatrix.getRow(choice)) { for (auto element : transitionMatrix.getRow(choice)) {
if (statesNotContainedInAnyMec.get(element.first)) { if (statesNotContainedInAnyMec.get(element.getColumn())) {
// If the target state is not contained in an MEC, we can copy over the entry. // If the target state is not contained in an MEC, we can copy over the entry.
sspMatrixBuilder.addNextValue(currentChoice, statesNotInMecsBeforeIndex[element.first], element.second); sspMatrixBuilder.addNextValue(currentChoice, statesNotInMecsBeforeIndex[element.getColumn()], element.getValue());
} else { } else {
// If the target state is contained in MEC i, we need to add the probability to the corresponding field in the vector // If the target state is contained in MEC i, we need to add the probability to the corresponding field in the vector
// so that we are able to write the cumulative probability to the MEC into the matrix. // so that we are able to write the cumulative probability to the MEC into the matrix.
auxiliaryStateToProbabilityMap[stateToMecIndexMap[element.first]] += element.second; auxiliaryStateToProbabilityMap[stateToMecIndexMap[element.getColumn()]] += element.getValue();
} }
} }
@ -428,61 +428,61 @@ namespace storm {
*/ */
static ValueType computeLraForMaximalEndComponent(bool min, storm::storage::SparseMatrix<ValueType> const& transitionMatrix, std::vector<uint_fast64_t> const& nondeterministicChoiceIndices, storm::storage::BitVector const& markovianStates, std::vector<ValueType> const& exitRates, storm::storage::BitVector const& goalStates, storm::storage::MaximalEndComponent const& mec, uint_fast64_t mecIndex = 0) { static ValueType computeLraForMaximalEndComponent(bool min, storm::storage::SparseMatrix<ValueType> const& transitionMatrix, std::vector<uint_fast64_t> const& nondeterministicChoiceIndices, storm::storage::BitVector const& markovianStates, std::vector<ValueType> const& exitRates, storm::storage::BitVector const& goalStates, storm::storage::MaximalEndComponent const& mec, uint_fast64_t mecIndex = 0) {
std::shared_ptr<storm::solver::LpSolver> solver = storm::utility::solver::getLpSolver("LRA for MEC"); std::shared_ptr<storm::solver::LpSolver> solver = storm::utility::solver::getLpSolver("LRA for MEC");
solver->setModelSense(min ? storm::solver::LpSolver::MAXIMIZE : storm::solver::LpSolver::MINIMIZE); solver->setModelSense(min ? storm::solver::LpSolver::ModelSense::Maximize : storm::solver::LpSolver::ModelSense::Minimize);
// First, we need to create the variables for the problem. // First, we need to create the variables for the problem.
std::map<uint_fast64_t, uint_fast64_t> stateToVariableIndexMap; std::map<uint_fast64_t, std::string> stateToVariableNameMap;
for (auto const& stateChoicesPair : mec) { for (auto const& stateChoicesPair : mec) {
stateToVariableIndexMap[stateChoicesPair.first] = solver->createContinuousVariable("x" + std::to_string(stateChoicesPair.first), storm::solver::LpSolver::UNBOUNDED, 0, 0, 0); std::string variableName = "x" + std::to_string(stateChoicesPair.first);
stateToVariableNameMap[stateChoicesPair.first] = variableName;
solver->addUnboundedContinuousVariable(variableName);
} }
uint_fast64_t lraValueVariableIndex = solver->createContinuousVariable("k", storm::solver::LpSolver::UNBOUNDED, 0, 0, 1); solver->addUnboundedContinuousVariable("k", 1);
solver->update(); solver->update();
// Now we encode the problem as constraints. // Now we encode the problem as constraints.
std::vector<uint_fast64_t> variables;
std::vector<double> coefficients;
for (auto const& stateChoicesPair : mec) { for (auto const& stateChoicesPair : mec) {
uint_fast64_t state = stateChoicesPair.first; uint_fast64_t state = stateChoicesPair.first;
// Now, based on the type of the state, create a suitable constraint. // Now, based on the type of the state, create a suitable constraint.
if (markovianStates.get(state)) { if (markovianStates.get(state)) {
variables.clear(); storm::expressions::Expression constraint = storm::expressions::Expression::createDoubleVariable(stateToVariableNameMap.at(state));
coefficients.clear();
variables.push_back(stateToVariableIndexMap.at(state));
coefficients.push_back(1);
for (auto element : transitionMatrix.getRow(nondeterministicChoiceIndices[state])) { for (auto element : transitionMatrix.getRow(nondeterministicChoiceIndices[state])) {
variables.push_back(stateToVariableIndexMap.at(element.first)); constraint = constraint - storm::expressions::Expression::createDoubleVariable(stateToVariableNameMap.at(element.getColumn()));
coefficients.push_back(-element.second);
} }
variables.push_back(lraValueVariableIndex); constraint = constraint + storm::expressions::Expression::createDoubleLiteral(storm::utility::constantOne<ValueType>() / exitRates[state]) * storm::expressions::Expression::createDoubleVariable("k");
coefficients.push_back(storm::utility::constantOne<ValueType>() / exitRates[state]); storm::expressions::Expression rightHandSide = goalStates.get(state) ? storm::expressions::Expression::createDoubleLiteral(storm::utility::constantOne<ValueType>() / exitRates[state]) : storm::expressions::Expression::createDoubleLiteral(storm::utility::constantZero<ValueType>());
if (min) {
solver->addConstraint("state" + std::to_string(state), variables, coefficients, min ? storm::solver::LpSolver::LESS_EQUAL : storm::solver::LpSolver::GREATER_EQUAL, goalStates.get(state) ? storm::utility::constantOne<ValueType>() / exitRates[state] : storm::utility::constantZero<ValueType>()); constraint = constraint <= rightHandSide;
} else {
constraint = constraint >= rightHandSide;
}
solver->addConstraint("state" + std::to_string(state), constraint);
} else { } else {
// For probabilistic states, we want to add the constraint x_s <= sum P(s, a, s') * x_s' where a is the current action // For probabilistic states, we want to add the constraint x_s <= sum P(s, a, s') * x_s' where a is the current action
// and the sum ranges over all states s'. // and the sum ranges over all states s'.
for (auto choice : stateChoicesPair.second) { for (auto choice : stateChoicesPair.second) {
variables.clear(); storm::expressions::Expression constraint = storm::expressions::Expression::createDoubleVariable(stateToVariableNameMap.at(state));
coefficients.clear();
variables.push_back(stateToVariableIndexMap.at(state));
coefficients.push_back(1);
for (auto element : transitionMatrix.getRow(choice)) { for (auto element : transitionMatrix.getRow(choice)) {
variables.push_back(stateToVariableIndexMap.at(element.first)); constraint = constraint - storm::expressions::Expression::createDoubleVariable(stateToVariableNameMap.at(element.getColumn()));
coefficients.push_back(-element.second);
} }
solver->addConstraint("state" + std::to_string(state), variables, coefficients, min ? storm::solver::LpSolver::LESS_EQUAL : storm::solver::LpSolver::GREATER_EQUAL, storm::utility::constantZero<ValueType>()); storm::expressions::Expression rightHandSide = storm::expressions::Expression::createDoubleLiteral(storm::utility::constantZero<ValueType>());
if (min) {
constraint = constraint <= rightHandSide;
} else {
constraint = constraint >= rightHandSide;
}
solver->addConstraint("state" + std::to_string(state), constraint);
} }
} }
} }
solver->optimize(); solver->optimize();
return solver->getContinuousValue(lraValueVariableIndex); return solver->getContinuousValue("k");
} }
/*! /*!

6
src/models/AbstractDeterministicModel.h

@ -87,9 +87,9 @@ class AbstractDeterministicModel: public AbstractModel<T> {
for (uint_fast64_t i = 0; i < this->transitionMatrix.getRowCount(); ++i, ++rowIt) { for (uint_fast64_t i = 0; i < this->transitionMatrix.getRowCount(); ++i, ++rowIt) {
typename storm::storage::SparseMatrix<T>::const_rows row = this->transitionMatrix.getRow(i); typename storm::storage::SparseMatrix<T>::const_rows row = this->transitionMatrix.getRow(i);
for (auto const& transition : row) { for (auto const& transition : row) {
if (transition.second != storm::utility::constantZero<T>()) { if (transition.getValue() != storm::utility::constantZero<T>()) {
if (subsystem == nullptr || subsystem->get(transition.first)) { if (subsystem == nullptr || subsystem->get(transition.getColumn())) {
outStream << "\t" << i << " -> " << transition.first << " [ label= \"" << transition.second << "\" ];" << std::endl; outStream << "\t" << i << " -> " << transition.getColumn() << " [ label= \"" << transition.getValue() << "\" ];" << std::endl;
} }
} }
} }

2
src/models/AbstractModel.h

@ -220,7 +220,7 @@ class AbstractModel: public std::enable_shared_from_this<AbstractModel<T>> {
* @return The number of (non-zero) transitions of the model. * @return The number of (non-zero) transitions of the model.
*/ */
virtual uint_fast64_t getNumberOfTransitions() const { virtual uint_fast64_t getNumberOfTransitions() const {
return this->getTransitionMatrix().getEntryCount(); return this->getTransitionMatrix().getNonzeroEntryCount();
} }
/*! /*!

4
src/models/AbstractNondeterministicModel.h

@ -189,8 +189,8 @@ namespace storm {
// Now draw all probabilitic arcs that belong to this nondeterminstic choice. // Now draw all probabilitic arcs that belong to this nondeterminstic choice.
for (auto const& transition : row) { for (auto const& transition : row) {
if (subsystem == nullptr || subsystem->get(transition.first)) { if (subsystem == nullptr || subsystem->get(transition.getColumn())) {
outStream << "\t\"" << state << "c" << choice << "\" -> " << transition.first << " [ label= \"" << transition.second << "\" ]"; outStream << "\t\"" << state << "c" << choice << "\" -> " << transition.getColumn() << " [ label= \"" << transition.getValue() << "\" ]";
// If we were given a scheduler to highlight, we do so now. // If we were given a scheduler to highlight, we do so now.
if (scheduler != nullptr) { if (scheduler != nullptr) {

12
src/models/Dtmc.h

@ -170,7 +170,7 @@ public:
for(uint_fast64_t row = 0; row < origMat.getRowCount(); ++row) { for(uint_fast64_t row = 0; row < origMat.getRowCount(); ++row) {
if(subSysStates.get(row)){ if(subSysStates.get(row)){
for(auto const& entry : origMat.getRow(row)) { for(auto const& entry : origMat.getRow(row)) {
if(subSysStates.get(entry.first)) { if(subSysStates.get(entry.getColumn())) {
subSysTransitionCount++; subSysTransitionCount++;
} }
} }
@ -198,10 +198,10 @@ public:
if(subSysStates.get(row)){ if(subSysStates.get(row)){
// Transfer transitions // Transfer transitions
for(auto& entry : origMat.getRow(row)) { for(auto& entry : origMat.getRow(row)) {
if(subSysStates.get(entry.first)) { if(subSysStates.get(entry.getColumn())) {
newMatBuilder.addNextValue(newRow, stateMapping[entry.first], entry.second); newMatBuilder.addNextValue(newRow, stateMapping[entry.getColumn()], entry.getValue());
} else { } else {
rest += entry.second; rest += entry.getValue();
} }
} }
@ -251,8 +251,8 @@ public:
if(subSysStates.get(row)){ if(subSysStates.get(row)){
// Transfer transition rewards // Transfer transition rewards
for(auto& entry : this->getTransitionRewardMatrix().getRow(row)) { for(auto& entry : this->getTransitionRewardMatrix().getRow(row)) {
if(subSysStates.get(entry.first)) { if(subSysStates.get(entry.getColumn())) {
newTransRewardsBuilder.addNextValue(newRow, stateMapping[entry.first], entry.second); newTransRewardsBuilder.addNextValue(newRow, stateMapping[entry.getColumn()], entry.getValue());
} }
} }

12
src/models/MarkovAutomaton.h

@ -147,7 +147,7 @@ namespace storm {
for (uint_fast64_t row = this->getTransitionMatrix().getRowGroupIndices()[state] + (this->isHybridState(state) ? 1 : 0); row < this->getTransitionMatrix().getRowGroupIndices()[state + 1]; ++row) { for (uint_fast64_t row = this->getTransitionMatrix().getRowGroupIndices()[state] + (this->isHybridState(state) ? 1 : 0); row < this->getTransitionMatrix().getRowGroupIndices()[state + 1]; ++row) {
for (auto const& entry : this->transitionMatrix.getRow(row)) { for (auto const& entry : this->transitionMatrix.getRow(row)) {
newTransitionMatrixBuilder.addNextValue(currentChoice, entry.first, entry.second); newTransitionMatrixBuilder.addNextValue(currentChoice, entry.getColumn(), entry.getValue());
} }
++currentChoice; ++currentChoice;
} }
@ -220,8 +220,8 @@ namespace storm {
// Now draw all probabilitic arcs that belong to this nondeterminstic choice. // Now draw all probabilitic arcs that belong to this nondeterminstic choice.
for (auto const& transition : row) { for (auto const& transition : row) {
if (subsystem == nullptr || subsystem->get(transition.first)) { if (subsystem == nullptr || subsystem->get(transition.getColumn())) {
outStream << "\t\"" << state << "c" << choice << "\" -> " << transition.first << " [ label= \"" << transition.second << "\" ]"; outStream << "\t\"" << state << "c" << choice << "\" -> " << transition.getColumn() << " [ label= \"" << transition.getValue() << "\" ]";
// If we were given a scheduler to highlight, we do so now. // If we were given a scheduler to highlight, we do so now.
if (scheduler != nullptr) { if (scheduler != nullptr) {
@ -237,8 +237,8 @@ namespace storm {
} else { } else {
// In this case we are emitting a Markovian choice, so draw the arrows directly to the target states. // In this case we are emitting a Markovian choice, so draw the arrows directly to the target states.
for (auto const& transition : row) { for (auto const& transition : row) {
if (subsystem == nullptr || subsystem->get(transition.first)) { if (subsystem == nullptr || subsystem->get(transition.getColumn())) {
outStream << "\t\"" << state << "\" -> " << transition.first << " [ label= \"" << transition.second << " (" << this->exitRates[state] << ")\" ]"; outStream << "\t\"" << state << "\" -> " << transition.getColumn() << " [ label= \"" << transition.getValue() << " (" << this->exitRates[state] << ")\" ]";
} }
} }
} }
@ -259,7 +259,7 @@ namespace storm {
void turnRatesToProbabilities() { void turnRatesToProbabilities() {
for (auto state : this->markovianStates) { for (auto state : this->markovianStates) {
for (auto& transition : this->transitionMatrix.getRowGroup(state)) { for (auto& transition : this->transitionMatrix.getRowGroup(state)) {
transition.second /= this->exitRates[state]; transition.getValue() /= this->exitRates[state];
} }
} }
} }

273
src/solver/GlpkLpSolver.cpp

@ -4,13 +4,12 @@
#include <iostream> #include <iostream>
#include "src/exceptions/InvalidStateException.h" #include "src/storage/expressions/LinearCoefficientVisitor.h"
#include "src/settings/Settings.h"
#include "log4cplus/logger.h"
#include "log4cplus/loggingmacros.h"
extern log4cplus::Logger logger; #include "src/settings/Settings.h"
#include "src/exceptions/ExceptionMacros.h"
#include "src/exceptions/InvalidAccessException.h"
#include "src/exceptions/InvalidStateException.h"
bool GlpkLpSolverOptionsRegistered = storm::settings::Settings::registerNewModule([] (storm::settings::Settings* instance) -> bool { bool GlpkLpSolverOptionsRegistered = storm::settings::Settings::registerNewModule([] (storm::settings::Settings* instance) -> bool {
instance->addOption(storm::settings::OptionBuilder("GlpkLpSolver", "glpkoutput", "", "If set, the glpk output will be printed to the command line.").build()); instance->addOption(storm::settings::OptionBuilder("GlpkLpSolver", "glpkoutput", "", "If set, the glpk output will be printed to the command line.").build());
@ -22,7 +21,7 @@ bool GlpkLpSolverOptionsRegistered = storm::settings::Settings::registerNewModul
namespace storm { namespace storm {
namespace solver { namespace solver {
GlpkLpSolver::GlpkLpSolver(std::string const& name, ModelSense const& modelSense) : LpSolver(modelSense), lp(nullptr), nextVariableIndex(1), nextConstraintIndex(1), modelContainsIntegerVariables(false), isInfeasibleFlag(false), isUnboundedFlag(false), rowIndices(), columnIndices(), coefficientValues() { GlpkLpSolver::GlpkLpSolver(std::string const& name, ModelSense const& modelSense) : LpSolver(modelSense), lp(nullptr), variableNameToIndexMap(), nextVariableIndex(1), nextConstraintIndex(1), modelContainsIntegerVariables(false), isInfeasibleFlag(false), isUnboundedFlag(false), rowIndices(), columnIndices(), coefficientValues() {
// Create the LP problem for glpk. // Create the LP problem for glpk.
lp = glp_create_prob(); lp = glp_create_prob();
@ -38,11 +37,11 @@ namespace storm {
coefficientValues.push_back(0); coefficientValues.push_back(0);
} }
GlpkLpSolver::GlpkLpSolver(std::string const& name) : GlpkLpSolver(name, MINIMIZE) { GlpkLpSolver::GlpkLpSolver(std::string const& name) : GlpkLpSolver(name, ModelSense::Minimize) {
// Intentionally left empty. // Intentionally left empty.
} }
GlpkLpSolver::GlpkLpSolver() : GlpkLpSolver("", MINIMIZE) { GlpkLpSolver::GlpkLpSolver() : GlpkLpSolver("", ModelSense::Minimize) {
// Intentionally left empty. // Intentionally left empty.
} }
@ -56,76 +55,120 @@ namespace storm {
glp_free_env(); glp_free_env();
} }
uint_fast64_t GlpkLpSolver::createContinuousVariable(std::string const& name, VariableType const& variableType, double lowerBound, double upperBound, double objectiveFunctionCoefficient) { void GlpkLpSolver::addBoundedContinuousVariable(std::string const& name, double lowerBound, double upperBound, double objectiveFunctionCoefficient) {
glp_add_cols(this->lp, 1); this->addVariable(name, GLP_CV, GLP_DB, lowerBound, upperBound, objectiveFunctionCoefficient);
glp_set_col_name(this->lp, nextVariableIndex, name.c_str()); }
switch (variableType) { void GlpkLpSolver::addLowerBoundedContinuousVariable(std::string const& name, double lowerBound, double objectiveFunctionCoefficient) {
case LpSolver::BOUNDED: this->addVariable(name, GLP_CV, GLP_LO, lowerBound, 0, objectiveFunctionCoefficient);
glp_set_col_bnds(lp, nextVariableIndex, GLP_DB, lowerBound, upperBound); }
break; void GlpkLpSolver::addUpperBoundedContinuousVariable(std::string const& name, double upperBound, double objectiveFunctionCoefficient) {
case LpSolver::UNBOUNDED: this->addVariable(name, GLP_CV, GLP_UP, 0, upperBound, objectiveFunctionCoefficient);
glp_set_col_bnds(lp, nextVariableIndex, GLP_FR, 0, 0);
break;
case LpSolver::UPPER_BOUND:
glp_set_col_bnds(lp, nextVariableIndex, GLP_UP, 0, upperBound);
break;
case LpSolver::LOWER_BOUND:
glp_set_col_bnds(lp, nextVariableIndex, GLP_LO, lowerBound, 0);
break;
}
glp_set_col_kind(this->lp, nextVariableIndex, GLP_CV);
glp_set_obj_coef(this->lp, nextVariableIndex, objectiveFunctionCoefficient);
++nextVariableIndex;
this->currentModelHasBeenOptimized = false;
return nextVariableIndex - 1;
} }
uint_fast64_t GlpkLpSolver::createIntegerVariable(std::string const& name, VariableType const& variableType, double lowerBound, double upperBound, double objectiveFunctionCoefficient) { void GlpkLpSolver::addUnboundedContinuousVariable(std::string const& name, double objectiveFunctionCoefficient) {
uint_fast64_t index = this->createContinuousVariable(name, variableType, lowerBound, upperBound, objectiveFunctionCoefficient); this->addVariable(name, GLP_CV, GLP_FR, 0, 0, objectiveFunctionCoefficient);
glp_set_col_kind(this->lp, index, GLP_IV); }
void GlpkLpSolver::addBoundedIntegerVariable(std::string const& name, double lowerBound, double upperBound, double objectiveFunctionCoefficient) {
this->addVariable(name, GLP_IV, GLP_DB, lowerBound, upperBound, objectiveFunctionCoefficient);
this->modelContainsIntegerVariables = true;
}
void GlpkLpSolver::addLowerBoundedIntegerVariable(std::string const& name, double lowerBound, double objectiveFunctionCoefficient) {
this->addVariable(name, GLP_IV, GLP_LO, lowerBound, 0, objectiveFunctionCoefficient);
this->modelContainsIntegerVariables = true;
}
void GlpkLpSolver::addUpperBoundedIntegerVariable(std::string const& name, double upperBound, double objectiveFunctionCoefficient) {
this->addVariable(name, GLP_IV, GLP_UP, 0, upperBound, objectiveFunctionCoefficient);
this->modelContainsIntegerVariables = true;
}
void GlpkLpSolver::addUnboundedIntegerVariable(std::string const& name, double objectiveFunctionCoefficient) {
this->addVariable(name, GLP_IV, GLP_FR, 0, 0, objectiveFunctionCoefficient);
this->modelContainsIntegerVariables = true; this->modelContainsIntegerVariables = true;
return index;
} }
uint_fast64_t GlpkLpSolver::createBinaryVariable(std::string const& name, double objectiveFunctionCoefficient) { void GlpkLpSolver::addBinaryVariable(std::string const& name, double objectiveFunctionCoefficient) {
uint_fast64_t index = this->createContinuousVariable(name, UNBOUNDED, 0, 1, objectiveFunctionCoefficient); this->addVariable(name, GLP_BV, GLP_FR, 0, 0, objectiveFunctionCoefficient);
glp_set_col_kind(this->lp, index, GLP_BV);
this->modelContainsIntegerVariables = true; this->modelContainsIntegerVariables = true;
return index; }
void GlpkLpSolver::addVariable(std::string const& name, int variableType, int boundType, double lowerBound, double upperBound, double objectiveFunctionCoefficient) {
// Check whether variable already exists.
auto nameIndexPair = this->variableNameToIndexMap.find(name);
LOG_THROW(nameIndexPair == this->variableNameToIndexMap.end(), storm::exceptions::InvalidArgumentException, "Variable '" << nameIndexPair->first << "' already exists.");
// Check for valid variable type.
LOG_ASSERT(variableType == GLP_CV || variableType == GLP_IV || variableType == GLP_BV, "Illegal type '" << variableType << "' for glpk variable.");
// Check for valid bound type.
LOG_ASSERT(boundType == GLP_FR || boundType == GLP_UP || boundType == GLP_LO || boundType == GLP_DB, "Illegal bound type for variable '" << name << "'.");
// Finally, create the actual variable.
glp_add_cols(this->lp, 1);
glp_set_col_name(this->lp, nextVariableIndex, name.c_str());
glp_set_col_bnds(lp, nextVariableIndex, boundType, lowerBound, upperBound);
glp_set_col_kind(this->lp, nextVariableIndex, variableType);
glp_set_obj_coef(this->lp, nextVariableIndex, objectiveFunctionCoefficient);
this->variableNameToIndexMap.emplace(name, this->nextVariableIndex);
++this->nextVariableIndex;
} }
void GlpkLpSolver::update() const { void GlpkLpSolver::update() const {
// Intentionally left empty. // Intentionally left empty.
} }
void GlpkLpSolver::addConstraint(std::string const& name, std::vector<uint_fast64_t> const& variables, std::vector<double> const& coefficients, BoundType const& boundType, double rightHandSideValue) { void GlpkLpSolver::addConstraint(std::string const& name, storm::expressions::Expression const& constraint) {
if (variables.size() != coefficients.size()) {
LOG4CPLUS_ERROR(logger, "Sizes of variable indices vector and coefficients vector do not match.");
throw storm::exceptions::InvalidStateException() << "Sizes of variable indices vector and coefficients vector do not match.";
}
// Add the row that will represent this constraint. // Add the row that will represent this constraint.
glp_add_rows(this->lp, 1); glp_add_rows(this->lp, 1);
glp_set_row_name(this->lp, nextConstraintIndex, name.c_str()); glp_set_row_name(this->lp, nextConstraintIndex, name.c_str());
LOG_THROW(constraint.isRelationalExpression(), storm::exceptions::InvalidArgumentException, "Illegal constraint is not a relational expression.");
LOG_THROW(constraint.getOperator() != storm::expressions::OperatorType::NotEqual, storm::exceptions::InvalidArgumentException, "Illegal constraint uses inequality operator.");
std::pair<storm::expressions::SimpleValuation, double> leftCoefficients = storm::expressions::LinearCoefficientVisitor().getLinearCoefficients(constraint.getOperand(0));
std::pair<storm::expressions::SimpleValuation, double> rightCoefficients = storm::expressions::LinearCoefficientVisitor().getLinearCoefficients(constraint.getOperand(1));
for (auto const& identifier : rightCoefficients.first.getDoubleIdentifiers()) {
if (leftCoefficients.first.containsDoubleIdentifier(identifier)) {
leftCoefficients.first.setDoubleValue(identifier, leftCoefficients.first.getDoubleValue(identifier) - rightCoefficients.first.getDoubleValue(identifier));
} else {
leftCoefficients.first.addDoubleIdentifier(identifier, -rightCoefficients.first.getDoubleValue(identifier));
}
}
rightCoefficients.second -= leftCoefficients.second;
// Now we need to transform the coefficients to the vector representation.
std::vector<int> variables;
std::vector<double> coefficients;
for (auto const& identifier : leftCoefficients.first.getDoubleIdentifiers()) {
auto identifierIndexPair = this->variableNameToIndexMap.find(identifier);
LOG_THROW(identifierIndexPair != this->variableNameToIndexMap.end(), storm::exceptions::InvalidArgumentException, "Constraint contains illegal identifier '" << identifier << "'.");
variables.push_back(identifierIndexPair->second);
coefficients.push_back(leftCoefficients.first.getDoubleValue(identifier));
}
// Determine the type of the constraint and add it properly. // Determine the type of the constraint and add it properly.
switch (boundType) { switch (constraint.getOperator()) {
case LESS: case storm::expressions::OperatorType::Less:
glp_set_row_bnds(this->lp, nextConstraintIndex, GLP_UP, 0, rightHandSideValue - storm::settings::Settings::getInstance()->getOptionByLongName("precision").getArgument(0).getValueAsDouble()); glp_set_row_bnds(this->lp, nextConstraintIndex, GLP_UP, 0, rightCoefficients.second - storm::settings::Settings::getInstance()->getOptionByLongName("glpkinttol").getArgument(0).getValueAsDouble());
break; break;
case LESS_EQUAL: case storm::expressions::OperatorType::LessOrEqual:
glp_set_row_bnds(this->lp, nextConstraintIndex, GLP_UP, 0, rightHandSideValue); glp_set_row_bnds(this->lp, nextConstraintIndex, GLP_UP, 0, rightCoefficients.second);
break; break;
case GREATER: case storm::expressions::OperatorType::Greater:
glp_set_row_bnds(this->lp, nextConstraintIndex, GLP_LO, rightHandSideValue + storm::settings::Settings::getInstance()->getOptionByLongName("precision").getArgument(0).getValueAsDouble(), 0); glp_set_row_bnds(this->lp, nextConstraintIndex, GLP_LO, rightCoefficients.second + storm::settings::Settings::getInstance()->getOptionByLongName("glpkinttol").getArgument(0).getValueAsDouble(), 0);
break; break;
case GREATER_EQUAL: case storm::expressions::OperatorType::GreaterOrEqual:
glp_set_row_bnds(this->lp, nextConstraintIndex, GLP_LO, rightHandSideValue, 0); glp_set_row_bnds(this->lp, nextConstraintIndex, GLP_LO, rightCoefficients.second, 0);
break; break;
case EQUAL: case storm::expressions::OperatorType::Equal:
glp_set_row_bnds(this->lp, nextConstraintIndex, GLP_FX, rightHandSideValue, rightHandSideValue); glp_set_row_bnds(this->lp, nextConstraintIndex, GLP_FX, rightCoefficients.second, rightCoefficients.second);
break; break;
default:
LOG_ASSERT(false, "Illegal operator in LP solver constraint.");
} }
// Record the variables and coefficients in the coefficient matrix. // Record the variables and coefficients in the coefficient matrix.
@ -143,13 +186,13 @@ namespace storm {
this->isUnboundedFlag = false; this->isUnboundedFlag = false;
// Start by setting the model sense. // Start by setting the model sense.
glp_set_obj_dir(this->lp, this->getModelSense() == MINIMIZE ? GLP_MIN : GLP_MAX); glp_set_obj_dir(this->lp, this->getModelSense() == LpSolver::ModelSense::Minimize ? GLP_MIN : GLP_MAX);
glp_load_matrix(this->lp, rowIndices.size() - 1, rowIndices.data(), columnIndices.data(), coefficientValues.data()); glp_load_matrix(this->lp, rowIndices.size() - 1, rowIndices.data(), columnIndices.data(), coefficientValues.data());
int error = 0; int error = 0;
if (this->modelContainsIntegerVariables) { if (this->modelContainsIntegerVariables) {
glp_iocp* parameters = new glp_iocp; glp_iocp* parameters = new glp_iocp();
glp_init_iocp(parameters); glp_init_iocp(parameters);
parameters->presolve = GLP_ON; parameters->presolve = GLP_ON;
parameters->tol_int = storm::settings::Settings::getInstance()->getOptionByLongName("glpkinttol").getArgument(0).getValueAsDouble(); parameters->tol_int = storm::settings::Settings::getInstance()->getOptionByLongName("glpkinttol").getArgument(0).getValueAsDouble();
@ -171,11 +214,7 @@ namespace storm {
error = glp_simplex(this->lp, nullptr); error = glp_simplex(this->lp, nullptr);
} }
if (error != 0) { LOG_THROW(error == 0, storm::exceptions::InvalidStateException, "Unable to optimize glpk model (" << error << ").");
LOG4CPLUS_ERROR(logger, "Unable to optimize glpk model (" << error << ").");
throw storm::exceptions::InvalidStateException() << "Unable to optimize glpk model (" << error << ").";
}
this->currentModelHasBeenOptimized = true; this->currentModelHasBeenOptimized = true;
} }
@ -217,103 +256,75 @@ namespace storm {
return status == GLP_OPT; return status == GLP_OPT;
} }
int_fast64_t GlpkLpSolver::getIntegerValue(uint_fast64_t variableIndex) const { double GlpkLpSolver::getContinuousValue(std::string const& name) const {
if (!this->isOptimal()) { if (!this->isOptimal()) {
if (this->isInfeasible()) { LOG_THROW(!this->isInfeasible(), storm::exceptions::InvalidAccessException, "Unable to get glpk solution from infeasible model.");
LOG4CPLUS_ERROR(logger, "Unable to get glpk solution from infeasible model."); LOG_THROW(!this->isUnbounded(), storm::exceptions::InvalidAccessException, "Unable to get glpk solution from unbounded model.");
throw storm::exceptions::InvalidStateException() << "Unable to get Gurobi solution from infeasible model."; LOG_THROW(false, storm::exceptions::InvalidAccessException, "Unable to get glpk solution from unoptimized model.");
} else if (this->isUnbounded()) {
LOG4CPLUS_ERROR(logger, "Unable to get glpk solution from unbounded model.");
throw storm::exceptions::InvalidStateException() << "Unable to get Gurobi solution from unbounded model.";
} else {
LOG4CPLUS_ERROR(logger, "Unable to get glpk solution from unoptimized model.");
throw storm::exceptions::InvalidStateException() << "Unable to get Gurobi solution from unoptimized model.";
}
} }
auto variableIndexPair = this->variableNameToIndexMap.find(name);
LOG_THROW(variableIndexPair != this->variableNameToIndexMap.end(), storm::exceptions::InvalidAccessException, "Accessing value of unknown variable '" << name << "'.");
double value = 0; double value = 0;
if (this->modelContainsIntegerVariables) { if (this->modelContainsIntegerVariables) {
value = glp_mip_col_val(this->lp, static_cast<int>(variableIndex)); value = glp_mip_col_val(this->lp, static_cast<int>(variableIndexPair->second));
} else { } else {
value = glp_get_col_prim(this->lp, static_cast<int>(variableIndex)); value = glp_get_col_prim(this->lp, static_cast<int>(variableIndexPair->second));
}
if (std::abs(value - static_cast<int>(value)) <= storm::settings::Settings::getInstance()->getOptionByLongName("precision").getArgument(0).getValueAsDouble()) {
// Nothing to do in this case.
} else if (std::abs(value) > storm::settings::Settings::getInstance()->getOptionByLongName("precision").getArgument(0).getValueAsDouble()) {
LOG4CPLUS_ERROR(logger, "Illegal value for integer variable in glpk solution (" << value << ").");
throw storm::exceptions::InvalidStateException() << "Illegal value for integer variable in glpk solution (" << value << ").";
} }
return value;
return static_cast<int_fast64_t>(value);
} }
bool GlpkLpSolver::getBinaryValue(uint_fast64_t variableIndex) const { int_fast64_t GlpkLpSolver::getIntegerValue(std::string const& name) const {
if (!this->isOptimal()) { if (!this->isOptimal()) {
if (this->isInfeasible()) { LOG_THROW(!this->isInfeasible(), storm::exceptions::InvalidAccessException, "Unable to get glpk solution from infeasible model.");
LOG4CPLUS_ERROR(logger, "Unable to get glpk solution from infeasible model."); LOG_THROW(!this->isUnbounded(), storm::exceptions::InvalidAccessException, "Unable to get glpk solution from unbounded model.");
throw storm::exceptions::InvalidStateException() << "Unable to get Gurobi solution from infeasible model."; LOG_THROW(false, storm::exceptions::InvalidAccessException, "Unable to get glpk solution from unoptimized model.");
} else if (this->isUnbounded()) {
LOG4CPLUS_ERROR(logger, "Unable to get glpk solution from unbounded model.");
throw storm::exceptions::InvalidStateException() << "Unable to get Gurobi solution from unbounded model.";
} else {
LOG4CPLUS_ERROR(logger, "Unable to get glpk solution from unoptimized model.");
throw storm::exceptions::InvalidStateException() << "Unable to get Gurobi solution from unoptimized model.";
}
} }
auto variableIndexPair = this->variableNameToIndexMap.find(name);
LOG_THROW(variableIndexPair != this->variableNameToIndexMap.end(), storm::exceptions::InvalidAccessException, "Accessing value of unknown variable '" << name << "'.");
double value = 0; double value = 0;
if (this->modelContainsIntegerVariables) { if (this->modelContainsIntegerVariables) {
value = glp_mip_col_val(this->lp, static_cast<int>(variableIndex)); value = glp_mip_col_val(this->lp, static_cast<int>(variableIndexPair->second));
} else { } else {
value = glp_get_col_prim(this->lp, static_cast<int>(variableIndex)); value = glp_get_col_prim(this->lp, static_cast<int>(variableIndexPair->second));
} }
if (std::abs(value - 1) <= storm::settings::Settings::getInstance()->getOptionByLongName("precision").getArgument(0).getValueAsDouble()) { // Now check the desired precision was actually achieved.
// Nothing to do in this case. LOG_THROW(std::abs(static_cast<int>(value) - value) <= storm::settings::Settings::getInstance()->getOptionByLongName("glpkinttol").getArgument(0).getValueAsDouble(), storm::exceptions::InvalidStateException, "Illegal value for integer variable in glpk solution (" << value << ").");
} else if (std::abs(value) > storm::settings::Settings::getInstance()->getOptionByLongName("precision").getArgument(0).getValueAsDouble()) {
LOG4CPLUS_ERROR(logger, "Illegal value for binary variable in Gurobi solution (" << value << ").");
throw storm::exceptions::InvalidStateException() << "Illegal value for binary variable in Gurobi solution (" << value << ").";
}
return static_cast<bool>(value); return static_cast<int_fast64_t>(value);
} }
double GlpkLpSolver::getContinuousValue(uint_fast64_t variableIndex) const { bool GlpkLpSolver::getBinaryValue(std::string const& name) const {
if (!this->isOptimal()) { if (!this->isOptimal()) {
if (this->isInfeasible()) { LOG_THROW(!this->isInfeasible(), storm::exceptions::InvalidAccessException, "Unable to get glpk solution from infeasible model.");
LOG4CPLUS_ERROR(logger, "Unable to get glpk solution from infeasible model."); LOG_THROW(!this->isUnbounded(), storm::exceptions::InvalidAccessException, "Unable to get glpk solution from unbounded model.");
throw storm::exceptions::InvalidStateException() << "Unable to get Gurobi solution from infeasible model."; LOG_THROW(false, storm::exceptions::InvalidAccessException, "Unable to get glpk solution from unoptimized model.");
} else if (this->isUnbounded()) {
LOG4CPLUS_ERROR(logger, "Unable to get glpk solution from unbounded model.");
throw storm::exceptions::InvalidStateException() << "Unable to get Gurobi solution from unbounded model.";
} else {
LOG4CPLUS_ERROR(logger, "Unable to get glpk solution from unoptimized model.");
throw storm::exceptions::InvalidStateException() << "Unable to get Gurobi solution from unoptimized model.";
}
} }
auto variableIndexPair = this->variableNameToIndexMap.find(name);
LOG_THROW(variableIndexPair != this->variableNameToIndexMap.end(), storm::exceptions::InvalidAccessException, "Accessing value of unknown variable '" << name << "'.");
double value = 0; double value = 0;
if (this->modelContainsIntegerVariables) { if (this->modelContainsIntegerVariables) {
value = glp_mip_col_val(this->lp, static_cast<int>(variableIndex)); value = glp_mip_col_val(this->lp, static_cast<int>(variableIndexPair->second));
} else { } else {
value = glp_get_col_prim(this->lp, static_cast<int>(variableIndex)); value = glp_get_col_prim(this->lp, static_cast<int>(variableIndexPair->second));
} }
return value; LOG_THROW(std::abs(static_cast<int>(value) - value) <= storm::settings::Settings::getInstance()->getOptionByLongName("glpkinttol").getArgument(0).getValueAsDouble(), storm::exceptions::InvalidStateException, "Illegal value for binary variable in glpk solution (" << value << ").");
return static_cast<bool>(value);
} }
double GlpkLpSolver::getObjectiveValue() const { double GlpkLpSolver::getObjectiveValue() const {
if (!this->isOptimal()) { if (!this->isOptimal()) {
if (this->isInfeasible()) { LOG_THROW(!this->isInfeasible(), storm::exceptions::InvalidAccessException, "Unable to get glpk solution from infeasible model.");
LOG4CPLUS_ERROR(logger, "Unable to get glpk solution from infeasible model."); LOG_THROW(!this->isUnbounded(), storm::exceptions::InvalidAccessException, "Unable to get glpk solution from unbounded model.");
throw storm::exceptions::InvalidStateException() << "Unable to get Gurobi solution from infeasible model."; LOG_THROW(false, storm::exceptions::InvalidAccessException, "Unable to get glpk solution from unoptimized model.");
} else if (this->isUnbounded()) {
LOG4CPLUS_ERROR(logger, "Unable to get glpk solution from unbounded model.");
throw storm::exceptions::InvalidStateException() << "Unable to get Gurobi solution from unbounded model.";
} else {
LOG4CPLUS_ERROR(logger, "Unable to get glpk solution from unoptimized model.");
throw storm::exceptions::InvalidStateException() << "Unable to get Gurobi solution from unoptimized model.";
}
} }
double value = 0; double value = 0;

97
src/solver/GlpkLpSolver.h

@ -14,7 +14,6 @@
namespace storm { namespace storm {
namespace solver { namespace solver {
#ifdef STORM_HAVE_GLPK #ifdef STORM_HAVE_GLPK
/*! /*!
* A class that implements the LpSolver interface using glpk as the background solver. * A class that implements the LpSolver interface using glpk as the background solver.
*/ */
@ -56,34 +55,66 @@ namespace storm {
*/ */
virtual ~GlpkLpSolver(); virtual ~GlpkLpSolver();
virtual uint_fast64_t createContinuousVariable(std::string const& name, VariableType const& variableType, double lowerBound, double upperBound, double objectiveFunctionCoefficient) override; // Methods to add continuous variables.
virtual uint_fast64_t createIntegerVariable(std::string const& name, VariableType const& variableType, double lowerBound, double upperBound, double objectiveFunctionCoefficient) override; virtual void addBoundedContinuousVariable(std::string const& name, double lowerBound, double upperBound, double objectiveFunctionCoefficient = 0) override;
virtual uint_fast64_t createBinaryVariable(std::string const& name, double objectiveFunctionCoefficient) override; virtual void addLowerBoundedContinuousVariable(std::string const& name, double lowerBound, double objectiveFunctionCoefficient = 0) override;
virtual void addUpperBoundedContinuousVariable(std::string const& name, double upperBound, double objectiveFunctionCoefficient = 0) override;
virtual void addUnboundedContinuousVariable(std::string const& name, double objectiveFunctionCoefficient = 0) override;
// Methods to add integer variables.
virtual void addBoundedIntegerVariable(std::string const& name, double lowerBound, double upperBound, double objectiveFunctionCoefficient = 0) override;
virtual void addLowerBoundedIntegerVariable(std::string const& name, double lowerBound, double objectiveFunctionCoefficient = 0) override;
virtual void addUpperBoundedIntegerVariable(std::string const& name, double upperBound, double objectiveFunctionCoefficient = 0) override;
virtual void addUnboundedIntegerVariable(std::string const& name, double objectiveFunctionCoefficient = 0) override;
// Methods to add binary variables.
virtual void addBinaryVariable(std::string const& name, double objectiveFunctionCoefficient = 0) override;
// Methods to incorporate recent changes.
virtual void update() const override; virtual void update() const override;
virtual void addConstraint(std::string const& name, std::vector<uint_fast64_t> const& variables, std::vector<double> const& coefficients, BoundType const& boundType, double rightHandSideValue) override; // Methods to add constraints
virtual void addConstraint(std::string const& name, storm::expressions::Expression const& constraint) override;
// Methods to optimize and retrieve optimality status.
virtual void optimize() const override; virtual void optimize() const override;
virtual bool isInfeasible() const override; virtual bool isInfeasible() const override;
virtual bool isUnbounded() const override; virtual bool isUnbounded() const override;
virtual bool isOptimal() const override; virtual bool isOptimal() const override;
virtual int_fast64_t getIntegerValue(uint_fast64_t variableIndex) const override; // Methods to retrieve values of variables and the objective function in the optimal solutions.
virtual bool getBinaryValue(uint_fast64_t variableIndex) const override; virtual double getContinuousValue(std::string const& name) const override;
virtual double getContinuousValue(uint_fast64_t variableIndex) const override; virtual int_fast64_t getIntegerValue(std::string const& name) const override;
virtual bool getBinaryValue(std::string const& name) const override;
virtual double getObjectiveValue() const override; virtual double getObjectiveValue() const override;
// Methods to print the LP problem to a file.
virtual void writeModelToFile(std::string const& filename) const override; virtual void writeModelToFile(std::string const& filename) const override;
private: private:
/*!
* Adds a variable with the given name, type, lower and upper bound and objective function coefficient.
*
* @param name The name of the variable.
* @param variableType The type of the variable in terms of glpk's constants.
* @param boundType A glpk flag indicating which bounds apply to the variable.
* @param lowerBound The lower bound of the range of the variable.
* @param upperBound The upper bound of the range of the variable.
* @param objectiveFunctionCoefficient The coefficient of the variable in the objective function.
*/
void addVariable(std::string const& name, int variableType, int boundType, double lowerBound, double upperBound, double objectiveFunctionCoefficient);
// The glpk LP problem. // The glpk LP problem.
glp_prob* lp; glp_prob* lp;
// A counter that keeps track of the next free variable index. // A mapping from variable names to their indices.
uint_fast64_t nextVariableIndex; std::map<std::string, int> variableNameToIndexMap;
// A counter used for getting the next variable index.
int nextVariableIndex;
// A counter that keeps track of the next free constraint index. // A counter used for getting the next constraint index.
uint_fast64_t nextConstraintIndex; int nextConstraintIndex;
// A flag storing whether the model is an LP or an MILP. // A flag storing whether the model is an LP or an MILP.
bool modelContainsIntegerVariables; bool modelContainsIntegerVariables;
@ -121,15 +152,39 @@ namespace storm {
throw storm::exceptions::NotImplementedException() << "This version of StoRM was compiled without support for glpk. Yet, a method was called that requires this support. Please choose a version of support with glpk support."; throw storm::exceptions::NotImplementedException() << "This version of StoRM was compiled without support for glpk. Yet, a method was called that requires this support. Please choose a version of support with glpk support.";
} }
virtual uint_fast64_t createContinuousVariable(std::string const& name, VariableType const& variableType, double lowerBound, double upperBound, double objectiveFunctionCoefficient) override { virtual void addBoundedContinuousVariable(std::string const& name, double lowerBound, double upperBound, double objectiveFunctionCoefficient = 0) override {
throw storm::exceptions::NotImplementedException() << "This version of StoRM was compiled without support for glpk. Yet, a method was called that requires this support. Please choose a version of support with glpk support.";
}
virtual void addLowerBoundedContinuousVariable(std::string const& name, double lowerBound, double objectiveFunctionCoefficient = 0) override {
throw storm::exceptions::NotImplementedException() << "This version of StoRM was compiled without support for glpk. Yet, a method was called that requires this support. Please choose a version of support with glpk support.";
}
virtual void addUpperBoundedContinuousVariable(std::string const& name, double upperBound, double objectiveFunctionCoefficient = 0) override {
throw storm::exceptions::NotImplementedException() << "This version of StoRM was compiled without support for glpk. Yet, a method was called that requires this support. Please choose a version of support with glpk support.";
}
virtual void addUnboundedContinuousVariable(std::string const& name, double objectiveFunctionCoefficient = 0) override {
throw storm::exceptions::NotImplementedException() << "This version of StoRM was compiled without support for glpk. Yet, a method was called that requires this support. Please choose a version of support with glpk support.";
}
virtual void addBoundedIntegerVariable(std::string const& name, double lowerBound, double upperBound, double objectiveFunctionCoefficient = 0) override {
throw storm::exceptions::NotImplementedException() << "This version of StoRM was compiled without support for glpk. Yet, a method was called that requires this support. Please choose a version of support with glpk support.";
}
virtual void addLowerBoundedIntegerVariable(std::string const& name, double lowerBound, double objectiveFunctionCoefficient = 0) override {
throw storm::exceptions::NotImplementedException() << "This version of StoRM was compiled without support for glpk. Yet, a method was called that requires this support. Please choose a version of support with glpk support.";
}
virtual void addUpperBoundedIntegerVariable(std::string const& name, double upperBound, double objectiveFunctionCoefficient = 0) override {
throw storm::exceptions::NotImplementedException() << "This version of StoRM was compiled without support for glpk. Yet, a method was called that requires this support. Please choose a version of support with glpk support."; throw storm::exceptions::NotImplementedException() << "This version of StoRM was compiled without support for glpk. Yet, a method was called that requires this support. Please choose a version of support with glpk support.";
} }
virtual uint_fast64_t createIntegerVariable(std::string const& name, VariableType const& variableType, double lowerBound, double upperBound, double objectiveFunctionCoefficient) override { virtual void addUnboundedIntegerVariable(std::string const& name, double objectiveFunctionCoefficient = 0) override {
throw storm::exceptions::NotImplementedException() << "This version of StoRM was compiled without support for glpk. Yet, a method was called that requires this support. Please choose a version of support with glpk support."; throw storm::exceptions::NotImplementedException() << "This version of StoRM was compiled without support for glpk. Yet, a method was called that requires this support. Please choose a version of support with glpk support.";
} }
virtual uint_fast64_t createBinaryVariable(std::string const& name, double objectiveFunctionCoefficient) override { virtual uint_fast64_t addBinaryVariable(std::string const& name, double objectiveFunctionCoefficient = 0) override {
throw storm::exceptions::NotImplementedException() << "This version of StoRM was compiled without support for glpk. Yet, a method was called that requires this support. Please choose a version of support with glpk support."; throw storm::exceptions::NotImplementedException() << "This version of StoRM was compiled without support for glpk. Yet, a method was called that requires this support. Please choose a version of support with glpk support.";
} }
@ -137,14 +192,14 @@ namespace storm {
throw storm::exceptions::NotImplementedException() << "This version of StoRM was compiled without support for glpk. Yet, a method was called that requires this support. Please choose a version of support with glpk support."; throw storm::exceptions::NotImplementedException() << "This version of StoRM was compiled without support for glpk. Yet, a method was called that requires this support. Please choose a version of support with glpk support.";
} }
virtual void addConstraint(std::string const& name, std::vector<uint_fast64_t> const& variables, std::vector<double> const& coefficients, BoundType const& boundType, double rightHandSideValue) override { virtual void addConstraint(std::string const& name, storm::expressions::Expression const& constraint) override {
throw storm::exceptions::NotImplementedException() << "This version of StoRM was compiled without support for glpk. Yet, a method was called that requires this support. Please choose a version of support with glpk support."; throw storm::exceptions::NotImplementedException() << "This version of StoRM was compiled without support for glpk. Yet, a method was called that requires this support. Please choose a version of support with glpk support.";
} }
virtual void optimize() const override { virtual void optimize() const override {
throw storm::exceptions::NotImplementedException() << "This version of StoRM was compiled without support for glpk. Yet, a method was called that requires this support. Please choose a version of support with glpk support."; throw storm::exceptions::NotImplementedException() << "This version of StoRM was compiled without support for glpk. Yet, a method was called that requires this support. Please choose a version of support with glpk support.";
} }
virtual bool isInfeasible() const override { virtual bool isInfeasible() const override {
throw storm::exceptions::NotImplementedException() << "This version of StoRM was compiled without support for glpk. Yet, a method was called that requires this support. Please choose a version of support with glpk support."; throw storm::exceptions::NotImplementedException() << "This version of StoRM was compiled without support for glpk. Yet, a method was called that requires this support. Please choose a version of support with glpk support.";
} }
@ -157,15 +212,15 @@ namespace storm {
throw storm::exceptions::NotImplementedException() << "This version of StoRM was compiled without support for glpk. Yet, a method was called that requires this support. Please choose a version of support with glpk support."; throw storm::exceptions::NotImplementedException() << "This version of StoRM was compiled without support for glpk. Yet, a method was called that requires this support. Please choose a version of support with glpk support.";
} }
virtual int_fast64_t getIntegerValue(uint_fast64_t variableIndex) const override { virtual double getContinuousValue(std::string const& name) const override {
throw storm::exceptions::NotImplementedException() << "This version of StoRM was compiled without support for glpk. Yet, a method was called that requires this support. Please choose a version of support with glpk support."; throw storm::exceptions::NotImplementedException() << "This version of StoRM was compiled without support for glpk. Yet, a method was called that requires this support. Please choose a version of support with glpk support.";
} }
virtual bool getBinaryValue(uint_fast64_t variableIndex) const override { virtual int_fast64_t getIntegerValue(std::string const& name) const override {
throw storm::exceptions::NotImplementedException() << "This version of StoRM was compiled without support for glpk. Yet, a method was called that requires this support. Please choose a version of support with glpk support."; throw storm::exceptions::NotImplementedException() << "This version of StoRM was compiled without support for glpk. Yet, a method was called that requires this support. Please choose a version of support with glpk support.";
} }
virtual double getContinuousValue(uint_fast64_t variableIndex) const override { virtual bool getBinaryValue(std::string const& name) const override {
throw storm::exceptions::NotImplementedException() << "This version of StoRM was compiled without support for glpk. Yet, a method was called that requires this support. Please choose a version of support with glpk support."; throw storm::exceptions::NotImplementedException() << "This version of StoRM was compiled without support for glpk. Yet, a method was called that requires this support. Please choose a version of support with glpk support.";
} }

386
src/solver/GurobiLpSolver.cpp

@ -3,13 +3,12 @@
#ifdef STORM_HAVE_GUROBI #ifdef STORM_HAVE_GUROBI
#include <numeric> #include <numeric>
#include "src/exceptions/InvalidStateException.h" #include "src/storage/expressions/LinearCoefficientVisitor.h"
#include "src/settings/Settings.h"
#include "log4cplus/logger.h" #include "src/settings/Settings.h"
#include "log4cplus/loggingmacros.h" #include "src/exceptions/ExceptionMacros.h"
#include "src/exceptions/InvalidStateException.h"
extern log4cplus::Logger logger; #include "src/exceptions/InvalidAccessException.h"
bool GurobiLpSolverOptionsRegistered = storm::settings::Settings::registerNewModule([] (storm::settings::Settings* instance) -> bool { bool GurobiLpSolverOptionsRegistered = storm::settings::Settings::registerNewModule([] (storm::settings::Settings* instance) -> bool {
instance->addOption(storm::settings::OptionBuilder("GurobiLpSolver", "gurobithreads", "", "The number of threads that may be used by Gurobi.").addArgument(storm::settings::ArgumentBuilder::createUnsignedIntegerArgument("count", "The number of threads.").setDefaultValueUnsignedInteger(1).build()).build()); instance->addOption(storm::settings::OptionBuilder("GurobiLpSolver", "gurobithreads", "", "The number of threads that may be used by Gurobi.").addArgument(storm::settings::ArgumentBuilder::createUnsignedIntegerArgument("count", "The number of threads.").setDefaultValueUnsignedInteger(1).build()).build());
@ -43,7 +42,7 @@ namespace storm {
} }
} }
GurobiLpSolver::GurobiLpSolver(std::string const& name) : GurobiLpSolver(name, MINIMIZE) { GurobiLpSolver::GurobiLpSolver(std::string const& name) : GurobiLpSolver(name, ModelSense::Minimize) {
// Intentionally left empty. // Intentionally left empty.
} }
@ -51,7 +50,7 @@ namespace storm {
// Intentionally left empty. // Intentionally left empty.
} }
GurobiLpSolver::GurobiLpSolver() : GurobiLpSolver("", MINIMIZE) { GurobiLpSolver::GurobiLpSolver() : GurobiLpSolver("", ModelSense::Minimize) {
// Intentionally left empty. // Intentionally left empty.
} }
@ -66,145 +65,124 @@ namespace storm {
// Enable the following line to only print the output of Gurobi if the debug flag is set. // Enable the following line to only print the output of Gurobi if the debug flag is set.
error = GRBsetintparam(env, "OutputFlag", storm::settings::Settings::getInstance()->isSet("debug") || storm::settings::Settings::getInstance()->isSet("gurobioutput") ? 1 : 0); error = GRBsetintparam(env, "OutputFlag", storm::settings::Settings::getInstance()->isSet("debug") || storm::settings::Settings::getInstance()->isSet("gurobioutput") ? 1 : 0);
if (error) { LOG_THROW(error == 0, storm::exceptions::InvalidStateException, "Unable to set Gurobi Parameter OutputFlag (" << GRBgeterrormsg(env) << ", error code " << error << ").");
LOG4CPLUS_ERROR(logger, "Unable to set Gurobi Parameter OutputFlag (" << GRBgeterrormsg(env) << ", error code " << error << ").");
throw storm::exceptions::InvalidStateException() << "Unable to set Gurobi Parameter OutputFlag (" << GRBgeterrormsg(env) << ", error code " << error << ").";
}
// Enable the following line to restrict Gurobi to one thread only. // Enable the following line to restrict Gurobi to one thread only.
error = GRBsetintparam(env, "Threads", storm::settings::Settings::getInstance()->getOptionByLongName("gurobithreads").getArgument(0).getValueAsUnsignedInteger()); error = GRBsetintparam(env, "Threads", storm::settings::Settings::getInstance()->getOptionByLongName("gurobithreads").getArgument(0).getValueAsUnsignedInteger());
if (error) { LOG_THROW(error == 0, storm::exceptions::InvalidStateException, "Unable to set Gurobi Parameter Threads (" << GRBgeterrormsg(env) << ", error code " << error << ").");
LOG4CPLUS_ERROR(logger, "Unable to set Gurobi Parameter Threads (" << GRBgeterrormsg(env) << ", error code " << error << ").");
throw storm::exceptions::InvalidStateException() << "Unable to set Gurobi Parameter Threads (" << GRBgeterrormsg(env) << ", error code " << error << ").";
}
// Enable the following line to force Gurobi to be as precise about the binary variables as required by the given precision option. // Enable the following line to force Gurobi to be as precise about the binary variables as required by the given precision option.
error = GRBsetdblparam(env, "IntFeasTol", storm::settings::Settings::getInstance()->getOptionByLongName("gurobiinttol").getArgument(0).getValueAsDouble()); error = GRBsetdblparam(env, "IntFeasTol", storm::settings::Settings::getInstance()->getOptionByLongName("gurobiinttol").getArgument(0).getValueAsDouble());
if (error) { LOG_THROW(error == 0, storm::exceptions::InvalidStateException, "Unable to set Gurobi Parameter IntFeasTol (" << GRBgeterrormsg(env) << ", error code " << error << ").");
LOG4CPLUS_ERROR(logger, "Unable to set Gurobi Parameter IntFeasTol (" << GRBgeterrormsg(env) << ", error code " << error << ").");
throw storm::exceptions::InvalidStateException() << "Unable to set Gurobi Parameter IntFeasTol (" << GRBgeterrormsg(env) << ", error code " << error << ").";
}
} }
void GurobiLpSolver::update() const { void GurobiLpSolver::update() const {
int error = GRBupdatemodel(model); int error = GRBupdatemodel(model);
if (error) { LOG_THROW(error == 0, storm::exceptions::InvalidStateException, "Unable to update Gurobi model (" << GRBgeterrormsg(env) << ", error code " << error << ").");
LOG4CPLUS_ERROR(logger, "Unable to update Gurobi model (" << GRBgeterrormsg(env) << ", error code " << error << ").");
throw storm::exceptions::InvalidStateException() << "Unable to update Gurobi model (" << GRBgeterrormsg(env) << ", error code " << error << ").";
}
// Since the model changed, we erase the optimality flag. // Since the model changed, we erase the optimality flag.
this->currentModelHasBeenOptimized = false; this->currentModelHasBeenOptimized = false;
} }
uint_fast64_t GurobiLpSolver::createContinuousVariable(std::string const& name, VariableType const& variableType, double lowerBound, double upperBound, double objectiveFunctionCoefficient) { void GurobiLpSolver::addBoundedContinuousVariable(std::string const& name, double lowerBound, double upperBound, double objectiveFunctionCoefficient) {
int error = 0; this->addVariable(name, GRB_CONTINUOUS, lowerBound, upperBound, objectiveFunctionCoefficient);
switch (variableType) {
case LpSolver::BOUNDED:
error = GRBaddvar(model, 0, nullptr, nullptr, objectiveFunctionCoefficient, lowerBound, upperBound, GRB_CONTINUOUS, name.c_str());
break;
case LpSolver::UNBOUNDED:
error = GRBaddvar(model, 0, nullptr, nullptr, objectiveFunctionCoefficient, -GRB_INFINITY, GRB_INFINITY, GRB_CONTINUOUS, name.c_str());
break;
case LpSolver::UPPER_BOUND:
error = GRBaddvar(model, 0, nullptr, nullptr, objectiveFunctionCoefficient, -GRB_INFINITY, upperBound, GRB_CONTINUOUS, name.c_str());
break;
case LpSolver::LOWER_BOUND:
error = GRBaddvar(model, 0, nullptr, nullptr, objectiveFunctionCoefficient, lowerBound, GRB_INFINITY, GRB_CONTINUOUS, name.c_str());
break;
}
if (error) {
LOG4CPLUS_ERROR(logger, "Could not create binary Gurobi variable (" << GRBgeterrormsg(env) << ", error code " << error << ").");
throw storm::exceptions::InvalidStateException() << "Could not create binary Gurobi variable (" << GRBgeterrormsg(env) << ", error code " << error << ").";
}
++nextVariableIndex;
return nextVariableIndex - 1;
} }
uint_fast64_t GurobiLpSolver::createIntegerVariable(std::string const& name, VariableType const& variableType, double lowerBound, double upperBound, double objectiveFunctionCoefficient) { void GurobiLpSolver::addLowerBoundedContinuousVariable(std::string const& name, double lowerBound, double objectiveFunctionCoefficient) {
int error = 0; this->addVariable(name, GRB_CONTINUOUS, lowerBound, GRB_INFINITY, objectiveFunctionCoefficient);
switch (variableType) { }
case LpSolver::BOUNDED:
error = GRBaddvar(model, 0, nullptr, nullptr, objectiveFunctionCoefficient, lowerBound, upperBound, GRB_INTEGER, name.c_str());
break;
case LpSolver::UNBOUNDED:
error = GRBaddvar(model, 0, nullptr, nullptr, objectiveFunctionCoefficient, -GRB_INFINITY, GRB_INFINITY, GRB_INTEGER, name.c_str());
break;
case LpSolver::UPPER_BOUND:
error = GRBaddvar(model, 0, nullptr, nullptr, objectiveFunctionCoefficient, -GRB_INFINITY, upperBound, GRB_INTEGER, name.c_str());
break;
case LpSolver::LOWER_BOUND:
error = GRBaddvar(model, 0, nullptr, nullptr, objectiveFunctionCoefficient, lowerBound, GRB_INFINITY, GRB_INTEGER, name.c_str());
break;
}
if (error) { void GurobiLpSolver::addUpperBoundedContinuousVariable(std::string const& name, double upperBound, double objectiveFunctionCoefficient) {
LOG4CPLUS_ERROR(logger, "Could not create binary Gurobi variable (" << GRBgeterrormsg(env) << ", error code " << error << ")."); this->addVariable(name, GRB_CONTINUOUS, -GRB_INFINITY, upperBound, objectiveFunctionCoefficient);
throw storm::exceptions::InvalidStateException() << "Could not create binary Gurobi variable (" << GRBgeterrormsg(env) << ", error code " << error << ")."; }
} void GurobiLpSolver::addUnboundedContinuousVariable(std::string const& name, double objectiveFunctionCoefficient) {
++nextVariableIndex; this->addVariable(name, GRB_CONTINUOUS, -GRB_INFINITY, GRB_INFINITY, objectiveFunctionCoefficient);
return nextVariableIndex - 1;
} }
uint_fast64_t GurobiLpSolver::createBinaryVariable(std::string const& name, double objectiveFunctionCoefficient) { void GurobiLpSolver::addBoundedIntegerVariable(std::string const& name, double lowerBound, double upperBound, double objectiveFunctionCoefficient) {
int error = GRBaddvar(model, 0, nullptr, nullptr, objectiveFunctionCoefficient, 0.0, 1.0, GRB_BINARY, name.c_str()); this->addVariable(name, GRB_INTEGER, lowerBound, upperBound, objectiveFunctionCoefficient);
if (error) {
LOG4CPLUS_ERROR(logger, "Could not create binary Gurobi variable (" << GRBgeterrormsg(env) << ", error code " << error << ").");
throw storm::exceptions::InvalidStateException() << "Could not create binary Gurobi variable (" << GRBgeterrormsg(env) << ", error code " << error << ").";
}
++nextVariableIndex;
return nextVariableIndex - 1;
} }
void GurobiLpSolver::addConstraint(std::string const& name, std::vector<uint_fast64_t> const& variables, std::vector<double> const& coefficients, BoundType const& boundType, double rightHandSideValue) { void GurobiLpSolver::addLowerBoundedIntegerVariable(std::string const& name, double lowerBound, double objectiveFunctionCoefficient) {
if (variables.size() != coefficients.size()) { this->addVariable(name, GRB_INTEGER, lowerBound, GRB_INFINITY, objectiveFunctionCoefficient);
LOG4CPLUS_ERROR(logger, "Sizes of variable indices vector and coefficients vector do not match."); }
throw storm::exceptions::InvalidStateException() << "Sizes of variable indices vector and coefficients vector do not match."; void GurobiLpSolver::addUpperBoundedIntegerVariable(std::string const& name, double upperBound, double objectiveFunctionCoefficient) {
} this->addVariable(name, GRB_INTEGER, -GRB_INFINITY, upperBound, objectiveFunctionCoefficient);
}
void GurobiLpSolver::addUnboundedIntegerVariable(std::string const& name, double objectiveFunctionCoefficient) {
this->addVariable(name, GRB_INTEGER, -GRB_INFINITY, GRB_INFINITY, objectiveFunctionCoefficient);
}
void GurobiLpSolver::addBinaryVariable(std::string const& name, double objectiveFunctionCoefficient) {
this->addVariable(name, GRB_BINARY, 0, 1, objectiveFunctionCoefficient);
}
void GurobiLpSolver::addVariable(std::string const& name, char variableType, double lowerBound, double upperBound, double objectiveFunctionCoefficient) {
// Check whether variable already exists.
auto nameIndexPair = this->variableNameToIndexMap.find(name);
LOG_THROW(nameIndexPair == this->variableNameToIndexMap.end(), storm::exceptions::InvalidArgumentException, "Variable '" << nameIndexPair->first << "' already exists.");
// As Gurobi requires the indices to be unique, we now explicitly make them unique. For this, we sort the // Check for valid variable type.
// variables and coefficients and eliminated duplicates by adding the coefficients. LOG_ASSERT(variableType == GRB_CONTINUOUS || variableType == GRB_INTEGER || variableType == GRB_BINARY, "Illegal type '" << variableType << "' for Gurobi variable.");
// We start by sorting both vectors. // Finally, create the actual variable.
std::vector<uint_fast64_t> sortedVariables(variables); int error = 0;
std::vector<double> sortedCoefficients(coefficients); error = GRBaddvar(model, 0, nullptr, nullptr, objectiveFunctionCoefficient, lowerBound, upperBound, variableType, name.c_str());
std::vector<uint_fast64_t> permutation(variables.size()); LOG_THROW(error == 0, storm::exceptions::InvalidStateException, "Could not create binary Gurobi variable (" << GRBgeterrormsg(env) << ", error code " << error << ").");
std::iota(permutation.begin(), permutation.end(), 0); this->variableNameToIndexMap.emplace(name, nextVariableIndex);
std::sort(permutation.begin(), permutation.end(), [&] (uint_fast64_t i, uint_fast64_t j) { return variables[i] < variables[j]; } ); ++nextVariableIndex;
std::transform(permutation.begin(), permutation.end(), sortedVariables.begin(), [&] (uint_fast64_t i) { return variables[i]; } ); }
std::transform(permutation.begin(), permutation.end(), sortedCoefficients.begin(), [&] (uint_fast64_t i) { return coefficients[i]; } ); void GurobiLpSolver::addConstraint(std::string const& name, storm::expressions::Expression const& constraint) {
LOG_THROW(constraint.isRelationalExpression(), storm::exceptions::InvalidArgumentException, "Illegal constraint is not a relational expression.");
LOG_THROW(constraint.getOperator() != storm::expressions::OperatorType::NotEqual, storm::exceptions::InvalidArgumentException, "Illegal constraint uses inequality operator.");
// Now we perform the duplicate elimination step. std::pair<storm::expressions::SimpleValuation, double> leftCoefficients = storm::expressions::LinearCoefficientVisitor().getLinearCoefficients(constraint.getOperand(0));
std::vector<int> uniqueVariables; std::pair<storm::expressions::SimpleValuation, double> rightCoefficients = storm::expressions::LinearCoefficientVisitor().getLinearCoefficients(constraint.getOperand(1));
std::vector<double> uniqueCoefficients; for (auto const& identifier : rightCoefficients.first.getDoubleIdentifiers()) {
for (uint_fast64_t i = 0; i < sortedVariables.size(); ++i) { if (leftCoefficients.first.containsDoubleIdentifier(identifier)) {
if (!uniqueVariables.empty() && uniqueVariables.back() == sortedVariables[i]) { leftCoefficients.first.setDoubleValue(identifier, leftCoefficients.first.getDoubleValue(identifier) - rightCoefficients.first.getDoubleValue(identifier));
uniqueCoefficients.back() += sortedCoefficients[i];
} else { } else {
uniqueVariables.push_back(static_cast<int>(sortedVariables[i])); leftCoefficients.first.addDoubleIdentifier(identifier, -rightCoefficients.first.getDoubleValue(identifier));
uniqueCoefficients.push_back(sortedCoefficients[i]);
} }
} }
rightCoefficients.second -= leftCoefficients.second;
bool strictBound = boundType == LESS || boundType == GREATER; // Now we need to transform the coefficients to the vector representation.
char sense = boundType == LESS || boundType == LESS_EQUAL ? GRB_LESS_EQUAL : boundType == EQUAL ? GRB_EQUAL : GRB_GREATER_EQUAL; std::vector<int> variables;
std::vector<double> coefficients;
// If the constraint enforces a strict bound, we need to do some tweaking of the right-hand side value, because Gurobi only supports for (auto const& identifier : leftCoefficients.first.getDoubleIdentifiers()) {
// non-strict bounds. auto identifierIndexPair = this->variableNameToIndexMap.find(identifier);
if (strictBound) { LOG_THROW(identifierIndexPair != this->variableNameToIndexMap.end(), storm::exceptions::InvalidArgumentException, "Constraint contains illegal identifier '" << identifier << "'.");
if (boundType == LESS) { variables.push_back(identifierIndexPair->second);
rightHandSideValue -= storm::settings::Settings::getInstance()->getOptionByLongName("precision").getArgument(0).getValueAsDouble(); coefficients.push_back(leftCoefficients.first.getDoubleValue(identifier));
} else if (boundType == GREATER) {
rightHandSideValue += storm::settings::Settings::getInstance()->getOptionByLongName("precision").getArgument(0).getValueAsDouble();
}
} }
int error = GRBaddconstr(model, uniqueVariables.size(), uniqueVariables.data(), uniqueCoefficients.data(), sense, rightHandSideValue, name == "" ? nullptr : name.c_str());
if (error) { // Determine the type of the constraint and add it properly.
LOG4CPLUS_ERROR(logger, "Unable to assert Gurobi constraint (" << GRBgeterrormsg(env) << ", error code " << error << ")."); int error = 0;
throw storm::exceptions::InvalidStateException() << "Unable to assert Gurobi constraint (" << GRBgeterrormsg(env) << ", error code " << error << ")."; switch (constraint.getOperator()) {
case storm::expressions::OperatorType::Less:
error = GRBaddconstr(model, variables.size(), variables.data(), coefficients.data(), GRB_LESS_EQUAL, rightCoefficients.second - storm::settings::Settings::getInstance()->getOptionByLongName("gurobiinttol").getArgument(0).getValueAsDouble(), name == "" ? nullptr : name.c_str());
break;
case storm::expressions::OperatorType::LessOrEqual:
error = GRBaddconstr(model, variables.size(), variables.data(), coefficients.data(), GRB_LESS_EQUAL, rightCoefficients.second, name == "" ? nullptr : name.c_str());
break;
case storm::expressions::OperatorType::Greater:
error = GRBaddconstr(model, variables.size(), variables.data(), coefficients.data(), GRB_GREATER_EQUAL, rightCoefficients.second + storm::settings::Settings::getInstance()->getOptionByLongName("gurobiinttol").getArgument(0).getValueAsDouble(), name == "" ? nullptr : name.c_str());
break;
case storm::expressions::OperatorType::GreaterOrEqual:
error = GRBaddconstr(model, variables.size(), variables.data(), coefficients.data(), GRB_GREATER_EQUAL, rightCoefficients.second, name == "" ? nullptr : name.c_str());
break;
case storm::expressions::OperatorType::Equal:
error = GRBaddconstr(model, variables.size(), variables.data(), coefficients.data(), GRB_EQUAL, rightCoefficients.second, name == "" ? nullptr : name.c_str());
break;
default:
LOG_ASSERT(false, "Illegal operator in LP solver constraint.");
} }
LOG_THROW(error == 0, storm::exceptions::InvalidStateException, "Could not assert constraint (" << GRBgeterrormsg(env) << ", error code " << error << ").");
} }
void GurobiLpSolver::optimize() const { void GurobiLpSolver::optimize() const {
@ -212,18 +190,12 @@ namespace storm {
this->update(); this->update();
// Set the most recently set model sense. // Set the most recently set model sense.
int error = GRBsetintattr(model, "ModelSense", this->getModelSense() == MINIMIZE ? 1 : -1); int error = GRBsetintattr(model, "ModelSense", this->getModelSense() == ModelSense::Minimize ? 1 : -1);
if (error) { LOG_THROW(error == 0, storm::exceptions::InvalidStateException, "Unable to set Gurobi model sense (" << GRBgeterrormsg(env) << ", error code " << error << ").");
LOG4CPLUS_ERROR(logger, "Unable to set Gurobi model sense (" << GRBgeterrormsg(env) << ", error code " << error << ").");
throw storm::exceptions::InvalidStateException() << "Unable to set Gurobi model sense (" << GRBgeterrormsg(env) << ", error code " << error << ").";
}
// Then we actually optimize the model. // Then we actually optimize the model.
error = GRBoptimize(model); error = GRBoptimize(model);
if (error) { LOG_THROW(error == 0, storm::exceptions::InvalidStateException, "Unable to optimize Gurobi model (" << GRBgeterrormsg(env) << ", error code " << error << ").");
LOG4CPLUS_ERROR(logger, "Unable to optimize Gurobi model (" << GRBgeterrormsg(env) << ", error code " << error << ").");
throw storm::exceptions::InvalidStateException() << "Unable to optimize Gurobi model (" << GRBgeterrormsg(env) << ", error code " << error << ").";
}
this->currentModelHasBeenOptimized = true; this->currentModelHasBeenOptimized = true;
} }
@ -236,34 +208,21 @@ namespace storm {
int optimalityStatus = 0; int optimalityStatus = 0;
int error = GRBgetintattr(model, GRB_INT_ATTR_STATUS, &optimalityStatus); int error = GRBgetintattr(model, GRB_INT_ATTR_STATUS, &optimalityStatus);
if (error) { LOG_THROW(error == 0, storm::exceptions::InvalidStateException, "Unable to retrieve optimization status of Gurobi model (" << GRBgeterrormsg(env) << ", error code " << error << ").");
LOG4CPLUS_ERROR(logger, "Unable to retrieve optimization status of Gurobi model (" << GRBgeterrormsg(env) << ", error code " << error << ").");
throw storm::exceptions::InvalidStateException() << "Unable to retrieve optimization status of Gurobi model (" << GRBgeterrormsg(env) << ", error code " << error << ").";
}
// By default, Gurobi may tell us only that the model is either infeasible or unbounded. To decide which one // By default, Gurobi may tell us only that the model is either infeasible or unbounded. To decide which one
// it is, we need to perform an extra step. // it is, we need to perform an extra step.
if (optimalityStatus == GRB_INF_OR_UNBD) { if (optimalityStatus == GRB_INF_OR_UNBD) {
std::cout << "here" << std::endl;
error = GRBsetintparam(GRBgetenv(model), GRB_INT_PAR_DUALREDUCTIONS, 0); error = GRBsetintparam(GRBgetenv(model), GRB_INT_PAR_DUALREDUCTIONS, 0);
if (error) { LOG_THROW(error == 0, storm::exceptions::InvalidStateException, "Unable to set Gurobi parameter (" << GRBgeterrormsg(env) << ", error code " << error << ").");
LOG4CPLUS_ERROR(logger, "Unable to set Gurobi parameter (" << GRBgeterrormsg(env) << ", error code " << error << ").");
throw storm::exceptions::InvalidStateException() << "Unable to set Gurobi parameter (" << GRBgeterrormsg(env) << ", error code " << error << ").";
}
this->optimize(); this->optimize();
error = GRBgetintattr(model, GRB_INT_ATTR_STATUS, &optimalityStatus); error = GRBgetintattr(model, GRB_INT_ATTR_STATUS, &optimalityStatus);
if (error) { LOG_THROW(error == 0, storm::exceptions::InvalidStateException, "Unable to retrieve optimization status of Gurobi model (" << GRBgeterrormsg(env) << ", error code " << error << ").");
LOG4CPLUS_ERROR(logger, "Unable to retrieve optimization status of Gurobi model (" << GRBgeterrormsg(env) << ", error code " << error << ").");
throw storm::exceptions::InvalidStateException() << "Unable to retrieve optimization status of Gurobi model (" << GRBgeterrormsg(env) << ", error code " << error << ").";
}
error = GRBsetintparam(GRBgetenv(model), GRB_INT_PAR_DUALREDUCTIONS, 1); error = GRBsetintparam(GRBgetenv(model), GRB_INT_PAR_DUALREDUCTIONS, 1);
if (error) { LOG_THROW(error == 0, storm::exceptions::InvalidStateException, "Unable to set Gurobi parameter (" << GRBgeterrormsg(env) << ", error code " << error << ").");
LOG4CPLUS_ERROR(logger, "Unable to set Gurobi parameter (" << GRBgeterrormsg(env) << ", error code " << error << ").");
throw storm::exceptions::InvalidStateException() << "Unable to set Gurobi parameter (" << GRBgeterrormsg(env) << ", error code " << error << ").";
}
} }
return optimalityStatus == GRB_INFEASIBLE; return optimalityStatus == GRB_INFEASIBLE;
@ -277,33 +236,21 @@ namespace storm {
int optimalityStatus = 0; int optimalityStatus = 0;
int error = GRBgetintattr(model, GRB_INT_ATTR_STATUS, &optimalityStatus); int error = GRBgetintattr(model, GRB_INT_ATTR_STATUS, &optimalityStatus);
if (error) { LOG_THROW(error == 0, storm::exceptions::InvalidStateException, "Unable to retrieve optimization status of Gurobi model (" << GRBgeterrormsg(env) << ", error code " << error << ").");
LOG4CPLUS_ERROR(logger, "Unable to retrieve optimization status of Gurobi model (" << GRBgeterrormsg(env) << ", error code " << error << ").");
throw storm::exceptions::InvalidStateException() << "Unable to retrieve optimization status of Gurobi model (" << GRBgeterrormsg(env) << ", error code " << error << ").";
}
// By default, Gurobi may tell us only that the model is either infeasible or unbounded. To decide which one // By default, Gurobi may tell us only that the model is either infeasible or unbounded. To decide which one
// it is, we need to perform an extra step. // it is, we need to perform an extra step.
if (optimalityStatus == GRB_INF_OR_UNBD) { if (optimalityStatus == GRB_INF_OR_UNBD) {
error = GRBsetintparam(GRBgetenv(model), GRB_INT_PAR_DUALREDUCTIONS, 0); error = GRBsetintparam(GRBgetenv(model), GRB_INT_PAR_DUALREDUCTIONS, 0);
if (error) { LOG_THROW(error == 0, storm::exceptions::InvalidStateException, "Unable to set Gurobi parameter (" << GRBgeterrormsg(env) << ", error code " << error << ").");
LOG4CPLUS_ERROR(logger, "Unable to set Gurobi parameter (" << GRBgeterrormsg(env) << ", error code " << error << ").");
throw storm::exceptions::InvalidStateException() << "Unable to set Gurobi parameter (" << GRBgeterrormsg(env) << ", error code " << error << ").";
}
this->optimize(); this->optimize();
error = GRBgetintattr(model, GRB_INT_ATTR_STATUS, &optimalityStatus); error = GRBgetintattr(model, GRB_INT_ATTR_STATUS, &optimalityStatus);
if (error) { LOG_THROW(error == 0, storm::exceptions::InvalidStateException, "Unable to retrieve optimization status of Gurobi model (" << GRBgeterrormsg(env) << ", error code " << error << ").");
LOG4CPLUS_ERROR(logger, "Unable to retrieve optimization status of Gurobi model (" << GRBgeterrormsg(env) << ", error code " << error << ").");
throw storm::exceptions::InvalidStateException() << "Unable to retrieve optimization status of Gurobi model (" << GRBgeterrormsg(env) << ", error code " << error << ").";
}
error = GRBsetintparam(GRBgetenv(model), GRB_INT_PAR_DUALREDUCTIONS, 1); error = GRBsetintparam(GRBgetenv(model), GRB_INT_PAR_DUALREDUCTIONS, 1);
if (error) { LOG_THROW(error == 0, storm::exceptions::InvalidStateException, "Unable to set Gurobi parameter (" << GRBgeterrormsg(env) << ", error code " << error << ").");
LOG4CPLUS_ERROR(logger, "Unable to set Gurobi parameter (" << GRBgeterrormsg(env) << ", error code " << error << ").");
throw storm::exceptions::InvalidStateException() << "Unable to set Gurobi parameter (" << GRBgeterrormsg(env) << ", error code " << error << ").";
}
} }
return optimalityStatus == GRB_UNBOUNDED; return optimalityStatus == GRB_UNBOUNDED;
@ -316,120 +263,79 @@ namespace storm {
int optimalityStatus = 0; int optimalityStatus = 0;
int error = GRBgetintattr(model, GRB_INT_ATTR_STATUS, &optimalityStatus); int error = GRBgetintattr(model, GRB_INT_ATTR_STATUS, &optimalityStatus);
if (error) { LOG_THROW(error == 0, storm::exceptions::InvalidStateException, "Unable to retrieve optimization status of Gurobi model (" << GRBgeterrormsg(env) << ", error code " << error << ").");
LOG4CPLUS_ERROR(logger, "Unable to retrieve optimization status of Gurobi model (" << GRBgeterrormsg(env) << ", error code " << error << ").");
throw storm::exceptions::InvalidStateException() << "Unable to retrieve optimization status of Gurobi model (" << GRBgeterrormsg(env) << ", error code " << error << ").";
}
return optimalityStatus == GRB_OPTIMAL; return optimalityStatus == GRB_OPTIMAL;
} }
int_fast64_t GurobiLpSolver::getIntegerValue(uint_fast64_t variableIndex) const { double GurobiLpSolver::getContinuousValue(std::string const& name) const {
if (!this->isOptimal()) { if (!this->isOptimal()) {
if (this->isInfeasible()) { LOG_THROW(!this->isInfeasible(), storm::exceptions::InvalidAccessException, "Unable to get Gurobi solution from infeasible model (" << GRBgeterrormsg(env) << ").");
LOG4CPLUS_ERROR(logger, "Unable to get Gurobi solution from infeasible model (" << GRBgeterrormsg(env) << ")."); LOG_THROW(!this->isUnbounded(), storm::exceptions::InvalidAccessException, "Unable to get Gurobi solution from unbounded model (" << GRBgeterrormsg(env) << ").");
throw storm::exceptions::InvalidStateException() << "Unable to get Gurobi solution from infeasible model (" << GRBgeterrormsg(env) << ")."; LOG_THROW(false, storm::exceptions::InvalidAccessException, "Unable to get Gurobi solution from unoptimized model (" << GRBgeterrormsg(env) << ").");
} else if (this->isUnbounded()) {
LOG4CPLUS_ERROR(logger, "Unable to get Gurobi solution from unbounded model (" << GRBgeterrormsg(env) << ").");
throw storm::exceptions::InvalidStateException() << "Unable to get Gurobi solution from unbounded model (" << GRBgeterrormsg(env) << ").";
} else {
LOG4CPLUS_ERROR(logger, "Unable to get Gurobi solution from unoptimized model (" << GRBgeterrormsg(env) << ").");
throw storm::exceptions::InvalidStateException() << "Unable to get Gurobi solution from unoptimized model (" << GRBgeterrormsg(env) << ").";
}
} }
double value = 0; auto variableIndexPair = this->variableNameToIndexMap.find(name);
int error = GRBgetdblattrelement(model, GRB_DBL_ATTR_X, variableIndex, &value); LOG_THROW(variableIndexPair != this->variableNameToIndexMap.end(), storm::exceptions::InvalidAccessException, "Accessing value of unknown variable '" << name << "'.");
if (error) {
LOG4CPLUS_ERROR(logger, "Unable to get Gurobi solution (" << GRBgeterrormsg(env) << ", error code " << error << ").");
throw storm::exceptions::InvalidStateException() << "Unable to get Gurobi solution (" << GRBgeterrormsg(env) << ", error code " << error << ").";
}
if (std::abs(value - static_cast<int>(value)) <= storm::settings::Settings::getInstance()->getOptionByLongName("gurobiinttol").getArgument(0).getValueAsDouble()) { double value = 0;
// Nothing to do in this case. int error = GRBgetdblattrelement(model, GRB_DBL_ATTR_X, variableIndexPair->second, &value);
} else if (std::abs(value) > storm::settings::Settings::getInstance()->getOptionByLongName("gurobiinttol").getArgument(0).getValueAsDouble()) { LOG_THROW(error == 0, storm::exceptions::InvalidStateException, "Unable to get Gurobi solution (" << GRBgeterrormsg(env) << ", error code " << error << ").");
LOG4CPLUS_ERROR(logger, "Illegal value for integer variable in Gurobi solution (" << value << ").");
throw storm::exceptions::InvalidStateException() << "Illegal value for integer variable in Gurobi solution (" << value << ").";
}
return static_cast<int_fast64_t>(value); return value;
} }
bool GurobiLpSolver::getBinaryValue(uint_fast64_t variableIndex) const { int_fast64_t GurobiLpSolver::getIntegerValue(std::string const& name) const {
if (!this->isOptimal()) { if (!this->isOptimal()) {
if (this->isInfeasible()) { LOG_THROW(!this->isInfeasible(), storm::exceptions::InvalidAccessException, "Unable to get Gurobi solution from infeasible model (" << GRBgeterrormsg(env) << ").");
LOG4CPLUS_ERROR(logger, "Unable to get Gurobi solution from infeasible model (" << GRBgeterrormsg(env) << ")."); LOG_THROW(!this->isUnbounded(), storm::exceptions::InvalidAccessException, "Unable to get Gurobi solution from unbounded model (" << GRBgeterrormsg(env) << ").");
throw storm::exceptions::InvalidStateException() << "Unable to get Gurobi solution from infeasible model (" << GRBgeterrormsg(env) << ")."; LOG_THROW(false, storm::exceptions::InvalidAccessException, "Unable to get Gurobi solution from unoptimized model (" << GRBgeterrormsg(env) << ").");
} else if (this->isUnbounded()) {
LOG4CPLUS_ERROR(logger, "Unable to get Gurobi solution from unbounded model (" << GRBgeterrormsg(env) << ").");
throw storm::exceptions::InvalidStateException() << "Unable to get Gurobi solution from unbounded model (" << GRBgeterrormsg(env) << ").";
} else {
LOG4CPLUS_ERROR(logger, "Unable to get Gurobi solution from unoptimized model (" << GRBgeterrormsg(env) << ").");
throw storm::exceptions::InvalidStateException() << "Unable to get Gurobi solution from unoptimized model (" << GRBgeterrormsg(env) << ").";
}
}
double value = 0;
int error = GRBgetdblattrelement(model, GRB_DBL_ATTR_X, variableIndex, &value);
if (error) {
LOG4CPLUS_ERROR(logger, "Unable to get Gurobi solution (" << GRBgeterrormsg(env) << ", error code " << error << ").");
throw storm::exceptions::InvalidStateException() << "Unable to get Gurobi solution (" << GRBgeterrormsg(env) << ", error code " << error << ").";
} }
if (std::abs(value - 1) <= storm::settings::Settings::getInstance()->getOptionByLongName("gurobiinttol").getArgument(0).getValueAsDouble()) { auto variableIndexPair = this->variableNameToIndexMap.find(name);
// Nothing to do in this case. LOG_THROW(variableIndexPair != this->variableNameToIndexMap.end(), storm::exceptions::InvalidAccessException, "Accessing value of unknown variable '" << name << "'.");
} else if (std::abs(value) > storm::settings::Settings::getInstance()->getOptionByLongName("gurobiinttol").getArgument(0).getValueAsDouble()) {
LOG4CPLUS_ERROR(logger, "Illegal value for binary variable in Gurobi solution (" << value << ").");
throw storm::exceptions::InvalidStateException() << "Illegal value for binary variable in Gurobi solution (" << value << ").";
}
return static_cast<bool>(value); double value = 0;
int error = GRBgetdblattrelement(model, GRB_DBL_ATTR_X, variableIndexPair->second, &value);
LOG_THROW(error == 0, storm::exceptions::InvalidStateException, "Unable to get Gurobi solution (" << GRBgeterrormsg(env) << ", error code " << error << ").");
LOG_THROW(std::abs(static_cast<int>(value) - value) <= storm::settings::Settings::getInstance()->getOptionByLongName("gurobiinttol").getArgument(0).getValueAsDouble(), storm::exceptions::InvalidStateException, "Illegal value for integer variable in Gurobi solution (" << value << ").");
return static_cast<int_fast64_t>(value);
} }
double GurobiLpSolver::getContinuousValue(uint_fast64_t variableIndex) const { bool GurobiLpSolver::getBinaryValue(std::string const& name) const {
if (!this->isOptimal()) { if (!this->isOptimal()) {
if (this->isInfeasible()) { LOG_THROW(!this->isInfeasible(), storm::exceptions::InvalidAccessException, "Unable to get Gurobi solution from infeasible model (" << GRBgeterrormsg(env) << ").");
LOG4CPLUS_ERROR(logger, "Unable to get Gurobi solution from infeasible model (" << GRBgeterrormsg(env) << ")."); LOG_THROW(!this->isUnbounded(), storm::exceptions::InvalidAccessException, "Unable to get Gurobi solution from unbounded model (" << GRBgeterrormsg(env) << ").");
throw storm::exceptions::InvalidStateException() << "Unable to get Gurobi solution from infeasible model (" << GRBgeterrormsg(env) << ")."; LOG_THROW(false, storm::exceptions::InvalidAccessException, "Unable to get Gurobi solution from unoptimized model (" << GRBgeterrormsg(env) << ").");
} else if (this->isUnbounded()) {
LOG4CPLUS_ERROR(logger, "Unable to get Gurobi solution from unbounded model (" << GRBgeterrormsg(env) << ").");
throw storm::exceptions::InvalidStateException() << "Unable to get Gurobi solution from unbounded model (" << GRBgeterrormsg(env) << ").";
} else {
LOG4CPLUS_ERROR(logger, "Unable to get Gurobi solution from unoptimized model (" << GRBgeterrormsg(env) << ").");
throw storm::exceptions::InvalidStateException() << "Unable to get Gurobi solution from unoptimized model (" << GRBgeterrormsg(env) << ").";
}
} }
auto variableIndexPair = this->variableNameToIndexMap.find(name);
LOG_THROW(variableIndexPair != this->variableNameToIndexMap.end(), storm::exceptions::InvalidAccessException, "Accessing value of unknown variable '" << name << "'.");
double value = 0; double value = 0;
int error = GRBgetdblattrelement(model, GRB_DBL_ATTR_X, variableIndex, &value); int error = GRBgetdblattrelement(model, GRB_DBL_ATTR_X, variableIndexPair->second, &value);
if (error) { LOG_THROW(error == 0, storm::exceptions::InvalidStateException, "Unable to get Gurobi solution (" << GRBgeterrormsg(env) << ", error code " << error << ").");
LOG4CPLUS_ERROR(logger, "Unable to get Gurobi solution (" << GRBgeterrormsg(env) << ", error code " << error << ")."); if (value > 0.5) {
throw storm::exceptions::InvalidStateException() << "Unable to get Gurobi solution (" << GRBgeterrormsg(env) << ", error code " << error << ")."; LOG_THROW(std::abs(static_cast<int>(value) - 1) <= storm::settings::Settings::getInstance()->getOptionByLongName("gurobiinttol").getArgument(0).getValueAsDouble(), storm::exceptions::InvalidStateException, "Illegal value for integer variable in Gurobi solution (" << value << ").");
} else {
LOG_THROW(value <= storm::settings::Settings::getInstance()->getOptionByLongName("gurobiinttol").getArgument(0).getValueAsDouble(), storm::exceptions::InvalidStateException, "Illegal value for integer variable in Gurobi solution (" << value << ").");
} }
return value; return static_cast<bool>(value);
} }
double GurobiLpSolver::getObjectiveValue() const { double GurobiLpSolver::getObjectiveValue() const {
if (!this->isOptimal()) { if (!this->isOptimal()) {
if (this->isInfeasible()) { LOG_THROW(!this->isInfeasible(), storm::exceptions::InvalidAccessException, "Unable to get Gurobi solution from infeasible model (" << GRBgeterrormsg(env) << ").");
LOG4CPLUS_ERROR(logger, "Unable to get Gurobi solution from infeasible model (" << GRBgeterrormsg(env) << ")."); LOG_THROW(!this->isUnbounded(), storm::exceptions::InvalidAccessException, "Unable to get Gurobi solution from unbounded model (" << GRBgeterrormsg(env) << ").");
throw storm::exceptions::InvalidStateException() << "Unable to get Gurobi solution from infeasible model (" << GRBgeterrormsg(env) << ")."; LOG_THROW(false, storm::exceptions::InvalidAccessException, "Unable to get Gurobi solution from unoptimized model (" << GRBgeterrormsg(env) << ").");
} else if (this->isUnbounded()) {
LOG4CPLUS_ERROR(logger, "Unable to get Gurobi solution from unbounded model (" << GRBgeterrormsg(env) << ").");
throw storm::exceptions::InvalidStateException() << "Unable to get Gurobi solution from unbounded model (" << GRBgeterrormsg(env) << ").";
} else {
LOG4CPLUS_ERROR(logger, "Unable to get Gurobi solution from unoptimized model (" << GRBgeterrormsg(env) << ").");
throw storm::exceptions::InvalidStateException() << "Unable to get Gurobi solution from unoptimized model (" << GRBgeterrormsg(env) << ").";
}
} }
double value = 0; double value = 0;
int error = GRBgetdblattr(model, GRB_DBL_ATTR_OBJVAL, &value); int error = GRBgetdblattr(model, GRB_DBL_ATTR_OBJVAL, &value);
if (error) { LOG_THROW(error == 0, storm::exceptions::InvalidStateException, "Unable to get Gurobi solution (" << GRBgeterrormsg(env) << ", error code " << error << ").");
LOG4CPLUS_ERROR(logger, "Unable to get Gurobi solution (" << GRBgeterrormsg(env) << ", error code " << error << ").");
throw storm::exceptions::InvalidStateException() << "Unable to get Gurobi solution (" << GRBgeterrormsg(env) << ", error code " << error << ").";
}
return value; return value;
} }

94
src/solver/GurobiLpSolver.h

@ -60,23 +60,40 @@ namespace storm {
*/ */
virtual ~GurobiLpSolver(); virtual ~GurobiLpSolver();
virtual uint_fast64_t createContinuousVariable(std::string const& name, VariableType const& variableType, double lowerBound, double upperBound, double objectiveFunctionCoefficient) override; // Methods to add continuous variables.
virtual uint_fast64_t createIntegerVariable(std::string const& name, VariableType const& variableType, double lowerBound, double upperBound, double objectiveFunctionCoefficient) override; virtual void addBoundedContinuousVariable(std::string const& name, double lowerBound, double upperBound, double objectiveFunctionCoefficient = 0) override;
virtual uint_fast64_t createBinaryVariable(std::string const& name, double objectiveFunctionCoefficient) override; virtual void addLowerBoundedContinuousVariable(std::string const& name, double lowerBound, double objectiveFunctionCoefficient = 0) override;
virtual void addUpperBoundedContinuousVariable(std::string const& name, double upperBound, double objectiveFunctionCoefficient = 0) override;
virtual void addUnboundedContinuousVariable(std::string const& name, double objectiveFunctionCoefficient = 0) override;
// Methods to add integer variables.
virtual void addBoundedIntegerVariable(std::string const& name, double lowerBound, double upperBound, double objectiveFunctionCoefficient = 0) override;
virtual void addLowerBoundedIntegerVariable(std::string const& name, double lowerBound, double objectiveFunctionCoefficient = 0) override;
virtual void addUpperBoundedIntegerVariable(std::string const& name, double upperBound, double objectiveFunctionCoefficient = 0) override;
virtual void addUnboundedIntegerVariable(std::string const& name, double objectiveFunctionCoefficient = 0) override;
// Methods to add binary variables.
virtual void addBinaryVariable(std::string const& name, double objectiveFunctionCoefficient = 0) override;
// Methods to incorporate recent changes.
virtual void update() const override; virtual void update() const override;
virtual void addConstraint(std::string const& name, std::vector<uint_fast64_t> const& variables, std::vector<double> const& coefficients, BoundType const& boundType, double rightHandSideValue) override;
// Methods to add constraints
virtual void addConstraint(std::string const& name, storm::expressions::Expression const& constraint) override;
// Methods to optimize and retrieve optimality status.
virtual void optimize() const override; virtual void optimize() const override;
virtual bool isInfeasible() const override; virtual bool isInfeasible() const override;
virtual bool isUnbounded() const override; virtual bool isUnbounded() const override;
virtual bool isOptimal() const override; virtual bool isOptimal() const override;
// Methods to retrieve values of variables and the objective function in the optimal solutions.
virtual int_fast64_t getIntegerValue(uint_fast64_t variableIndex) const override; virtual double getContinuousValue(std::string const& name) const override;
virtual bool getBinaryValue(uint_fast64_t variableIndex) const override; virtual int_fast64_t getIntegerValue(std::string const& name) const override;
virtual double getContinuousValue(uint_fast64_t variableIndex) const override; virtual bool getBinaryValue(std::string const& name) const override;
virtual double getObjectiveValue() const override; virtual double getObjectiveValue() const override;
// Methods to print the LP problem to a file.
virtual void writeModelToFile(std::string const& filename) const override; virtual void writeModelToFile(std::string const& filename) const override;
private: private:
@ -85,14 +102,28 @@ namespace storm {
*/ */
void setGurobiEnvironmentProperties() const; void setGurobiEnvironmentProperties() const;
/*!
* Adds a variable with the given name, type, lower and upper bound and objective function coefficient.
*
* @param name The name of the variable.
* @param variableType The type of the variable in terms of Gurobi's constants.
* @param lowerBound The lower bound of the range of the variable.
* @param upperBound The upper bound of the range of the variable.
* @param objectiveFunctionCoefficient The coefficient of the variable in the objective function.
*/
void addVariable(std::string const& name, char variableType, double lowerBound, double upperBound, double objectiveFunctionCoefficient);
// The Gurobi environment. // The Gurobi environment.
GRBenv* env; GRBenv* env;
// The Gurobi model. // The Gurobi model.
GRBmodel* model; GRBmodel* model;
// A counter that keeps track of the next free variable index. // The index of the next variable.
uint_fast64_t nextVariableIndex; int nextVariableIndex;
// A mapping from variable names to their indices.
std::map<std::string, int> variableNameToIndexMap;
}; };
#else #else
// If Gurobi is not available, we provide a stub implementation that emits an error if any of its methods is called. // If Gurobi is not available, we provide a stub implementation that emits an error if any of its methods is called.
@ -114,27 +145,46 @@ namespace storm {
throw storm::exceptions::NotImplementedException() << "This version of StoRM was compiled without support for Gurobi. Yet, a method was called that requires this support. Please choose a version of support with Gurobi support."; throw storm::exceptions::NotImplementedException() << "This version of StoRM was compiled without support for Gurobi. Yet, a method was called that requires this support. Please choose a version of support with Gurobi support.";
} }
virtual uint_fast64_t createContinuousVariable(std::string const& name, VariableType const& variableType, double lowerBound, double upperBound, double objectiveFunctionCoefficient) override { virtual void addBoundedContinuousVariable(std::string const& name, double lowerBound, double upperBound, double objectiveFunctionCoefficient = 0) override {
throw storm::exceptions::NotImplementedException() << "This version of StoRM was compiled without support for Gurobi. Yet, a method was called that requires this support. Please choose a version of support with Gurobi support."; throw storm::exceptions::NotImplementedException() << "This version of StoRM was compiled without support for Gurobi. Yet, a method was called that requires this support. Please choose a version of support with Gurobi support.";
} }
virtual uint_fast64_t createIntegerVariable(std::string const& name, VariableType const& variableType, double lowerBound, double upperBound, double objectiveFunctionCoefficient) override { virtual void addLowerBoundedContinuousVariable(std::string const& name, double lowerBound, double objectiveFunctionCoefficient = 0) override {
throw storm::exceptions::NotImplementedException() << "This version of StoRM was compiled without support for Gurobi. Yet, a method was called that requires this support. Please choose a version of support with Gurobi support."; }
virtual void addUpperBoundedContinuousVariable(std::string const& name, double upperBound, double objectiveFunctionCoefficient = 0) override {
throw storm::exceptions::NotImplementedException() << "This version of StoRM was compiled without support for Gurobi. Yet, a method was called that requires this support. Please choose a version of support with Gurobi support."; throw storm::exceptions::NotImplementedException() << "This version of StoRM was compiled without support for Gurobi. Yet, a method was called that requires this support. Please choose a version of support with Gurobi support.";
} }
virtual uint_fast64_t createBinaryVariable(std::string const& name, double objectiveFunctionCoefficient) override { virtual void addUnboundedContinuousVariable(std::string const& name, double objectiveFunctionCoefficient = 0) override {
throw storm::exceptions::NotImplementedException() << "This version of StoRM was compiled without support for Gurobi. Yet, a method was called that requires this support. Please choose a version of support with Gurobi support."; throw storm::exceptions::NotImplementedException() << "This version of StoRM was compiled without support for Gurobi. Yet, a method was called that requires this support. Please choose a version of support with Gurobi support.";
} }
virtual void update() const override { virtual void addBoundedIntegerVariable(std::string const& name, double lowerBound, double upperBound, double objectiveFunctionCoefficient = 0) override {
throw storm::exceptions::NotImplementedException() << "This version of StoRM was compiled without support for Gurobi. Yet, a method was called that requires this support. Please choose a version of support with Gurobi support.";
}
virtual void addLowerBoundedIntegerVariable(std::string const& name, double lowerBound, double objectiveFunctionCoefficient = 0) override {
throw storm::exceptions::NotImplementedException() << "This version of StoRM was compiled without support for Gurobi. Yet, a method was called that requires this support. Please choose a version of support with Gurobi support.";
}
virtual void addUpperBoundedIntegerVariable(std::string const& name, double upperBound, double objectiveFunctionCoefficient = 0) override {
throw storm::exceptions::NotImplementedException() << "This version of StoRM was compiled without support for Gurobi. Yet, a method was called that requires this support. Please choose a version of support with Gurobi support.";
}
virtual void addUnboundedIntegerVariable(std::string const& name, double objectiveFunctionCoefficient = 0) override {
throw storm::exceptions::NotImplementedException() << "This version of StoRM was compiled without support for Gurobi. Yet, a method was called that requires this support. Please choose a version of support with Gurobi support."; throw storm::exceptions::NotImplementedException() << "This version of StoRM was compiled without support for Gurobi. Yet, a method was called that requires this support. Please choose a version of support with Gurobi support.";
} }
virtual void addConstraint(std::string const& name, std::vector<uint_fast64_t> const& variables, std::vector<double> const& coefficients, BoundType const& boundType, double rightHandSideValue) override { virtual uint_fast64_t addBinaryVariable(std::string const& name, double objectiveFunctionCoefficient = 0) override {
throw storm::exceptions::NotImplementedException() << "This version of StoRM was compiled without support for Gurobi. Yet, a method was called that requires this support. Please choose a version of support with Gurobi support."; throw storm::exceptions::NotImplementedException() << "This version of StoRM was compiled without support for Gurobi. Yet, a method was called that requires this support. Please choose a version of support with Gurobi support.";
} }
virtual void setModelSense(ModelSense const& modelSense) { virtual void update() const override {
throw storm::exceptions::NotImplementedException() << "This version of StoRM was compiled without support for Gurobi. Yet, a method was called that requires this support. Please choose a version of support with Gurobi support.";
}
virtual void addConstraint(std::string const& name, storm::expressions::Expression const& constraint) override {
throw storm::exceptions::NotImplementedException() << "This version of StoRM was compiled without support for Gurobi. Yet, a method was called that requires this support. Please choose a version of support with Gurobi support."; throw storm::exceptions::NotImplementedException() << "This version of StoRM was compiled without support for Gurobi. Yet, a method was called that requires this support. Please choose a version of support with Gurobi support.";
} }
@ -154,15 +204,15 @@ namespace storm {
throw storm::exceptions::NotImplementedException() << "This version of StoRM was compiled without support for Gurobi. Yet, a method was called that requires this support. Please choose a version of support with Gurobi support."; throw storm::exceptions::NotImplementedException() << "This version of StoRM was compiled without support for Gurobi. Yet, a method was called that requires this support. Please choose a version of support with Gurobi support.";
} }
virtual int_fast64_t getIntegerValue(uint_fast64_t variableIndex) const override { virtual double getContinuousValue(std::string const& name) const override {
throw storm::exceptions::NotImplementedException() << "This version of StoRM was compiled without support for Gurobi. Yet, a method was called that requires this support. Please choose a version of support with Gurobi support."; throw storm::exceptions::NotImplementedException() << "This version of StoRM was compiled without support for Gurobi. Yet, a method was called that requires this support. Please choose a version of support with Gurobi support.";
} }
virtual bool getBinaryValue(uint_fast64_t variableIndex) const override { virtual int_fast64_t getIntegerValue(std::string const& name) const override {
throw storm::exceptions::NotImplementedException() << "This version of StoRM was compiled without support for Gurobi. Yet, a method was called that requires this support. Please choose a version of support with Gurobi support."; throw storm::exceptions::NotImplementedException() << "This version of StoRM was compiled without support for Gurobi. Yet, a method was called that requires this support. Please choose a version of support with Gurobi support.";
} }
virtual double getContinuousValue(uint_fast64_t variableIndex) const override { virtual bool getBinaryValue(std::string const& name) const override {
throw storm::exceptions::NotImplementedException() << "This version of StoRM was compiled without support for Gurobi. Yet, a method was called that requires this support. Please choose a version of support with Gurobi support."; throw storm::exceptions::NotImplementedException() << "This version of StoRM was compiled without support for Gurobi. Yet, a method was called that requires this support. Please choose a version of support with Gurobi support.";
} }
@ -175,7 +225,7 @@ namespace storm {
} }
}; };
#endif #endif
} }
} }

170
src/solver/LpSolver.h

@ -5,42 +5,25 @@
#include <vector> #include <vector>
#include <cstdint> #include <cstdint>
#include "src/storage/expressions/Expression.h"
namespace storm { namespace storm {
namespace solver { namespace solver {
/*! /*!
* An interface that captures the functionality of an LP solver. * An interface that captures the functionality of an LP solver.
*/ */
class LpSolver { class LpSolver {
public: public:
// An enumeration to represent the possible types of variables. Variables may be either unbounded, have only
// a lower or an upper bound, respectively, or be bounded from below and from above.
enum VariableType {
UNBOUNDED,
LOWER_BOUND,
UPPER_BOUND,
BOUNDED,
};
// An enumeration to represent the possible types of constraints.
enum BoundType {
LESS,
LESS_EQUAL,
GREATER,
GREATER_EQUAL,
EQUAL
};
// An enumeration to represent whether the objective function is to be minimized or maximized. // An enumeration to represent whether the objective function is to be minimized or maximized.
enum ModelSense { enum class ModelSense {
MINIMIZE, Minimize,
MAXIMIZE Maximize
}; };
/*! /*!
* Creates an empty LP solver. By default the objective function is assumed to be minimized. * Creates an empty LP solver. By default the objective function is assumed to be minimized.
*/ */
LpSolver() : currentModelHasBeenOptimized(false), modelSense(MINIMIZE) { LpSolver() : currentModelHasBeenOptimized(false), modelSense(ModelSense::Minimize) {
// Intentionally left empty. // Intentionally left empty.
} }
@ -55,52 +38,99 @@ namespace storm {
} }
/*! /*!
* Creates a continuous variable, i.e. a variable that may take all real values within its bounds. * Registers an upper- and lower-bounded continuous variable, i.e. a variable that may take all real values
* within its bounds.
*
* @param name The name of the variable.
* @param lowerBound The lower bound of the variable.
* @param upperBound The upper bound of the variable.
* @param objectiveFunctionCoefficient The coefficient with which the variable appears in the objective
* function. If omitted (or set to zero), the variable is irrelevant for the objective value.
*/
virtual void addBoundedContinuousVariable(std::string const& name, double lowerBound, double upperBound, double objectiveFunctionCoefficient = 0) = 0;
/*!
* Registers a lower-bounded continuous variable, i.e. a variable that may take all real values up to its
* lower bound.
*
* @param name The name of the variable.
* @param lowerBound The lower bound of the variable.
* @param objectiveFunctionCoefficient The coefficient with which the variable appears in the objective
* function. If omitted (or set to zero), the variable is irrelevant for the objective value.
*/
virtual void addLowerBoundedContinuousVariable(std::string const& name, double lowerBound, double objectiveFunctionCoefficient = 0) = 0;
/*!
* Registers an upper-bounded continuous variable, i.e. a variable that may take all real values up to its
* upper bound.
*
* @param name The name of the variable.
* @param upperBound The upper bound of the variable.
* @param objectiveFunctionCoefficient The coefficient with which the variable appears in the objective
* function. If omitted (or set to zero), the variable is irrelevant for the objective value.
*/
virtual void addUpperBoundedContinuousVariable(std::string const& name, double upperBound, double objectiveFunctionCoefficient = 0) = 0;
/*!
* Registers a unbounded continuous variable, i.e. a variable that may take all real values.
* *
* @param name The name of the variable. * @param name The name of the variable.
* @param variableType The type of the variable.
* @param lowerBound The lower bound of the variable. Note that this parameter is ignored if the variable
* is not bounded from below.
* @param upperBound The upper bound of the variable. Note that this parameter is ignored if the variable
* is not bounded from above.
* @param objectiveFunctionCoefficient The coefficient with which the variable appears in the objective * @param objectiveFunctionCoefficient The coefficient with which the variable appears in the objective
* function. If set to zero, the variable is irrelevant for the objective value. * function. If omitted (or set to zero), the variable is irrelevant for the objective value.
* @return The index of the newly created variable. This index can be used to retrieve the variables value
* in a solution after the model has been optimized.
*/ */
virtual uint_fast64_t createContinuousVariable(std::string const& name, VariableType const& variableType, double lowerBound, double upperBound, double objectiveFunctionCoefficient) = 0; virtual void addUnboundedContinuousVariable(std::string const& name, double objectiveFunctionCoefficient = 0) = 0;
/*! /*!
* Creates an integer variable. * Registers an upper- and lower-bounded integer variable, i.e. a variable that may take all integer values
* within its bounds.
*
* @param name The name of the variable.
* @param lowerBound The lower bound of the variable.
* @param upperBound The upper bound of the variable.
* @param objectiveFunctionCoefficient The coefficient with which the variable appears in the objective
* function. If omitted (or set to zero), the variable is irrelevant for the objective value.
*/
virtual void addBoundedIntegerVariable(std::string const& name, double lowerBound, double upperBound, double objectiveFunctionCoefficient = 0) = 0;
/*!
* Registers a lower-bounded integer variable, i.e. a variable that may take all integer values up to its
* lower bound.
*
* @param name The name of the variable.
* @param lowerBound The lower bound of the variable.
* @param objectiveFunctionCoefficient The coefficient with which the variable appears in the objective
* function. If omitted (or set to zero), the variable is irrelevant for the objective value.
*/
virtual void addLowerBoundedIntegerVariable(std::string const& name, double lowerBound, double objectiveFunctionCoefficient = 0) = 0;
/*!
* Registers an upper-bounded integer variable, i.e. a variable that may take all integer values up to its
* lower bound.
*
* @param name The name of the variable.
* @param upperBound The upper bound of the variable.
* @param objectiveFunctionCoefficient The coefficient with which the variable appears in the objective
* function. If omitted (or set to zero), the variable is irrelevant for the objective value.
*/
virtual void addUpperBoundedIntegerVariable(std::string const& name, double upperBound, double objectiveFunctionCoefficient = 0) = 0;
/*!
* Registers an unbounded integer variable, i.e. a variable that may take all integer values.
* *
* @param name The name of the variable. * @param name The name of the variable.
* @param variableType The type of the variable.
* @param lowerBound The lower bound of the variable. Note that this parameter is ignored if the variable
* is not bounded from below.
* @param upperBound The upper bound of the variable. Note that this parameter is ignored if the variable
* is not bounded from above.
* @param objectiveFunctionCoefficient The coefficient with which the variable appears in the objective * @param objectiveFunctionCoefficient The coefficient with which the variable appears in the objective
* function. If set to zero, the variable is irrelevant for the objective value. * function. If omitted (or set to zero), the variable is irrelevant for the objective value.
* @return The index of the newly created variable. This index can be used to retrieve the variables value
* in a solution after the model has been optimized.
*/ */
virtual uint_fast64_t createIntegerVariable(std::string const& name, VariableType const& variableType, double lowerBound, double upperBound, double objectiveFunctionCoefficient) = 0; virtual void addUnboundedIntegerVariable(std::string const& name, double objectiveFunctionCoefficient = 0) = 0;
/*! /*!
* Creates a binary variable, i.e. a variable that may be either zero or one. * Registers a boolean variable, i.e. a variable that may be either 0 or 1.
* *
* @param name The name of the variable. * @param name The name of the variable.
* @param variableType The type of the variable.
* @param lowerBound The lower bound of the variable. Note that this parameter is ignored if the variable
* is not bounded from below.
* @param upperBound The upper bound of the variable. Note that this parameter is ignored if the variable
* is not bounded from above.
* @param objectiveFunctionCoefficient The coefficient with which the variable appears in the objective * @param objectiveFunctionCoefficient The coefficient with which the variable appears in the objective
* function. If set to zero, the variable is irrelevant for the objective value. * function. If omitted (or set to zero), the variable is irrelevant for the objective value.
* @return The index of the newly created variable. This index can be used to retrieve the variables value
* in a solution after the model has been optimized.
*/ */
virtual uint_fast64_t createBinaryVariable(std::string const& name, double objectiveFunctionCoefficient) = 0; virtual void addBinaryVariable(std::string const& name, double objectiveFunctionCoefficient = 0) = 0;
/*! /*!
* Updates the model to make the variables that have been declared since the last call to <code>update</code> * Updates the model to make the variables that have been declared since the last call to <code>update</code>
@ -109,18 +139,13 @@ namespace storm {
virtual void update() const = 0; virtual void update() const = 0;
/*! /*!
* Adds a constraint of the form * Adds a the given constraint to the LP problem.
* a_1*x_1 + ... + a_n*x_n op c
* to the LP problem.
* *
* @param name The name of the constraint. If empty, the constraint has no name. * @param name The name of the constraint. If empty, the constraint has no name.
* @param variables A vector of variable indices that define the appearing variables x_1, ..., x_n. * @param constraint An expression that represents the constraint. The given constraint must be a linear
* @param coefficients A vector of coefficients that define the a_1, ..., a_n. The i-ith entry specifies the * (in)equality over the registered variables.
* coefficient of the variable whose index appears at the i-th position in the vector of variable indices.
* @param boundType The bound type specifies the operator op used in the constraint.
* @param rhs This defines the value of the constant appearing on the right-hand side of the constraint.
*/ */
virtual void addConstraint(std::string const& name, std::vector<uint_fast64_t> const& variables, std::vector<double> const& coefficients, BoundType const& boundType, double rhs) = 0; virtual void addConstraint(std::string const& name, storm::expressions::Expression const& constraint) = 0;
/*! /*!
* Optimizes the LP problem previously constructed. Afterwards, the methods isInfeasible, isUnbounded and * Optimizes the LP problem previously constructed. Afterwards, the methods isInfeasible, isUnbounded and
@ -154,34 +179,31 @@ namespace storm {
virtual bool isOptimal() const = 0; virtual bool isOptimal() const = 0;
/*! /*!
* Retrieves the value of the integer variable with the given index. Note that this may only be called, if * Retrieves the value of the integer variable with the given name. Note that this may only be called, if
* the model was found to be optimal, i.e. iff isOptimal() returns true. * the model was found to be optimal, i.e. iff isOptimal() returns true.
* *
* @param variableIndex The index of the integer variable whose value to query. If this index does not * @param name The name of the variable whose integer value (in the optimal solution) to retrieve.
* belong to a previously declared integer variable, the behaviour is undefined.
* @return The value of the integer variable in the optimal solution. * @return The value of the integer variable in the optimal solution.
*/ */
virtual int_fast64_t getIntegerValue(uint_fast64_t variableIndex) const = 0; virtual int_fast64_t getIntegerValue(std::string const& name) const = 0;
/*! /*!
* Retrieves the value of the binary variable with the given index. Note that this may only be called, if * Retrieves the value of the binary variable with the given name. Note that this may only be called, if
* the model was found to be optimal, i.e. iff isOptimal() returns true. * the model was found to be optimal, i.e. iff isOptimal() returns true.
* *
* @param variableIndex The index of the binary variable whose value to query. If this index does not * @param name The name of the variable whose binary (boolean) value (in the optimal solution) to retrieve.
* belong to a previously declared binary variable, the behaviour is undefined.
* @return The value of the binary variable in the optimal solution. * @return The value of the binary variable in the optimal solution.
*/ */
virtual bool getBinaryValue(uint_fast64_t variableIndex) const = 0; virtual bool getBinaryValue(std::string const& name) const = 0;
/*! /*!
* Retrieves the value of the continuous variable with the given index. Note that this may only be called, * Retrieves the value of the continuous variable with the given name. Note that this may only be called,
* if the model was found to be optimal, i.e. iff isOptimal() returns true. * if the model was found to be optimal, i.e. iff isOptimal() returns true.
* *
* @param variableIndex The index of the continuous variable whose value to query. If this index does not * @param name The name of the variable whose continuous value (in the optimal solution) to retrieve.
* belong to a previously declared continuous variable, the behaviour is undefined.
* @return The value of the continuous variable in the optimal solution. * @return The value of the continuous variable in the optimal solution.
*/ */
virtual double getContinuousValue(uint_fast64_t variableIndex) const = 0; virtual double getContinuousValue(std::string const& name) const = 0;
/*! /*!
* Retrieves the value of the objective function. Note that this may only be called, if the model was found * Retrieves the value of the objective function. Note that this may only be called, if the model was found

8
src/storage/MaximalEndComponentDecomposition.cpp

@ -88,7 +88,7 @@ namespace storm {
for (uint_fast64_t choice = nondeterministicChoiceIndices[state]; choice < nondeterministicChoiceIndices[state + 1]; ++choice) { for (uint_fast64_t choice = nondeterministicChoiceIndices[state]; choice < nondeterministicChoiceIndices[state + 1]; ++choice) {
bool choiceContainedInMEC = true; bool choiceContainedInMEC = true;
for (auto const& entry : transitionMatrix.getRow(choice)) { for (auto const& entry : transitionMatrix.getRow(choice)) {
if (scc.find(entry.first) == scc.end()) { if (scc.find(entry.getColumn()) == scc.end()) {
choiceContainedInMEC = false; choiceContainedInMEC = false;
break; break;
} }
@ -116,8 +116,8 @@ namespace storm {
statesToCheck.clear(); statesToCheck.clear();
for (auto state : statesToRemove) { for (auto state : statesToRemove) {
for (auto const& entry : backwardTransitions.getRow(state)) { for (auto const& entry : backwardTransitions.getRow(state)) {
if (scc.find(entry.first) != scc.end()) { if (scc.find(entry.getColumn()) != scc.end()) {
statesToCheck.set(entry.first); statesToCheck.set(entry.getColumn());
} }
} }
} }
@ -154,7 +154,7 @@ namespace storm {
for (uint_fast64_t choice = nondeterministicChoiceIndices[state]; choice < nondeterministicChoiceIndices[state + 1]; ++choice) { for (uint_fast64_t choice = nondeterministicChoiceIndices[state]; choice < nondeterministicChoiceIndices[state + 1]; ++choice) {
bool choiceContained = true; bool choiceContained = true;
for (auto const& entry : transitionMatrix.getRow(choice)) { for (auto const& entry : transitionMatrix.getRow(choice)) {
if (mecStateSet.find(entry.first) == mecStateSet.end()) { if (mecStateSet.find(entry.getColumn()) == mecStateSet.end()) {
choiceContained = false; choiceContained = false;
break; break;
} }

158
src/storage/SparseMatrix.cpp

@ -17,6 +17,41 @@ extern log4cplus::Logger logger;
namespace storm { namespace storm {
namespace storage { namespace storage {
template<typename T>
MatrixEntry<T>::MatrixEntry(uint_fast64_t column, T value) : entry(column, value) {
// Intentionally left empty.
}
template<typename T>
MatrixEntry<T>::MatrixEntry(std::pair<uint_fast64_t, T>&& pair) : entry(std::move(pair)) {
// Intentionally left empty.
}
template<typename T>
uint_fast64_t const& MatrixEntry<T>::getColumn() const {
return this->entry.first;
}
template<typename T>
uint_fast64_t& MatrixEntry<T>::getColumn() {
return this->entry.first;
}
template<typename T>
T const& MatrixEntry<T>::getValue() const {
return this->entry.second;
}
template<typename T>
T& MatrixEntry<T>::getValue() {
return this->entry.second;
}
template<typename T>
std::pair<uint_fast64_t, T> const& MatrixEntry<T>::getColumnValuePair() const {
return this->entry;
}
template<typename T> template<typename T>
SparseMatrixBuilder<T>::SparseMatrixBuilder(uint_fast64_t rows, uint_fast64_t columns, uint_fast64_t entries, bool hasCustomRowGrouping, uint_fast64_t rowGroups) : rowCountSet(rows != 0), rowCount(rows), columnCountSet(columns != 0), columnCount(columns), entryCount(entries), hasCustomRowGrouping(hasCustomRowGrouping), rowGroupCountSet(rowGroups != 0), rowGroupCount(rowGroups), rowGroupIndices(), storagePreallocated(rows != 0 && columns != 0 && entries != 0), columnsAndValues(), rowIndications(), currentEntryCount(0), lastRow(0), lastColumn(0), currentRowGroup(0) { SparseMatrixBuilder<T>::SparseMatrixBuilder(uint_fast64_t rows, uint_fast64_t columns, uint_fast64_t entries, bool hasCustomRowGrouping, uint_fast64_t rowGroups) : rowCountSet(rows != 0), rowCount(rows), columnCountSet(columns != 0), columnCount(columns), entryCount(entries), hasCustomRowGrouping(hasCustomRowGrouping), rowGroupCountSet(rowGroups != 0), rowGroupCount(rowGroups), rowGroupIndices(), storagePreallocated(rows != 0 && columns != 0 && entries != 0), columnsAndValues(), rowIndications(), currentEntryCount(0), lastRow(0), lastColumn(0), currentRowGroup(0) {
this->prepareInternalStorage(); this->prepareInternalStorage();
@ -168,7 +203,7 @@ namespace storm {
void SparseMatrixBuilder<T>::prepareInternalStorage() { void SparseMatrixBuilder<T>::prepareInternalStorage() {
// Only allocate the memory for the matrix contents if the dimensions of the matrix are already known. // Only allocate the memory for the matrix contents if the dimensions of the matrix are already known.
if (storagePreallocated) { if (storagePreallocated) {
columnsAndValues = std::vector<std::pair<uint_fast64_t, T>>(entryCount, std::make_pair(0, storm::utility::constantZero<T>())); columnsAndValues = std::vector<MatrixEntry<T>>(entryCount, MatrixEntry<T>(0, storm::utility::constantZero<T>()));
rowIndications = std::vector<uint_fast64_t>(rowCount + 1, 0); rowIndications = std::vector<uint_fast64_t>(rowCount + 1, 0);
} else { } else {
rowIndications.push_back(0); rowIndications.push_back(0);
@ -218,17 +253,17 @@ namespace storm {
} }
template<typename T> template<typename T>
SparseMatrix<T>::SparseMatrix() : rowCount(0), columnCount(0), entryCount(0), columnsAndValues(), rowIndications(), rowGroupIndices() { SparseMatrix<T>::SparseMatrix() : rowCount(0), columnCount(0), entryCount(0), nonzeroEntryCount(0), columnsAndValues(), rowIndications(), rowGroupIndices() {
// Intentionally left empty. // Intentionally left empty.
} }
template<typename T> template<typename T>
SparseMatrix<T>::SparseMatrix(SparseMatrix<T> const& other) : rowCount(other.rowCount), columnCount(other.columnCount), entryCount(other.entryCount), columnsAndValues(other.columnsAndValues), rowIndications(other.rowIndications), rowGroupIndices(other.rowGroupIndices) { SparseMatrix<T>::SparseMatrix(SparseMatrix<T> const& other) : rowCount(other.rowCount), columnCount(other.columnCount), entryCount(other.entryCount), nonzeroEntryCount(other.nonzeroEntryCount), columnsAndValues(other.columnsAndValues), rowIndications(other.rowIndications), rowGroupIndices(other.rowGroupIndices) {
// Intentionally left empty. // Intentionally left empty.
} }
template<typename T> template<typename T>
SparseMatrix<T>::SparseMatrix(SparseMatrix<T>&& other) : rowCount(other.rowCount), columnCount(other.columnCount), entryCount(other.entryCount), columnsAndValues(std::move(other.columnsAndValues)), rowIndications(std::move(other.rowIndications)), rowGroupIndices(std::move(other.rowGroupIndices)) { SparseMatrix<T>::SparseMatrix(SparseMatrix<T>&& other) : rowCount(other.rowCount), columnCount(other.columnCount), entryCount(other.entryCount), nonzeroEntryCount(other.nonzeroEntryCount), columnsAndValues(std::move(other.columnsAndValues)), rowIndications(std::move(other.rowIndications)), rowGroupIndices(std::move(other.rowGroupIndices)) {
// Now update the source matrix // Now update the source matrix
other.rowCount = 0; other.rowCount = 0;
other.columnCount = 0; other.columnCount = 0;
@ -236,13 +271,21 @@ namespace storm {
} }
template<typename T> template<typename T>
SparseMatrix<T>::SparseMatrix(uint_fast64_t columnCount, std::vector<uint_fast64_t> const& rowIndications, std::vector<std::pair<uint_fast64_t, T>> const& columnsAndValues, std::vector<uint_fast64_t> const& rowGroupIndices) : rowCount(rowIndications.size() - 1), columnCount(columnCount), entryCount(columnsAndValues.size()), columnsAndValues(columnsAndValues), rowIndications(rowIndications), rowGroupIndices(rowGroupIndices) { SparseMatrix<T>::SparseMatrix(uint_fast64_t columnCount, std::vector<uint_fast64_t> const& rowIndications, std::vector<MatrixEntry<T>> const& columnsAndValues, std::vector<uint_fast64_t> const& rowGroupIndices) : rowCount(rowIndications.size() - 1), columnCount(columnCount), entryCount(columnsAndValues.size()), nonzeroEntryCount(0), columnsAndValues(columnsAndValues), rowIndications(rowIndications), rowGroupIndices(rowGroupIndices) {
// Intentionally left empty. for (auto const& element : *this) {
if (element.getValue() != storm::utility::constantZero<T>()) {
++this->nonzeroEntryCount;
}
}
} }
template<typename T> template<typename T>
SparseMatrix<T>::SparseMatrix(uint_fast64_t columnCount, std::vector<uint_fast64_t>&& rowIndications, std::vector<std::pair<uint_fast64_t, T>>&& columnsAndValues, std::vector<uint_fast64_t>&& rowGroupIndices) : rowCount(rowIndications.size() - 1), columnCount(columnCount), entryCount(columnsAndValues.size()), columnsAndValues(std::move(columnsAndValues)), rowIndications(std::move(rowIndications)), rowGroupIndices(std::move(rowGroupIndices)) { SparseMatrix<T>::SparseMatrix(uint_fast64_t columnCount, std::vector<uint_fast64_t>&& rowIndications, std::vector<MatrixEntry<T>>&& columnsAndValues, std::vector<uint_fast64_t>&& rowGroupIndices) : rowCount(rowIndications.size() - 1), columnCount(columnCount), entryCount(columnsAndValues.size()), nonzeroEntryCount(0), columnsAndValues(std::move(columnsAndValues)), rowIndications(std::move(rowIndications)), rowGroupIndices(std::move(rowGroupIndices)) {
// Intentionally left empty. for (auto const& element : *this) {
if (element.getValue() != storm::utility::constantZero<T>()) {
++this->nonzeroEntryCount;
}
}
} }
template<typename T> template<typename T>
@ -252,6 +295,7 @@ namespace storm {
rowCount = other.rowCount; rowCount = other.rowCount;
columnCount = other.columnCount; columnCount = other.columnCount;
entryCount = other.entryCount; entryCount = other.entryCount;
nonzeroEntryCount = other.nonzeroEntryCount;
columnsAndValues = other.columnsAndValues; columnsAndValues = other.columnsAndValues;
rowIndications = other.rowIndications; rowIndications = other.rowIndications;
@ -268,6 +312,7 @@ namespace storm {
rowCount = other.rowCount; rowCount = other.rowCount;
columnCount = other.columnCount; columnCount = other.columnCount;
entryCount = other.entryCount; entryCount = other.entryCount;
nonzeroEntryCount = other.nonzeroEntryCount;
columnsAndValues = std::move(other.columnsAndValues); columnsAndValues = std::move(other.columnsAndValues);
rowIndications = std::move(other.rowIndications); rowIndications = std::move(other.rowIndications);
@ -294,17 +339,17 @@ namespace storm {
for (uint_fast64_t row = 0; row < this->getRowCount(); ++row) { for (uint_fast64_t row = 0; row < this->getRowCount(); ++row) {
for (const_iterator it1 = this->begin(row), ite1 = this->end(row), it2 = other.begin(row), ite2 = other.end(row); it1 != ite1 && it2 != ite2; ++it1, ++it2) { for (const_iterator it1 = this->begin(row), ite1 = this->end(row), it2 = other.begin(row), ite2 = other.end(row); it1 != ite1 && it2 != ite2; ++it1, ++it2) {
// Skip over all zero entries in both matrices. // Skip over all zero entries in both matrices.
while (it1 != ite1 && it1->second == storm::utility::constantZero<T>()) { while (it1 != ite1 && it1->getValue() == storm::utility::constantZero<T>()) {
++it1; ++it1;
} }
while (it2 != ite2 && it2->second == storm::utility::constantZero<T>()) { while (it2 != ite2 && it2->getValue() == storm::utility::constantZero<T>()) {
++it2; ++it2;
} }
if ((it1 == ite1) || (it2 == ite2)) { if ((it1 == ite1) || (it2 == ite2)) {
equalityResult = (it1 == ite1) ^ (it2 == ite2); equalityResult = (it1 == ite1) ^ (it2 == ite2);
break; break;
} else { } else {
if (it1->first != it2->first || it1->second != it2->second) { if (it1->getColumn() != it2->getColumn() || it1->getValue() != it2->getValue()) {
equalityResult = false; equalityResult = false;
break; break;
} }
@ -330,6 +375,11 @@ namespace storm {
return entryCount; return entryCount;
} }
template<typename T>
uint_fast64_t SparseMatrix<T>::getNonzeroEntryCount() const {
return nonzeroEntryCount;
}
template<typename T> template<typename T>
uint_fast64_t SparseMatrix<T>::getRowGroupCount() const { uint_fast64_t SparseMatrix<T>::getRowGroupCount() const {
return rowGroupIndices.size() - 1; return rowGroupIndices.size() - 1;
@ -374,12 +424,12 @@ namespace storm {
// If there is at least one entry in this row, we can just set it to one, modify its column value to the // If there is at least one entry in this row, we can just set it to one, modify its column value to the
// one given by the parameter and set all subsequent elements of this row to zero. // one given by the parameter and set all subsequent elements of this row to zero.
columnValuePtr->first = column; columnValuePtr->getColumn() = column;
columnValuePtr->second = storm::utility::constantOne<T>(); columnValuePtr->getValue() = storm::utility::constantOne<T>();
++columnValuePtr; ++columnValuePtr;
for (; columnValuePtr != columnValuePtrEnd; ++columnValuePtr) { for (; columnValuePtr != columnValuePtrEnd; ++columnValuePtr) {
columnValuePtr->first = 0; columnValuePtr->getColumn() = 0;
columnValuePtr->second = storm::utility::constantZero<T>(); columnValuePtr->getValue() = storm::utility::constantZero<T>();
} }
} }
@ -387,8 +437,8 @@ namespace storm {
T SparseMatrix<T>::getConstrainedRowSum(uint_fast64_t row, storm::storage::BitVector const& constraint) const { T SparseMatrix<T>::getConstrainedRowSum(uint_fast64_t row, storm::storage::BitVector const& constraint) const {
T result(0); T result(0);
for (const_iterator it = this->begin(row), ite = this->end(row); it != ite; ++it) { for (const_iterator it = this->begin(row), ite = this->end(row); it != ite; ++it) {
if (constraint.get(it->first)) { if (constraint.get(it->getColumn())) {
result += it->second; result += it->getValue();
} }
} }
return result; return result;
@ -442,10 +492,10 @@ namespace storm {
bool foundDiagonalElement = false; bool foundDiagonalElement = false;
for (const_iterator it = this->begin(i), ite = this->end(i); it != ite; ++it) { for (const_iterator it = this->begin(i), ite = this->end(i); it != ite; ++it) {
if (columnConstraint.get(it->first)) { if (columnConstraint.get(it->getColumn())) {
++subEntries; ++subEntries;
if (index == it->first) { if (index == it->getColumn()) {
foundDiagonalElement = true; foundDiagonalElement = true;
} }
} }
@ -492,14 +542,14 @@ namespace storm {
bool insertedDiagonalElement = false; bool insertedDiagonalElement = false;
for (const_iterator it = this->begin(i), ite = this->end(i); it != ite; ++it) { for (const_iterator it = this->begin(i), ite = this->end(i); it != ite; ++it) {
if (columnConstraint.get(it->first)) { if (columnConstraint.get(it->getColumn())) {
if (index == it->first) { if (index == it->getColumn()) {
insertedDiagonalElement = true; insertedDiagonalElement = true;
} else if (insertDiagonalEntries && !insertedDiagonalElement && it->first > index) { } else if (insertDiagonalEntries && !insertedDiagonalElement && it->getColumn() > index) {
matrixBuilder.addNextValue(rowCount, bitsSetBeforeIndex[index], storm::utility::constantZero<T>()); matrixBuilder.addNextValue(rowCount, bitsSetBeforeIndex[index], storm::utility::constantZero<T>());
insertedDiagonalElement = true; insertedDiagonalElement = true;
} }
matrixBuilder.addNextValue(rowCount, bitsSetBeforeIndex[it->first], it->second); matrixBuilder.addNextValue(rowCount, bitsSetBeforeIndex[it->getColumn()], it->getValue());
} }
} }
if (insertDiagonalEntries && !insertedDiagonalElement) { if (insertDiagonalEntries && !insertedDiagonalElement) {
@ -525,7 +575,7 @@ namespace storm {
// Iterate through that row and count the number of slots we have to reserve for copying. // Iterate through that row and count the number of slots we have to reserve for copying.
bool foundDiagonalElement = false; bool foundDiagonalElement = false;
for (const_iterator it = this->begin(rowToCopy), ite = this->end(rowToCopy); it != ite; ++it) { for (const_iterator it = this->begin(rowToCopy), ite = this->end(rowToCopy); it != ite; ++it) {
if (it->first == rowGroupIndex) { if (it->getColumn() == rowGroupIndex) {
foundDiagonalElement = true; foundDiagonalElement = true;
} }
++subEntries; ++subEntries;
@ -547,13 +597,13 @@ namespace storm {
// there is no entry yet. // there is no entry yet.
bool insertedDiagonalElement = false; bool insertedDiagonalElement = false;
for (const_iterator it = this->begin(rowToCopy), ite = this->end(rowToCopy); it != ite; ++it) { for (const_iterator it = this->begin(rowToCopy), ite = this->end(rowToCopy); it != ite; ++it) {
if (it->first == rowGroupIndex) { if (it->getColumn() == rowGroupIndex) {
insertedDiagonalElement = true; insertedDiagonalElement = true;
} else if (insertDiagonalEntries && !insertedDiagonalElement && it->first > rowGroupIndex) { } else if (insertDiagonalEntries && !insertedDiagonalElement && it->getColumn() > rowGroupIndex) {
matrixBuilder.addNextValue(rowGroupIndex, rowGroupIndex, storm::utility::constantZero<T>()); matrixBuilder.addNextValue(rowGroupIndex, rowGroupIndex, storm::utility::constantZero<T>());
insertedDiagonalElement = true; insertedDiagonalElement = true;
} }
matrixBuilder.addNextValue(rowGroupIndex, it->first, it->second); matrixBuilder.addNextValue(rowGroupIndex, it->getColumn(), it->getValue());
} }
if (insertDiagonalEntries && !insertedDiagonalElement) { if (insertDiagonalEntries && !insertedDiagonalElement) {
matrixBuilder.addNextValue(rowGroupIndex, rowGroupIndex, storm::utility::constantZero<T>()); matrixBuilder.addNextValue(rowGroupIndex, rowGroupIndex, storm::utility::constantZero<T>());
@ -571,13 +621,13 @@ namespace storm {
uint_fast64_t entryCount = this->getEntryCount(); uint_fast64_t entryCount = this->getEntryCount();
std::vector<uint_fast64_t> rowIndications(rowCount + 1); std::vector<uint_fast64_t> rowIndications(rowCount + 1);
std::vector<std::pair<uint_fast64_t, T>> columnsAndValues(entryCount); std::vector<MatrixEntry<T>> columnsAndValues(entryCount);
// First, we need to count how many entries each column has. // First, we need to count how many entries each column has.
for (uint_fast64_t group = 0; group < columnCount; ++group) { for (uint_fast64_t group = 0; group < columnCount; ++group) {
for (auto const& transition : joinGroups ? this->getRowGroup(group) : this->getRow(group)) { for (auto const& transition : joinGroups ? this->getRowGroup(group) : this->getRow(group)) {
if (transition.second != storm::utility::constantZero<T>()) { if (transition.getValue() != storm::utility::constantZero<T>()) {
++rowIndications[transition.first + 1]; ++rowIndications[transition.getColumn() + 1];
} }
} }
} }
@ -595,9 +645,9 @@ namespace storm {
// Now we are ready to actually fill in the values of the transposed matrix. // Now we are ready to actually fill in the values of the transposed matrix.
for (uint_fast64_t group = 0; group < columnCount; ++group) { for (uint_fast64_t group = 0; group < columnCount; ++group) {
for (auto const& transition : joinGroups ? this->getRowGroup(group) : this->getRow(group)) { for (auto const& transition : joinGroups ? this->getRowGroup(group) : this->getRow(group)) {
if (transition.second != storm::utility::constantZero<T>()) { if (transition.getValue() != storm::utility::constantZero<T>()) {
columnsAndValues[nextIndices[transition.first]] = std::make_pair(group, transition.second); columnsAndValues[nextIndices[transition.getColumn()]] = std::make_pair(group, transition.getValue());
nextIndices[transition.first]++; nextIndices[transition.getColumn()]++;
} }
} }
} }
@ -626,8 +676,8 @@ namespace storm {
bool foundDiagonalElement = false; bool foundDiagonalElement = false;
for (uint_fast64_t group = 0; group < this->getRowGroupCount(); ++group) { for (uint_fast64_t group = 0; group < this->getRowGroupCount(); ++group) {
for (auto& entry : this->getRowGroup(group)) { for (auto& entry : this->getRowGroup(group)) {
if (entry.first == group) { if (entry.getColumn() == group) {
entry.second = one - entry.second; entry.getValue() = one - entry.getValue();
foundDiagonalElement = true; foundDiagonalElement = true;
} }
} }
@ -644,8 +694,8 @@ namespace storm {
// Iterate over all row groups and negate all the elements that are not on the diagonal. // Iterate over all row groups and negate all the elements that are not on the diagonal.
for (uint_fast64_t group = 0; group < this->getRowGroupCount(); ++group) { for (uint_fast64_t group = 0; group < this->getRowGroupCount(); ++group) {
for (auto& entry : this->getRowGroup(group)) { for (auto& entry : this->getRowGroup(group)) {
if (entry.first != group) { if (entry.getColumn() != group) {
entry.second = -entry.second; entry.getValue() = -entry.getValue();
} }
} }
} }
@ -656,8 +706,8 @@ namespace storm {
// Iterate over all rows and negate all the elements that are not on the diagonal. // Iterate over all rows and negate all the elements that are not on the diagonal.
for (uint_fast64_t group = 0; group < this->getRowGroupCount(); ++group) { for (uint_fast64_t group = 0; group < this->getRowGroupCount(); ++group) {
for (auto& entry : this->getRowGroup(group)) { for (auto& entry : this->getRowGroup(group)) {
if (entry.first == group) { if (entry.getColumn() == group) {
entry.second = storm::utility::constantZero<T>(); entry.getValue() = storm::utility::constantZero<T>();
} }
} }
} }
@ -680,9 +730,9 @@ namespace storm {
// to invert the entry. // to invert the entry.
T diagonalValue = storm::utility::constantZero<T>(); T diagonalValue = storm::utility::constantZero<T>();
for (const_iterator it = this->begin(rowNumber), ite = this->end(rowNumber); it != ite; ++it) { for (const_iterator it = this->begin(rowNumber), ite = this->end(rowNumber); it != ite; ++it) {
if (it->first == rowNumber) { if (it->getColumn() == rowNumber) {
diagonalValue += it->second; diagonalValue += it->getValue();
} else if (it->first > rowNumber) { } else if (it->getColumn() > rowNumber) {
break; break;
} }
} }
@ -701,13 +751,13 @@ namespace storm {
// add the result to the corresponding position in the vector. // add the result to the corresponding position in the vector.
for (uint_fast64_t row = 0; row < rowCount && row < otherMatrix.rowCount; ++row) { for (uint_fast64_t row = 0; row < rowCount && row < otherMatrix.rowCount; ++row) {
for (const_iterator it1 = this->begin(row), ite1 = this->end(row), it2 = otherMatrix.begin(row), ite2 = otherMatrix.end(row); it1 != ite1 && it2 != ite2; ++it1) { for (const_iterator it1 = this->begin(row), ite1 = this->end(row), it2 = otherMatrix.begin(row), ite2 = otherMatrix.end(row); it1 != ite1 && it2 != ite2; ++it1) {
if (it1->first < it2->first) { if (it1->getColumn() < it2->getColumn()) {
continue; continue;
} else { } else {
// If the precondition of this method (i.e. that the given matrix is a submatrix // If the precondition of this method (i.e. that the given matrix is a submatrix
// of the current one) was fulfilled, we know now that the two elements are in // of the current one) was fulfilled, we know now that the two elements are in
// the same column, so we can multiply and add them to the row sum vector. // the same column, so we can multiply and add them to the row sum vector.
result[row] += it2->second * it1->second; result[row] += it2->getValue() * it1->getValue();
++it2; ++it2;
} }
} }
@ -735,7 +785,7 @@ namespace storm {
*resultIterator = storm::utility::constantZero<T>(); *resultIterator = storm::utility::constantZero<T>();
for (ite = this->begin() + *(rowIterator + 1); it != ite; ++it) { for (ite = this->begin() + *(rowIterator + 1); it != ite; ++it) {
*resultIterator += it->second * vector[it->first]; *resultIterator += it->getValue() * vector[it->getColumn()];
} }
} }
}); });
@ -750,7 +800,7 @@ namespace storm {
*resultIterator = storm::utility::constantZero<T>(); *resultIterator = storm::utility::constantZero<T>();
for (ite = this->begin() + *(rowIterator + 1); it != ite; ++it) { for (ite = this->begin() + *(rowIterator + 1); it != ite; ++it) {
*resultIterator += it->second * vector[it->first]; *resultIterator += it->getValue() * vector[it->getColumn()];
} }
} }
#endif #endif
@ -761,7 +811,7 @@ namespace storm {
uint_fast64_t size = sizeof(*this); uint_fast64_t size = sizeof(*this);
// Add size of columns and values. // Add size of columns and values.
size += sizeof(std::pair<uint_fast64_t, T>) * columnsAndValues.capacity(); size += sizeof(MatrixEntry<T>) * columnsAndValues.capacity();
// Add row_indications size. // Add row_indications size.
size += sizeof(uint_fast64_t) * rowIndications.capacity(); size += sizeof(uint_fast64_t) * rowIndications.capacity();
@ -833,7 +883,7 @@ namespace storm {
T SparseMatrix<T>::getRowSum(uint_fast64_t row) const { T SparseMatrix<T>::getRowSum(uint_fast64_t row) const {
T sum = storm::utility::constantZero<T>(); T sum = storm::utility::constantZero<T>();
for (const_iterator it = this->begin(row), ite = this->end(row); it != ite; ++it) { for (const_iterator it = this->begin(row), ite = this->end(row); it != ite; ++it) {
sum += it->second; sum += it->getValue();
} }
return sum; return sum;
} }
@ -849,10 +899,10 @@ namespace storm {
for (uint_fast64_t row = 0; row < this->getRowCount(); ++row) { for (uint_fast64_t row = 0; row < this->getRowCount(); ++row) {
for (const_iterator it1 = this->begin(row), ite1 = this->end(row), it2 = matrix.begin(row), ite2 = matrix.end(row); it1 != ite1; ++it1) { for (const_iterator it1 = this->begin(row), ite1 = this->end(row), it2 = matrix.begin(row), ite2 = matrix.end(row); it1 != ite1; ++it1) {
// Skip over all entries of the other matrix that are before the current entry in the current matrix. // Skip over all entries of the other matrix that are before the current entry in the current matrix.
while (it2 != ite2 && it2->first < it1->first) { while (it2 != ite2 && it2->getColumn() < it1->getColumn()) {
++it2; ++it2;
} }
if (it2 == ite2 || it1->first != it2->first) { if (it2 == ite2 || it1->getColumn() != it2->getColumn()) {
return false; return false;
} }
} }
@ -879,8 +929,8 @@ namespace storm {
out << i << "\t(\t"; out << i << "\t(\t";
uint_fast64_t currentRealIndex = 0; uint_fast64_t currentRealIndex = 0;
while (currentRealIndex < matrix.columnCount) { while (currentRealIndex < matrix.columnCount) {
if (nextIndex < matrix.rowIndications[i + 1] && currentRealIndex == matrix.columnsAndValues[nextIndex].first) { if (nextIndex < matrix.rowIndications[i + 1] && currentRealIndex == matrix.columnsAndValues[nextIndex].getColumn()) {
out << matrix.columnsAndValues[nextIndex].second << "\t"; out << matrix.columnsAndValues[nextIndex].getValue() << "\t";
++nextIndex; ++nextIndex;
} else { } else {
out << "0\t"; out << "0\t";
@ -915,10 +965,12 @@ namespace storm {
return result; return result;
} }
// Explicitly instantiate the builder and the matrix. // Explicitly instantiate the entry, builder and the matrix.
template class MatrixEntry<double>;
template class SparseMatrixBuilder<double>; template class SparseMatrixBuilder<double>;
template class SparseMatrix<double>; template class SparseMatrix<double>;
template std::ostream& operator<<(std::ostream& out, SparseMatrix<double> const& matrix); template std::ostream& operator<<(std::ostream& out, SparseMatrix<double> const& matrix);
template class MatrixEntry<int>;
template class SparseMatrixBuilder<int>; template class SparseMatrixBuilder<int>;
template class SparseMatrix<int>; template class SparseMatrix<int>;
template std::ostream& operator<<(std::ostream& out, SparseMatrix<int> const& matrix); template std::ostream& operator<<(std::ostream& out, SparseMatrix<int> const& matrix);

100
src/storage/SparseMatrix.h

@ -8,6 +8,7 @@
#include "src/storage/BitVector.h" #include "src/storage/BitVector.h"
#include "src/utility/constants.h" #include "src/utility/constants.h"
#include "src/utility/OsDetection.h"
#include "src/exceptions/InvalidArgumentException.h" #include "src/exceptions/InvalidArgumentException.h"
#include "src/exceptions/OutOfRangeException.h" #include "src/exceptions/OutOfRangeException.h"
@ -27,6 +28,83 @@ namespace storm {
// Forward declare matrix class. // Forward declare matrix class.
template<typename T> class SparseMatrix; template<typename T> class SparseMatrix;
template<typename T>
class MatrixEntry {
public:
/*!
* Constructs a matrix entry with the given column and value.
*
* @param column The column of the matrix entry.
* @param value The value of the matrix entry.
*/
MatrixEntry(uint_fast64_t column, T value);
/*!
* Move-constructs the matrix entry fro the given column-value pair.
*
* @param pair The column-value pair from which to move-construct the matrix entry.
*/
MatrixEntry(std::pair<uint_fast64_t, T>&& pair);
MatrixEntry() = default;
MatrixEntry(MatrixEntry const& other) = default;
MatrixEntry& operator=(MatrixEntry const& other) = default;
#ifndef WINDOWS
MatrixEntry(MatrixEntry&& other) = default;
MatrixEntry& operator=(MatrixEntry&& other) = default;
#endif
/*!
* Retrieves the column of the matrix entry.
*
* @return The column of the matrix entry.
*/
uint_fast64_t const& getColumn() const;
/*!
* Retrieves the column of the matrix entry.
*
* @return The column of the matrix entry.
*/
uint_fast64_t& getColumn();
/*!
* Retrieves the value of the matrix entry.
*
* @return The value of the matrix entry.
*/
T const& getValue() const;
/*!
* Retrieves the value of the matrix entry.
*
* @return The value of the matrix entry.
*/
T& getValue();
/*!
* Retrieves a pair of column and value that characterizes this entry.
*
* @return A column-value pair that characterizes this entry.
*/
std::pair<uint_fast64_t, T> const& getColumnValuePair() const;
private:
// The actual matrix entry.
std::pair<uint_fast64_t, T> entry;
};
/*!
* Computes the hash value of a matrix entry.
*/
template<typename T>
std::size_t hash_value(MatrixEntry<T> const& matrixEntry) {
std::size_t seed = 0;
boost::hash_combine(seed, matrixEntry.getColumn());
boost::hash_combine(seed, matrixEntry.getValue());
return seed;
}
/*! /*!
* A class that can be used to build a sparse matrix by adding value by value. * A class that can be used to build a sparse matrix by adding value by value.
*/ */
@ -128,7 +206,7 @@ namespace storm {
bool storagePreallocated; bool storagePreallocated;
// The storage for the columns and values of all entries in the matrix. // The storage for the columns and values of all entries in the matrix.
std::vector<std::pair<uint_fast64_t, T>> columnsAndValues; std::vector<MatrixEntry<T>> columnsAndValues;
// A vector containing the indices at which each given row begins. This index is to be interpreted as an // A vector containing the indices at which each given row begins. This index is to be interpreted as an
// index in the valueStorage and the columnIndications vectors. Put differently, the values of the entries // index in the valueStorage and the columnIndications vectors. Put differently, the values of the entries
@ -175,8 +253,8 @@ namespace storm {
friend class storm::adapters::EigenAdapter; friend class storm::adapters::EigenAdapter;
friend class storm::adapters::StormAdapter; friend class storm::adapters::StormAdapter;
typedef typename std::vector<std::pair<uint_fast64_t, T>>::iterator iterator; typedef typename std::vector<MatrixEntry<T>>::iterator iterator;
typedef typename std::vector<std::pair<uint_fast64_t, T>>::const_iterator const_iterator; typedef typename std::vector<MatrixEntry<T>>::const_iterator const_iterator;
/*! /*!
* This class represents a number of consecutive rows of the matrix. * This class represents a number of consecutive rows of the matrix.
@ -284,7 +362,7 @@ namespace storm {
* @param columnsAndValues The vector containing the columns and values of the entries in the matrix. * @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 rowGroupIndices The vector representing the row groups in the matrix.
*/ */
SparseMatrix(uint_fast64_t columnCount, std::vector<uint_fast64_t> const& rowIndications, std::vector<std::pair<uint_fast64_t, T>> const& columnsAndValues, std::vector<uint_fast64_t> const& rowGroupIndices); SparseMatrix(uint_fast64_t columnCount, std::vector<uint_fast64_t> const& rowIndications, std::vector<MatrixEntry<T>> const& columnsAndValues, std::vector<uint_fast64_t> const& rowGroupIndices);
/*! /*!
* Constructs a sparse matrix by moving the given contents. * Constructs a sparse matrix by moving the given contents.
@ -294,7 +372,7 @@ namespace storm {
* @param columnsAndValues The vector containing the columns and values of the entries in the matrix. * @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 rowGroupIndices The vector representing the row groups in the matrix.
*/ */
SparseMatrix(uint_fast64_t columnCount, std::vector<uint_fast64_t>&& rowIndications, std::vector<std::pair<uint_fast64_t, T>>&& columnsAndValues, std::vector<uint_fast64_t>&& rowGroupIndices); SparseMatrix(uint_fast64_t columnCount, std::vector<uint_fast64_t>&& rowIndications, std::vector<MatrixEntry<T>>&& columnsAndValues, std::vector<uint_fast64_t>&& rowGroupIndices);
/*! /*!
* Assigns the contents of the given matrix to the current one by deep-copying its contents. * Assigns the contents of the given matrix to the current one by deep-copying its contents.
@ -339,6 +417,13 @@ namespace storm {
*/ */
uint_fast64_t getEntryCount() const; uint_fast64_t getEntryCount() const;
/*!
* Returns the number of nonzero entries in the matrix.
*
* @return The number of nonzero entries in the matrix.
*/
uint_fast64_t getNonzeroEntryCount() const;
/*! /*!
* Returns the number of row groups in the matrix. * Returns the number of row groups in the matrix.
* *
@ -651,8 +736,11 @@ namespace storm {
// The number of entries in the matrix. // The number of entries in the matrix.
uint_fast64_t entryCount; uint_fast64_t entryCount;
// The number of nonzero entries in the matrix.
uint_fast64_t nonzeroEntryCount;
// The storage for the columns and values of all entries in the matrix. // The storage for the columns and values of all entries in the matrix.
std::vector<std::pair<uint_fast64_t, T>> columnsAndValues; std::vector<MatrixEntry<T>> columnsAndValues;
// A vector containing the indices at which each given row begins. This index is to be interpreted as an // A vector containing the indices at which each given row begins. This index is to be interpreted as an
// index in the valueStorage and the columnIndications vectors. Put differently, the values of the entries // index in the valueStorage and the columnIndications vectors. Put differently, the values of the entries

20
src/storage/StronglyConnectedComponentDecomposition.cpp

@ -114,33 +114,33 @@ namespace storm {
// Now, traverse all successors of the current state. // Now, traverse all successors of the current state.
for(; successorIt != model.getRows(currentState).end(); ++successorIt) { for(; successorIt != model.getRows(currentState).end(); ++successorIt) {
// Record if the current state has a self-loop if we are to drop naive SCCs later. // Record if the current state has a self-loop if we are to drop naive SCCs later.
if (dropNaiveSccs && currentState == successorIt->first) { if (dropNaiveSccs && currentState == successorIt->getColumn()) {
statesWithSelfloop.set(currentState, true); statesWithSelfloop.set(currentState, true);
} }
// If we have not visited the successor already, we need to perform the procedure recursively on the // If we have not visited the successor already, we need to perform the procedure recursively on the
// newly found state, but only if it belongs to the subsystem in which we are interested. // newly found state, but only if it belongs to the subsystem in which we are interested.
if (subsystem.get(successorIt->first)) { if (subsystem.get(successorIt->getColumn())) {
if (!visitedStates.get(successorIt->first)) { if (!visitedStates.get(successorIt->getColumn())) {
// Save current iterator position so we can continue where we left off later. // Save current iterator position so we can continue where we left off later.
recursionIteratorStack.pop_back(); recursionIteratorStack.pop_back();
recursionIteratorStack.push_back(successorIt); recursionIteratorStack.push_back(successorIt);
// Put unvisited successor on top of our recursion stack and remember that. // Put unvisited successor on top of our recursion stack and remember that.
recursionStateStack.push_back(successorIt->first); recursionStateStack.push_back(successorIt->getColumn());
statesInStack[successorIt->first] = true; statesInStack[successorIt->getColumn()] = true;
// Also, put initial value for iterator on corresponding recursion stack. // Also, put initial value for iterator on corresponding recursion stack.
recursionIteratorStack.push_back(model.getRows(successorIt->first).begin()); recursionIteratorStack.push_back(model.getRows(successorIt->getColumn()).begin());
// Perform the actual recursion step in an iterative way. // Perform the actual recursion step in an iterative way.
goto recursionStepForward; goto recursionStepForward;
recursionStepBackward: recursionStepBackward:
lowlinks[currentState] = std::min(lowlinks[currentState], lowlinks[successorIt->first]); lowlinks[currentState] = std::min(lowlinks[currentState], lowlinks[successorIt->getColumn()]);
} else if (tarjanStackStates.get(successorIt->first)) { } else if (tarjanStackStates.get(successorIt->getColumn())) {
// Update the lowlink of the current state. // Update the lowlink of the current state.
lowlinks[currentState] = std::min(lowlinks[currentState], stateIndices[successorIt->first]); lowlinks[currentState] = std::min(lowlinks[currentState], stateIndices[successorIt->getColumn()]);
} }
} }
} }
@ -165,7 +165,7 @@ namespace storm {
if (onlyBottomSccs) { if (onlyBottomSccs) {
for (auto const& state : scc) { for (auto const& state : scc) {
for (auto const& successor : model.getRows(state)) { for (auto const& successor : model.getRows(state)) {
if (scc.find(successor.first) == scc.end()) { if (scc.find(successor.getColumn()) == scc.end()) {
isBottomScc = false; isBottomScc = false;
break; break;
} }

8
src/storage/dd/CuddDd.cpp

@ -473,15 +473,15 @@ namespace storm {
return this->ddManager; return this->ddManager;
} }
DdForwardIterator<DdType::CUDD> Dd<DdType::CUDD>::begin() const { DdForwardIterator<DdType::CUDD> Dd<DdType::CUDD>::begin(bool enumerateDontCareMetaVariables) const {
int* cube; int* cube;
double value; double value;
DdGen* generator = this->getCuddAdd().FirstCube(&cube, &value); DdGen* generator = this->getCuddAdd().FirstCube(&cube, &value);
return DdForwardIterator<DdType::CUDD>(this->getDdManager(), generator, cube, value, Cudd_IsGenEmpty(generator), &this->getContainedMetaVariableNames()); return DdForwardIterator<DdType::CUDD>(this->getDdManager(), generator, cube, value, Cudd_IsGenEmpty(generator), &this->getContainedMetaVariableNames(), enumerateDontCareMetaVariables);
} }
DdForwardIterator<DdType::CUDD> Dd<DdType::CUDD>::end() const { DdForwardIterator<DdType::CUDD> Dd<DdType::CUDD>::end(bool enumerateDontCareMetaVariables) const {
return DdForwardIterator<DdType::CUDD>(this->getDdManager(), nullptr, nullptr, 0, true, nullptr); return DdForwardIterator<DdType::CUDD>(this->getDdManager(), nullptr, nullptr, 0, true, nullptr, enumerateDontCareMetaVariables);
} }
std::ostream & operator<<(std::ostream& out, const Dd<DdType::CUDD>& dd) { std::ostream & operator<<(std::ostream& out, const Dd<DdType::CUDD>& dd) {

8
src/storage/dd/CuddDd.h

@ -440,16 +440,20 @@ namespace storm {
/*! /*!
* Retrieves an iterator that points to the first meta variable assignment with a non-zero function value. * Retrieves an iterator that points to the first meta variable assignment with a non-zero function value.
* *
* @param enumerateDontCareMetaVariables If set to true, all meta variable assignments are enumerated, even
* if a meta variable does not at all influence the the function value.
* @return An iterator that points to the first meta variable assignment with a non-zero function value. * @return An iterator that points to the first meta variable assignment with a non-zero function value.
*/ */
DdForwardIterator<DdType::CUDD> begin() const; DdForwardIterator<DdType::CUDD> begin(bool enumerateDontCareMetaVariables = true) const;
/*! /*!
* Retrieves an iterator that points past the end of the container. * Retrieves an iterator that points past the end of the container.
* *
* @param enumerateDontCareMetaVariables If set to true, all meta variable assignments are enumerated, even
* if a meta variable does not at all influence the the function value.
* @return An iterator that points past the end of the container. * @return An iterator that points past the end of the container.
*/ */
DdForwardIterator<DdType::CUDD> end() const; DdForwardIterator<DdType::CUDD> end(bool enumerateDontCareMetaVariables = true) const;
friend std::ostream & operator<<(std::ostream& out, const Dd<DdType::CUDD>& dd); friend std::ostream & operator<<(std::ostream& out, const Dd<DdType::CUDD>& dd);
private: private:

48
src/storage/dd/CuddDdForwardIterator.cpp

@ -5,7 +5,11 @@
namespace storm { namespace storm {
namespace dd { namespace dd {
DdForwardIterator<DdType::CUDD>::DdForwardIterator(std::shared_ptr<DdManager<DdType::CUDD>> ddManager, DdGen* generator, int* cube, double value, bool isAtEnd, std::set<std::string> const* metaVariables) : ddManager(ddManager), generator(generator), cube(cube), value(value), isAtEnd(isAtEnd), metaVariables(metaVariables), cubeCounter(), relevantDontCareDdVariables(), currentValuation() { DdForwardIterator<DdType::CUDD>::DdForwardIterator() : ddManager(), generator(), cube(), value(), isAtEnd(), metaVariables(), enumerateDontCareMetaVariables(), cubeCounter(), relevantDontCareDdVariables(), currentValuation() {
// Intentionally left empty.
}
DdForwardIterator<DdType::CUDD>::DdForwardIterator(std::shared_ptr<DdManager<DdType::CUDD>> ddManager, DdGen* generator, int* cube, double value, bool isAtEnd, std::set<std::string> const* metaVariables, bool enumerateDontCareMetaVariables) : ddManager(ddManager), generator(generator), cube(cube), value(value), isAtEnd(isAtEnd), metaVariables(metaVariables), enumerateDontCareMetaVariables(enumerateDontCareMetaVariables), cubeCounter(), relevantDontCareDdVariables(), currentValuation() {
// If the given generator is not yet at its end, we need to create the current valuation from the cube from // If the given generator is not yet at its end, we need to create the current valuation from the cube from
// scratch. // scratch.
if (!this->isAtEnd) { if (!this->isAtEnd) {
@ -49,6 +53,7 @@ namespace storm {
} }
DdForwardIterator<DdType::CUDD>::~DdForwardIterator() { DdForwardIterator<DdType::CUDD>::~DdForwardIterator() {
// We free the pointers sind Cudd allocates them using malloc rather than new/delete.
if (this->cube != nullptr) { if (this->cube != nullptr) {
free(this->cube); free(this->cube);
} }
@ -108,29 +113,60 @@ namespace storm {
// don't cares. In the latter case, we add them to a special list, so we can iterate over their concrete // don't cares. In the latter case, we add them to a special list, so we can iterate over their concrete
// valuations later. // valuations later.
for (auto const& metaVariableName : *this->metaVariables) { for (auto const& metaVariableName : *this->metaVariables) {
bool metaVariableAppearsInCube = false;
std::vector<std::tuple<ADD, std::string, uint_fast64_t>> localRelenvantDontCareDdVariables;
auto const& metaVariable = this->ddManager->getMetaVariable(metaVariableName); auto const& metaVariable = this->ddManager->getMetaVariable(metaVariableName);
if (metaVariable.getType() == DdMetaVariable<DdType::CUDD>::MetaVariableType::Bool) { if (metaVariable.getType() == DdMetaVariable<DdType::CUDD>::MetaVariableType::Bool) {
if (this->cube[metaVariable.getDdVariables()[0].getCuddAdd().NodeReadIndex()] == 0) { if (this->cube[metaVariable.getDdVariables()[0].getCuddAdd().NodeReadIndex()] == 0) {
currentValuation.setBooleanValue(metaVariableName, false); metaVariableAppearsInCube = true;
if (!currentValuation.containsBooleanIdentifier(metaVariableName)) {
currentValuation.addBooleanIdentifier(metaVariableName, false);
} else {
currentValuation.setBooleanValue(metaVariableName, false);
}
} else if (this->cube[metaVariable.getDdVariables()[0].getCuddAdd().NodeReadIndex()] == 1) { } else if (this->cube[metaVariable.getDdVariables()[0].getCuddAdd().NodeReadIndex()] == 1) {
currentValuation.setBooleanValue(metaVariableName, true); metaVariableAppearsInCube = true;
if (!currentValuation.containsBooleanIdentifier(metaVariableName)) {
currentValuation.addBooleanIdentifier(metaVariableName, true);
} else {
currentValuation.setBooleanValue(metaVariableName, true);
}
} else { } else {
relevantDontCareDdVariables.push_back(std::make_tuple(metaVariable.getDdVariables()[0].getCuddAdd(), metaVariableName, 0)); localRelenvantDontCareDdVariables.push_back(std::make_tuple(metaVariable.getDdVariables()[0].getCuddAdd(), metaVariableName, 0));
} }
} else { } else {
int_fast64_t intValue = 0; int_fast64_t intValue = 0;
for (uint_fast64_t bitIndex = 0; bitIndex < metaVariable.getNumberOfDdVariables(); ++bitIndex) { for (uint_fast64_t bitIndex = 0; bitIndex < metaVariable.getNumberOfDdVariables(); ++bitIndex) {
if (cube[metaVariable.getDdVariables()[bitIndex].getCuddAdd().NodeReadIndex()] == 0) { if (cube[metaVariable.getDdVariables()[bitIndex].getCuddAdd().NodeReadIndex()] == 0) {
// Leave bit unset. // Leave bit unset.
metaVariableAppearsInCube = true;
} else if (cube[metaVariable.getDdVariables()[bitIndex].getCuddAdd().NodeReadIndex()] == 1) { } else if (cube[metaVariable.getDdVariables()[bitIndex].getCuddAdd().NodeReadIndex()] == 1) {
intValue |= 1ull << (metaVariable.getNumberOfDdVariables() - bitIndex - 1); intValue |= 1ull << (metaVariable.getNumberOfDdVariables() - bitIndex - 1);
metaVariableAppearsInCube = true;
} else { } else {
// Temporarily leave bit unset so we can iterate trough the other option later. // Temporarily leave bit unset so we can iterate trough the other option later.
// Add the bit to the relevant don't care bits. // Add the bit to the relevant don't care bits.
this->relevantDontCareDdVariables.push_back(std::make_tuple(metaVariable.getDdVariables()[bitIndex].getCuddAdd(), metaVariableName, metaVariable.getNumberOfDdVariables() - bitIndex - 1)); localRelenvantDontCareDdVariables.push_back(std::make_tuple(metaVariable.getDdVariables()[bitIndex].getCuddAdd(), metaVariableName, metaVariable.getNumberOfDdVariables() - bitIndex - 1));
} }
} }
currentValuation.setIntegerValue(metaVariableName, intValue + metaVariable.getLow()); if (this->enumerateDontCareMetaVariables || metaVariableAppearsInCube) {
if (!currentValuation.containsIntegerIdentifier(metaVariableName)) {
currentValuation.addIntegerIdentifier(metaVariableName);
}
currentValuation.setIntegerValue(metaVariableName, intValue + metaVariable.getLow());
}
}
// If all meta variables are to be enumerated or the meta variable appeared in the cube, we register the
// missing bits to later enumerate all possible valuations.
if (this->enumerateDontCareMetaVariables || metaVariableAppearsInCube) {
relevantDontCareDdVariables.insert(relevantDontCareDdVariables.end(), localRelenvantDontCareDdVariables.begin(), localRelenvantDontCareDdVariables.end());
}
// If the meta variable does not appear in the cube and we're not supposed to enumerate such meta variables
// we remove the meta variable from the valuation.
if (!this->enumerateDontCareMetaVariables && !metaVariableAppearsInCube) {
currentValuation.removeIdentifier(metaVariableName);
} }
} }

10
src/storage/dd/CuddDdForwardIterator.h

@ -25,7 +25,7 @@ namespace storm {
friend class Dd<DdType::CUDD>; friend class Dd<DdType::CUDD>;
// Default-instantiate the constructor. // Default-instantiate the constructor.
DdForwardIterator() = default; DdForwardIterator();
// Forbid copy-construction and copy assignment, because ownership of the internal pointer is unclear then. // Forbid copy-construction and copy assignment, because ownership of the internal pointer is unclear then.
DdForwardIterator(DdForwardIterator<DdType::CUDD> const& other) = delete; DdForwardIterator(DdForwardIterator<DdType::CUDD> const& other) = delete;
@ -82,8 +82,10 @@ namespace storm {
* @param isAtEnd A flag that indicates whether the iterator is at its end and may not be moved forward any * @param isAtEnd A flag that indicates whether the iterator is at its end and may not be moved forward any
* more. * more.
* @param metaVariables The meta variables that appear in the DD. * @param metaVariables The meta variables that appear in the DD.
* @param enumerateDontCareMetaVariables If set to true, all meta variable assignments are enumerated, even
* if a meta variable does not at all influence the the function value.
*/ */
DdForwardIterator(std::shared_ptr<DdManager<DdType::CUDD>> ddManager, DdGen* generator, int* cube, double value, bool isAtEnd, std::set<std::string> const* metaVariables = nullptr); DdForwardIterator(std::shared_ptr<DdManager<DdType::CUDD>> ddManager, DdGen* generator, int* cube, double value, bool isAtEnd, std::set<std::string> const* metaVariables = nullptr, bool enumerateDontCareMetaVariables = true);
/*! /*!
* Recreates the internal information when a new cube needs to be treated. * Recreates the internal information when a new cube needs to be treated.
@ -114,6 +116,10 @@ namespace storm {
// The set of meta variables appearing in the DD. // The set of meta variables appearing in the DD.
std::set<std::string> const* metaVariables; std::set<std::string> const* metaVariables;
// A flag that indicates whether the iterator is supposed to enumerate meta variable valuations even if
// they don't influence the function value.
bool enumerateDontCareMetaVariables;
// A number that represents how many assignments of the current cube have already been returned previously. // A number that represents how many assignments of the current cube have already been returned previously.
// This is needed, because cubes may represent many assignments (if they have don't care variables). // This is needed, because cubes may represent many assignments (if they have don't care variables).
uint_fast64_t cubeCounter; uint_fast64_t cubeCounter;

23
src/storage/dd/CuddDdManager.cpp

@ -32,7 +32,7 @@ bool CuddOptionsRegistered = storm::settings::Settings::registerNewModule([] (st
namespace storm { namespace storm {
namespace dd { namespace dd {
DdManager<DdType::CUDD>::DdManager() : metaVariableMap(), cuddManager() { DdManager<DdType::CUDD>::DdManager() : metaVariableMap(), cuddManager() {
this->cuddManager.SetMaxMemory(storm::settings::Settings::getInstance()->getOptionByLongName("cuddmaxmem").getArgument(0).getValueAsUnsignedInteger() * 1024); this->cuddManager.SetMaxMemory(storm::settings::Settings::getInstance()->getOptionByLongName("cuddmaxmem").getArgument(0).getValueAsUnsignedInteger() * 1024 * 1024);
this->cuddManager.SetEpsilon(storm::settings::Settings::getInstance()->getOptionByLongName("cuddprec").getArgument(0).getValueAsDouble()); this->cuddManager.SetEpsilon(storm::settings::Settings::getInstance()->getOptionByLongName("cuddprec").getArgument(0).getValueAsDouble());
} }
@ -224,6 +224,10 @@ namespace storm {
Cudd& DdManager<DdType::CUDD>::getCuddManager() { Cudd& DdManager<DdType::CUDD>::getCuddManager() {
return this->cuddManager; return this->cuddManager;
} }
Cudd const& DdManager<DdType::CUDD>::getCuddManager() const {
return this->cuddManager;
}
std::vector<std::string> DdManager<DdType::CUDD>::getDdVariableNames() const { std::vector<std::string> DdManager<DdType::CUDD>::getDdVariableNames() const {
// First, we initialize a list DD variables and their names. // First, we initialize a list DD variables and their names.
@ -246,5 +250,22 @@ namespace storm {
return result; return result;
} }
void DdManager<DdType::CUDD>::allowDynamicReordering(bool value) {
if (value) {
this->getCuddManager().AutodynEnable(CUDD_REORDER_GROUP_SIFT_CONV);
} else {
this->getCuddManager().AutodynDisable();
}
}
bool DdManager<DdType::CUDD>::isDynamicReorderingAllowed() const {
Cudd_ReorderingType type;
return this->getCuddManager().ReorderingStatus(&type);
}
void DdManager<DdType::CUDD>::triggerReordering() {
this->getCuddManager().ReduceHeap(CUDD_REORDER_GROUP_SIFT_CONV, 0);
}
} }
} }

26
src/storage/dd/CuddDdManager.h

@ -138,6 +138,25 @@ namespace storm {
*/ */
bool hasMetaVariable(std::string const& metaVariableName) const; bool hasMetaVariable(std::string const& metaVariableName) const;
/*!
* Sets whether or not dynamic reordering is allowed for the DDs managed by this manager.
*
* @param value If set to true, dynamic reordering is allowed and forbidden otherwise.
*/
void allowDynamicReordering(bool value);
/*!
* Retrieves whether dynamic reordering is currently allowed.
*
* @return True iff dynamic reordering is currently allowed.
*/
bool isDynamicReorderingAllowed() const;
/*!
* Triggers a reordering of the DDs managed by this manager.
*/
void triggerReordering();
private: private:
/*! /*!
* Retrieves a list of names of the DD variables in the order of their index. * Retrieves a list of names of the DD variables in the order of their index.
@ -153,6 +172,13 @@ namespace storm {
*/ */
Cudd& getCuddManager(); Cudd& getCuddManager();
/*!
* Retrieves the underlying CUDD manager.
*
* @return The underlying CUDD manager.
*/
Cudd const& getCuddManager() const;
// A mapping from variable names to the meta variable information. // A mapping from variable names to the meta variable information.
std::unordered_map<std::string, DdMetaVariable<DdType::CUDD>> metaVariableMap; std::unordered_map<std::string, DdMetaVariable<DdType::CUDD>> metaVariableMap;

18
src/storage/expressions/BaseExpression.cpp

@ -49,6 +49,10 @@ namespace storm {
LOG_THROW(false, storm::exceptions::InvalidAccessException, "Unable to access identifier of non-constant, non-variable expression."); LOG_THROW(false, storm::exceptions::InvalidAccessException, "Unable to access identifier of non-constant, non-variable expression.");
} }
OperatorType BaseExpression::getOperator() const {
LOG_THROW(false, storm::exceptions::InvalidAccessException, "Unable to access operator of non-function application expression.");
}
bool BaseExpression::containsVariables() const { bool BaseExpression::containsVariables() const {
return false; return false;
} }
@ -69,18 +73,12 @@ namespace storm {
return false; return false;
} }
std::shared_ptr<BaseExpression const> BaseExpression::getSharedPointer() const { bool BaseExpression::isFunctionApplication() const {
return this->shared_from_this(); return false;
} }
std::ostream& operator<<(std::ostream& stream, ExpressionReturnType const& enumValue) { std::shared_ptr<BaseExpression const> BaseExpression::getSharedPointer() const {
switch (enumValue) { return this->shared_from_this();
case ExpressionReturnType::Undefined: stream << "undefined"; break;
case ExpressionReturnType::Bool: stream << "bool"; break;
case ExpressionReturnType::Int: stream << "int"; break;
case ExpressionReturnType::Double: stream << "double"; break;
}
return stream;
} }
std::ostream& operator<<(std::ostream& stream, BaseExpression const& expression) { std::ostream& operator<<(std::ostream& stream, BaseExpression const& expression) {

26
src/storage/expressions/BaseExpression.h

@ -7,20 +7,15 @@
#include <map> #include <map>
#include <iostream> #include <iostream>
#include "src/storage/expressions/ExpressionReturnType.h"
#include "src/storage/expressions/Valuation.h" #include "src/storage/expressions/Valuation.h"
#include "src/storage/expressions/ExpressionVisitor.h" #include "src/storage/expressions/ExpressionVisitor.h"
#include "src/storage/expressions/OperatorType.h"
#include "src/exceptions/InvalidArgumentException.h" #include "src/exceptions/InvalidArgumentException.h"
#include "src/utility/OsDetection.h" #include "src/utility/OsDetection.h"
namespace storm { namespace storm {
namespace expressions { namespace expressions {
/*!
* Each node in an expression tree has a uniquely defined type from this enum.
*/
enum class ExpressionReturnType {Undefined, Bool, Int, Double};
std::ostream& operator<<(std::ostream& stream, ExpressionReturnType const& enumValue);
/*! /*!
* The base class of all expression classes. * The base class of all expression classes.
*/ */
@ -97,6 +92,14 @@ namespace storm {
*/ */
virtual std::string const& getIdentifier() const; virtual std::string const& getIdentifier() const;
/*!
* Retrieves the operator of a function application. This is only legal to call if the expression is
* function application.
*
* @return The operator associated with the function application.
*/
virtual OperatorType getOperator() const;
/*! /*!
* Retrieves whether the expression contains a variable. * Retrieves whether the expression contains a variable.
* *
@ -132,6 +135,13 @@ namespace storm {
*/ */
virtual bool isFalse() const; virtual bool isFalse() const;
/*!
* Checks if the expression is a function application (of any sort).
*
* @return True iff the expression is a function application.
*/
virtual bool isFunctionApplication() const;
/*! /*!
* Retrieves the set of all variables that appear in the expression. * Retrieves the set of all variables that appear in the expression.
* *

10
src/storage/expressions/BinaryBooleanFunctionExpression.cpp

@ -13,6 +13,16 @@ namespace storm {
return this->operatorType; return this->operatorType;
} }
storm::expressions::OperatorType BinaryBooleanFunctionExpression::getOperator() const {
switch (this->getOperatorType()) {
case OperatorType::And: return storm::expressions::OperatorType::And; break;
case OperatorType::Or: return storm::expressions::OperatorType::Or; break;
case OperatorType::Xor: return storm::expressions::OperatorType::Xor; break;
case OperatorType::Implies: return storm::expressions::OperatorType::Implies; break;
case OperatorType::Iff: return storm::expressions::OperatorType::Iff; break;
}
}
bool BinaryBooleanFunctionExpression::evaluateAsBool(Valuation const* valuation) const { bool BinaryBooleanFunctionExpression::evaluateAsBool(Valuation const* valuation) const {
LOG_THROW(this->hasBooleanReturnType(), storm::exceptions::InvalidTypeException, "Unable to evaluate expression as boolean."); LOG_THROW(this->hasBooleanReturnType(), storm::exceptions::InvalidTypeException, "Unable to evaluate expression as boolean.");

1
src/storage/expressions/BinaryBooleanFunctionExpression.h

@ -33,6 +33,7 @@ namespace storm {
virtual ~BinaryBooleanFunctionExpression() = default; virtual ~BinaryBooleanFunctionExpression() = default;
// Override base class methods. // Override base class methods.
virtual storm::expressions::OperatorType getOperator() const override;
virtual bool evaluateAsBool(Valuation const* valuation = nullptr) const override; virtual bool evaluateAsBool(Valuation const* valuation = nullptr) const override;
virtual std::shared_ptr<BaseExpression const> simplify() const override; virtual std::shared_ptr<BaseExpression const> simplify() const override;
virtual void accept(ExpressionVisitor* visitor) const override; virtual void accept(ExpressionVisitor* visitor) const override;

6
src/storage/expressions/BinaryExpression.cpp

@ -9,6 +9,10 @@ namespace storm {
// Intentionally left empty. // Intentionally left empty.
} }
bool BinaryExpression::isFunctionApplication() const {
return true;
}
bool BinaryExpression::containsVariables() const { bool BinaryExpression::containsVariables() const {
return this->getFirstOperand()->containsVariables() || this->getSecondOperand()->containsVariables(); return this->getFirstOperand()->containsVariables() || this->getSecondOperand()->containsVariables();
} }
@ -41,7 +45,7 @@ namespace storm {
std::shared_ptr<BaseExpression const> BinaryExpression::getOperand(uint_fast64_t operandIndex) const { std::shared_ptr<BaseExpression const> BinaryExpression::getOperand(uint_fast64_t operandIndex) const {
LOG_THROW(operandIndex < 2, storm::exceptions::InvalidAccessException, "Unable to access operand " << operandIndex << " in expression of arity 2."); LOG_THROW(operandIndex < 2, storm::exceptions::InvalidAccessException, "Unable to access operand " << operandIndex << " in expression of arity 2.");
if (operandIndex == 1) { if (operandIndex == 0) {
return this->getFirstOperand(); return this->getFirstOperand();
} else { } else {
return this->getSecondOperand(); return this->getSecondOperand();

1
src/storage/expressions/BinaryExpression.h

@ -30,6 +30,7 @@ namespace storm {
virtual ~BinaryExpression() = default; virtual ~BinaryExpression() = default;
// Override base class methods. // Override base class methods.
virtual bool isFunctionApplication() const override;
virtual bool containsVariables() const override; virtual bool containsVariables() const override;
virtual uint_fast64_t getArity() const override; virtual uint_fast64_t getArity() const override;
virtual std::shared_ptr<BaseExpression const> getOperand(uint_fast64_t operandIndex) const override; virtual std::shared_ptr<BaseExpression const> getOperand(uint_fast64_t operandIndex) const override;

11
src/storage/expressions/BinaryNumericalFunctionExpression.cpp

@ -14,6 +14,17 @@ namespace storm {
return this->operatorType; return this->operatorType;
} }
storm::expressions::OperatorType BinaryNumericalFunctionExpression::getOperator() const {
switch (this->getOperatorType()) {
case OperatorType::Plus: return storm::expressions::OperatorType::Plus; break;
case OperatorType::Minus: return storm::expressions::OperatorType::Minus; break;
case OperatorType::Times: return storm::expressions::OperatorType::Times; break;
case OperatorType::Divide: return storm::expressions::OperatorType::Divide; break;
case OperatorType::Min: return storm::expressions::OperatorType::Min; break;
case OperatorType::Max: return storm::expressions::OperatorType::Max; break;
}
}
int_fast64_t BinaryNumericalFunctionExpression::evaluateAsInt(Valuation const* valuation) const { int_fast64_t BinaryNumericalFunctionExpression::evaluateAsInt(Valuation const* valuation) const {
LOG_THROW(this->hasIntegralReturnType(), storm::exceptions::InvalidTypeException, "Unable to evaluate expression as integer."); LOG_THROW(this->hasIntegralReturnType(), storm::exceptions::InvalidTypeException, "Unable to evaluate expression as integer.");

1
src/storage/expressions/BinaryNumericalFunctionExpression.h

@ -33,6 +33,7 @@ namespace storm {
virtual ~BinaryNumericalFunctionExpression() = default; virtual ~BinaryNumericalFunctionExpression() = default;
// Override base class methods. // Override base class methods.
virtual storm::expressions::OperatorType getOperator() const override;
virtual int_fast64_t evaluateAsInt(Valuation const* valuation = nullptr) const override; virtual int_fast64_t evaluateAsInt(Valuation const* valuation = nullptr) const override;
virtual double evaluateAsDouble(Valuation const* valuation = nullptr) const override; virtual double evaluateAsDouble(Valuation const* valuation = nullptr) const override;
virtual std::shared_ptr<BaseExpression const> simplify() const override; virtual std::shared_ptr<BaseExpression const> simplify() const override;

13
src/storage/expressions/BinaryRelationExpression.cpp

@ -8,7 +8,18 @@ namespace storm {
BinaryRelationExpression::BinaryRelationExpression(ExpressionReturnType returnType, std::shared_ptr<BaseExpression const> const& firstOperand, std::shared_ptr<BaseExpression const> const& secondOperand, RelationType relationType) : BinaryExpression(returnType, firstOperand, secondOperand), relationType(relationType) { BinaryRelationExpression::BinaryRelationExpression(ExpressionReturnType returnType, std::shared_ptr<BaseExpression const> const& firstOperand, std::shared_ptr<BaseExpression const> const& secondOperand, RelationType relationType) : BinaryExpression(returnType, firstOperand, secondOperand), relationType(relationType) {
// Intentionally left empty. // Intentionally left empty.
} }
storm::expressions::OperatorType BinaryRelationExpression::getOperator() const {
switch (this->getRelationType()) {
case RelationType::Equal: return storm::expressions::OperatorType::Equal; break;
case RelationType::NotEqual: return storm::expressions::OperatorType::NotEqual; break;
case RelationType::Less: return storm::expressions::OperatorType::Less; break;
case RelationType::LessOrEqual: return storm::expressions::OperatorType::LessOrEqual; break;
case RelationType::Greater: return storm::expressions::OperatorType::Greater; break;
case RelationType::GreaterOrEqual: return storm::expressions::OperatorType::GreaterOrEqual; break;
}
}
bool BinaryRelationExpression::evaluateAsBool(Valuation const* valuation) const { bool BinaryRelationExpression::evaluateAsBool(Valuation const* valuation) const {
LOG_THROW(this->hasBooleanReturnType(), storm::exceptions::InvalidTypeException, "Unable to evaluate expression as boolean."); LOG_THROW(this->hasBooleanReturnType(), storm::exceptions::InvalidTypeException, "Unable to evaluate expression as boolean.");

1
src/storage/expressions/BinaryRelationExpression.h

@ -33,6 +33,7 @@ namespace storm {
virtual ~BinaryRelationExpression() = default; virtual ~BinaryRelationExpression() = default;
// Override base class methods. // Override base class methods.
virtual storm::expressions::OperatorType getOperator() const override;
virtual bool evaluateAsBool(Valuation const* valuation = nullptr) const override; virtual bool evaluateAsBool(Valuation const* valuation = nullptr) const override;
virtual std::shared_ptr<BaseExpression const> simplify() const override; virtual std::shared_ptr<BaseExpression const> simplify() const override;
virtual void accept(ExpressionVisitor* visitor) const override; virtual void accept(ExpressionVisitor* visitor) const override;

39
src/storage/expressions/Expression.cpp

@ -5,6 +5,7 @@
#include "src/storage/expressions/SubstitutionVisitor.h" #include "src/storage/expressions/SubstitutionVisitor.h"
#include "src/storage/expressions/IdentifierSubstitutionVisitor.h" #include "src/storage/expressions/IdentifierSubstitutionVisitor.h"
#include "src/storage/expressions/TypeCheckVisitor.h" #include "src/storage/expressions/TypeCheckVisitor.h"
#include "src/storage/expressions/LinearityCheckVisitor.h"
#include "src/storage/expressions/Expressions.h" #include "src/storage/expressions/Expressions.h"
#include "src/exceptions/InvalidTypeException.h" #include "src/exceptions/InvalidTypeException.h"
#include "src/exceptions/ExceptionMacros.h" #include "src/exceptions/ExceptionMacros.h"
@ -16,27 +17,27 @@ namespace storm {
} }
Expression Expression::substitute(std::map<std::string, Expression> const& identifierToExpressionMap) const { Expression Expression::substitute(std::map<std::string, Expression> const& identifierToExpressionMap) const {
return SubstitutionVisitor<std::map<std::string, Expression>>(identifierToExpressionMap).substitute(this->getBaseExpressionPointer().get()); return SubstitutionVisitor<std::map<std::string, Expression>>(identifierToExpressionMap).substitute(*this);
} }
Expression Expression::substitute(std::unordered_map<std::string, Expression> const& identifierToExpressionMap) const { Expression Expression::substitute(std::unordered_map<std::string, Expression> const& identifierToExpressionMap) const {
return SubstitutionVisitor<std::unordered_map<std::string, Expression>>(identifierToExpressionMap).substitute(this->getBaseExpressionPointer().get()); return SubstitutionVisitor<std::unordered_map<std::string, Expression>>(identifierToExpressionMap).substitute(*this);
} }
Expression Expression::substitute(std::map<std::string, std::string> const& identifierToIdentifierMap) const { Expression Expression::substitute(std::map<std::string, std::string> const& identifierToIdentifierMap) const {
return IdentifierSubstitutionVisitor<std::map<std::string, std::string>>(identifierToIdentifierMap).substitute(this->getBaseExpressionPointer().get()); return IdentifierSubstitutionVisitor<std::map<std::string, std::string>>(identifierToIdentifierMap).substitute(*this);
} }
Expression Expression::substitute(std::unordered_map<std::string, std::string> const& identifierToIdentifierMap) const { Expression Expression::substitute(std::unordered_map<std::string, std::string> const& identifierToIdentifierMap) const {
return IdentifierSubstitutionVisitor<std::unordered_map<std::string, std::string>>(identifierToIdentifierMap).substitute(this->getBaseExpressionPointer().get()); return IdentifierSubstitutionVisitor<std::unordered_map<std::string, std::string>>(identifierToIdentifierMap).substitute(*this);
} }
void Expression::check(std::map<std::string, storm::expressions::ExpressionReturnType> const& identifierToTypeMap) const { void Expression::check(std::map<std::string, storm::expressions::ExpressionReturnType> const& identifierToTypeMap) const {
return TypeCheckVisitor<std::map<std::string, storm::expressions::ExpressionReturnType>>(identifierToTypeMap).check(this->getBaseExpressionPointer().get()); return TypeCheckVisitor<std::map<std::string, storm::expressions::ExpressionReturnType>>(identifierToTypeMap).check(*this);
} }
void Expression::check(std::unordered_map<std::string, storm::expressions::ExpressionReturnType> const& identifierToTypeMap) const { void Expression::check(std::unordered_map<std::string, storm::expressions::ExpressionReturnType> const& identifierToTypeMap) const {
return TypeCheckVisitor<std::unordered_map<std::string, storm::expressions::ExpressionReturnType>>(identifierToTypeMap).check(this->getBaseExpressionPointer().get()); return TypeCheckVisitor<std::unordered_map<std::string, storm::expressions::ExpressionReturnType>>(identifierToTypeMap).check(*this);
} }
bool Expression::evaluateAsBool(Valuation const* valuation) const { bool Expression::evaluateAsBool(Valuation const* valuation) const {
@ -55,6 +56,14 @@ namespace storm {
return Expression(this->getBaseExpression().simplify()); return Expression(this->getBaseExpression().simplify());
} }
OperatorType Expression::getOperator() const {
return this->getBaseExpression().getOperator();
}
bool Expression::isFunctionApplication() const {
return this->getBaseExpression().isFunctionApplication();
}
uint_fast64_t Expression::getArity() const { uint_fast64_t Expression::getArity() const {
return this->getBaseExpression().getArity(); return this->getBaseExpression().getArity();
} }
@ -102,6 +111,24 @@ namespace storm {
} }
} }
bool Expression::isRelationalExpression() const {
if (!this->isFunctionApplication()) {
return false;
}
return this->getOperator() == OperatorType::Equal || this->getOperator() == OperatorType::NotEqual
|| this->getOperator() == OperatorType::Less || this->getOperator() == OperatorType::LessOrEqual
|| this->getOperator() == OperatorType::Greater || this->getOperator() == OperatorType::GreaterOrEqual;
}
bool Expression::isLinear() const {
return LinearityCheckVisitor().check(*this);
}
std::set<std::string> Expression::getVariables() const {
return this->getBaseExpression().getVariables();
}
BaseExpression const& Expression::getBaseExpression() const { BaseExpression const& Expression::getBaseExpression() const {
return *this->expressionPtr; return *this->expressionPtr;
} }

38
src/storage/expressions/Expression.h

@ -6,6 +6,7 @@
#include <unordered_map> #include <unordered_map>
#include "src/storage/expressions/BaseExpression.h" #include "src/storage/expressions/BaseExpression.h"
#include "src/storage/expressions/ExpressionVisitor.h"
#include "src/utility/OsDetection.h" #include "src/utility/OsDetection.h"
namespace storm { namespace storm {
@ -157,6 +158,21 @@ namespace storm {
*/ */
Expression simplify(); Expression simplify();
/*!
* Retrieves the operator of a function application. This is only legal to call if the expression is
* function application.
*
* @return The operator associated with the function application.
*/
OperatorType getOperator() const;
/*!
* Checks if the expression is a function application (of any sort).
*
* @return True iff the expression is a function application.
*/
bool isFunctionApplication() const;
/*! /*!
* Retrieves the arity of the expression. * Retrieves the arity of the expression.
* *
@ -215,6 +231,21 @@ namespace storm {
*/ */
bool isFalse() const; bool isFalse() const;
/*!
* Retrieves whether this expression is a relation expression, i.e., an expression that has a relation
* (equal, not equal, less, less or equal, etc.) as its top-level operator.
*
* @return True iff the expression is a relation expression.
*/
bool isRelationalExpression() const;
/*!
* Retrieves whether this expression is a linear expression.
*
* @return True iff the expression is linear.
*/
bool isLinear() const;
/*! /*!
* Retrieves the set of all variables that appear in the expression. * Retrieves the set of all variables that appear in the expression.
* *
@ -271,6 +302,13 @@ namespace storm {
*/ */
bool hasBooleanReturnType() const; bool hasBooleanReturnType() const;
/*!
* Accepts the given visitor.
*
* @param visitor The visitor to accept.
*/
void accept(ExpressionVisitor* visitor) const;
friend std::ostream& operator<<(std::ostream& stream, Expression const& expression); friend std::ostream& operator<<(std::ostream& stream, Expression const& expression);
private: private:

15
src/storage/expressions/ExpressionReturnType.cpp

@ -0,0 +1,15 @@
#include "src/storage/expressions/ExpressionReturnType.h"
namespace storm {
namespace expressions {
std::ostream& operator<<(std::ostream& stream, ExpressionReturnType const& enumValue) {
switch (enumValue) {
case ExpressionReturnType::Undefined: stream << "undefined"; break;
case ExpressionReturnType::Bool: stream << "bool"; break;
case ExpressionReturnType::Int: stream << "int"; break;
case ExpressionReturnType::Double: stream << "double"; break;
}
return stream;
}
}
}

17
src/storage/expressions/ExpressionReturnType.h

@ -0,0 +1,17 @@
#ifndef STORM_STORAGE_EXPRESSIONS_EXPRESSIONRETURNTYPE_H_
#define STORM_STORAGE_EXPRESSIONS_EXPRESSIONRETURNTYPE_H_
#include <iostream>
namespace storm {
namespace expressions {
/*!
* Each node in an expression tree has a uniquely defined type from this enum.
*/
enum class ExpressionReturnType {Undefined, Bool, Int, Double};
std::ostream& operator<<(std::ostream& stream, ExpressionReturnType const& enumValue);
}
}
#endif /* STORM_STORAGE_EXPRESSIONS_EXPRESSIONRETURNTYPE_H_ */

4
src/storage/expressions/IdentifierSubstitutionVisitor.cpp

@ -13,8 +13,8 @@ namespace storm {
} }
template<typename MapType> template<typename MapType>
Expression IdentifierSubstitutionVisitor<MapType>::substitute(BaseExpression const* expression) { Expression IdentifierSubstitutionVisitor<MapType>::substitute(Expression const& expression) {
expression->accept(this); expression.getBaseExpression().accept(this);
return Expression(this->expressionStack.top()); return Expression(this->expressionStack.top());
} }

2
src/storage/expressions/IdentifierSubstitutionVisitor.h

@ -26,7 +26,7 @@ namespace storm {
* @return The expression in which all identifiers in the key set of the previously given mapping are * @return The expression in which all identifiers in the key set of the previously given mapping are
* substituted with the mapped-to expressions. * substituted with the mapped-to expressions.
*/ */
Expression substitute(BaseExpression const* expression); Expression substitute(Expression const& expression);
virtual void visit(IfThenElseExpression const* expression) override; virtual void visit(IfThenElseExpression const* expression) override;
virtual void visit(BinaryBooleanFunctionExpression const* expression) override; virtual void visit(BinaryBooleanFunctionExpression const* expression) override;

30
src/storage/expressions/IfThenElseExpression.cpp

@ -1,11 +1,41 @@
#include "src/storage/expressions/IfThenElseExpression.h" #include "src/storage/expressions/IfThenElseExpression.h"
#include "src/exceptions/ExceptionMacros.h"
#include "src/exceptions/InvalidAccessException.h"
namespace storm { namespace storm {
namespace expressions { namespace expressions {
IfThenElseExpression::IfThenElseExpression(ExpressionReturnType returnType, std::shared_ptr<BaseExpression const> const& condition, std::shared_ptr<BaseExpression const> const& thenExpression, std::shared_ptr<BaseExpression const> const& elseExpression) : BaseExpression(returnType), condition(condition), thenExpression(thenExpression), elseExpression(elseExpression) { IfThenElseExpression::IfThenElseExpression(ExpressionReturnType returnType, std::shared_ptr<BaseExpression const> const& condition, std::shared_ptr<BaseExpression const> const& thenExpression, std::shared_ptr<BaseExpression const> const& elseExpression) : BaseExpression(returnType), condition(condition), thenExpression(thenExpression), elseExpression(elseExpression) {
// Intentionally left empty. // Intentionally left empty.
} }
std::shared_ptr<BaseExpression const> IfThenElseExpression::getOperand(uint_fast64_t operandIndex) const {
LOG_THROW(operandIndex < 3, storm::exceptions::InvalidAccessException, "Unable to access operand " << operandIndex << " in expression of arity 3.");
if (operandIndex == 0) {
return this->getCondition();
} else if (operandIndex == 1) {
return this->getThenExpression();
} else {
return this->getElseExpression();
}
}
OperatorType IfThenElseExpression::getOperator() const {
return OperatorType::Ite;
}
bool IfThenElseExpression::isFunctionApplication() const {
return true;
}
bool IfThenElseExpression::containsVariables() const {
return this->getCondition()->containsVariables() || this->getThenExpression()->containsVariables() || this->getElseExpression()->containsVariables();
}
uint_fast64_t IfThenElseExpression::getArity() const {
return 3;
}
bool IfThenElseExpression::evaluateAsBool(Valuation const* valuation) const { bool IfThenElseExpression::evaluateAsBool(Valuation const* valuation) const {
bool conditionValue = this->condition->evaluateAsBool(valuation); bool conditionValue = this->condition->evaluateAsBool(valuation);
if (conditionValue) { if (conditionValue) {

5
src/storage/expressions/IfThenElseExpression.h

@ -27,6 +27,11 @@ namespace storm {
virtual ~IfThenElseExpression() = default; virtual ~IfThenElseExpression() = default;
// Override base class methods. // Override base class methods.
virtual std::shared_ptr<BaseExpression const> getOperand(uint_fast64_t operandIndex) const override;
virtual OperatorType getOperator() const override;
virtual bool isFunctionApplication() const override;
virtual bool containsVariables() const override;
virtual uint_fast64_t getArity() const override;
virtual bool evaluateAsBool(Valuation const* valuation = nullptr) const override; virtual bool evaluateAsBool(Valuation const* valuation = nullptr) const override;
virtual int_fast64_t evaluateAsInt(Valuation const* valuation = nullptr) const override; virtual int_fast64_t evaluateAsInt(Valuation const* valuation = nullptr) const override;
virtual double evaluateAsDouble(Valuation const* valuation = nullptr) const override; virtual double evaluateAsDouble(Valuation const* valuation = nullptr) const override;

151
src/storage/expressions/LinearCoefficientVisitor.cpp

@ -0,0 +1,151 @@
#include "src/storage/expressions/LinearCoefficientVisitor.h"
#include "src/storage/expressions/Expressions.h"
#include "src/exceptions/ExceptionMacros.h"
#include "src/exceptions/InvalidArgumentException.h"
namespace storm {
namespace expressions {
std::pair<SimpleValuation, double> LinearCoefficientVisitor::getLinearCoefficients(Expression const& expression) {
expression.getBaseExpression().accept(this);
return resultStack.top();
}
void LinearCoefficientVisitor::visit(IfThenElseExpression const* expression) {
LOG_THROW(false, storm::exceptions::InvalidArgumentException, "Expression is non-linear.");
}
void LinearCoefficientVisitor::visit(BinaryBooleanFunctionExpression const* expression) {
LOG_THROW(false, storm::exceptions::InvalidArgumentException, "Expression is non-linear.");
}
void LinearCoefficientVisitor::visit(BinaryNumericalFunctionExpression const* expression) {
if (expression->getOperatorType() == BinaryNumericalFunctionExpression::OperatorType::Plus) {
expression->getFirstOperand()->accept(this);
std::pair<SimpleValuation, double> leftResult = resultStack.top();
resultStack.pop();
expression->getSecondOperand()->accept(this);
std::pair<SimpleValuation, double>& rightResult = resultStack.top();
// Now add the left result to the right result.
for (auto const& identifier : leftResult.first.getDoubleIdentifiers()) {
if (rightResult.first.containsDoubleIdentifier(identifier)) {
rightResult.first.setDoubleValue(identifier, leftResult.first.getDoubleValue(identifier) + rightResult.first.getDoubleValue(identifier));
} else {
rightResult.first.setDoubleValue(identifier, leftResult.first.getDoubleValue(identifier));
}
}
rightResult.second += leftResult.second;
return;
} else if (expression->getOperatorType() == BinaryNumericalFunctionExpression::OperatorType::Minus) {
expression->getFirstOperand()->accept(this);
std::pair<SimpleValuation, double> leftResult = resultStack.top();
resultStack.pop();
expression->getSecondOperand()->accept(this);
std::pair<SimpleValuation, double>& rightResult = resultStack.top();
// Now subtract the right result from the left result.
for (auto const& identifier : leftResult.first.getDoubleIdentifiers()) {
if (rightResult.first.containsDoubleIdentifier(identifier)) {
rightResult.first.setDoubleValue(identifier, leftResult.first.getDoubleValue(identifier) - rightResult.first.getDoubleValue(identifier));
} else {
rightResult.first.setDoubleValue(identifier, leftResult.first.getDoubleValue(identifier));
}
}
for (auto const& identifier : rightResult.first.getDoubleIdentifiers()) {
if (!leftResult.first.containsDoubleIdentifier(identifier)) {
rightResult.first.setDoubleValue(identifier, -rightResult.first.getDoubleValue(identifier));
}
}
rightResult.second = leftResult.second - rightResult.second;
return;
} else if (expression->getOperatorType() == BinaryNumericalFunctionExpression::OperatorType::Times) {
expression->getFirstOperand()->accept(this);
std::pair<SimpleValuation, double> leftResult = resultStack.top();
resultStack.pop();
expression->getSecondOperand()->accept(this);
std::pair<SimpleValuation, double>& rightResult = resultStack.top();
// If the expression is linear, either the left or the right side must not contain variables.
LOG_THROW(leftResult.first.getNumberOfIdentifiers() == 0 || rightResult.first.getNumberOfIdentifiers() == 0, storm::exceptions::InvalidArgumentException, "Expression is non-linear.");
if (leftResult.first.getNumberOfIdentifiers() == 0) {
for (auto const& identifier : rightResult.first.getDoubleIdentifiers()) {
rightResult.first.setDoubleValue(identifier, leftResult.second * rightResult.first.getDoubleValue(identifier));
}
} else {
for (auto const& identifier : leftResult.first.getDoubleIdentifiers()) {
rightResult.first.addDoubleIdentifier(identifier, rightResult.second * leftResult.first.getDoubleValue(identifier));
}
}
rightResult.second *= leftResult.second;
return;
} else if (expression->getOperatorType() == BinaryNumericalFunctionExpression::OperatorType::Divide) {
expression->getFirstOperand()->accept(this);
std::pair<SimpleValuation, double> leftResult = resultStack.top();
resultStack.pop();
expression->getSecondOperand()->accept(this);
std::pair<SimpleValuation, double>& rightResult = resultStack.top();
// If the expression is linear, either the left or the right side must not contain variables.
LOG_THROW(leftResult.first.getNumberOfIdentifiers() == 0 || rightResult.first.getNumberOfIdentifiers() == 0, storm::exceptions::InvalidArgumentException, "Expression is non-linear.");
if (leftResult.first.getNumberOfIdentifiers() == 0) {
for (auto const& identifier : rightResult.first.getDoubleIdentifiers()) {
rightResult.first.setDoubleValue(identifier, leftResult.second / rightResult.first.getDoubleValue(identifier));
}
} else {
for (auto const& identifier : leftResult.first.getDoubleIdentifiers()) {
rightResult.first.addDoubleIdentifier(identifier, leftResult.first.getDoubleValue(identifier) / rightResult.second);
}
}
rightResult.second = leftResult.second / leftResult.second;
return;
} else {
LOG_THROW(false, storm::exceptions::InvalidArgumentException, "Expression is non-linear.");
}
}
void LinearCoefficientVisitor::visit(BinaryRelationExpression const* expression) {
LOG_THROW(false, storm::exceptions::InvalidArgumentException, "Expression is non-linear.");
}
void LinearCoefficientVisitor::visit(VariableExpression const* expression) {
SimpleValuation valuation;
switch (expression->getReturnType()) {
case ExpressionReturnType::Bool: LOG_THROW(false, storm::exceptions::InvalidArgumentException, "Expression is non-linear."); break;
case ExpressionReturnType::Int:
case ExpressionReturnType::Double: valuation.addDoubleIdentifier(expression->getVariableName(), 1); break;
case ExpressionReturnType::Undefined: LOG_THROW(false, storm::exceptions::InvalidArgumentException, "Illegal expression return type."); break;
}
resultStack.push(std::make_pair(valuation, 0));
}
void LinearCoefficientVisitor::visit(UnaryBooleanFunctionExpression const* expression) {
LOG_THROW(false, storm::exceptions::InvalidArgumentException, "Expression is non-linear.");
}
void LinearCoefficientVisitor::visit(UnaryNumericalFunctionExpression const* expression) {
if (expression->getOperatorType() == UnaryNumericalFunctionExpression::OperatorType::Minus) {
// Here, we need to negate all double identifiers.
std::pair<SimpleValuation, double>& valuationConstantPair = resultStack.top();
for (auto const& identifier : valuationConstantPair.first.getDoubleIdentifiers()) {
valuationConstantPair.first.setDoubleValue(identifier, -valuationConstantPair.first.getDoubleValue(identifier));
}
} else {
LOG_THROW(false, storm::exceptions::InvalidArgumentException, "Expression is non-linear.");
}
}
void LinearCoefficientVisitor::visit(BooleanLiteralExpression const* expression) {
LOG_THROW(false, storm::exceptions::InvalidArgumentException, "Expression is non-linear.");
}
void LinearCoefficientVisitor::visit(IntegerLiteralExpression const* expression) {
resultStack.push(std::make_pair(SimpleValuation(), static_cast<double>(expression->getValue())));
}
void LinearCoefficientVisitor::visit(DoubleLiteralExpression const* expression) {
resultStack.push(std::make_pair(SimpleValuation(), expression->getValue()));
}
}
}

46
src/storage/expressions/LinearCoefficientVisitor.h

@ -0,0 +1,46 @@
#ifndef STORM_STORAGE_EXPRESSIONS_LINEARCOEFFICIENTVISITOR_H_
#define STORM_STORAGE_EXPRESSIONS_LINEARCOEFFICIENTVISITOR_H_
#include <stack>
#include "src/storage/expressions/Expression.h"
#include "src/storage/expressions/ExpressionVisitor.h"
#include "src/storage/expressions/SimpleValuation.h"
namespace storm {
namespace expressions {
class LinearCoefficientVisitor : public ExpressionVisitor {
public:
/*!
* Creates a linear coefficient visitor.
*/
LinearCoefficientVisitor() = default;
/*!
* Computes the (double) coefficients of all identifiers appearing in the expression if the expression
* was rewritten as a sum of atoms.. If the expression is not linear, an exception is thrown.
*
* @param expression The expression for which to compute the coefficients.
* @return A pair consisting of a mapping from identifiers to their coefficients and the coefficient of
* the constant atom.
*/
std::pair<SimpleValuation, double> getLinearCoefficients(Expression const& expression);
virtual void visit(IfThenElseExpression const* expression) override;
virtual void visit(BinaryBooleanFunctionExpression const* expression) override;
virtual void visit(BinaryNumericalFunctionExpression const* expression) override;
virtual void visit(BinaryRelationExpression const* expression) override;
virtual void visit(VariableExpression const* expression) override;
virtual void visit(UnaryBooleanFunctionExpression const* expression) override;
virtual void visit(UnaryNumericalFunctionExpression const* expression) override;
virtual void visit(BooleanLiteralExpression const* expression) override;
virtual void visit(IntegerLiteralExpression const* expression) override;
virtual void visit(DoubleLiteralExpression const* expression) override;
private:
std::stack<std::pair<SimpleValuation, double>> resultStack;
};
}
}
#endif /* STORM_STORAGE_EXPRESSIONS_LINEARCOEFFICIENTVISITOR_H_ */

112
src/storage/expressions/LinearityCheckVisitor.cpp

@ -0,0 +1,112 @@
#include "src/storage/expressions/LinearityCheckVisitor.h"
#include "src/storage/expressions/Expressions.h"
#include "src/exceptions/ExceptionMacros.h"
#include "src/exceptions/InvalidTypeException.h"
namespace storm {
namespace expressions {
LinearityCheckVisitor::LinearityCheckVisitor() : resultStack() {
// Intentionally left empty.
}
bool LinearityCheckVisitor::check(Expression const& expression) {
expression.getBaseExpression().accept(this);
return resultStack.top() == LinearityStatus::LinearWithoutVariables || resultStack.top() == LinearityStatus::LinearContainsVariables;
}
void LinearityCheckVisitor::visit(IfThenElseExpression const* expression) {
// An if-then-else expression is never linear.
resultStack.push(LinearityStatus::NonLinear);
}
void LinearityCheckVisitor::visit(BinaryBooleanFunctionExpression const* expression) {
// Boolean function applications are not allowed in linear expressions.
resultStack.push(LinearityStatus::NonLinear);
}
void LinearityCheckVisitor::visit(BinaryNumericalFunctionExpression const* expression) {
LinearityStatus leftResult;
LinearityStatus rightResult;
switch (expression->getOperatorType()) {
case BinaryNumericalFunctionExpression::OperatorType::Plus:
case BinaryNumericalFunctionExpression::OperatorType::Minus:
expression->getFirstOperand()->accept(this);
leftResult = resultStack.top();
if (leftResult == LinearityStatus::NonLinear) {
return;
} else {
resultStack.pop();
expression->getSecondOperand()->accept(this);
rightResult = resultStack.top();
if (rightResult == LinearityStatus::NonLinear) {
return;
}
resultStack.pop();
}
resultStack.push(leftResult == LinearityStatus::LinearContainsVariables || rightResult == LinearityStatus::LinearContainsVariables ? LinearityStatus::LinearContainsVariables : LinearityStatus::LinearWithoutVariables);
break;
case BinaryNumericalFunctionExpression::OperatorType::Times:
case BinaryNumericalFunctionExpression::OperatorType::Divide:
expression->getFirstOperand()->accept(this);
leftResult = resultStack.top();
if (leftResult == LinearityStatus::NonLinear) {
return;
} else {
resultStack.pop();
expression->getSecondOperand()->accept(this);
rightResult = resultStack.top();
if (rightResult == LinearityStatus::NonLinear) {
return;
}
resultStack.pop();
}
if (leftResult == LinearityStatus::LinearContainsVariables && rightResult == LinearityStatus::LinearContainsVariables) {
resultStack.push(LinearityStatus::NonLinear);
}
resultStack.push(leftResult == LinearityStatus::LinearContainsVariables || rightResult == LinearityStatus::LinearContainsVariables ? LinearityStatus::LinearContainsVariables : LinearityStatus::LinearWithoutVariables);
break;
case BinaryNumericalFunctionExpression::OperatorType::Min: resultStack.push(LinearityStatus::NonLinear); break;
case BinaryNumericalFunctionExpression::OperatorType::Max: resultStack.push(LinearityStatus::NonLinear); break;
}
}
void LinearityCheckVisitor::visit(BinaryRelationExpression const* expression) {
resultStack.push(LinearityStatus::NonLinear);
}
void LinearityCheckVisitor::visit(VariableExpression const* expression) {
resultStack.push(LinearityStatus::LinearContainsVariables);
}
void LinearityCheckVisitor::visit(UnaryBooleanFunctionExpression const* expression) {
// Boolean function applications are not allowed in linear expressions.
resultStack.push(LinearityStatus::NonLinear);
}
void LinearityCheckVisitor::visit(UnaryNumericalFunctionExpression const* expression) {
switch (expression->getOperatorType()) {
case UnaryNumericalFunctionExpression::OperatorType::Minus: break;
case UnaryNumericalFunctionExpression::OperatorType::Floor:
case UnaryNumericalFunctionExpression::OperatorType::Ceil: resultStack.pop(); resultStack.push(LinearityStatus::NonLinear); break;
}
}
void LinearityCheckVisitor::visit(BooleanLiteralExpression const* expression) {
resultStack.push(LinearityStatus::NonLinear);
}
void LinearityCheckVisitor::visit(IntegerLiteralExpression const* expression) {
resultStack.push(LinearityStatus::LinearWithoutVariables);
}
void LinearityCheckVisitor::visit(DoubleLiteralExpression const* expression) {
resultStack.push(LinearityStatus::LinearWithoutVariables);
}
}
}

45
src/storage/expressions/LinearityCheckVisitor.h

@ -0,0 +1,45 @@
#ifndef STORM_STORAGE_EXPRESSIONS_LINEARITYCHECKVISITOR_H_
#define STORM_STORAGE_EXPRESSIONS_LINEARITYCHECKVISITOR_H_
#include <stack>
#include "src/storage/expressions/Expression.h"
#include "src/storage/expressions/ExpressionVisitor.h"
namespace storm {
namespace expressions {
class LinearityCheckVisitor : public ExpressionVisitor {
public:
/*!
* Creates a linearity check visitor.
*/
LinearityCheckVisitor();
/*!
* Checks that the given expression is linear.
*
* @param expression The expression to check for linearity.
*/
bool check(Expression const& expression);
virtual void visit(IfThenElseExpression const* expression) override;
virtual void visit(BinaryBooleanFunctionExpression const* expression) override;
virtual void visit(BinaryNumericalFunctionExpression const* expression) override;
virtual void visit(BinaryRelationExpression const* expression) override;
virtual void visit(VariableExpression const* expression) override;
virtual void visit(UnaryBooleanFunctionExpression const* expression) override;
virtual void visit(UnaryNumericalFunctionExpression const* expression) override;
virtual void visit(BooleanLiteralExpression const* expression) override;
virtual void visit(IntegerLiteralExpression const* expression) override;
virtual void visit(DoubleLiteralExpression const* expression) override;
private:
enum class LinearityStatus { NonLinear, LinearContainsVariables, LinearWithoutVariables };
// A stack for communicating the results of the subexpressions.
std::stack<LinearityStatus> resultStack;
};
}
}
#endif /* STORM_STORAGE_EXPRESSIONS_LINEARITYCHECKVISITOR_H_ */

33
src/storage/expressions/OperatorType.h

@ -0,0 +1,33 @@
#ifndef STORM_STORAGE_EXPRESSIONS_OPERATORTYPE_H_
#define STORM_STORAGE_EXPRESSIONS_OPERATORTYPE_H_
namespace storm {
namespace expressions {
// An enum representing all possible operator types.
enum class OperatorType {
And,
Or,
Xor,
Implies,
Iff,
Plus,
Minus,
Times,
Divide,
Min,
Max,
Equal,
NotEqual,
Less,
LessOrEqual,
Greater,
GreaterOrEqual,
Not,
Floor,
Ceil,
Ite
};
}
}
#endif /* STORM_STORAGE_EXPRESSIONS_OPERATORTYPE_H_ */

184
src/storage/expressions/SimpleValuation.cpp

@ -1,103 +1,167 @@
#include <boost/functional/hash.hpp>
#include "src/storage/expressions/SimpleValuation.h" #include "src/storage/expressions/SimpleValuation.h"
#include <set>
#include <boost/functional/hash.hpp>
#include "src/exceptions/ExceptionMacros.h" #include "src/exceptions/ExceptionMacros.h"
#include "src/exceptions/InvalidArgumentException.h" #include "src/exceptions/InvalidArgumentException.h"
#include "src/exceptions/InvalidAccessException.h"
namespace storm { namespace storm {
namespace expressions { namespace expressions {
SimpleValuation::SimpleValuation() : booleanIdentifierToIndexMap(new std::unordered_map<std::string, uint_fast64_t>()), integerIdentifierToIndexMap(new std::unordered_map<std::string, uint_fast64_t>()), doubleIdentifierToIndexMap(new std::unordered_map<std::string, uint_fast64_t>()), booleanValues(), integerValues(), doubleValues() {
// Intentionally left empty.
}
bool SimpleValuation::operator==(SimpleValuation const& other) const { bool SimpleValuation::operator==(SimpleValuation const& other) const {
return this->booleanIdentifierToIndexMap.get() == other.booleanIdentifierToIndexMap.get() && this->integerIdentifierToIndexMap.get() == other.integerIdentifierToIndexMap.get() && this->doubleIdentifierToIndexMap.get() == other.doubleIdentifierToIndexMap.get() && this->booleanValues == other.booleanValues && this->integerValues == other.integerValues && this->doubleValues == other.doubleValues; return this->identifierToValueMap == other.identifierToValueMap;
} }
void SimpleValuation::addBooleanIdentifier(std::string const& name, bool initialValue) { void SimpleValuation::addBooleanIdentifier(std::string const& name, bool initialValue) {
LOG_THROW(this->booleanIdentifierToIndexMap->find(name) == this->booleanIdentifierToIndexMap->end(), storm::exceptions::InvalidArgumentException, "Boolean identifier '" << name << "' already registered."); LOG_THROW(this->identifierToValueMap.find(name) == this->identifierToValueMap.end(), storm::exceptions::InvalidArgumentException, "Identifier '" << name << "' already registered.");
this->identifierToValueMap.emplace(name, initialValue);
this->booleanIdentifierToIndexMap->emplace(name, this->booleanValues.size());
this->booleanValues.push_back(initialValue);
} }
void SimpleValuation::addIntegerIdentifier(std::string const& name, int_fast64_t initialValue) { void SimpleValuation::addIntegerIdentifier(std::string const& name, int_fast64_t initialValue) {
LOG_THROW(this->booleanIdentifierToIndexMap->find(name) == this->booleanIdentifierToIndexMap->end(), storm::exceptions::InvalidArgumentException, "Integer identifier '" << name << "' already registered."); LOG_THROW(this->identifierToValueMap.find(name) == this->identifierToValueMap.end(), storm::exceptions::InvalidArgumentException, "Identifier '" << name << "' already registered.");
this->identifierToValueMap.emplace(name, initialValue);
this->integerIdentifierToIndexMap->emplace(name, this->integerValues.size());
this->integerValues.push_back(initialValue);
} }
void SimpleValuation::addDoubleIdentifier(std::string const& name, double initialValue) { void SimpleValuation::addDoubleIdentifier(std::string const& name, double initialValue) {
LOG_THROW(this->booleanIdentifierToIndexMap->find(name) == this->booleanIdentifierToIndexMap->end(), storm::exceptions::InvalidArgumentException, "Double identifier '" << name << "' already registered."); LOG_THROW(this->identifierToValueMap.find(name) == this->identifierToValueMap.end(), storm::exceptions::InvalidArgumentException, "Identifier '" << name << "' already registered.");
this->identifierToValueMap.emplace(name, initialValue);
this->doubleIdentifierToIndexMap->emplace(name, this->doubleValues.size());
this->doubleValues.push_back(initialValue);
} }
void SimpleValuation::setBooleanValue(std::string const& name, bool value) { void SimpleValuation::setBooleanValue(std::string const& name, bool value) {
this->booleanValues[this->booleanIdentifierToIndexMap->at(name)] = value; this->identifierToValueMap[name] = value;
} }
void SimpleValuation::setIntegerValue(std::string const& name, int_fast64_t value) { void SimpleValuation::setIntegerValue(std::string const& name, int_fast64_t value) {
this->integerValues[this->integerIdentifierToIndexMap->at(name)] = value; this->identifierToValueMap[name] = value;
} }
void SimpleValuation::setDoubleValue(std::string const& name, double value) { void SimpleValuation::setDoubleValue(std::string const& name, double value) {
this->doubleValues[this->doubleIdentifierToIndexMap->at(name)] = value; this->identifierToValueMap[name] = value;
}
void SimpleValuation::removeIdentifier(std::string const& name) {
auto nameValuePair = this->identifierToValueMap.find(name);
LOG_THROW(nameValuePair != this->identifierToValueMap.end(), storm::exceptions::InvalidArgumentException, "Deleting unknown identifier '" << name << "'.");
this->identifierToValueMap.erase(nameValuePair);
}
ExpressionReturnType SimpleValuation::getIdentifierType(std::string const& name) const {
auto nameValuePair = this->identifierToValueMap.find(name);
LOG_THROW(nameValuePair != this->identifierToValueMap.end(), storm::exceptions::InvalidAccessException, "Access to unkown identifier '" << name << "'.");
if (nameValuePair->second.type() == typeid(bool)) {
return ExpressionReturnType::Bool;
} else if (nameValuePair->second.type() == typeid(int_fast64_t)) {
return ExpressionReturnType::Int;
} else {
return ExpressionReturnType::Double;
}
}
bool SimpleValuation::containsBooleanIdentifier(std::string const& name) const {
auto nameValuePair = this->identifierToValueMap.find(name);
if (nameValuePair == this->identifierToValueMap.end()) {
return false;
}
return nameValuePair->second.type() == typeid(bool);
}
bool SimpleValuation::containsIntegerIdentifier(std::string const& name) const {
auto nameValuePair = this->identifierToValueMap.find(name);
if (nameValuePair == this->identifierToValueMap.end()) {
return false;
}
return nameValuePair->second.type() == typeid(int_fast64_t);
}
bool SimpleValuation::containsDoubleIdentifier(std::string const& name) const {
auto nameValuePair = this->identifierToValueMap.find(name);
if (nameValuePair == this->identifierToValueMap.end()) {
return false;
}
return nameValuePair->second.type() == typeid(double);
} }
bool SimpleValuation::getBooleanValue(std::string const& name) const { bool SimpleValuation::getBooleanValue(std::string const& name) const {
auto const& nameIndexPair = this->booleanIdentifierToIndexMap->find(name); auto nameValuePair = this->identifierToValueMap.find(name);
return this->booleanValues[nameIndexPair->second]; LOG_THROW(nameValuePair != this->identifierToValueMap.end(), storm::exceptions::InvalidAccessException, "Access to unkown identifier '" << name << "'.");
return boost::get<bool>(nameValuePair->second);
} }
int_fast64_t SimpleValuation::getIntegerValue(std::string const& name) const { int_fast64_t SimpleValuation::getIntegerValue(std::string const& name) const {
auto const& nameIndexPair = this->integerIdentifierToIndexMap->find(name); auto nameValuePair = this->identifierToValueMap.find(name);
return this->integerValues[nameIndexPair->second]; LOG_THROW(nameValuePair != this->identifierToValueMap.end(), storm::exceptions::InvalidAccessException, "Access to unkown identifier '" << name << "'.");
return boost::get<int_fast64_t>(nameValuePair->second);
} }
double SimpleValuation::getDoubleValue(std::string const& name) const { double SimpleValuation::getDoubleValue(std::string const& name) const {
auto const& nameIndexPair = this->doubleIdentifierToIndexMap->find(name); auto nameValuePair = this->identifierToValueMap.find(name);
return this->doubleValues[nameIndexPair->second]; LOG_THROW(nameValuePair != this->identifierToValueMap.end(), storm::exceptions::InvalidAccessException, "Access to unkown identifier '" << name << "'.");
return boost::get<double>(nameValuePair->second);
} }
std::ostream& operator<<(std::ostream& stream, SimpleValuation const& valuation) { std::size_t SimpleValuation::getNumberOfIdentifiers() const {
stream << "valuation { bool ["; return this->identifierToValueMap.size();
if (!valuation.booleanValues.empty()) { }
for (uint_fast64_t i = 0; i < valuation.booleanValues.size() - 1; ++i) { std::set<std::string> SimpleValuation::getIdentifiers() const {
stream << valuation.booleanValues[i] << ", "; std::set<std::string> result;
for (auto const& nameValuePair : this->identifierToValueMap) {
result.insert(nameValuePair.first);
}
return result;
}
std::set<std::string> SimpleValuation::getBooleanIdentifiers() const {
std::set<std::string> result;
for (auto const& nameValuePair : this->identifierToValueMap) {
if (nameValuePair.second.type() == typeid(bool)) {
result.insert(nameValuePair.first);
}
}
return result;
}
std::set<std::string> SimpleValuation::getIntegerIdentifiers() const {
std::set<std::string> result;
for (auto const& nameValuePair : this->identifierToValueMap) {
if (nameValuePair.second.type() == typeid(int_fast64_t)) {
result.insert(nameValuePair.first);
} }
stream << valuation.booleanValues.back();
} }
stream << "] int ["; return result;
if (!valuation.integerValues.empty()) { }
for (uint_fast64_t i = 0; i < valuation.integerValues.size() - 1; ++i) { std::set<std::string> SimpleValuation::getDoubleIdentifiers() const {
stream << valuation.integerValues[i] << ", "; std::set<std::string> result;
for (auto const& nameValuePair : this->identifierToValueMap) {
if (nameValuePair.second.type() == typeid(double)) {
result.insert(nameValuePair.first);
} }
stream << valuation.integerValues.back();
} }
stream << "] double ["; return result;
if (!valuation.doubleValues.empty()) { }
for (uint_fast64_t i = 0; i < valuation.doubleValues.size() - 1; ++i) { std::ostream& operator<<(std::ostream& stream, SimpleValuation const& valuation) {
stream << valuation.doubleValues[i] << ", "; stream << "{ ";
uint_fast64_t elementIndex = 0;
for (auto const& nameValuePair : valuation.identifierToValueMap) {
stream << nameValuePair.first << " -> " << nameValuePair.second << " ";
++elementIndex;
if (elementIndex < valuation.identifierToValueMap.size()) {
stream << ", ";
} }
stream << valuation.doubleValues.back();
} }
stream << "] }"; stream << "}";
return stream; return stream;
} }
std::size_t SimpleValuationPointerHash::operator()(SimpleValuation* valuation) const { std::size_t SimpleValuationPointerHash::operator()(SimpleValuation* valuation) const {
size_t seed = 0; size_t seed = 0;
for (auto const& value : valuation->booleanValues) { for (auto const& nameValuePair : valuation->identifierToValueMap) {
boost::hash_combine<bool>(seed, value); boost::hash_combine(seed, nameValuePair.first);
} boost::hash_combine(seed, nameValuePair.second);
for (auto const& value : valuation->integerValues) {
boost::hash_combine<int_fast64_t>(seed, value);
}
for (auto const& value : valuation->doubleValues) {
boost::hash_combine<double>(seed, value);
} }
return seed; return seed;
} }
@ -107,21 +171,7 @@ namespace storm {
} }
bool SimpleValuationPointerLess::operator()(SimpleValuation* valuation1, SimpleValuation* valuation2) const { bool SimpleValuationPointerLess::operator()(SimpleValuation* valuation1, SimpleValuation* valuation2) const {
// Compare boolean variables. return valuation1->identifierToValueMap < valuation2->identifierToValueMap;
bool less = valuation1->booleanValues < valuation2->booleanValues;
if (less) {
return true;
}
less = valuation1->integerValues < valuation2->integerValues;
if (less) {
return true;
}
less = valuation1->doubleValues < valuation2->doubleValues;
if (less) {
return true;
} else {
return false;
}
} }
} }
} }

52
src/storage/expressions/SimpleValuation.h

@ -1,12 +1,12 @@
#ifndef STORM_STORAGE_EXPRESSIONS_SIMPLEVALUATION_H_ #ifndef STORM_STORAGE_EXPRESSIONS_SIMPLEVALUATION_H_
#define STORM_STORAGE_EXPRESSIONS_SIMPLEVALUATION_H_ #define STORM_STORAGE_EXPRESSIONS_SIMPLEVALUATION_H_
#include <memory> #include <boost/container/flat_map.hpp>
#include <vector> #include <boost/variant.hpp>
#include <unordered_map>
#include <iostream> #include <iostream>
#include "src/storage/expressions/Valuation.h" #include "src/storage/expressions/Valuation.h"
#include "src/storage/expressions/ExpressionReturnType.h"
#include "src/utility/OsDetection.h" #include "src/utility/OsDetection.h"
namespace storm { namespace storm {
@ -16,12 +16,8 @@ namespace storm {
friend class SimpleValuationPointerHash; friend class SimpleValuationPointerHash;
friend class SimpleValuationPointerLess; friend class SimpleValuationPointerLess;
/*!
* Creates a simple valuation without any identifiers.
*/
SimpleValuation();
// Instantiate some constructors and assignments with their default implementations. // Instantiate some constructors and assignments with their default implementations.
SimpleValuation() = default;
SimpleValuation(SimpleValuation const&) = default; SimpleValuation(SimpleValuation const&) = default;
SimpleValuation& operator=(SimpleValuation const&) = default; SimpleValuation& operator=(SimpleValuation const&) = default;
#ifndef WINDOWS #ifndef WINDOWS
@ -83,7 +79,30 @@ namespace storm {
*/ */
void setDoubleValue(std::string const& name, double value); void setDoubleValue(std::string const& name, double value);
/*!
* Removes the given identifier from this valuation.
*
* @param name The name of the identifier that is to be removed.
*/
void removeIdentifier(std::string const& name);
/*!
* Retrieves the type of the identifier with the given name.
*
* @param name The name of the identifier whose type to retrieve.
* @return The type of the identifier with the given name.
*/
ExpressionReturnType getIdentifierType(std::string const& name) const;
// Override base class methods. // Override base class methods.
virtual bool containsBooleanIdentifier(std::string const& name) const override;
virtual bool containsIntegerIdentifier(std::string const& name) const override;
virtual bool containsDoubleIdentifier(std::string const& name) const override;
virtual std::size_t getNumberOfIdentifiers() const override;
virtual std::set<std::string> getIdentifiers() const override;
virtual std::set<std::string> getBooleanIdentifiers() const override;
virtual std::set<std::string> getIntegerIdentifiers() const override;
virtual std::set<std::string> getDoubleIdentifiers() const override;
virtual bool getBooleanValue(std::string const& name) const override; virtual bool getBooleanValue(std::string const& name) const override;
virtual int_fast64_t getIntegerValue(std::string const& name) const override; virtual int_fast64_t getIntegerValue(std::string const& name) const override;
virtual double getDoubleValue(std::string const& name) const override; virtual double getDoubleValue(std::string const& name) const override;
@ -92,22 +111,7 @@ namespace storm {
private: private:
// A mapping of boolean identifiers to their local indices in the value container. // A mapping of boolean identifiers to their local indices in the value container.
std::shared_ptr<std::unordered_map<std::string, uint_fast64_t>> booleanIdentifierToIndexMap; boost::container::flat_map<std::string, boost::variant<bool, int_fast64_t, double>> identifierToValueMap;
// A mapping of integer identifiers to their local indices in the value container.
std::shared_ptr<std::unordered_map<std::string, uint_fast64_t>> integerIdentifierToIndexMap;
// A mapping of double identifiers to their local indices in the value container.
std::shared_ptr<std::unordered_map<std::string, uint_fast64_t>> doubleIdentifierToIndexMap;
// The value container for all boolean identifiers.
std::vector<bool> booleanValues;
// The value container for all integer identifiers.
std::vector<int_fast64_t> integerValues;
// The value container for all double identifiers.
std::vector<double> doubleValues;
}; };
/*! /*!

4
src/storage/expressions/SubstitutionVisitor.cpp

@ -13,8 +13,8 @@ namespace storm {
} }
template<typename MapType> template<typename MapType>
Expression SubstitutionVisitor<MapType>::substitute(BaseExpression const* expression) { Expression SubstitutionVisitor<MapType>::substitute(Expression const& expression) {
expression->accept(this); expression.getBaseExpression().accept(this);
return Expression(this->expressionStack.top()); return Expression(this->expressionStack.top());
} }

2
src/storage/expressions/SubstitutionVisitor.h

@ -26,7 +26,7 @@ namespace storm {
* @return The expression in which all identifiers in the key set of the previously given mapping are * @return The expression in which all identifiers in the key set of the previously given mapping are
* substituted with the mapped-to expressions. * substituted with the mapped-to expressions.
*/ */
Expression substitute(BaseExpression const* expression); Expression substitute(Expression const& expression);
virtual void visit(IfThenElseExpression const* expression) override; virtual void visit(IfThenElseExpression const* expression) override;
virtual void visit(BinaryBooleanFunctionExpression const* expression) override; virtual void visit(BinaryBooleanFunctionExpression const* expression) override;

4
src/storage/expressions/TypeCheckVisitor.cpp

@ -12,8 +12,8 @@ namespace storm {
} }
template<typename MapType> template<typename MapType>
void TypeCheckVisitor<MapType>::check(BaseExpression const* expression) { void TypeCheckVisitor<MapType>::check(Expression const& expression) {
expression->accept(this); expression.getBaseExpression().accept(this);
} }
template<typename MapType> template<typename MapType>

2
src/storage/expressions/TypeCheckVisitor.h

@ -24,7 +24,7 @@ namespace storm {
* *
* @param expression The expression in which to check the types. * @param expression The expression in which to check the types.
*/ */
void check(BaseExpression const* expression); void check(Expression const& expression);
virtual void visit(IfThenElseExpression const* expression) override; virtual void visit(IfThenElseExpression const* expression) override;
virtual void visit(BinaryBooleanFunctionExpression const* expression) override; virtual void visit(BinaryBooleanFunctionExpression const* expression) override;

6
src/storage/expressions/UnaryBooleanFunctionExpression.cpp

@ -13,6 +13,12 @@ namespace storm {
return this->operatorType; return this->operatorType;
} }
storm::expressions::OperatorType UnaryBooleanFunctionExpression::getOperator() const {
switch (this->getOperatorType()) {
case OperatorType::Not: return storm::expressions::OperatorType::Not;
}
}
bool UnaryBooleanFunctionExpression::evaluateAsBool(Valuation const* valuation) const { bool UnaryBooleanFunctionExpression::evaluateAsBool(Valuation const* valuation) const {
LOG_THROW(this->hasBooleanReturnType(), storm::exceptions::InvalidTypeException, "Unable to evaluate expression as boolean."); LOG_THROW(this->hasBooleanReturnType(), storm::exceptions::InvalidTypeException, "Unable to evaluate expression as boolean.");

1
src/storage/expressions/UnaryBooleanFunctionExpression.h

@ -32,6 +32,7 @@ namespace storm {
virtual ~UnaryBooleanFunctionExpression() = default; virtual ~UnaryBooleanFunctionExpression() = default;
// Override base class methods. // Override base class methods.
virtual storm::expressions::OperatorType getOperator() const override;
virtual bool evaluateAsBool(Valuation const* valuation = nullptr) const override; virtual bool evaluateAsBool(Valuation const* valuation = nullptr) const override;
virtual std::shared_ptr<BaseExpression const> simplify() const override; virtual std::shared_ptr<BaseExpression const> simplify() const override;
virtual void accept(ExpressionVisitor* visitor) const override; virtual void accept(ExpressionVisitor* visitor) const override;

4
src/storage/expressions/UnaryExpression.cpp

@ -9,6 +9,10 @@ namespace storm {
// Intentionally left empty. // Intentionally left empty.
} }
bool UnaryExpression::isFunctionApplication() const {
return true;
}
bool UnaryExpression::containsVariables() const { bool UnaryExpression::containsVariables() const {
return this->getOperand()->containsVariables(); return this->getOperand()->containsVariables();
} }

1
src/storage/expressions/UnaryExpression.h

@ -26,6 +26,7 @@ namespace storm {
virtual ~UnaryExpression() = default; virtual ~UnaryExpression() = default;
// Override base class methods. // Override base class methods.
virtual bool isFunctionApplication() const override;
virtual bool containsVariables() const override; virtual bool containsVariables() const override;
virtual uint_fast64_t getArity() const override; virtual uint_fast64_t getArity() const override;
virtual std::shared_ptr<BaseExpression const> getOperand(uint_fast64_t operandIndex) const override; virtual std::shared_ptr<BaseExpression const> getOperand(uint_fast64_t operandIndex) const override;

8
src/storage/expressions/UnaryNumericalFunctionExpression.cpp

@ -14,6 +14,14 @@ namespace storm {
return this->operatorType; return this->operatorType;
} }
storm::expressions::OperatorType UnaryNumericalFunctionExpression::getOperator() const {
switch (this->getOperatorType()) {
case OperatorType::Minus: return storm::expressions::OperatorType::Minus; break;
case OperatorType::Floor: return storm::expressions::OperatorType::Floor; break;
case OperatorType::Ceil: return storm::expressions::OperatorType::Ceil; break;
}
}
int_fast64_t UnaryNumericalFunctionExpression::evaluateAsInt(Valuation const* valuation) const { int_fast64_t UnaryNumericalFunctionExpression::evaluateAsInt(Valuation const* valuation) const {
LOG_THROW(this->hasIntegralReturnType(), storm::exceptions::InvalidTypeException, "Unable to evaluate expression as integer."); LOG_THROW(this->hasIntegralReturnType(), storm::exceptions::InvalidTypeException, "Unable to evaluate expression as integer.");

1
src/storage/expressions/UnaryNumericalFunctionExpression.h

@ -32,6 +32,7 @@ namespace storm {
virtual ~UnaryNumericalFunctionExpression() = default; virtual ~UnaryNumericalFunctionExpression() = default;
// Override base class methods. // Override base class methods.
virtual storm::expressions::OperatorType getOperator() const override;
virtual int_fast64_t evaluateAsInt(Valuation const* valuation = nullptr) const override; virtual int_fast64_t evaluateAsInt(Valuation const* valuation = nullptr) const override;
virtual double evaluateAsDouble(Valuation const* valuation = nullptr) const override; virtual double evaluateAsDouble(Valuation const* valuation = nullptr) const override;
virtual std::shared_ptr<BaseExpression const> simplify() const override; virtual std::shared_ptr<BaseExpression const> simplify() const override;

61
src/storage/expressions/Valuation.h

@ -2,6 +2,7 @@
#define STORM_STORAGE_EXPRESSIONS_VALUATION_H_ #define STORM_STORAGE_EXPRESSIONS_VALUATION_H_
#include <string> #include <string>
#include <set>
namespace storm { namespace storm {
namespace expressions { namespace expressions {
@ -34,6 +35,66 @@ namespace storm {
* @return The value of the double identifier. * @return The value of the double identifier.
*/ */
virtual double getDoubleValue(std::string const& name) const = 0; virtual double getDoubleValue(std::string const& name) const = 0;
/*!
* Retrieves whether there exists a boolean identifier with the given name in the valuation.
*
* @param name The name of the boolean identifier to query.
* @return True iff the identifier exists and is of boolean type.
*/
virtual bool containsBooleanIdentifier(std::string const& name) const = 0;
/*!
* Retrieves whether there exists a integer identifier with the given name in the valuation.
*
* @param name The name of the integer identifier to query.
* @return True iff the identifier exists and is of boolean type.
*/
virtual bool containsIntegerIdentifier(std::string const& name) const = 0;
/*!
* Retrieves whether there exists a double identifier with the given name in the valuation.
*
* @param name The name of the double identifier to query.
* @return True iff the identifier exists and is of boolean type.
*/
virtual bool containsDoubleIdentifier(std::string const& name) const = 0;
/*!
* Retrieves the number of identifiers in this valuation.
*
* @return The number of identifiers in this valuation.
*/
virtual std::size_t getNumberOfIdentifiers() const = 0;
/*!
* Retrieves the set of all identifiers contained in this valuation.
*
* @return The set of all identifiers contained in this valuation.
*/
virtual std::set<std::string> getIdentifiers() const = 0;
/*!
* Retrieves the set of boolean identifiers contained in this valuation.
*
* @return The set of boolean identifiers contained in this valuation.
*/
virtual std::set<std::string> getBooleanIdentifiers() const = 0;
/*!
* Retrieves the set of integer identifiers contained in this valuation.
*
* @return The set of integer identifiers contained in this valuation.
*/
virtual std::set<std::string> getIntegerIdentifiers() const = 0;
/*!
* Retrieves the set of double identifiers contained in this valuation.
*
* @return The set of double identifiers contained in this valuation.
*/
virtual std::set<std::string> getDoubleIdentifiers() const = 0;
}; };
} }
} }

2
src/storage/prism/Program.cpp

@ -13,7 +13,7 @@ namespace storm {
Program::Program(ModelType modelType, std::vector<Constant> const& constants, std::vector<BooleanVariable> const& globalBooleanVariables, std::vector<IntegerVariable> const& globalIntegerVariables, std::vector<Formula> const& formulas, std::vector<Module> const& modules, std::vector<RewardModel> const& rewardModels, bool fixInitialConstruct, storm::prism::InitialConstruct const& initialConstruct, std::vector<Label> const& labels, std::string const& filename, uint_fast64_t lineNumber, bool checkValidity) : LocatedInformation(filename, lineNumber), modelType(modelType), constants(constants), constantToIndexMap(), globalBooleanVariables(globalBooleanVariables), globalBooleanVariableToIndexMap(), globalIntegerVariables(globalIntegerVariables), globalIntegerVariableToIndexMap(), formulas(formulas), formulaToIndexMap(), modules(modules), moduleToIndexMap(), rewardModels(rewardModels), rewardModelToIndexMap(), initialConstruct(initialConstruct), labels(labels), labelToIndexMap(), actions(), actionsToModuleIndexMap(), variableToModuleIndexMap() { Program::Program(ModelType modelType, std::vector<Constant> const& constants, std::vector<BooleanVariable> const& globalBooleanVariables, std::vector<IntegerVariable> const& globalIntegerVariables, std::vector<Formula> const& formulas, std::vector<Module> const& modules, std::vector<RewardModel> const& rewardModels, bool fixInitialConstruct, storm::prism::InitialConstruct const& initialConstruct, std::vector<Label> const& labels, std::string const& filename, uint_fast64_t lineNumber, bool checkValidity) : LocatedInformation(filename, lineNumber), modelType(modelType), constants(constants), constantToIndexMap(), globalBooleanVariables(globalBooleanVariables), globalBooleanVariableToIndexMap(), globalIntegerVariables(globalIntegerVariables), globalIntegerVariableToIndexMap(), formulas(formulas), formulaToIndexMap(), modules(modules), moduleToIndexMap(), rewardModels(rewardModels), rewardModelToIndexMap(), initialConstruct(initialConstruct), labels(labels), labelToIndexMap(), actions(), actionsToModuleIndexMap(), variableToModuleIndexMap() {
this->createMappings(); this->createMappings();
// Create a new initial construct if none was given explicitly. // Create a new initial construct if the corresponding flag was set.
if (fixInitialConstruct) { if (fixInitialConstruct) {
if (this->getInitialConstruct().getInitialStatesExpression().isFalse()) { if (this->getInitialConstruct().getInitialStatesExpression().isFalse()) {
storm::expressions::Expression newInitialExpression = storm::expressions::Expression::createTrue(); storm::expressions::Expression newInitialExpression = storm::expressions::Expression::createTrue();

28
src/utility/counterexamples.h

@ -36,8 +36,8 @@ namespace storm {
// for (auto state : psiStates) { // for (auto state : psiStates) {
// analysisInformation[state] = boost::container::flat_set<uint_fast64_t>(); // analysisInformation[state] = boost::container::flat_set<uint_fast64_t>();
// for (auto const& predecessorEntry : backwardTransitions.getRow(state)) { // for (auto const& predecessorEntry : backwardTransitions.getRow(state)) {
// if (predecessorEntry.first != state && !psiStates.get(predecessorEntry.first)) { // if (predecessorEntry.getColumn() != state && !psiStates.get(predecessorEntry.getColumn())) {
// worklist.push(std::make_pair(predecessorEntry.first, state)); // worklist.push(std::make_pair(predecessorEntry.getColumn(), state));
// } // }
// } // }
// } // }
@ -57,7 +57,7 @@ namespace storm {
// bool choiceTargetsTargetState = false; // bool choiceTargetsTargetState = false;
// //
// for (auto& entry : transitionMatrix.getRow(currentChoice)) { // for (auto& entry : transitionMatrix.getRow(currentChoice)) {
// if (entry.first == targetState) { // if (entry.getColumn() == targetState) {
// choiceTargetsTargetState = true; // choiceTargetsTargetState = true;
// break; // break;
// } // }
@ -79,8 +79,8 @@ namespace storm {
// if (analysisInformation[currentState].size() != analysisInformationSizeBefore) { // if (analysisInformation[currentState].size() != analysisInformationSizeBefore) {
// for (auto& predecessorEntry : backwardTransitions.getRow(currentState)) { // for (auto& predecessorEntry : backwardTransitions.getRow(currentState)) {
// // Only put the predecessor in the worklist if it's not already a target state. // // Only put the predecessor in the worklist if it's not already a target state.
// if (!psiStates.get(predecessorEntry.first)) { // if (!psiStates.get(predecessorEntry.getColumn())) {
// worklist.push(std::make_pair(predecessorEntry.first, currentState)); // worklist.push(std::make_pair(predecessorEntry.getColumn(), currentState));
// } // }
// } // }
// } // }
@ -96,9 +96,9 @@ namespace storm {
for (auto state : psiStates) { for (auto state : psiStates) {
analysisInformation[state] = boost::container::flat_set<uint_fast64_t>(); analysisInformation[state] = boost::container::flat_set<uint_fast64_t>();
for (auto const& predecessorEntry : backwardTransitions.getRow(state)) { for (auto const& predecessorEntry : backwardTransitions.getRow(state)) {
if (predecessorEntry.first != state && !statesInWorkList.get(predecessorEntry.first) && !psiStates.get(predecessorEntry.first)) { if (predecessorEntry.getColumn() != state && !statesInWorkList.get(predecessorEntry.getColumn()) && !psiStates.get(predecessorEntry.getColumn())) {
worklist.push(predecessorEntry.first); worklist.push(predecessorEntry.getColumn());
statesInWorkList.set(predecessorEntry.first); statesInWorkList.set(predecessorEntry.getColumn());
markedStates.set(state); markedStates.set(state);
} }
} }
@ -116,7 +116,7 @@ namespace storm {
bool modifiedChoice = false; bool modifiedChoice = false;
for (auto const& entry : transitionMatrix.getRow(currentChoice)) { for (auto const& entry : transitionMatrix.getRow(currentChoice)) {
if (markedStates.get(entry.first)) { if (markedStates.get(entry.getColumn())) {
modifiedChoice = true; modifiedChoice = true;
break; break;
} }
@ -127,9 +127,9 @@ namespace storm {
// and the choice labels. // and the choice labels.
if (modifiedChoice) { if (modifiedChoice) {
for (auto const& entry : transitionMatrix.getRow(currentChoice)) { for (auto const& entry : transitionMatrix.getRow(currentChoice)) {
if (markedStates.get(entry.first)) { if (markedStates.get(entry.getColumn())) {
boost::container::flat_set<uint_fast64_t> tmpIntersection; boost::container::flat_set<uint_fast64_t> tmpIntersection;
std::set_intersection(analysisInformation[currentState].begin(), analysisInformation[currentState].end(), analysisInformation[entry.first].begin(), analysisInformation[entry.first].end(), std::inserter(tmpIntersection, tmpIntersection.begin())); std::set_intersection(analysisInformation[currentState].begin(), analysisInformation[currentState].end(), analysisInformation[entry.getColumn()].begin(), analysisInformation[entry.getColumn()].end(), std::inserter(tmpIntersection, tmpIntersection.begin()));
std::set_intersection(analysisInformation[currentState].begin(), analysisInformation[currentState].end(), choiceLabeling[currentChoice].begin(), choiceLabeling[currentChoice].end(), std::inserter(tmpIntersection, tmpIntersection.begin())); std::set_intersection(analysisInformation[currentState].begin(), analysisInformation[currentState].end(), choiceLabeling[currentChoice].begin(), choiceLabeling[currentChoice].end(), std::inserter(tmpIntersection, tmpIntersection.begin()));
analysisInformation[currentState] = std::move(tmpIntersection); analysisInformation[currentState] = std::move(tmpIntersection);
} }
@ -142,9 +142,9 @@ namespace storm {
if (analysisInformation[currentState].size() != analysisInformationSizeBefore) { if (analysisInformation[currentState].size() != analysisInformationSizeBefore) {
for (auto const& predecessorEntry : backwardTransitions.getRow(currentState)) { for (auto const& predecessorEntry : backwardTransitions.getRow(currentState)) {
// Only put the predecessor in the worklist if it's not already a target state. // Only put the predecessor in the worklist if it's not already a target state.
if (!psiStates.get(predecessorEntry.first) && !statesInWorkList.get(predecessorEntry.first)) { if (!psiStates.get(predecessorEntry.getColumn()) && !statesInWorkList.get(predecessorEntry.getColumn())) {
worklist.push(predecessorEntry.first); worklist.push(predecessorEntry.getColumn());
statesInWorkList.set(predecessorEntry.first); statesInWorkList.set(predecessorEntry.getColumn());
} }
} }
markedStates.set(currentState, true); markedStates.set(currentState, true);

60
src/utility/graph.h

@ -79,16 +79,16 @@ namespace storm {
} }
for (typename storm::storage::SparseMatrix<T>::const_iterator entryIt = backwardTransitions.begin(currentState), entryIte = backwardTransitions.end(currentState); entryIt != entryIte; ++entryIt) { for (typename storm::storage::SparseMatrix<T>::const_iterator entryIt = backwardTransitions.begin(currentState), entryIte = backwardTransitions.end(currentState); entryIt != entryIte; ++entryIt) {
if (phiStates[entryIt->first] && (!statesWithProbabilityGreater0.get(entryIt->first) || (useStepBound && remainingSteps[entryIt->first] < currentStepBound - 1))) { if (phiStates[entryIt->getColumn()] && (!statesWithProbabilityGreater0.get(entryIt->getColumn()) || (useStepBound && remainingSteps[entryIt->getColumn()] < currentStepBound - 1))) {
// If we don't have a bound on the number of steps to take, just add the state to the stack. // If we don't have a bound on the number of steps to take, just add the state to the stack.
if (!useStepBound) { if (!useStepBound) {
statesWithProbabilityGreater0.set(entryIt->first, true); statesWithProbabilityGreater0.set(entryIt->getColumn(), true);
stack.push_back(entryIt->first); stack.push_back(entryIt->getColumn());
} else if (currentStepBound > 0) { } else if (currentStepBound > 0) {
// If there is at least one more step to go, we need to push the state and the new number of steps. // If there is at least one more step to go, we need to push the state and the new number of steps.
remainingSteps[entryIt->first] = currentStepBound - 1; remainingSteps[entryIt->getColumn()] = currentStepBound - 1;
statesWithProbabilityGreater0.set(entryIt->first, true); statesWithProbabilityGreater0.set(entryIt->getColumn(), true);
stack.push_back(entryIt->first); stack.push_back(entryIt->getColumn());
stepStack.push_back(currentStepBound - 1); stepStack.push_back(currentStepBound - 1);
} }
} }
@ -211,16 +211,16 @@ namespace storm {
} }
for (typename storm::storage::SparseMatrix<T>::const_iterator entryIt = backwardTransitions.begin(currentState), entryIte = backwardTransitions.end(currentState); entryIt != entryIte; ++entryIt) { for (typename storm::storage::SparseMatrix<T>::const_iterator entryIt = backwardTransitions.begin(currentState), entryIte = backwardTransitions.end(currentState); entryIt != entryIte; ++entryIt) {
if (phiStates.get(entryIt->first) && (!statesWithProbabilityGreater0.get(entryIt->first) || (useStepBound && remainingSteps[entryIt->first] < currentStepBound - 1))) { if (phiStates.get(entryIt->getColumn()) && (!statesWithProbabilityGreater0.get(entryIt->getColumn()) || (useStepBound && remainingSteps[entryIt->getColumn()] < currentStepBound - 1))) {
// If we don't have a bound on the number of steps to take, just add the state to the stack. // If we don't have a bound on the number of steps to take, just add the state to the stack.
if (!useStepBound) { if (!useStepBound) {
statesWithProbabilityGreater0.set(entryIt->first, true); statesWithProbabilityGreater0.set(entryIt->getColumn(), true);
stack.push_back(entryIt->first); stack.push_back(entryIt->getColumn());
} else if (currentStepBound > 0) { } else if (currentStepBound > 0) {
// If there is at least one more step to go, we need to push the state and the new number of steps. // If there is at least one more step to go, we need to push the state and the new number of steps.
remainingSteps[entryIt->first] = currentStepBound - 1; remainingSteps[entryIt->getColumn()] = currentStepBound - 1;
statesWithProbabilityGreater0.set(entryIt->first, true); statesWithProbabilityGreater0.set(entryIt->getColumn(), true);
stack.push_back(entryIt->first); stack.push_back(entryIt->getColumn());
stepStack.push_back(currentStepBound - 1); stepStack.push_back(currentStepBound - 1);
} }
} }
@ -290,13 +290,13 @@ namespace storm {
stack.pop_back(); stack.pop_back();
for (typename storm::storage::SparseMatrix<T>::const_iterator predecessorEntryIt = backwardTransitions.begin(currentState), predecessorEntryIte = backwardTransitions.end(currentState); predecessorEntryIt != predecessorEntryIte; ++predecessorEntryIt) { for (typename storm::storage::SparseMatrix<T>::const_iterator predecessorEntryIt = backwardTransitions.begin(currentState), predecessorEntryIte = backwardTransitions.end(currentState); predecessorEntryIt != predecessorEntryIte; ++predecessorEntryIt) {
if (phiStates.get(predecessorEntryIt->first) && !nextStates.get(predecessorEntryIt->first)) { if (phiStates.get(predecessorEntryIt->getColumn()) && !nextStates.get(predecessorEntryIt->getColumn())) {
// Check whether the predecessor has only successors in the current state set for one of the // Check whether the predecessor has only successors in the current state set for one of the
// nondeterminstic choices. // nondeterminstic choices.
for (uint_fast64_t row = nondeterministicChoiceIndices[predecessorEntryIt->first]; row < nondeterministicChoiceIndices[predecessorEntryIt->first + 1]; ++row) { for (uint_fast64_t row = nondeterministicChoiceIndices[predecessorEntryIt->getColumn()]; row < nondeterministicChoiceIndices[predecessorEntryIt->getColumn() + 1]; ++row) {
bool allSuccessorsInCurrentStates = true; bool allSuccessorsInCurrentStates = true;
for (typename storm::storage::SparseMatrix<T>::const_iterator successorEntryIt = transitionMatrix.begin(row), successorEntryIte = transitionMatrix.end(row); successorEntryIt != successorEntryIte; ++successorEntryIt) { for (typename storm::storage::SparseMatrix<T>::const_iterator successorEntryIt = transitionMatrix.begin(row), successorEntryIte = transitionMatrix.end(row); successorEntryIt != successorEntryIte; ++successorEntryIt) {
if (!currentStates.get(successorEntryIt->first)) { if (!currentStates.get(successorEntryIt->getColumn())) {
allSuccessorsInCurrentStates = false; allSuccessorsInCurrentStates = false;
break; break;
} }
@ -306,8 +306,8 @@ namespace storm {
// add it to the set of states for the next iteration and perform a backward search from // add it to the set of states for the next iteration and perform a backward search from
// that state. // that state.
if (allSuccessorsInCurrentStates) { if (allSuccessorsInCurrentStates) {
nextStates.set(predecessorEntryIt->first, true); nextStates.set(predecessorEntryIt->getColumn(), true);
stack.push_back(predecessorEntryIt->first); stack.push_back(predecessorEntryIt->getColumn());
break; break;
} }
} }
@ -401,14 +401,14 @@ namespace storm {
} }
for(typename storm::storage::SparseMatrix<T>::const_iterator predecessorEntryIt = backwardTransitions.begin(currentState), predecessorEntryIte = backwardTransitions.end(currentState); predecessorEntryIt != predecessorEntryIte; ++predecessorEntryIt) { for(typename storm::storage::SparseMatrix<T>::const_iterator predecessorEntryIt = backwardTransitions.begin(currentState), predecessorEntryIte = backwardTransitions.end(currentState); predecessorEntryIt != predecessorEntryIte; ++predecessorEntryIt) {
if (phiStates.get(predecessorEntryIt->first) && (!statesWithProbabilityGreater0.get(predecessorEntryIt->first) || (useStepBound && remainingSteps[predecessorEntryIt->first] < currentStepBound - 1))) { if (phiStates.get(predecessorEntryIt->getColumn()) && (!statesWithProbabilityGreater0.get(predecessorEntryIt->getColumn()) || (useStepBound && remainingSteps[predecessorEntryIt->getColumn()] < currentStepBound - 1))) {
// Check whether the predecessor has at least one successor in the current state set for every // Check whether the predecessor has at least one successor in the current state set for every
// nondeterministic choice. // nondeterministic choice.
bool addToStatesWithProbabilityGreater0 = true; bool addToStatesWithProbabilityGreater0 = true;
for (uint_fast64_t row = nondeterministicChoiceIndices[predecessorEntryIt->first]; row < nondeterministicChoiceIndices[predecessorEntryIt->first + 1]; ++row) { for (uint_fast64_t row = nondeterministicChoiceIndices[predecessorEntryIt->getColumn()]; row < nondeterministicChoiceIndices[predecessorEntryIt->getColumn() + 1]; ++row) {
bool hasAtLeastOneSuccessorWithProbabilityGreater0 = false; bool hasAtLeastOneSuccessorWithProbabilityGreater0 = false;
for (typename storm::storage::SparseMatrix<T>::const_iterator successorEntryIt = transitionMatrix.begin(row), successorEntryIte = transitionMatrix.end(row); successorEntryIt != successorEntryIte; ++successorEntryIt) { for (typename storm::storage::SparseMatrix<T>::const_iterator successorEntryIt = transitionMatrix.begin(row), successorEntryIte = transitionMatrix.end(row); successorEntryIt != successorEntryIte; ++successorEntryIt) {
if (statesWithProbabilityGreater0.get(successorEntryIt->first)) { if (statesWithProbabilityGreater0.get(successorEntryIt->getColumn())) {
hasAtLeastOneSuccessorWithProbabilityGreater0 = true; hasAtLeastOneSuccessorWithProbabilityGreater0 = true;
break; break;
} }
@ -424,13 +424,13 @@ namespace storm {
if (addToStatesWithProbabilityGreater0) { if (addToStatesWithProbabilityGreater0) {
// If we don't have a bound on the number of steps to take, just add the state to the stack. // If we don't have a bound on the number of steps to take, just add the state to the stack.
if (!useStepBound) { if (!useStepBound) {
statesWithProbabilityGreater0.set(predecessorEntryIt->first, true); statesWithProbabilityGreater0.set(predecessorEntryIt->getColumn(), true);
stack.push_back(predecessorEntryIt->first); stack.push_back(predecessorEntryIt->getColumn());
} else if (currentStepBound > 0) { } else if (currentStepBound > 0) {
// If there is at least one more step to go, we need to push the state and the new number of steps. // If there is at least one more step to go, we need to push the state and the new number of steps.
remainingSteps[predecessorEntryIt->first] = currentStepBound - 1; remainingSteps[predecessorEntryIt->getColumn()] = currentStepBound - 1;
statesWithProbabilityGreater0.set(predecessorEntryIt->first, true); statesWithProbabilityGreater0.set(predecessorEntryIt->getColumn(), true);
stack.push_back(predecessorEntryIt->first); stack.push_back(predecessorEntryIt->getColumn());
stepStack.push_back(currentStepBound - 1); stepStack.push_back(currentStepBound - 1);
} }
} }
@ -501,12 +501,12 @@ namespace storm {
stack.pop_back(); stack.pop_back();
for(typename storm::storage::SparseMatrix<T>::const_iterator predecessorEntryIt = backwardTransitions.begin(currentState), predecessorEntryIte = backwardTransitions.end(currentState); predecessorEntryIt != predecessorEntryIte; ++predecessorEntryIt) { for(typename storm::storage::SparseMatrix<T>::const_iterator predecessorEntryIt = backwardTransitions.begin(currentState), predecessorEntryIte = backwardTransitions.end(currentState); predecessorEntryIt != predecessorEntryIte; ++predecessorEntryIt) {
if (phiStates.get(predecessorEntryIt->first) && !nextStates.get(predecessorEntryIt->first)) { if (phiStates.get(predecessorEntryIt->getColumn()) && !nextStates.get(predecessorEntryIt->getColumn())) {
// Check whether the predecessor has only successors in the current state set for all of the // Check whether the predecessor has only successors in the current state set for all of the
// nondeterminstic choices. // nondeterminstic choices.
bool allSuccessorsInCurrentStatesForAllChoices = true; bool allSuccessorsInCurrentStatesForAllChoices = true;
for (typename storm::storage::SparseMatrix<T>::const_iterator successorEntryIt = transitionMatrix.begin(nondeterministicChoiceIndices[predecessorEntryIt->first]), successorEntryIte = transitionMatrix.begin(nondeterministicChoiceIndices[predecessorEntryIt->first + 1]); successorEntryIt != successorEntryIte; ++successorEntryIt) { for (typename storm::storage::SparseMatrix<T>::const_iterator successorEntryIt = transitionMatrix.begin(nondeterministicChoiceIndices[predecessorEntryIt->getColumn()]), successorEntryIte = transitionMatrix.begin(nondeterministicChoiceIndices[predecessorEntryIt->getColumn() + 1]); successorEntryIt != successorEntryIte; ++successorEntryIt) {
if (!currentStates.get(successorEntryIt->first)) { if (!currentStates.get(successorEntryIt->getColumn())) {
allSuccessorsInCurrentStatesForAllChoices = false; allSuccessorsInCurrentStatesForAllChoices = false;
goto afterCheckLoop; goto afterCheckLoop;
} }
@ -517,8 +517,8 @@ namespace storm {
// add it to the set of states for the next iteration and perform a backward search from // add it to the set of states for the next iteration and perform a backward search from
// that state. // that state.
if (allSuccessorsInCurrentStatesForAllChoices) { if (allSuccessorsInCurrentStatesForAllChoices) {
nextStates.set(predecessorEntryIt->first, true); nextStates.set(predecessorEntryIt->getColumn(), true);
stack.push_back(predecessorEntryIt->first); stack.push_back(predecessorEntryIt->getColumn());
} }
} }
} }

2
src/utility/matrix.h

@ -32,7 +32,7 @@ namespace storm {
// If a valid choice for this state is defined, we copy over the corresponding entries. // If a valid choice for this state is defined, we copy over the corresponding entries.
typename storm::storage::SparseMatrix<T>::const_rows selectedRow = transitionMatrix.getRow(choice); typename storm::storage::SparseMatrix<T>::const_rows selectedRow = transitionMatrix.getRow(choice);
for (auto const& entry : selectedRow) { for (auto const& entry : selectedRow) {
matrixBuilder.addNextValue(state, entry.first, entry.second); matrixBuilder.addNextValue(state, entry.getColumn(), entry.getValue());
} }
} else { } else {
// If no valid choice for the state is defined, we insert a self-loop. // If no valid choice for the state is defined, we insert a self-loop.

6
test/functional/modelchecker/GmmxxDtmcPrctlModelCheckerTest.cpp

@ -18,7 +18,7 @@ TEST(GmmxxDtmcPrctlModelCheckerTest, Die) {
std::shared_ptr<storm::models::Dtmc<double>> dtmc = abstractModel->as<storm::models::Dtmc<double>>(); std::shared_ptr<storm::models::Dtmc<double>> dtmc = abstractModel->as<storm::models::Dtmc<double>>();
ASSERT_EQ(dtmc->getNumberOfStates(), 13ull); ASSERT_EQ(dtmc->getNumberOfStates(), 13ull);
ASSERT_EQ(dtmc->getNumberOfTransitions(), 27ull); ASSERT_EQ(dtmc->getNumberOfTransitions(), 20ull);
storm::modelchecker::prctl::SparseDtmcPrctlModelChecker<double> mc(*dtmc, new storm::solver::GmmxxLinearEquationSolver<double>()); storm::modelchecker::prctl::SparseDtmcPrctlModelChecker<double> mc(*dtmc, new storm::solver::GmmxxLinearEquationSolver<double>());
@ -74,7 +74,7 @@ TEST(GmmxxDtmcPrctlModelCheckerTest, Crowds) {
std::shared_ptr<storm::models::Dtmc<double>> dtmc = abstractModel->as<storm::models::Dtmc<double>>(); std::shared_ptr<storm::models::Dtmc<double>> dtmc = abstractModel->as<storm::models::Dtmc<double>>();
ASSERT_EQ(dtmc->getNumberOfStates(), 8607ull); ASSERT_EQ(dtmc->getNumberOfStates(), 8607ull);
ASSERT_EQ(dtmc->getNumberOfTransitions(), 22460ull); ASSERT_EQ(dtmc->getNumberOfTransitions(), 15113ull);
storm::modelchecker::prctl::SparseDtmcPrctlModelChecker<double> mc(*dtmc, new storm::solver::GmmxxLinearEquationSolver<double>()); storm::modelchecker::prctl::SparseDtmcPrctlModelChecker<double> mc(*dtmc, new storm::solver::GmmxxLinearEquationSolver<double>());
@ -119,7 +119,7 @@ TEST(GmmxxDtmcPrctlModelCheckerTest, SynchronousLeader) {
std::shared_ptr<storm::models::Dtmc<double>> dtmc = abstractModel->as<storm::models::Dtmc<double>>(); std::shared_ptr<storm::models::Dtmc<double>> dtmc = abstractModel->as<storm::models::Dtmc<double>>();
ASSERT_EQ(dtmc->getNumberOfStates(), 12400ull); ASSERT_EQ(dtmc->getNumberOfStates(), 12400ull);
ASSERT_EQ(dtmc->getNumberOfTransitions(), 28894ull); ASSERT_EQ(dtmc->getNumberOfTransitions(), 16495ull);
storm::modelchecker::prctl::SparseDtmcPrctlModelChecker<double> mc(*dtmc, new storm::solver::GmmxxLinearEquationSolver<double>()); storm::modelchecker::prctl::SparseDtmcPrctlModelChecker<double> mc(*dtmc, new storm::solver::GmmxxLinearEquationSolver<double>());

12
test/functional/parser/AutoParserTest.cpp

@ -24,7 +24,7 @@ TEST(AutoParserTest, BasicParsing) {
// Test if parsed correctly. // Test if parsed correctly.
ASSERT_EQ(storm::models::DTMC, modelPtr->getType()); ASSERT_EQ(storm::models::DTMC, modelPtr->getType());
ASSERT_EQ(12, modelPtr->getNumberOfStates()); ASSERT_EQ(12, modelPtr->getNumberOfStates());
ASSERT_EQ(32, modelPtr->getNumberOfTransitions()); ASSERT_EQ(26, modelPtr->getNumberOfTransitions());
ASSERT_EQ(1, modelPtr->getInitialStates().getNumberOfSetBits()); ASSERT_EQ(1, modelPtr->getInitialStates().getNumberOfSetBits());
ASSERT_TRUE(modelPtr->hasAtomicProposition("three")); ASSERT_TRUE(modelPtr->hasAtomicProposition("three"));
ASSERT_FALSE(modelPtr->hasStateRewards()); ASSERT_FALSE(modelPtr->hasStateRewards());
@ -56,21 +56,21 @@ TEST(AutoParserTest, Decision) {
std::shared_ptr<storm::models::AbstractModel<double>> modelPtr = storm::parser::AutoParser::parseModel(STORM_CPP_TESTS_BASE_PATH "/functional/parser/tra_files/autoParser/dtmc.tra", STORM_CPP_TESTS_BASE_PATH "/functional/parser/lab_files/autoParser.lab"); std::shared_ptr<storm::models::AbstractModel<double>> modelPtr = storm::parser::AutoParser::parseModel(STORM_CPP_TESTS_BASE_PATH "/functional/parser/tra_files/autoParser/dtmc.tra", STORM_CPP_TESTS_BASE_PATH "/functional/parser/lab_files/autoParser.lab");
ASSERT_EQ(storm::models::DTMC, modelPtr->getType()); ASSERT_EQ(storm::models::DTMC, modelPtr->getType());
ASSERT_EQ(12, modelPtr->getNumberOfStates()); ASSERT_EQ(12, modelPtr->getNumberOfStates());
ASSERT_EQ(32, modelPtr->getNumberOfTransitions()); ASSERT_EQ(26, modelPtr->getNumberOfTransitions());
// Ctmc // Ctmc
modelPtr.reset(); modelPtr.reset();
modelPtr = storm::parser::AutoParser::parseModel(STORM_CPP_TESTS_BASE_PATH "/functional/parser/tra_files/autoParser/ctmc.tra", STORM_CPP_TESTS_BASE_PATH "/functional/parser/lab_files/autoParser.lab"); modelPtr = storm::parser::AutoParser::parseModel(STORM_CPP_TESTS_BASE_PATH "/functional/parser/tra_files/autoParser/ctmc.tra", STORM_CPP_TESTS_BASE_PATH "/functional/parser/lab_files/autoParser.lab");
ASSERT_EQ(storm::models::CTMC, modelPtr->getType()); ASSERT_EQ(storm::models::CTMC, modelPtr->getType());
ASSERT_EQ(12, modelPtr->getNumberOfStates()); ASSERT_EQ(12, modelPtr->getNumberOfStates());
ASSERT_EQ(31, modelPtr->getNumberOfTransitions()); ASSERT_EQ(26, modelPtr->getNumberOfTransitions());
// Mdp // Mdp
modelPtr.reset(); modelPtr.reset();
modelPtr = storm::parser::AutoParser::parseModel(STORM_CPP_TESTS_BASE_PATH "/functional/parser/tra_files/autoParser/mdp.tra", STORM_CPP_TESTS_BASE_PATH "/functional/parser/lab_files/autoParser.lab"); modelPtr = storm::parser::AutoParser::parseModel(STORM_CPP_TESTS_BASE_PATH "/functional/parser/tra_files/autoParser/mdp.tra", STORM_CPP_TESTS_BASE_PATH "/functional/parser/lab_files/autoParser.lab");
ASSERT_EQ(storm::models::MDP, modelPtr->getType()); ASSERT_EQ(storm::models::MDP, modelPtr->getType());
ASSERT_EQ(12, modelPtr->getNumberOfStates()); ASSERT_EQ(12, modelPtr->getNumberOfStates());
ASSERT_EQ(36, modelPtr->getNumberOfTransitions()); ASSERT_EQ(28, modelPtr->getNumberOfTransitions());
// Ctmdp // Ctmdp
// Note: For now we use the Mdp from above just given the ctmdp hint, since the implementation of the Ctmdp model seems not Quite right yet. // Note: For now we use the Mdp from above just given the ctmdp hint, since the implementation of the Ctmdp model seems not Quite right yet.
@ -80,12 +80,12 @@ TEST(AutoParserTest, Decision) {
modelPtr = storm::parser::AutoParser::parseModel(STORM_CPP_TESTS_BASE_PATH "/functional/parser/tra_files/autoParser/ctmdp.tra", STORM_CPP_TESTS_BASE_PATH "/functional/parser/lab_files/autoParser.lab"); modelPtr = storm::parser::AutoParser::parseModel(STORM_CPP_TESTS_BASE_PATH "/functional/parser/tra_files/autoParser/ctmdp.tra", STORM_CPP_TESTS_BASE_PATH "/functional/parser/lab_files/autoParser.lab");
ASSERT_EQ(storm::models::CTMDP, modelPtr->getType()); ASSERT_EQ(storm::models::CTMDP, modelPtr->getType());
ASSERT_EQ(12, modelPtr->getNumberOfStates()); ASSERT_EQ(12, modelPtr->getNumberOfStates());
ASSERT_EQ(36, modelPtr->getNumberOfTransitions()); ASSERT_EQ(28, modelPtr->getNumberOfTransitions());
// MA // MA
modelPtr.reset(); modelPtr.reset();
modelPtr = storm::parser::AutoParser::parseModel(STORM_CPP_TESTS_BASE_PATH "/functional/parser/tra_files/autoParser/ma.tra", STORM_CPP_TESTS_BASE_PATH "/functional/parser/lab_files/autoParser.lab"); modelPtr = storm::parser::AutoParser::parseModel(STORM_CPP_TESTS_BASE_PATH "/functional/parser/tra_files/autoParser/ma.tra", STORM_CPP_TESTS_BASE_PATH "/functional/parser/lab_files/autoParser.lab");
ASSERT_EQ(storm::models::MA, modelPtr->getType()); ASSERT_EQ(storm::models::MA, modelPtr->getType());
ASSERT_EQ(12, modelPtr->getNumberOfStates()); ASSERT_EQ(12, modelPtr->getNumberOfStates());
ASSERT_EQ(35, modelPtr->getNumberOfTransitions()); ASSERT_EQ(27, modelPtr->getNumberOfTransitions());
} }

4
test/functional/parser/DeterministicModelParserTest.cpp

@ -26,7 +26,7 @@ TEST(DeterministicModelParserTest, BasicDtmcParsing) {
storm::models::Dtmc<double> dtmc(storm::parser::DeterministicModelParser::parseDtmc(STORM_CPP_TESTS_BASE_PATH "/functional/parser/tra_files/dtmc_general.tra", STORM_CPP_TESTS_BASE_PATH "/functional/parser/lab_files/dtmc_general.lab", STORM_CPP_TESTS_BASE_PATH "/functional/parser/rew_files/dtmc_general.state.rew", STORM_CPP_TESTS_BASE_PATH "/functional/parser/rew_files/dtmc_general.trans.rew")); storm::models::Dtmc<double> dtmc(storm::parser::DeterministicModelParser::parseDtmc(STORM_CPP_TESTS_BASE_PATH "/functional/parser/tra_files/dtmc_general.tra", STORM_CPP_TESTS_BASE_PATH "/functional/parser/lab_files/dtmc_general.lab", STORM_CPP_TESTS_BASE_PATH "/functional/parser/rew_files/dtmc_general.state.rew", STORM_CPP_TESTS_BASE_PATH "/functional/parser/rew_files/dtmc_general.trans.rew"));
ASSERT_EQ(8, dtmc.getNumberOfStates()); ASSERT_EQ(8, dtmc.getNumberOfStates());
ASSERT_EQ(21, dtmc.getNumberOfTransitions()); ASSERT_EQ(16, dtmc.getNumberOfTransitions());
ASSERT_EQ(2, dtmc.getInitialStates().getNumberOfSetBits()); ASSERT_EQ(2, dtmc.getInitialStates().getNumberOfSetBits());
ASSERT_TRUE(dtmc.getInitialStates().get(0)); ASSERT_TRUE(dtmc.getInitialStates().get(0));
@ -58,7 +58,7 @@ TEST(DeterministicModelParserTest, BasicCtmcParsing) {
storm::models::Ctmc<double> ctmc(storm::parser::DeterministicModelParser::parseCtmc(STORM_CPP_TESTS_BASE_PATH "/functional/parser/tra_files/dtmc_general.tra", STORM_CPP_TESTS_BASE_PATH "/functional/parser/lab_files/dtmc_general.lab", STORM_CPP_TESTS_BASE_PATH "/functional/parser/rew_files/dtmc_general.state.rew", STORM_CPP_TESTS_BASE_PATH "/functional/parser/rew_files/dtmc_general.trans.rew")); storm::models::Ctmc<double> ctmc(storm::parser::DeterministicModelParser::parseCtmc(STORM_CPP_TESTS_BASE_PATH "/functional/parser/tra_files/dtmc_general.tra", STORM_CPP_TESTS_BASE_PATH "/functional/parser/lab_files/dtmc_general.lab", STORM_CPP_TESTS_BASE_PATH "/functional/parser/rew_files/dtmc_general.state.rew", STORM_CPP_TESTS_BASE_PATH "/functional/parser/rew_files/dtmc_general.trans.rew"));
ASSERT_EQ(8, ctmc.getNumberOfStates()); ASSERT_EQ(8, ctmc.getNumberOfStates());
ASSERT_EQ(21, ctmc.getNumberOfTransitions()); ASSERT_EQ(16, ctmc.getNumberOfTransitions());
ASSERT_EQ(2, ctmc.getInitialStates().getNumberOfSetBits()); ASSERT_EQ(2, ctmc.getInitialStates().getNumberOfSetBits());
ASSERT_TRUE(ctmc.getInitialStates().get(0)); ASSERT_TRUE(ctmc.getInitialStates().get(0));

168
test/functional/parser/DeterministicSparseTransitionParserTest.cpp

@ -35,68 +35,68 @@ TEST(DeterministicSparseTransitionParserTest, BasicTransitionsParsing) {
// Test every entry of the matrix. // Test every entry of the matrix.
storm::storage::SparseMatrix<double>::const_iterator cIter = transitionMatrix.begin(0); storm::storage::SparseMatrix<double>::const_iterator cIter = transitionMatrix.begin(0);
ASSERT_EQ(0, cIter->first); ASSERT_EQ(0, cIter->getColumn());
ASSERT_EQ(0, cIter->second); ASSERT_EQ(0, cIter->getValue());
cIter++; cIter++;
ASSERT_EQ(1, cIter->first); ASSERT_EQ(1, cIter->getColumn());
ASSERT_EQ(1, cIter->second); ASSERT_EQ(1, cIter->getValue());
cIter++; cIter++;
ASSERT_EQ(1, cIter->first); ASSERT_EQ(1, cIter->getColumn());
ASSERT_EQ(0, cIter->second); ASSERT_EQ(0, cIter->getValue());
cIter++; cIter++;
ASSERT_EQ(2, cIter->first); ASSERT_EQ(2, cIter->getColumn());
ASSERT_EQ(0.5, cIter->second); ASSERT_EQ(0.5, cIter->getValue());
cIter++; cIter++;
ASSERT_EQ(3, cIter->first); ASSERT_EQ(3, cIter->getColumn());
ASSERT_EQ(0.5, cIter->second); ASSERT_EQ(0.5, cIter->getValue());
cIter++; cIter++;
ASSERT_EQ(2, cIter->first); ASSERT_EQ(2, cIter->getColumn());
ASSERT_EQ(0, cIter->second); ASSERT_EQ(0, cIter->getValue());
cIter++; cIter++;
ASSERT_EQ(3, cIter->first); ASSERT_EQ(3, cIter->getColumn());
ASSERT_EQ(0.4, cIter->second); ASSERT_EQ(0.4, cIter->getValue());
cIter++; cIter++;
ASSERT_EQ(4, cIter->first); ASSERT_EQ(4, cIter->getColumn());
ASSERT_EQ(0.4, cIter->second); ASSERT_EQ(0.4, cIter->getValue());
cIter++; cIter++;
ASSERT_EQ(5, cIter->first); ASSERT_EQ(5, cIter->getColumn());
ASSERT_EQ(0.2, cIter->second); ASSERT_EQ(0.2, cIter->getValue());
cIter++; cIter++;
ASSERT_EQ(3, cIter->first); ASSERT_EQ(3, cIter->getColumn());
ASSERT_EQ(1, cIter->second); ASSERT_EQ(1, cIter->getValue());
cIter++; cIter++;
ASSERT_EQ(3, cIter->first); ASSERT_EQ(3, cIter->getColumn());
ASSERT_EQ(1, cIter->second); ASSERT_EQ(1, cIter->getValue());
cIter++; cIter++;
ASSERT_EQ(4, cIter->first); ASSERT_EQ(4, cIter->getColumn());
ASSERT_EQ(0, cIter->second); ASSERT_EQ(0, cIter->getValue());
cIter++; cIter++;
ASSERT_EQ(3, cIter->first); ASSERT_EQ(3, cIter->getColumn());
ASSERT_EQ(0.1, cIter->second); ASSERT_EQ(0.1, cIter->getValue());
cIter++; cIter++;
ASSERT_EQ(4, cIter->first); ASSERT_EQ(4, cIter->getColumn());
ASSERT_EQ(0.1, cIter->second); ASSERT_EQ(0.1, cIter->getValue());
cIter++; cIter++;
ASSERT_EQ(5, cIter->first); ASSERT_EQ(5, cIter->getColumn());
ASSERT_EQ(0.1, cIter->second); ASSERT_EQ(0.1, cIter->getValue());
cIter++; cIter++;
ASSERT_EQ(6, cIter->first); ASSERT_EQ(6, cIter->getColumn());
ASSERT_EQ(0.7, cIter->second); ASSERT_EQ(0.7, cIter->getValue());
cIter++; cIter++;
ASSERT_EQ(0, cIter->first); ASSERT_EQ(0, cIter->getColumn());
ASSERT_EQ(0.9, cIter->second); ASSERT_EQ(0.9, cIter->getValue());
cIter++; cIter++;
ASSERT_EQ(5, cIter->first); ASSERT_EQ(5, cIter->getColumn());
ASSERT_EQ(0, cIter->second); ASSERT_EQ(0, cIter->getValue());
cIter++; cIter++;
ASSERT_EQ(6, cIter->first); ASSERT_EQ(6, cIter->getColumn());
ASSERT_EQ(0.1, cIter->second); ASSERT_EQ(0.1, cIter->getValue());
cIter++; cIter++;
ASSERT_EQ(6, cIter->first); ASSERT_EQ(6, cIter->getColumn());
ASSERT_EQ(0.224653, cIter->second); ASSERT_EQ(0.224653, cIter->getValue());
cIter++; cIter++;
ASSERT_EQ(7, cIter->first); ASSERT_EQ(7, cIter->getColumn());
ASSERT_EQ(0.775347, cIter->second); ASSERT_EQ(0.775347, cIter->getValue());
} }
TEST(DeterministicSparseTransitionParserTest, BasicTransitionsRewardsParsing) { TEST(DeterministicSparseTransitionParserTest, BasicTransitionsRewardsParsing) {
@ -112,56 +112,56 @@ TEST(DeterministicSparseTransitionParserTest, BasicTransitionsRewardsParsing) {
// Test every entry of the matrix. // Test every entry of the matrix.
storm::storage::SparseMatrix<double>::const_iterator cIter = rewardMatrix.begin(0); storm::storage::SparseMatrix<double>::const_iterator cIter = rewardMatrix.begin(0);
ASSERT_EQ(1, cIter->first); ASSERT_EQ(1, cIter->getColumn());
ASSERT_EQ(10, cIter->second); ASSERT_EQ(10, cIter->getValue());
cIter++; cIter++;
ASSERT_EQ(2, cIter->first); ASSERT_EQ(2, cIter->getColumn());
ASSERT_EQ(5, cIter->second); ASSERT_EQ(5, cIter->getValue());
cIter++; cIter++;
ASSERT_EQ(3, cIter->first); ASSERT_EQ(3, cIter->getColumn());
ASSERT_EQ(5.5, cIter->second); ASSERT_EQ(5.5, cIter->getValue());
cIter++; cIter++;
ASSERT_EQ(3, cIter->first); ASSERT_EQ(3, cIter->getColumn());
ASSERT_EQ(21.4, cIter->second); ASSERT_EQ(21.4, cIter->getValue());
cIter++; cIter++;
ASSERT_EQ(4, cIter->first); ASSERT_EQ(4, cIter->getColumn());
ASSERT_EQ(4, cIter->second); ASSERT_EQ(4, cIter->getValue());
cIter++; cIter++;
ASSERT_EQ(5, cIter->first); ASSERT_EQ(5, cIter->getColumn());
ASSERT_EQ(2, cIter->second); ASSERT_EQ(2, cIter->getValue());
cIter++; cIter++;
ASSERT_EQ(3, cIter->first); ASSERT_EQ(3, cIter->getColumn());
ASSERT_EQ(1, cIter->second); ASSERT_EQ(1, cIter->getValue());
cIter++; cIter++;
ASSERT_EQ(3, cIter->first); ASSERT_EQ(3, cIter->getColumn());
ASSERT_EQ(1, cIter->second); ASSERT_EQ(1, cIter->getValue());
cIter++; cIter++;
ASSERT_EQ(3, cIter->first); ASSERT_EQ(3, cIter->getColumn());
ASSERT_EQ(0.1, cIter->second); ASSERT_EQ(0.1, cIter->getValue());
cIter++; cIter++;
ASSERT_EQ(4, cIter->first); ASSERT_EQ(4, cIter->getColumn());
ASSERT_EQ(1.1, cIter->second); ASSERT_EQ(1.1, cIter->getValue());
cIter++; cIter++;
ASSERT_EQ(5, cIter->first); ASSERT_EQ(5, cIter->getColumn());
ASSERT_EQ(9.5, cIter->second); ASSERT_EQ(9.5, cIter->getValue());
cIter++; cIter++;
ASSERT_EQ(6, cIter->first); ASSERT_EQ(6, cIter->getColumn());
ASSERT_EQ(6.7, cIter->second); ASSERT_EQ(6.7, cIter->getValue());
cIter++; cIter++;
ASSERT_EQ(0, cIter->first); ASSERT_EQ(0, cIter->getColumn());
ASSERT_EQ(1, cIter->second); ASSERT_EQ(1, cIter->getValue());
cIter++; cIter++;
ASSERT_EQ(5, cIter->first); ASSERT_EQ(5, cIter->getColumn());
ASSERT_EQ(0, cIter->second); ASSERT_EQ(0, cIter->getValue());
cIter++; cIter++;
ASSERT_EQ(6, cIter->first); ASSERT_EQ(6, cIter->getColumn());
ASSERT_EQ(12, cIter->second); ASSERT_EQ(12, cIter->getValue());
cIter++; cIter++;
ASSERT_EQ(6, cIter->first); ASSERT_EQ(6, cIter->getColumn());
ASSERT_EQ(35.224653, cIter->second); ASSERT_EQ(35.224653, cIter->getValue());
cIter++; cIter++;
ASSERT_EQ(7, cIter->first); ASSERT_EQ(7, cIter->getColumn());
ASSERT_EQ(9.875347, cIter->second); ASSERT_EQ(9.875347, cIter->getValue());
} }
@ -201,17 +201,17 @@ TEST(DeterministicSparseTransitionParserTest, FixDeadlocks) {
ASSERT_EQ(23, transitionMatrix.getEntryCount()); ASSERT_EQ(23, transitionMatrix.getEntryCount());
storm::storage::SparseMatrix<double>::const_iterator cIter = transitionMatrix.begin(7); storm::storage::SparseMatrix<double>::const_iterator cIter = transitionMatrix.begin(7);
ASSERT_EQ(7, cIter->first); ASSERT_EQ(7, cIter->getColumn());
ASSERT_EQ(1, cIter->second); ASSERT_EQ(1, cIter->getValue());
cIter++; cIter++;
ASSERT_EQ(6, cIter->first); ASSERT_EQ(6, cIter->getColumn());
ASSERT_EQ(0.224653, cIter->second); ASSERT_EQ(0.224653, cIter->getValue());
cIter++; cIter++;
ASSERT_EQ(7, cIter->first); ASSERT_EQ(7, cIter->getColumn());
ASSERT_EQ(0.775347, cIter->second); ASSERT_EQ(0.775347, cIter->getValue());
cIter++; cIter++;
ASSERT_EQ(8, cIter->first); ASSERT_EQ(8, cIter->getColumn());
ASSERT_EQ(0, cIter->second); ASSERT_EQ(0, cIter->getValue());
} }
TEST(DeterministicSparseTransitionParserTest, DontFixDeadlocks) { TEST(DeterministicSparseTransitionParserTest, DontFixDeadlocks) {

48
test/functional/parser/MarkovAutomatonSparseTransitionParserTest.cpp

@ -79,29 +79,29 @@ TEST(MarkovAutomatonSparseTransitionParserTest, BasicParsing) {
// Finally, test the transition matrix itself. // Finally, test the transition matrix itself.
storm::storage::SparseMatrix<double>::const_iterator cIter = transitionMatrix.begin(0); storm::storage::SparseMatrix<double>::const_iterator cIter = transitionMatrix.begin(0);
ASSERT_EQ(2, cIter->second); ASSERT_EQ(2, cIter->getValue());
cIter++; cIter++;
ASSERT_EQ(1, cIter->second); ASSERT_EQ(1, cIter->getValue());
cIter++; cIter++;
ASSERT_EQ(1, cIter->second); ASSERT_EQ(1, cIter->getValue());
cIter++; cIter++;
ASSERT_EQ(2, cIter->second); ASSERT_EQ(2, cIter->getValue());
cIter++; cIter++;
ASSERT_EQ(4, cIter->second); ASSERT_EQ(4, cIter->getValue());
cIter++; cIter++;
ASSERT_EQ(8, cIter->second); ASSERT_EQ(8, cIter->getValue());
cIter++; cIter++;
ASSERT_EQ(0.5, cIter->second); ASSERT_EQ(0.5, cIter->getValue());
cIter++; cIter++;
ASSERT_EQ(0.5, cIter->second); ASSERT_EQ(0.5, cIter->getValue());
cIter++; cIter++;
ASSERT_EQ(1, cIter->second); ASSERT_EQ(1, cIter->getValue());
cIter++; cIter++;
ASSERT_EQ(0.5, cIter->second); ASSERT_EQ(0.5, cIter->getValue());
cIter++; cIter++;
ASSERT_EQ(0.5, cIter->second); ASSERT_EQ(0.5, cIter->getValue());
cIter++; cIter++;
ASSERT_EQ(1, cIter->second); ASSERT_EQ(1, cIter->getValue());
cIter++; cIter++;
ASSERT_EQ(transitionMatrix.end(), cIter); ASSERT_EQ(transitionMatrix.end(), cIter);
} }
@ -157,29 +157,29 @@ TEST(MarkovAutomatonSparseTransitionParserTest, Whitespaces) {
// Finally, test the transition matrix itself. // Finally, test the transition matrix itself.
storm::storage::SparseMatrix<double>::const_iterator cIter = transitionMatrix.begin(0); storm::storage::SparseMatrix<double>::const_iterator cIter = transitionMatrix.begin(0);
ASSERT_EQ(2, cIter->second); ASSERT_EQ(2, cIter->getValue());
cIter++; cIter++;
ASSERT_EQ(1, cIter->second); ASSERT_EQ(1, cIter->getValue());
cIter++; cIter++;
ASSERT_EQ(1, cIter->second); ASSERT_EQ(1, cIter->getValue());
cIter++; cIter++;
ASSERT_EQ(2, cIter->second); ASSERT_EQ(2, cIter->getValue());
cIter++; cIter++;
ASSERT_EQ(4, cIter->second); ASSERT_EQ(4, cIter->getValue());
cIter++; cIter++;
ASSERT_EQ(8, cIter->second); ASSERT_EQ(8, cIter->getValue());
cIter++; cIter++;
ASSERT_EQ(0.5, cIter->second); ASSERT_EQ(0.5, cIter->getValue());
cIter++; cIter++;
ASSERT_EQ(0.5, cIter->second); ASSERT_EQ(0.5, cIter->getValue());
cIter++; cIter++;
ASSERT_EQ(1, cIter->second); ASSERT_EQ(1, cIter->getValue());
cIter++; cIter++;
ASSERT_EQ(0.5, cIter->second); ASSERT_EQ(0.5, cIter->getValue());
cIter++; cIter++;
ASSERT_EQ(0.5, cIter->second); ASSERT_EQ(0.5, cIter->getValue());
cIter++; cIter++;
ASSERT_EQ(1, cIter->second); ASSERT_EQ(1, cIter->getValue());
cIter++; cIter++;
ASSERT_EQ(transitionMatrix.end(), cIter); ASSERT_EQ(transitionMatrix.end(), cIter);
} }

184
test/functional/parser/NondeterministicSparseTransitionParserTest.cpp

@ -48,71 +48,71 @@ TEST(NondeterministicSparseTransitionParserTest, BasicTransitionsParsing) {
// Test every entry of the matrix. // Test every entry of the matrix.
storm::storage::SparseMatrix<double>::const_iterator cIter = result.begin(0); storm::storage::SparseMatrix<double>::const_iterator cIter = result.begin(0);
ASSERT_EQ(0, cIter->first); ASSERT_EQ(0, cIter->getColumn());
ASSERT_EQ(0.9, cIter->second); ASSERT_EQ(0.9, cIter->getValue());
cIter++; cIter++;
ASSERT_EQ(1, cIter->first); ASSERT_EQ(1, cIter->getColumn());
ASSERT_EQ(0.1, cIter->second); ASSERT_EQ(0.1, cIter->getValue());
cIter++; cIter++;
ASSERT_EQ(1, cIter->first); ASSERT_EQ(1, cIter->getColumn());
ASSERT_EQ(0.2, cIter->second); ASSERT_EQ(0.2, cIter->getValue());
cIter++; cIter++;
ASSERT_EQ(2, cIter->first); ASSERT_EQ(2, cIter->getColumn());
ASSERT_EQ(0.2, cIter->second); ASSERT_EQ(0.2, cIter->getValue());
cIter++; cIter++;
ASSERT_EQ(3, cIter->first); ASSERT_EQ(3, cIter->getColumn());
ASSERT_EQ(0.2, cIter->second); ASSERT_EQ(0.2, cIter->getValue());
cIter++; cIter++;
ASSERT_EQ(4, cIter->first); ASSERT_EQ(4, cIter->getColumn());
ASSERT_EQ(0.2, cIter->second); ASSERT_EQ(0.2, cIter->getValue());
cIter++; cIter++;
ASSERT_EQ(5, cIter->first); ASSERT_EQ(5, cIter->getColumn());
ASSERT_EQ(0.2, cIter->second); ASSERT_EQ(0.2, cIter->getValue());
cIter++; cIter++;
ASSERT_EQ(5, cIter->first); ASSERT_EQ(5, cIter->getColumn());
ASSERT_EQ(1, cIter->second); ASSERT_EQ(1, cIter->getValue());
cIter++; cIter++;
ASSERT_EQ(0, cIter->first); ASSERT_EQ(0, cIter->getColumn());
ASSERT_EQ(0.1, cIter->second); ASSERT_EQ(0.1, cIter->getValue());
cIter++; cIter++;
ASSERT_EQ(4, cIter->first); ASSERT_EQ(4, cIter->getColumn());
ASSERT_EQ(0.9, cIter->second); ASSERT_EQ(0.9, cIter->getValue());
cIter++; cIter++;
ASSERT_EQ(2, cIter->first); ASSERT_EQ(2, cIter->getColumn());
ASSERT_EQ(1, cIter->second); ASSERT_EQ(1, cIter->getValue());
cIter++; cIter++;
ASSERT_EQ(2, cIter->first); ASSERT_EQ(2, cIter->getColumn());
ASSERT_EQ(0.5, cIter->second); ASSERT_EQ(0.5, cIter->getValue());
cIter++; cIter++;
ASSERT_EQ(3, cIter->first); ASSERT_EQ(3, cIter->getColumn());
ASSERT_EQ(0.5, cIter->second); ASSERT_EQ(0.5, cIter->getValue());
cIter++; cIter++;
ASSERT_EQ(2, cIter->first); ASSERT_EQ(2, cIter->getColumn());
ASSERT_EQ(1, cIter->second); ASSERT_EQ(1, cIter->getValue());
cIter++; cIter++;
ASSERT_EQ(2, cIter->first); ASSERT_EQ(2, cIter->getColumn());
ASSERT_EQ(0.001, cIter->second); ASSERT_EQ(0.001, cIter->getValue());
cIter++; cIter++;
ASSERT_EQ(3, cIter->first); ASSERT_EQ(3, cIter->getColumn());
ASSERT_EQ(0.999, cIter->second); ASSERT_EQ(0.999, cIter->getValue());
cIter++; cIter++;
ASSERT_EQ(1, cIter->first); ASSERT_EQ(1, cIter->getColumn());
ASSERT_EQ(0.7, cIter->second); ASSERT_EQ(0.7, cIter->getValue());
cIter++; cIter++;
ASSERT_EQ(4, cIter->first); ASSERT_EQ(4, cIter->getColumn());
ASSERT_EQ(0.3, cIter->second); ASSERT_EQ(0.3, cIter->getValue());
cIter++; cIter++;
ASSERT_EQ(1, cIter->first); ASSERT_EQ(1, cIter->getColumn());
ASSERT_EQ(0.2, cIter->second); ASSERT_EQ(0.2, cIter->getValue());
cIter++; cIter++;
ASSERT_EQ(4, cIter->first); ASSERT_EQ(4, cIter->getColumn());
ASSERT_EQ(0.2, cIter->second); ASSERT_EQ(0.2, cIter->getValue());
cIter++; cIter++;
ASSERT_EQ(5, cIter->first); ASSERT_EQ(5, cIter->getColumn());
ASSERT_EQ(0.6, cIter->second); ASSERT_EQ(0.6, cIter->getValue());
cIter++; cIter++;
ASSERT_EQ(5, cIter->first); ASSERT_EQ(5, cIter->getColumn());
ASSERT_EQ(1, cIter->second); ASSERT_EQ(1, cIter->getValue());
} }
TEST(NondeterministicSparseTransitionParserTest, BasicTransitionsRewardsParsing) { TEST(NondeterministicSparseTransitionParserTest, BasicTransitionsRewardsParsing) {
@ -128,56 +128,56 @@ TEST(NondeterministicSparseTransitionParserTest, BasicTransitionsRewardsParsing)
// Test every entry of the matrix. // Test every entry of the matrix.
storm::storage::SparseMatrix<double>::const_iterator cIter = result.begin(0); storm::storage::SparseMatrix<double>::const_iterator cIter = result.begin(0);
ASSERT_EQ(0, cIter->first); ASSERT_EQ(0, cIter->getColumn());
ASSERT_EQ(1, cIter->second); ASSERT_EQ(1, cIter->getValue());
cIter++; cIter++;
ASSERT_EQ(1, cIter->first); ASSERT_EQ(1, cIter->getColumn());
ASSERT_EQ(30, cIter->second); ASSERT_EQ(30, cIter->getValue());
cIter++; cIter++;
ASSERT_EQ(1, cIter->first); ASSERT_EQ(1, cIter->getColumn());
ASSERT_EQ(15.2, cIter->second); ASSERT_EQ(15.2, cIter->getValue());
cIter++; cIter++;
ASSERT_EQ(2, cIter->first); ASSERT_EQ(2, cIter->getColumn());
ASSERT_EQ(75, cIter->second); ASSERT_EQ(75, cIter->getValue());
cIter++; cIter++;
ASSERT_EQ(5, cIter->first); ASSERT_EQ(5, cIter->getColumn());
ASSERT_EQ(2.45, cIter->second); ASSERT_EQ(2.45, cIter->getValue());
cIter++; cIter++;
ASSERT_EQ(5, cIter->first); ASSERT_EQ(5, cIter->getColumn());
ASSERT_EQ(1, cIter->second); ASSERT_EQ(1, cIter->getValue());
cIter++; cIter++;
ASSERT_EQ(0, cIter->first); ASSERT_EQ(0, cIter->getColumn());
ASSERT_EQ(0.114, cIter->second); ASSERT_EQ(0.114, cIter->getValue());
cIter++; cIter++;
ASSERT_EQ(4, cIter->first); ASSERT_EQ(4, cIter->getColumn());
ASSERT_EQ(90, cIter->second); ASSERT_EQ(90, cIter->getValue());
cIter++; cIter++;
ASSERT_EQ(2, cIter->first); ASSERT_EQ(2, cIter->getColumn());
ASSERT_EQ(1, cIter->second); ASSERT_EQ(1, cIter->getValue());
cIter++; cIter++;
ASSERT_EQ(2, cIter->first); ASSERT_EQ(2, cIter->getColumn());
ASSERT_EQ(55, cIter->second); ASSERT_EQ(55, cIter->getValue());
cIter++; cIter++;
ASSERT_EQ(3, cIter->first); ASSERT_EQ(3, cIter->getColumn());
ASSERT_EQ(87, cIter->second); ASSERT_EQ(87, cIter->getValue());
cIter++; cIter++;
ASSERT_EQ(2, cIter->first); ASSERT_EQ(2, cIter->getColumn());
ASSERT_EQ(13, cIter->second); ASSERT_EQ(13, cIter->getValue());
cIter++; cIter++;
ASSERT_EQ(3, cIter->first); ASSERT_EQ(3, cIter->getColumn());
ASSERT_EQ(999, cIter->second); ASSERT_EQ(999, cIter->getValue());
cIter++; cIter++;
ASSERT_EQ(1, cIter->first); ASSERT_EQ(1, cIter->getColumn());
ASSERT_EQ(0.7, cIter->second); ASSERT_EQ(0.7, cIter->getValue());
cIter++; cIter++;
ASSERT_EQ(4, cIter->first); ASSERT_EQ(4, cIter->getColumn());
ASSERT_EQ(0.3, cIter->second); ASSERT_EQ(0.3, cIter->getValue());
cIter++; cIter++;
ASSERT_EQ(1, cIter->first); ASSERT_EQ(1, cIter->getColumn());
ASSERT_EQ(0.1, cIter->second); ASSERT_EQ(0.1, cIter->getValue());
cIter++; cIter++;
ASSERT_EQ(5, cIter->first); ASSERT_EQ(5, cIter->getColumn());
ASSERT_EQ(6, cIter->second); ASSERT_EQ(6, cIter->getValue());
} }
TEST(NondeterministicSparseTransitionParserTest, Whitespaces) { TEST(NondeterministicSparseTransitionParserTest, Whitespaces) {
@ -224,26 +224,26 @@ TEST(NondeterministicSparseTransitionParserTest, FixDeadlocks) {
storm::storage::SparseMatrix<double>::const_iterator cIter = result.begin(8); storm::storage::SparseMatrix<double>::const_iterator cIter = result.begin(8);
ASSERT_EQ(1, cIter->first); ASSERT_EQ(1, cIter->getColumn());
ASSERT_EQ(0.7, cIter->second); ASSERT_EQ(0.7, cIter->getValue());
cIter++; cIter++;
ASSERT_EQ(4, cIter->first); ASSERT_EQ(4, cIter->getColumn());
ASSERT_EQ(0.3, cIter->second); ASSERT_EQ(0.3, cIter->getValue());
cIter++; cIter++;
ASSERT_EQ(5, cIter->first); ASSERT_EQ(5, cIter->getColumn());
ASSERT_EQ(1, cIter->second); ASSERT_EQ(1, cIter->getValue());
cIter++; cIter++;
ASSERT_EQ(1, cIter->first); ASSERT_EQ(1, cIter->getColumn());
ASSERT_EQ(0.2, cIter->second); ASSERT_EQ(0.2, cIter->getValue());
cIter++; cIter++;
ASSERT_EQ(4, cIter->first); ASSERT_EQ(4, cIter->getColumn());
ASSERT_EQ(0.2, cIter->second); ASSERT_EQ(0.2, cIter->getValue());
cIter++; cIter++;
ASSERT_EQ(5, cIter->first); ASSERT_EQ(5, cIter->getColumn());
ASSERT_EQ(0.6, cIter->second); ASSERT_EQ(0.6, cIter->getValue());
cIter++; cIter++;
ASSERT_EQ(5, cIter->first); ASSERT_EQ(5, cIter->getColumn());
ASSERT_EQ(1, cIter->second); ASSERT_EQ(1, cIter->getValue());
} }

243
test/functional/solver/GlpkLpSolverTest.cpp

@ -3,34 +3,34 @@
#include "src/solver/GlpkLpSolver.h" #include "src/solver/GlpkLpSolver.h"
#include "src/exceptions/InvalidStateException.h" #include "src/exceptions/InvalidStateException.h"
#include "src/exceptions/InvalidAccessException.h"
#include "src/settings/Settings.h" #include "src/settings/Settings.h"
TEST(GlpkLpSolver, LPOptimizeMax) { TEST(GlpkLpSolver, LPOptimizeMax) {
#ifdef STORM_HAVE_GLPK #ifdef STORM_HAVE_GLPK
storm::solver::GlpkLpSolver solver(storm::solver::LpSolver::MAXIMIZE); storm::solver::GlpkLpSolver solver(storm::solver::LpSolver::ModelSense::Maximize);
uint_fast64_t xIndex; ASSERT_NO_THROW(solver.addBoundedContinuousVariable("x", 0, 1, -1));
ASSERT_NO_THROW(xIndex = solver.createContinuousVariable("x", storm::solver::LpSolver::VariableType::BOUNDED, 0, 1, -1)); ASSERT_NO_THROW(solver.addLowerBoundedContinuousVariable("y", 0, 2));
uint_fast64_t yIndex; ASSERT_NO_THROW(solver.addLowerBoundedContinuousVariable("z", 0, 1));
ASSERT_NO_THROW(yIndex = solver.createContinuousVariable("y", storm::solver::LpSolver::VariableType::LOWER_BOUND, 0, 0, 2)); ASSERT_NO_THROW(solver.update());
uint_fast64_t zIndex; ASSERT_NO_THROW(solver.addConstraint("", storm::expressions::Expression::createDoubleVariable("x") + storm::expressions::Expression::createDoubleVariable("y") + storm::expressions::Expression::createDoubleVariable("z") <= storm::expressions::Expression::createDoubleLiteral(12)));
ASSERT_NO_THROW(zIndex = solver.createContinuousVariable("z", storm::solver::LpSolver::VariableType::LOWER_BOUND, 0, 0, 1)); ASSERT_NO_THROW(solver.addConstraint("", storm::expressions::Expression::createDoubleLiteral(0.5) * storm::expressions::Expression::createDoubleVariable("y") + storm::expressions::Expression::createDoubleVariable("z") - storm::expressions::Expression::createDoubleVariable("x") == storm::expressions::Expression::createDoubleLiteral(5)));
ASSERT_NO_THROW(solver.addConstraint("", storm::expressions::Expression::createDoubleVariable("y") - storm::expressions::Expression::createDoubleVariable("x") <= storm::expressions::Expression::createDoubleLiteral(5.5)));
ASSERT_NO_THROW(solver.addConstraint("", {xIndex, yIndex, zIndex}, {1, 1, 1}, storm::solver::LpSolver::BoundType::LESS_EQUAL, 12)); ASSERT_NO_THROW(solver.update());
ASSERT_NO_THROW(solver.addConstraint("", {yIndex, zIndex, xIndex}, {0.5, 1, -1}, storm::solver::LpSolver::BoundType::EQUAL, 5));
ASSERT_NO_THROW(solver.addConstraint("", {yIndex, xIndex}, {1, -1}, storm::solver::LpSolver::BoundType::LESS_EQUAL, 5.5));
ASSERT_NO_THROW(solver.optimize()); ASSERT_NO_THROW(solver.optimize());
ASSERT_TRUE(solver.isOptimal()); ASSERT_TRUE(solver.isOptimal());
ASSERT_FALSE(solver.isUnbounded()); ASSERT_FALSE(solver.isUnbounded());
ASSERT_FALSE(solver.isInfeasible()); ASSERT_FALSE(solver.isInfeasible());
double xValue = 0; double xValue = 0;
ASSERT_NO_THROW(xValue = solver.getContinuousValue(xIndex)); ASSERT_NO_THROW(xValue = solver.getContinuousValue("x"));
ASSERT_LT(std::abs(xValue - 1), storm::settings::Settings::getInstance()->getOptionByLongName("precision").getArgument(0).getValueAsDouble()); ASSERT_LT(std::abs(xValue - 1), storm::settings::Settings::getInstance()->getOptionByLongName("precision").getArgument(0).getValueAsDouble());
double yValue = 0; double yValue = 0;
ASSERT_NO_THROW(yValue = solver.getContinuousValue(yIndex)); ASSERT_NO_THROW(yValue = solver.getContinuousValue("y"));
ASSERT_LT(std::abs(yValue - 6.5), storm::settings::Settings::getInstance()->getOptionByLongName("precision").getArgument(0).getValueAsDouble()); ASSERT_LT(std::abs(yValue - 6.5), storm::settings::Settings::getInstance()->getOptionByLongName("precision").getArgument(0).getValueAsDouble());
double zValue = 0; double zValue = 0;
ASSERT_NO_THROW(zValue = solver.getContinuousValue(zIndex)); ASSERT_NO_THROW(zValue = solver.getContinuousValue("z"));
ASSERT_LT(std::abs(zValue - 2.75), storm::settings::Settings::getInstance()->getOptionByLongName("precision").getArgument(0).getValueAsDouble()); ASSERT_LT(std::abs(zValue - 2.75), storm::settings::Settings::getInstance()->getOptionByLongName("precision").getArgument(0).getValueAsDouble());
double objectiveValue = 0; double objectiveValue = 0;
ASSERT_NO_THROW(objectiveValue = solver.getObjectiveValue()); ASSERT_NO_THROW(objectiveValue = solver.getObjectiveValue());
@ -42,30 +42,29 @@ TEST(GlpkLpSolver, LPOptimizeMax) {
TEST(GlpkLpSolver, LPOptimizeMin) { TEST(GlpkLpSolver, LPOptimizeMin) {
#ifdef STORM_HAVE_GLPK #ifdef STORM_HAVE_GLPK
storm::solver::GlpkLpSolver solver(storm::solver::LpSolver::MINIMIZE); storm::solver::GlpkLpSolver solver(storm::solver::LpSolver::ModelSense::Minimize);
uint_fast64_t xIndex; ASSERT_NO_THROW(solver.addBoundedContinuousVariable("x", 0, 1, -1));
ASSERT_NO_THROW(xIndex = solver.createContinuousVariable("x", storm::solver::LpSolver::VariableType::BOUNDED, 0, 1, -1)); ASSERT_NO_THROW(solver.addLowerBoundedContinuousVariable("y", 0, 2));
uint_fast64_t yIndex; ASSERT_NO_THROW(solver.addBoundedContinuousVariable("z", 1, 5.7, -1));
ASSERT_NO_THROW(yIndex = solver.createContinuousVariable("y", storm::solver::LpSolver::VariableType::LOWER_BOUND, 0, 0, 2)); ASSERT_NO_THROW(solver.update());
uint_fast64_t zIndex; ASSERT_NO_THROW(solver.addConstraint("", storm::expressions::Expression::createDoubleVariable("x") + storm::expressions::Expression::createDoubleVariable("y") + storm::expressions::Expression::createDoubleVariable("z") <= storm::expressions::Expression::createDoubleLiteral(12)));
ASSERT_NO_THROW(zIndex = solver.createContinuousVariable("z", storm::solver::LpSolver::VariableType::BOUNDED, 1, 5.7, -1)); ASSERT_NO_THROW(solver.addConstraint("", storm::expressions::Expression::createDoubleLiteral(0.5) * storm::expressions::Expression::createDoubleVariable("y") + storm::expressions::Expression::createDoubleVariable("z") - storm::expressions::Expression::createDoubleVariable("x") <= storm::expressions::Expression::createDoubleLiteral(5)));
ASSERT_NO_THROW(solver.addConstraint("", storm::expressions::Expression::createDoubleVariable("y") - storm::expressions::Expression::createDoubleVariable("x") <= storm::expressions::Expression::createDoubleLiteral(5.5)));
ASSERT_NO_THROW(solver.addConstraint("", {xIndex, yIndex, zIndex}, {1, 1, 1}, storm::solver::LpSolver::BoundType::LESS_EQUAL, 12)); ASSERT_NO_THROW(solver.update());
ASSERT_NO_THROW(solver.addConstraint("", {yIndex, zIndex, xIndex}, {0.5, 1, -1}, storm::solver::LpSolver::BoundType::LESS_EQUAL, 5));
ASSERT_NO_THROW(solver.addConstraint("", {yIndex, xIndex}, {1, -1}, storm::solver::LpSolver::BoundType::LESS_EQUAL, 5.5));
ASSERT_NO_THROW(solver.optimize()); ASSERT_NO_THROW(solver.optimize());
ASSERT_TRUE(solver.isOptimal()); ASSERT_TRUE(solver.isOptimal());
ASSERT_FALSE(solver.isUnbounded()); ASSERT_FALSE(solver.isUnbounded());
ASSERT_FALSE(solver.isInfeasible()); ASSERT_FALSE(solver.isInfeasible());
double xValue = 0; double xValue = 0;
ASSERT_NO_THROW(xValue = solver.getContinuousValue(xIndex)); ASSERT_NO_THROW(xValue = solver.getContinuousValue("x"));
ASSERT_LT(std::abs(xValue - 1), storm::settings::Settings::getInstance()->getOptionByLongName("precision").getArgument(0).getValueAsDouble()); ASSERT_LT(std::abs(xValue - 1), storm::settings::Settings::getInstance()->getOptionByLongName("precision").getArgument(0).getValueAsDouble());
double yValue = 0; double yValue = 0;
ASSERT_NO_THROW(yValue = solver.getContinuousValue(yIndex)); ASSERT_NO_THROW(yValue = solver.getContinuousValue("y"));
ASSERT_LT(std::abs(yValue - 0), storm::settings::Settings::getInstance()->getOptionByLongName("precision").getArgument(0).getValueAsDouble()); ASSERT_LT(std::abs(yValue - 0), storm::settings::Settings::getInstance()->getOptionByLongName("precision").getArgument(0).getValueAsDouble());
double zValue = 0; double zValue = 0;
ASSERT_NO_THROW(zValue = solver.getContinuousValue(zIndex)); ASSERT_NO_THROW(zValue = solver.getContinuousValue("z"));
ASSERT_LT(std::abs(zValue - 5.7), storm::settings::Settings::getInstance()->getOptionByLongName("precision").getArgument(0).getValueAsDouble()); ASSERT_LT(std::abs(zValue - 5.7), storm::settings::Settings::getInstance()->getOptionByLongName("precision").getArgument(0).getValueAsDouble());
double objectiveValue = 0; double objectiveValue = 0;
ASSERT_NO_THROW(objectiveValue = solver.getObjectiveValue()); ASSERT_NO_THROW(objectiveValue = solver.getObjectiveValue());
@ -77,30 +76,29 @@ TEST(GlpkLpSolver, LPOptimizeMin) {
TEST(GlpkLpSolver, MILPOptimizeMax) { TEST(GlpkLpSolver, MILPOptimizeMax) {
#ifdef STORM_HAVE_GLPK #ifdef STORM_HAVE_GLPK
storm::solver::GlpkLpSolver solver(storm::solver::LpSolver::MAXIMIZE); storm::solver::GlpkLpSolver solver(storm::solver::LpSolver::ModelSense::Maximize);
uint_fast64_t xIndex; ASSERT_NO_THROW(solver.addBinaryVariable("x", -1));
ASSERT_NO_THROW(xIndex = solver.createBinaryVariable("x", -1)); ASSERT_NO_THROW(solver.addLowerBoundedIntegerVariable("y", 0, 2));
uint_fast64_t yIndex; ASSERT_NO_THROW(solver.addLowerBoundedContinuousVariable("z", 0, 1));
ASSERT_NO_THROW(yIndex = solver.createIntegerVariable("y", storm::solver::LpSolver::VariableType::LOWER_BOUND, 0, 0, 2)); ASSERT_NO_THROW(solver.update());
uint_fast64_t zIndex; ASSERT_NO_THROW(solver.addConstraint("", storm::expressions::Expression::createDoubleVariable("x") + storm::expressions::Expression::createDoubleVariable("y") + storm::expressions::Expression::createDoubleVariable("z") <= storm::expressions::Expression::createDoubleLiteral(12)));
ASSERT_NO_THROW(zIndex = solver.createContinuousVariable("z", storm::solver::LpSolver::VariableType::LOWER_BOUND, 0, 0, 1)); ASSERT_NO_THROW(solver.addConstraint("", storm::expressions::Expression::createDoubleLiteral(0.5) * storm::expressions::Expression::createDoubleVariable("y") + storm::expressions::Expression::createDoubleVariable("z") - storm::expressions::Expression::createDoubleVariable("x") == storm::expressions::Expression::createDoubleLiteral(5)));
ASSERT_NO_THROW(solver.addConstraint("", storm::expressions::Expression::createDoubleVariable("y") - storm::expressions::Expression::createDoubleVariable("x") <= storm::expressions::Expression::createDoubleLiteral(5.5)));
ASSERT_NO_THROW(solver.addConstraint("", {xIndex, yIndex, zIndex}, {1, 1, 1}, storm::solver::LpSolver::BoundType::LESS_EQUAL, 12)); ASSERT_NO_THROW(solver.update());
ASSERT_NO_THROW(solver.addConstraint("", {yIndex, zIndex, xIndex}, {0.5, 1, -1}, storm::solver::LpSolver::BoundType::EQUAL, 5));
ASSERT_NO_THROW(solver.addConstraint("", {yIndex, xIndex}, {1, -1}, storm::solver::LpSolver::BoundType::LESS_EQUAL, 5.5));
ASSERT_NO_THROW(solver.optimize()); ASSERT_NO_THROW(solver.optimize());
ASSERT_TRUE(solver.isOptimal()); ASSERT_TRUE(solver.isOptimal());
ASSERT_FALSE(solver.isUnbounded()); ASSERT_FALSE(solver.isUnbounded());
ASSERT_FALSE(solver.isInfeasible()); ASSERT_FALSE(solver.isInfeasible());
bool xValue = false; bool xValue = false;
ASSERT_NO_THROW(xValue = solver.getBinaryValue(xIndex)); ASSERT_NO_THROW(xValue = solver.getBinaryValue("x"));
ASSERT_EQ(true, xValue); ASSERT_EQ(true, xValue);
int_fast64_t yValue = 0; int_fast64_t yValue = 0;
ASSERT_NO_THROW(yValue = solver.getIntegerValue(yIndex)); ASSERT_NO_THROW(yValue = solver.getIntegerValue("y"));
ASSERT_EQ(6, yValue); ASSERT_EQ(6, yValue);
double zValue = 0; double zValue = 0;
ASSERT_NO_THROW(zValue = solver.getContinuousValue(zIndex)); ASSERT_NO_THROW(zValue = solver.getContinuousValue("z"));
ASSERT_LT(std::abs(zValue - 3), storm::settings::Settings::getInstance()->getOptionByLongName("precision").getArgument(0).getValueAsDouble()); ASSERT_LT(std::abs(zValue - 3), storm::settings::Settings::getInstance()->getOptionByLongName("precision").getArgument(0).getValueAsDouble());
double objectiveValue = 0; double objectiveValue = 0;
ASSERT_NO_THROW(objectiveValue = solver.getObjectiveValue()); ASSERT_NO_THROW(objectiveValue = solver.getObjectiveValue());
@ -112,30 +110,29 @@ TEST(GlpkLpSolver, MILPOptimizeMax) {
TEST(GlpkLpSolver, MILPOptimizeMin) { TEST(GlpkLpSolver, MILPOptimizeMin) {
#ifdef STORM_HAVE_GLPK #ifdef STORM_HAVE_GLPK
storm::solver::GlpkLpSolver solver(storm::solver::LpSolver::MINIMIZE); storm::solver::GlpkLpSolver solver(storm::solver::LpSolver::ModelSense::Minimize);
uint_fast64_t xIndex; ASSERT_NO_THROW(solver.addBinaryVariable("x", -1));
ASSERT_NO_THROW(xIndex = solver.createBinaryVariable("x", -1)); ASSERT_NO_THROW(solver.addLowerBoundedIntegerVariable("y", 0, 2));
uint_fast64_t yIndex; ASSERT_NO_THROW(solver.addBoundedContinuousVariable("z", 0, 5, -1));
ASSERT_NO_THROW(yIndex = solver.createContinuousVariable("y", storm::solver::LpSolver::VariableType::LOWER_BOUND, 0, 0, 2)); ASSERT_NO_THROW(solver.update());
uint_fast64_t zIndex; ASSERT_NO_THROW(solver.addConstraint("", storm::expressions::Expression::createDoubleVariable("x") + storm::expressions::Expression::createDoubleVariable("y") + storm::expressions::Expression::createDoubleVariable("z") <= storm::expressions::Expression::createDoubleLiteral(12)));
ASSERT_NO_THROW(zIndex = solver.createIntegerVariable("z", storm::solver::LpSolver::VariableType::BOUNDED, 0, 5, -1)); ASSERT_NO_THROW(solver.addConstraint("", storm::expressions::Expression::createDoubleLiteral(0.5) * storm::expressions::Expression::createDoubleVariable("y") + storm::expressions::Expression::createDoubleVariable("z") - storm::expressions::Expression::createDoubleVariable("x") <= storm::expressions::Expression::createDoubleLiteral(5)));
ASSERT_NO_THROW(solver.addConstraint("", storm::expressions::Expression::createDoubleVariable("y") - storm::expressions::Expression::createDoubleVariable("x") <= storm::expressions::Expression::createDoubleLiteral(5.5)));
ASSERT_NO_THROW(solver.addConstraint("", {xIndex, yIndex, zIndex}, {1, 1, 1}, storm::solver::LpSolver::BoundType::LESS_EQUAL, 12)); ASSERT_NO_THROW(solver.update());
ASSERT_NO_THROW(solver.addConstraint("", {yIndex, zIndex, xIndex}, {0.5, 1, -1}, storm::solver::LpSolver::BoundType::LESS_EQUAL, 5));
ASSERT_NO_THROW(solver.addConstraint("", {yIndex, xIndex}, {1, -1}, storm::solver::LpSolver::BoundType::LESS_EQUAL, 5.5));
ASSERT_NO_THROW(solver.optimize()); ASSERT_NO_THROW(solver.optimize());
ASSERT_TRUE(solver.isOptimal()); ASSERT_TRUE(solver.isOptimal());
ASSERT_FALSE(solver.isUnbounded()); ASSERT_FALSE(solver.isUnbounded());
ASSERT_FALSE(solver.isInfeasible()); ASSERT_FALSE(solver.isInfeasible());
bool xValue = false; bool xValue = false;
ASSERT_NO_THROW(xValue = solver.getBinaryValue(xIndex)); ASSERT_NO_THROW(xValue = solver.getBinaryValue("x"));
ASSERT_EQ(true, xValue); ASSERT_EQ(true, xValue);
int_fast64_t yValue = 0; int_fast64_t yValue = 0;
ASSERT_NO_THROW(yValue = solver.getIntegerValue(yIndex)); ASSERT_NO_THROW(yValue = solver.getIntegerValue("y"));
ASSERT_EQ(0, yValue); ASSERT_EQ(0, yValue);
double zValue = 0; double zValue = 0;
ASSERT_NO_THROW(zValue = solver.getContinuousValue(zIndex)); ASSERT_NO_THROW(zValue = solver.getContinuousValue("z"));
ASSERT_LT(std::abs(zValue - 5), storm::settings::Settings::getInstance()->getOptionByLongName("precision").getArgument(0).getValueAsDouble()); ASSERT_LT(std::abs(zValue - 5), storm::settings::Settings::getInstance()->getOptionByLongName("precision").getArgument(0).getValueAsDouble());
double objectiveValue = 0; double objectiveValue = 0;
ASSERT_NO_THROW(objectiveValue = solver.getObjectiveValue()); ASSERT_NO_THROW(objectiveValue = solver.getObjectiveValue());
@ -147,31 +144,30 @@ TEST(GlpkLpSolver, MILPOptimizeMin) {
TEST(GlpkLpSolver, LPInfeasible) { TEST(GlpkLpSolver, LPInfeasible) {
#ifdef STORM_HAVE_GLPK #ifdef STORM_HAVE_GLPK
storm::solver::GlpkLpSolver solver(storm::solver::LpSolver::MAXIMIZE); storm::solver::GlpkLpSolver solver(storm::solver::LpSolver::ModelSense::Maximize);
uint_fast64_t xIndex; ASSERT_NO_THROW(solver.addBoundedContinuousVariable("x", 0, 1, -1));
ASSERT_NO_THROW(xIndex = solver.createContinuousVariable("x", storm::solver::LpSolver::VariableType::BOUNDED, 0, 1, -1)); ASSERT_NO_THROW(solver.addLowerBoundedContinuousVariable("y", 0, 2));
uint_fast64_t yIndex; ASSERT_NO_THROW(solver.addLowerBoundedContinuousVariable("z", 0, 1));
ASSERT_NO_THROW(yIndex = solver.createContinuousVariable("y", storm::solver::LpSolver::VariableType::LOWER_BOUND, 0, 0, 2)); ASSERT_NO_THROW(solver.update());
uint_fast64_t zIndex; ASSERT_NO_THROW(solver.addConstraint("", storm::expressions::Expression::createDoubleVariable("x") + storm::expressions::Expression::createDoubleVariable("y") + storm::expressions::Expression::createDoubleVariable("z") <= storm::expressions::Expression::createDoubleLiteral(12)));
ASSERT_NO_THROW(zIndex = solver.createContinuousVariable("z", storm::solver::LpSolver::VariableType::LOWER_BOUND, 0, 0, 1)); ASSERT_NO_THROW(solver.addConstraint("", storm::expressions::Expression::createDoubleLiteral(0.5) * storm::expressions::Expression::createDoubleVariable("y") + storm::expressions::Expression::createDoubleVariable("z") - storm::expressions::Expression::createDoubleVariable("x") == storm::expressions::Expression::createDoubleLiteral(5)));
ASSERT_NO_THROW(solver.addConstraint("", storm::expressions::Expression::createDoubleVariable("y") - storm::expressions::Expression::createDoubleVariable("x") <= storm::expressions::Expression::createDoubleLiteral(5.5)));
ASSERT_NO_THROW(solver.addConstraint("", {xIndex, yIndex, zIndex}, {1, 1, 1}, storm::solver::LpSolver::BoundType::LESS_EQUAL, 12)); ASSERT_NO_THROW(solver.addConstraint("", storm::expressions::Expression::createDoubleVariable("y") > storm::expressions::Expression::createDoubleLiteral(7)));
ASSERT_NO_THROW(solver.addConstraint("", {yIndex, zIndex, xIndex}, {0.5, 1, -1}, storm::solver::LpSolver::BoundType::EQUAL, 5)); ASSERT_NO_THROW(solver.update());
ASSERT_NO_THROW(solver.addConstraint("", {yIndex, xIndex}, {1, -1}, storm::solver::LpSolver::BoundType::LESS_EQUAL, 5.5));
ASSERT_NO_THROW(solver.addConstraint("", {yIndex}, {1}, storm::solver::LpSolver::BoundType::GREATER_EQUAL, 7));
ASSERT_NO_THROW(solver.optimize()); ASSERT_NO_THROW(solver.optimize());
ASSERT_FALSE(solver.isOptimal()); ASSERT_FALSE(solver.isOptimal());
ASSERT_FALSE(solver.isUnbounded()); ASSERT_FALSE(solver.isUnbounded());
ASSERT_TRUE(solver.isInfeasible()); ASSERT_TRUE(solver.isInfeasible());
double xValue = 0; double xValue = 0;
ASSERT_THROW(xValue = solver.getContinuousValue(xIndex), storm::exceptions::InvalidStateException); ASSERT_THROW(xValue = solver.getContinuousValue("x"), storm::exceptions::InvalidAccessException);
double yValue = 0; double yValue = 0;
ASSERT_THROW(yValue = solver.getContinuousValue(yIndex), storm::exceptions::InvalidStateException); ASSERT_THROW(yValue = solver.getContinuousValue("y"), storm::exceptions::InvalidAccessException);
double zValue = 0; double zValue = 0;
ASSERT_THROW(zValue = solver.getContinuousValue(zIndex), storm::exceptions::InvalidStateException); ASSERT_THROW(zValue = solver.getContinuousValue("z"), storm::exceptions::InvalidAccessException);
double objectiveValue = 0; double objectiveValue = 0;
ASSERT_THROW(objectiveValue = solver.getObjectiveValue(), storm::exceptions::InvalidStateException); ASSERT_THROW(objectiveValue = solver.getObjectiveValue(), storm::exceptions::InvalidAccessException);
#else #else
ASSERT_TRUE(false) << "StoRM built without glpk support."; ASSERT_TRUE(false) << "StoRM built without glpk support.";
#endif #endif
@ -179,31 +175,30 @@ TEST(GlpkLpSolver, LPInfeasible) {
TEST(GlpkLpSolver, MILPInfeasible) { TEST(GlpkLpSolver, MILPInfeasible) {
#ifdef STORM_HAVE_GLPK #ifdef STORM_HAVE_GLPK
storm::solver::GlpkLpSolver solver(storm::solver::LpSolver::MAXIMIZE); storm::solver::GlpkLpSolver solver(storm::solver::LpSolver::ModelSense::Maximize);
uint_fast64_t xIndex; ASSERT_NO_THROW(solver.addBinaryVariable("x", -1));
ASSERT_NO_THROW(xIndex = solver.createBinaryVariable("x", -1)); ASSERT_NO_THROW(solver.addLowerBoundedContinuousVariable("y", 0, 2));
uint_fast64_t yIndex; ASSERT_NO_THROW(solver.addLowerBoundedContinuousVariable("z", 0, 1));
ASSERT_NO_THROW(yIndex = solver.createIntegerVariable("y", storm::solver::LpSolver::VariableType::LOWER_BOUND, 0, 0, 2)); ASSERT_NO_THROW(solver.update());
uint_fast64_t zIndex; ASSERT_NO_THROW(solver.addConstraint("", storm::expressions::Expression::createDoubleVariable("x") + storm::expressions::Expression::createDoubleVariable("y") + storm::expressions::Expression::createDoubleVariable("z") <= storm::expressions::Expression::createDoubleLiteral(12)));
ASSERT_NO_THROW(zIndex = solver.createContinuousVariable("z", storm::solver::LpSolver::VariableType::LOWER_BOUND, 0, 0, 1)); ASSERT_NO_THROW(solver.addConstraint("", storm::expressions::Expression::createDoubleLiteral(0.5) * storm::expressions::Expression::createDoubleVariable("y") + storm::expressions::Expression::createDoubleVariable("z") - storm::expressions::Expression::createDoubleVariable("x") == storm::expressions::Expression::createDoubleLiteral(5)));
ASSERT_NO_THROW(solver.addConstraint("", storm::expressions::Expression::createDoubleVariable("y") - storm::expressions::Expression::createDoubleVariable("x") <= storm::expressions::Expression::createDoubleLiteral(5.5)));
ASSERT_NO_THROW(solver.addConstraint("", {xIndex, yIndex, zIndex}, {1, 1, 1}, storm::solver::LpSolver::BoundType::LESS_EQUAL, 12)); ASSERT_NO_THROW(solver.addConstraint("", storm::expressions::Expression::createDoubleVariable("y") > storm::expressions::Expression::createDoubleLiteral(7)));
ASSERT_NO_THROW(solver.addConstraint("", {yIndex, zIndex, xIndex}, {0.5, 1, -1}, storm::solver::LpSolver::BoundType::EQUAL, 5)); ASSERT_NO_THROW(solver.update());
ASSERT_NO_THROW(solver.addConstraint("", {yIndex, xIndex}, {1, -1}, storm::solver::LpSolver::BoundType::LESS_EQUAL, 5.5));
ASSERT_NO_THROW(solver.addConstraint("", {yIndex}, {1}, storm::solver::LpSolver::BoundType::GREATER_EQUAL, 7));
ASSERT_NO_THROW(solver.optimize()); ASSERT_NO_THROW(solver.optimize());
ASSERT_FALSE(solver.isOptimal()); ASSERT_FALSE(solver.isOptimal());
ASSERT_FALSE(solver.isUnbounded()); ASSERT_FALSE(solver.isUnbounded());
ASSERT_TRUE(solver.isInfeasible()); ASSERT_TRUE(solver.isInfeasible());
bool xValue = false; bool xValue = false;
ASSERT_THROW(xValue = solver.getBinaryValue(xIndex), storm::exceptions::InvalidStateException); ASSERT_THROW(xValue = solver.getBinaryValue("x"), storm::exceptions::InvalidAccessException);
int_fast64_t yValue = 0; int_fast64_t yValue = 0;
ASSERT_THROW(yValue = solver.getIntegerValue(yIndex), storm::exceptions::InvalidStateException); ASSERT_THROW(yValue = solver.getIntegerValue("y"), storm::exceptions::InvalidAccessException);
double zValue = 0; double zValue = 0;
ASSERT_THROW(zValue = solver.getContinuousValue(zIndex), storm::exceptions::InvalidStateException); ASSERT_THROW(zValue = solver.getContinuousValue("z"), storm::exceptions::InvalidAccessException);
double objectiveValue = 0; double objectiveValue = 0;
ASSERT_THROW(objectiveValue = solver.getObjectiveValue(), storm::exceptions::InvalidStateException); ASSERT_THROW(objectiveValue = solver.getObjectiveValue(), storm::exceptions::InvalidAccessException);
#else #else
ASSERT_TRUE(false) << "StoRM built without glpk support."; ASSERT_TRUE(false) << "StoRM built without glpk support.";
#endif #endif
@ -211,29 +206,28 @@ TEST(GlpkLpSolver, MILPInfeasible) {
TEST(GlpkLpSolver, LPUnbounded) { TEST(GlpkLpSolver, LPUnbounded) {
#ifdef STORM_HAVE_GLPK #ifdef STORM_HAVE_GLPK
storm::solver::GlpkLpSolver solver(storm::solver::LpSolver::MAXIMIZE); storm::solver::GlpkLpSolver solver(storm::solver::LpSolver::ModelSense::Maximize);
uint_fast64_t xIndex; ASSERT_NO_THROW(solver.addBoundedContinuousVariable("x", 0, 1, -1));
ASSERT_NO_THROW(xIndex = solver.createContinuousVariable("x", storm::solver::LpSolver::VariableType::BOUNDED, 0, 1, -1)); ASSERT_NO_THROW(solver.addLowerBoundedContinuousVariable("y", 0, 2));
uint_fast64_t yIndex; ASSERT_NO_THROW(solver.addLowerBoundedContinuousVariable("z", 0, 1));
ASSERT_NO_THROW(yIndex = solver.createContinuousVariable("y", storm::solver::LpSolver::VariableType::LOWER_BOUND, 0, 0, 2)); ASSERT_NO_THROW(solver.update());
uint_fast64_t zIndex; ASSERT_NO_THROW(solver.addConstraint("", storm::expressions::Expression::createDoubleVariable("x") + storm::expressions::Expression::createDoubleVariable("y") - storm::expressions::Expression::createDoubleVariable("z") <= storm::expressions::Expression::createDoubleLiteral(12)));
ASSERT_NO_THROW(zIndex = solver.createContinuousVariable("z", storm::solver::LpSolver::VariableType::LOWER_BOUND, 0, 0, 1)); ASSERT_NO_THROW(solver.addConstraint("", storm::expressions::Expression::createDoubleVariable("y") - storm::expressions::Expression::createDoubleVariable("x") <= storm::expressions::Expression::createDoubleLiteral(5.5)));
ASSERT_NO_THROW(solver.update());
ASSERT_NO_THROW(solver.addConstraint("", {xIndex, yIndex, zIndex}, {1, 1, -1}, storm::solver::LpSolver::BoundType::LESS_EQUAL, 12));
ASSERT_NO_THROW(solver.addConstraint("", {yIndex, xIndex}, {1, -1}, storm::solver::LpSolver::BoundType::LESS_EQUAL, 5.5));
ASSERT_NO_THROW(solver.optimize()); ASSERT_NO_THROW(solver.optimize());
ASSERT_FALSE(solver.isOptimal()); ASSERT_FALSE(solver.isOptimal());
ASSERT_TRUE(solver.isUnbounded()); ASSERT_TRUE(solver.isUnbounded());
ASSERT_FALSE(solver.isInfeasible()); ASSERT_FALSE(solver.isInfeasible());
double xValue = 0; double xValue = 0;
ASSERT_THROW(xValue = solver.getContinuousValue(xIndex), storm::exceptions::InvalidStateException); ASSERT_THROW(xValue = solver.getContinuousValue("x"), storm::exceptions::InvalidAccessException);
double yValue = 0; double yValue = 0;
ASSERT_THROW(yValue = solver.getContinuousValue(yIndex), storm::exceptions::InvalidStateException); ASSERT_THROW(yValue = solver.getContinuousValue("y"), storm::exceptions::InvalidAccessException);
double zValue = 0; double zValue = 0;
ASSERT_THROW(zValue = solver.getContinuousValue(zIndex), storm::exceptions::InvalidStateException); ASSERT_THROW(zValue = solver.getContinuousValue("z"), storm::exceptions::InvalidAccessException);
double objectiveValue = 0; double objectiveValue = 0;
ASSERT_THROW(objectiveValue = solver.getObjectiveValue(), storm::exceptions::InvalidStateException); ASSERT_THROW(objectiveValue = solver.getObjectiveValue(), storm::exceptions::InvalidAccessException);
#else #else
ASSERT_TRUE(false) << "StoRM built without glpk support."; ASSERT_TRUE(false) << "StoRM built without glpk support.";
#endif #endif
@ -241,30 +235,29 @@ TEST(GlpkLpSolver, LPUnbounded) {
TEST(GlpkLpSolver, MILPUnbounded) { TEST(GlpkLpSolver, MILPUnbounded) {
#ifdef STORM_HAVE_GLPK #ifdef STORM_HAVE_GLPK
storm::solver::GlpkLpSolver solver(storm::solver::LpSolver::MAXIMIZE); storm::solver::GlpkLpSolver solver(storm::solver::LpSolver::ModelSense::Maximize);
uint_fast64_t xIndex; ASSERT_NO_THROW(solver.addBinaryVariable("x", -1));
ASSERT_NO_THROW(xIndex = solver.createBinaryVariable("x", -1)); ASSERT_NO_THROW(solver.addLowerBoundedContinuousVariable("y", 0, 2));
uint_fast64_t yIndex; ASSERT_NO_THROW(solver.addLowerBoundedContinuousVariable("z", 0, 1));
ASSERT_NO_THROW(yIndex = solver.createIntegerVariable("y", storm::solver::LpSolver::VariableType::LOWER_BOUND, 0, 0, 2)); ASSERT_NO_THROW(solver.update());
uint_fast64_t zIndex; ASSERT_NO_THROW(solver.addConstraint("", storm::expressions::Expression::createDoubleVariable("x") + storm::expressions::Expression::createDoubleVariable("y") - storm::expressions::Expression::createDoubleVariable("z") <= storm::expressions::Expression::createDoubleLiteral(12)));
ASSERT_NO_THROW(zIndex = solver.createContinuousVariable("z", storm::solver::LpSolver::VariableType::LOWER_BOUND, 0, 0, 1)); ASSERT_NO_THROW(solver.addConstraint("", storm::expressions::Expression::createDoubleVariable("y") - storm::expressions::Expression::createDoubleVariable("x") <= storm::expressions::Expression::createDoubleLiteral(5.5)));
ASSERT_NO_THROW(solver.update());
ASSERT_NO_THROW(solver.addConstraint("", {xIndex, yIndex, zIndex}, {1, 1, -1}, storm::solver::LpSolver::BoundType::LESS_EQUAL, 12));
ASSERT_NO_THROW(solver.addConstraint("", {yIndex, xIndex}, {1, -1}, storm::solver::LpSolver::BoundType::LESS_EQUAL, 5.5));
ASSERT_NO_THROW(solver.optimize()); ASSERT_NO_THROW(solver.optimize());
ASSERT_FALSE(solver.isOptimal()); ASSERT_FALSE(solver.isOptimal());
ASSERT_TRUE(solver.isUnbounded()); ASSERT_TRUE(solver.isUnbounded());
ASSERT_FALSE(solver.isInfeasible()); ASSERT_FALSE(solver.isInfeasible());
bool xValue = false; bool xValue = false;
ASSERT_THROW(xValue = solver.getBinaryValue(xIndex), storm::exceptions::InvalidStateException); ASSERT_THROW(xValue = solver.getBinaryValue("x"), storm::exceptions::InvalidAccessException);
int_fast64_t yValue = 0; int_fast64_t yValue = 0;
ASSERT_THROW(yValue = solver.getIntegerValue(yIndex), storm::exceptions::InvalidStateException); ASSERT_THROW(yValue = solver.getIntegerValue("y"), storm::exceptions::InvalidAccessException);
double zValue = 0; double zValue = 0;
ASSERT_THROW(zValue = solver.getContinuousValue(zIndex), storm::exceptions::InvalidStateException); ASSERT_THROW(zValue = solver.getContinuousValue("z"), storm::exceptions::InvalidAccessException);
double objectiveValue = 0; double objectiveValue = 0;
ASSERT_THROW(objectiveValue = solver.getObjectiveValue(), storm::exceptions::InvalidStateException); ASSERT_THROW(objectiveValue = solver.getObjectiveValue(), storm::exceptions::InvalidAccessException);
#else #else
ASSERT_TRUE(false) << "StoRM built without glpk support."; ASSERT_TRUE(false) << "StoRM built without glpk support.";
#endif #endif
} }

240
test/functional/solver/GurobiLpSolverTest.cpp

@ -3,36 +3,34 @@
#include "src/solver/GurobiLpSolver.h" #include "src/solver/GurobiLpSolver.h"
#include "src/exceptions/InvalidStateException.h" #include "src/exceptions/InvalidStateException.h"
#include "src/exceptions/InvalidAccessException.h"
#include "src/settings/Settings.h" #include "src/settings/Settings.h"
TEST(GurobiLpSolver, LPOptimizeMax) { TEST(GurobiLpSolver, LPOptimizeMax) {
#ifdef STORM_HAVE_GUROBI #ifdef STORM_HAVE_GUROBI
storm::solver::GurobiLpSolver solver(storm::solver::LpSolver::MAXIMIZE); storm::solver::GurobiLpSolver solver(storm::solver::LpSolver::ModelSense::Maximize);
uint_fast64_t xIndex; ASSERT_NO_THROW(solver.addBoundedContinuousVariable("x", 0, 1, -1));
ASSERT_NO_THROW(xIndex = solver.createContinuousVariable("x", storm::solver::LpSolver::VariableType::BOUNDED, 0, 1, -1)); ASSERT_NO_THROW(solver.addLowerBoundedContinuousVariable("y", 0, 2));
uint_fast64_t yIndex; ASSERT_NO_THROW(solver.addLowerBoundedContinuousVariable("z", 0, 1));
ASSERT_NO_THROW(yIndex = solver.createContinuousVariable("y", storm::solver::LpSolver::VariableType::LOWER_BOUND, 0, 0, 2)); ASSERT_NO_THROW(solver.update());
uint_fast64_t zIndex;
ASSERT_NO_THROW(zIndex = solver.createContinuousVariable("z", storm::solver::LpSolver::VariableType::LOWER_BOUND, 0, 0, 1));
ASSERT_NO_THROW(solver.update());
ASSERT_NO_THROW(solver.addConstraint("", {xIndex, yIndex, zIndex}, {1, 1, 1}, storm::solver::LpSolver::BoundType::LESS_EQUAL, 12));
ASSERT_NO_THROW(solver.addConstraint("", {yIndex, zIndex, xIndex}, {0.5, 1, -1}, storm::solver::LpSolver::BoundType::EQUAL, 5));
ASSERT_NO_THROW(solver.addConstraint("", {yIndex, xIndex}, {1, -1}, storm::solver::LpSolver::BoundType::LESS_EQUAL, 5.5));
ASSERT_NO_THROW(solver.addConstraint("", storm::expressions::Expression::createDoubleVariable("x") + storm::expressions::Expression::createDoubleVariable("y") + storm::expressions::Expression::createDoubleVariable("z") <= storm::expressions::Expression::createDoubleLiteral(12)));
ASSERT_NO_THROW(solver.addConstraint("", storm::expressions::Expression::createDoubleLiteral(0.5) * storm::expressions::Expression::createDoubleVariable("y") + storm::expressions::Expression::createDoubleVariable("z") - storm::expressions::Expression::createDoubleVariable("x") == storm::expressions::Expression::createDoubleLiteral(5)));
ASSERT_NO_THROW(solver.addConstraint("", storm::expressions::Expression::createDoubleVariable("y") - storm::expressions::Expression::createDoubleVariable("x") <= storm::expressions::Expression::createDoubleLiteral(5.5)));
ASSERT_NO_THROW(solver.update());
ASSERT_NO_THROW(solver.optimize()); ASSERT_NO_THROW(solver.optimize());
ASSERT_TRUE(solver.isOptimal()); ASSERT_TRUE(solver.isOptimal());
ASSERT_FALSE(solver.isUnbounded()); ASSERT_FALSE(solver.isUnbounded());
ASSERT_FALSE(solver.isInfeasible()); ASSERT_FALSE(solver.isInfeasible());
double xValue = 0; double xValue = 0;
ASSERT_NO_THROW(xValue = solver.getContinuousValue(xIndex)); ASSERT_NO_THROW(xValue = solver.getContinuousValue("x"));
ASSERT_LT(std::abs(xValue - 1), storm::settings::Settings::getInstance()->getOptionByLongName("precision").getArgument(0).getValueAsDouble()); ASSERT_LT(std::abs(xValue - 1), storm::settings::Settings::getInstance()->getOptionByLongName("precision").getArgument(0).getValueAsDouble());
double yValue = 0; double yValue = 0;
ASSERT_NO_THROW(yValue = solver.getContinuousValue(yIndex)); ASSERT_NO_THROW(yValue = solver.getContinuousValue("y"));
ASSERT_LT(std::abs(yValue - 6.5), storm::settings::Settings::getInstance()->getOptionByLongName("precision").getArgument(0).getValueAsDouble()); ASSERT_LT(std::abs(yValue - 6.5), storm::settings::Settings::getInstance()->getOptionByLongName("precision").getArgument(0).getValueAsDouble());
double zValue = 0; double zValue = 0;
ASSERT_NO_THROW(zValue = solver.getContinuousValue(zIndex)); ASSERT_NO_THROW(zValue = solver.getContinuousValue("z"));
ASSERT_LT(std::abs(zValue - 2.75), storm::settings::Settings::getInstance()->getOptionByLongName("precision").getArgument(0).getValueAsDouble()); ASSERT_LT(std::abs(zValue - 2.75), storm::settings::Settings::getInstance()->getOptionByLongName("precision").getArgument(0).getValueAsDouble());
double objectiveValue = 0; double objectiveValue = 0;
ASSERT_NO_THROW(objectiveValue = solver.getObjectiveValue()); ASSERT_NO_THROW(objectiveValue = solver.getObjectiveValue());
@ -44,32 +42,29 @@ TEST(GurobiLpSolver, LPOptimizeMax) {
TEST(GurobiLpSolver, LPOptimizeMin) { TEST(GurobiLpSolver, LPOptimizeMin) {
#ifdef STORM_HAVE_GUROBI #ifdef STORM_HAVE_GUROBI
storm::solver::GurobiLpSolver solver(storm::solver::LpSolver::MINIMIZE); storm::solver::GurobiLpSolver solver(storm::solver::LpSolver::ModelSense::Minimize);
uint_fast64_t xIndex; ASSERT_NO_THROW(solver.addBoundedContinuousVariable("x", 0, 1, -1));
ASSERT_NO_THROW(xIndex = solver.createContinuousVariable("x", storm::solver::LpSolver::VariableType::BOUNDED, 0, 1, -1)); ASSERT_NO_THROW(solver.addLowerBoundedIntegerVariable("y", 0, 2));
uint_fast64_t yIndex; ASSERT_NO_THROW(solver.addBoundedContinuousVariable("z", 1, 5.7, -1));
ASSERT_NO_THROW(yIndex = solver.createContinuousVariable("y", storm::solver::LpSolver::VariableType::LOWER_BOUND, 0, 0, 2)); ASSERT_NO_THROW(solver.update());
uint_fast64_t zIndex; ASSERT_NO_THROW(solver.addConstraint("", storm::expressions::Expression::createDoubleVariable("x") + storm::expressions::Expression::createDoubleVariable("y") + storm::expressions::Expression::createDoubleVariable("z") <= storm::expressions::Expression::createDoubleLiteral(12)));
ASSERT_NO_THROW(zIndex = solver.createContinuousVariable("z", storm::solver::LpSolver::VariableType::BOUNDED, 1, 5.7, -1)); ASSERT_NO_THROW(solver.addConstraint("", storm::expressions::Expression::createDoubleLiteral(0.5) * storm::expressions::Expression::createDoubleVariable("y") + storm::expressions::Expression::createDoubleVariable("z") - storm::expressions::Expression::createDoubleVariable("x") <= storm::expressions::Expression::createDoubleLiteral(5)));
ASSERT_NO_THROW(solver.addConstraint("", storm::expressions::Expression::createDoubleVariable("y") - storm::expressions::Expression::createDoubleVariable("x") <= storm::expressions::Expression::createDoubleLiteral(5.5)));
ASSERT_NO_THROW(solver.update()); ASSERT_NO_THROW(solver.update());
ASSERT_NO_THROW(solver.addConstraint("", {xIndex, yIndex, zIndex}, {1, 1, 1}, storm::solver::LpSolver::BoundType::LESS_EQUAL, 12));
ASSERT_NO_THROW(solver.addConstraint("", {yIndex, zIndex, xIndex}, {0.5, 1, -1}, storm::solver::LpSolver::BoundType::LESS_EQUAL, 5));
ASSERT_NO_THROW(solver.addConstraint("", {yIndex, xIndex}, {1, -1}, storm::solver::LpSolver::BoundType::LESS_EQUAL, 5.5));
ASSERT_NO_THROW(solver.optimize()); ASSERT_NO_THROW(solver.optimize());
ASSERT_TRUE(solver.isOptimal()); ASSERT_TRUE(solver.isOptimal());
ASSERT_FALSE(solver.isUnbounded()); ASSERT_FALSE(solver.isUnbounded());
ASSERT_FALSE(solver.isInfeasible()); ASSERT_FALSE(solver.isInfeasible());
double xValue = 0; double xValue = 0;
ASSERT_NO_THROW(xValue = solver.getContinuousValue(xIndex)); ASSERT_NO_THROW(xValue = solver.getContinuousValue("x"));
ASSERT_LT(std::abs(xValue - 1), storm::settings::Settings::getInstance()->getOptionByLongName("precision").getArgument(0).getValueAsDouble()); ASSERT_LT(std::abs(xValue - 1), storm::settings::Settings::getInstance()->getOptionByLongName("precision").getArgument(0).getValueAsDouble());
double yValue = 0; double yValue = 0;
ASSERT_NO_THROW(yValue = solver.getContinuousValue(yIndex)); ASSERT_NO_THROW(yValue = solver.getContinuousValue("y"));
ASSERT_LT(std::abs(yValue - 0), storm::settings::Settings::getInstance()->getOptionByLongName("precision").getArgument(0).getValueAsDouble()); ASSERT_LT(std::abs(yValue - 0), storm::settings::Settings::getInstance()->getOptionByLongName("precision").getArgument(0).getValueAsDouble());
double zValue = 0; double zValue = 0;
ASSERT_NO_THROW(zValue = solver.getContinuousValue(zIndex)); ASSERT_NO_THROW(zValue = solver.getContinuousValue("z"));
ASSERT_LT(std::abs(zValue - 5.7), storm::settings::Settings::getInstance()->getOptionByLongName("precision").getArgument(0).getValueAsDouble()); ASSERT_LT(std::abs(zValue - 5.7), storm::settings::Settings::getInstance()->getOptionByLongName("precision").getArgument(0).getValueAsDouble());
double objectiveValue = 0; double objectiveValue = 0;
ASSERT_NO_THROW(objectiveValue = solver.getObjectiveValue()); ASSERT_NO_THROW(objectiveValue = solver.getObjectiveValue());
@ -81,32 +76,29 @@ TEST(GurobiLpSolver, LPOptimizeMin) {
TEST(GurobiLpSolver, MILPOptimizeMax) { TEST(GurobiLpSolver, MILPOptimizeMax) {
#ifdef STORM_HAVE_GUROBI #ifdef STORM_HAVE_GUROBI
storm::solver::GurobiLpSolver solver(storm::solver::LpSolver::MAXIMIZE); storm::solver::GurobiLpSolver solver(storm::solver::LpSolver::ModelSense::Maximize);
uint_fast64_t xIndex; ASSERT_NO_THROW(solver.addBinaryVariable("x", -1));
ASSERT_NO_THROW(xIndex = solver.createBinaryVariable("x", -1)); ASSERT_NO_THROW(solver.addLowerBoundedIntegerVariable("y", 0, 2));
uint_fast64_t yIndex; ASSERT_NO_THROW(solver.addLowerBoundedContinuousVariable("z", 0, 1));
ASSERT_NO_THROW(yIndex = solver.createIntegerVariable("y", storm::solver::LpSolver::VariableType::LOWER_BOUND, 0, 0, 2)); ASSERT_NO_THROW(solver.update());
uint_fast64_t zIndex; ASSERT_NO_THROW(solver.addConstraint("", storm::expressions::Expression::createDoubleVariable("x") + storm::expressions::Expression::createDoubleVariable("y") + storm::expressions::Expression::createDoubleVariable("z") <= storm::expressions::Expression::createDoubleLiteral(12)));
ASSERT_NO_THROW(zIndex = solver.createContinuousVariable("z", storm::solver::LpSolver::VariableType::LOWER_BOUND, 0, 0, 1)); ASSERT_NO_THROW(solver.addConstraint("", storm::expressions::Expression::createDoubleLiteral(0.5) * storm::expressions::Expression::createDoubleVariable("y") + storm::expressions::Expression::createDoubleVariable("z") - storm::expressions::Expression::createDoubleVariable("x") == storm::expressions::Expression::createDoubleLiteral(5)));
ASSERT_NO_THROW(solver.addConstraint("", storm::expressions::Expression::createDoubleVariable("y") - storm::expressions::Expression::createDoubleVariable("x") <= storm::expressions::Expression::createDoubleLiteral(5.5)));
ASSERT_NO_THROW(solver.update()); ASSERT_NO_THROW(solver.update());
ASSERT_NO_THROW(solver.addConstraint("", {xIndex, yIndex, zIndex}, {1, 1, 1}, storm::solver::LpSolver::BoundType::LESS_EQUAL, 12));
ASSERT_NO_THROW(solver.addConstraint("", {yIndex, zIndex, xIndex}, {0.5, 1, -1}, storm::solver::LpSolver::BoundType::EQUAL, 5));
ASSERT_NO_THROW(solver.addConstraint("", {yIndex, xIndex}, {1, -1}, storm::solver::LpSolver::BoundType::LESS_EQUAL, 5.5));
ASSERT_NO_THROW(solver.optimize()); ASSERT_NO_THROW(solver.optimize());
ASSERT_TRUE(solver.isOptimal()); ASSERT_TRUE(solver.isOptimal());
ASSERT_FALSE(solver.isUnbounded()); ASSERT_FALSE(solver.isUnbounded());
ASSERT_FALSE(solver.isInfeasible()); ASSERT_FALSE(solver.isInfeasible());
bool xValue = false; bool xValue = false;
ASSERT_NO_THROW(xValue = solver.getBinaryValue(xIndex)); ASSERT_NO_THROW(xValue = solver.getBinaryValue("x"));
ASSERT_EQ(true, xValue); ASSERT_EQ(true, xValue);
int_fast64_t yValue = 0; int_fast64_t yValue = 0;
ASSERT_NO_THROW(yValue = solver.getIntegerValue(yIndex)); ASSERT_NO_THROW(yValue = solver.getIntegerValue("y"));
ASSERT_EQ(6, yValue); ASSERT_EQ(6, yValue);
double zValue = 0; double zValue = 0;
ASSERT_NO_THROW(zValue = solver.getContinuousValue(zIndex)); ASSERT_NO_THROW(zValue = solver.getContinuousValue("z"));
ASSERT_LT(std::abs(zValue - 3), storm::settings::Settings::getInstance()->getOptionByLongName("precision").getArgument(0).getValueAsDouble()); ASSERT_LT(std::abs(zValue - 3), storm::settings::Settings::getInstance()->getOptionByLongName("precision").getArgument(0).getValueAsDouble());
double objectiveValue = 0; double objectiveValue = 0;
ASSERT_NO_THROW(objectiveValue = solver.getObjectiveValue()); ASSERT_NO_THROW(objectiveValue = solver.getObjectiveValue());
@ -118,32 +110,29 @@ TEST(GurobiLpSolver, MILPOptimizeMax) {
TEST(GurobiLpSolver, MILPOptimizeMin) { TEST(GurobiLpSolver, MILPOptimizeMin) {
#ifdef STORM_HAVE_GUROBI #ifdef STORM_HAVE_GUROBI
storm::solver::GurobiLpSolver solver(storm::solver::LpSolver::MINIMIZE); storm::solver::GurobiLpSolver solver(storm::solver::LpSolver::ModelSense::Minimize);
uint_fast64_t xIndex; ASSERT_NO_THROW(solver.addBinaryVariable("x", -1));
ASSERT_NO_THROW(xIndex = solver.createBinaryVariable("x", -1)); ASSERT_NO_THROW(solver.addLowerBoundedIntegerVariable("y", 0, 2));
uint_fast64_t yIndex; ASSERT_NO_THROW(solver.addBoundedContinuousVariable("z", 0, 5, -1));
ASSERT_NO_THROW(yIndex = solver.createContinuousVariable("y", storm::solver::LpSolver::VariableType::LOWER_BOUND, 0, 0, 2)); ASSERT_NO_THROW(solver.update());
uint_fast64_t zIndex; ASSERT_NO_THROW(solver.addConstraint("", storm::expressions::Expression::createDoubleVariable("x") + storm::expressions::Expression::createDoubleVariable("y") + storm::expressions::Expression::createDoubleVariable("z") <= storm::expressions::Expression::createDoubleLiteral(12)));
ASSERT_NO_THROW(zIndex = solver.createIntegerVariable("z", storm::solver::LpSolver::VariableType::BOUNDED, 0, 5.7, -1)); ASSERT_NO_THROW(solver.addConstraint("", storm::expressions::Expression::createDoubleLiteral(0.5) * storm::expressions::Expression::createDoubleVariable("y") + storm::expressions::Expression::createDoubleVariable("z") - storm::expressions::Expression::createDoubleVariable("x") <= storm::expressions::Expression::createDoubleLiteral(5)));
ASSERT_NO_THROW(solver.addConstraint("", storm::expressions::Expression::createDoubleVariable("y") - storm::expressions::Expression::createDoubleVariable("x") <= storm::expressions::Expression::createDoubleLiteral(5.5)));
ASSERT_NO_THROW(solver.update()); ASSERT_NO_THROW(solver.update());
ASSERT_NO_THROW(solver.addConstraint("", {xIndex, yIndex, zIndex}, {1, 1, 1}, storm::solver::LpSolver::BoundType::LESS_EQUAL, 12));
ASSERT_NO_THROW(solver.addConstraint("", {yIndex, zIndex, xIndex}, {0.5, 1, -1}, storm::solver::LpSolver::BoundType::LESS_EQUAL, 5));
ASSERT_NO_THROW(solver.addConstraint("", {yIndex, xIndex}, {1, -1}, storm::solver::LpSolver::BoundType::LESS_EQUAL, 5.5));
ASSERT_NO_THROW(solver.optimize()); ASSERT_NO_THROW(solver.optimize());
ASSERT_TRUE(solver.isOptimal()); ASSERT_TRUE(solver.isOptimal());
ASSERT_FALSE(solver.isUnbounded()); ASSERT_FALSE(solver.isUnbounded());
ASSERT_FALSE(solver.isInfeasible()); ASSERT_FALSE(solver.isInfeasible());
bool xValue = false; bool xValue = false;
ASSERT_NO_THROW(xValue = solver.getBinaryValue(xIndex)); ASSERT_NO_THROW(xValue = solver.getBinaryValue("x"));
ASSERT_EQ(true, xValue); ASSERT_EQ(true, xValue);
int_fast64_t yValue = 0; int_fast64_t yValue = 0;
ASSERT_NO_THROW(yValue = solver.getIntegerValue(yIndex)); ASSERT_NO_THROW(yValue = solver.getIntegerValue("y"));
ASSERT_EQ(0, yValue); ASSERT_EQ(0, yValue);
double zValue = 0; double zValue = 0;
ASSERT_NO_THROW(zValue = solver.getContinuousValue(zIndex)); ASSERT_NO_THROW(zValue = solver.getContinuousValue("z"));
ASSERT_LT(std::abs(zValue - 5), storm::settings::Settings::getInstance()->getOptionByLongName("precision").getArgument(0).getValueAsDouble()); ASSERT_LT(std::abs(zValue - 5), storm::settings::Settings::getInstance()->getOptionByLongName("precision").getArgument(0).getValueAsDouble());
double objectiveValue = 0; double objectiveValue = 0;
ASSERT_NO_THROW(objectiveValue = solver.getObjectiveValue()); ASSERT_NO_THROW(objectiveValue = solver.getObjectiveValue());
@ -155,33 +144,30 @@ TEST(GurobiLpSolver, MILPOptimizeMin) {
TEST(GurobiLpSolver, LPInfeasible) { TEST(GurobiLpSolver, LPInfeasible) {
#ifdef STORM_HAVE_GUROBI #ifdef STORM_HAVE_GUROBI
storm::solver::GurobiLpSolver solver(storm::solver::LpSolver::MAXIMIZE); storm::solver::GurobiLpSolver solver(storm::solver::LpSolver::ModelSense::Maximize);
uint_fast64_t xIndex; ASSERT_NO_THROW(solver.addBoundedContinuousVariable("x", 0, 1, -1));
ASSERT_NO_THROW(xIndex = solver.createContinuousVariable("x", storm::solver::LpSolver::VariableType::BOUNDED, 0, 1, -1)); ASSERT_NO_THROW(solver.addLowerBoundedContinuousVariable("y", 0, 2));
uint_fast64_t yIndex; ASSERT_NO_THROW(solver.addLowerBoundedContinuousVariable("z", 0, 1));
ASSERT_NO_THROW(yIndex = solver.createContinuousVariable("y", storm::solver::LpSolver::VariableType::LOWER_BOUND, 0, 0, 2)); ASSERT_NO_THROW(solver.update());
uint_fast64_t zIndex; ASSERT_NO_THROW(solver.addConstraint("", storm::expressions::Expression::createDoubleVariable("x") + storm::expressions::Expression::createDoubleVariable("y") + storm::expressions::Expression::createDoubleVariable("z") <= storm::expressions::Expression::createDoubleLiteral(12)));
ASSERT_NO_THROW(zIndex = solver.createContinuousVariable("z", storm::solver::LpSolver::VariableType::LOWER_BOUND, 0, 0, 1)); ASSERT_NO_THROW(solver.addConstraint("", storm::expressions::Expression::createDoubleLiteral(0.5) * storm::expressions::Expression::createDoubleVariable("y") + storm::expressions::Expression::createDoubleVariable("z") - storm::expressions::Expression::createDoubleVariable("x") == storm::expressions::Expression::createDoubleLiteral(5)));
ASSERT_NO_THROW(solver.addConstraint("", storm::expressions::Expression::createDoubleVariable("y") - storm::expressions::Expression::createDoubleVariable("x") <= storm::expressions::Expression::createDoubleLiteral(5.5)));
ASSERT_NO_THROW(solver.update()); ASSERT_NO_THROW(solver.addConstraint("", storm::expressions::Expression::createDoubleVariable("y") > storm::expressions::Expression::createDoubleLiteral(7)));
ASSERT_NO_THROW(solver.update());
ASSERT_NO_THROW(solver.addConstraint("", {xIndex, yIndex, zIndex}, {1, 1, 1}, storm::solver::LpSolver::BoundType::LESS_EQUAL, 12));
ASSERT_NO_THROW(solver.addConstraint("", {yIndex, zIndex, xIndex}, {0.5, 1, -1}, storm::solver::LpSolver::BoundType::EQUAL, 5));
ASSERT_NO_THROW(solver.addConstraint("", {yIndex, xIndex}, {1, -1}, storm::solver::LpSolver::BoundType::LESS_EQUAL, 5.5));
ASSERT_NO_THROW(solver.addConstraint("", {yIndex}, {1}, storm::solver::LpSolver::BoundType::GREATER_EQUAL, 7));
ASSERT_NO_THROW(solver.optimize()); ASSERT_NO_THROW(solver.optimize());
ASSERT_FALSE(solver.isOptimal()); ASSERT_FALSE(solver.isOptimal());
ASSERT_FALSE(solver.isUnbounded()); ASSERT_FALSE(solver.isUnbounded());
ASSERT_TRUE(solver.isInfeasible()); ASSERT_TRUE(solver.isInfeasible());
double xValue = 0; double xValue = 0;
ASSERT_THROW(xValue = solver.getContinuousValue(xIndex), storm::exceptions::InvalidStateException); ASSERT_THROW(xValue = solver.getContinuousValue("x"), storm::exceptions::InvalidAccessException);
double yValue = 0; double yValue = 0;
ASSERT_THROW(yValue = solver.getContinuousValue(yIndex), storm::exceptions::InvalidStateException); ASSERT_THROW(yValue = solver.getContinuousValue("y"), storm::exceptions::InvalidAccessException);
double zValue = 0; double zValue = 0;
ASSERT_THROW(zValue = solver.getContinuousValue(zIndex), storm::exceptions::InvalidStateException); ASSERT_THROW(zValue = solver.getContinuousValue("z"), storm::exceptions::InvalidAccessException);
double objectiveValue = 0; double objectiveValue = 0;
ASSERT_THROW(objectiveValue = solver.getObjectiveValue(), storm::exceptions::InvalidStateException); ASSERT_THROW(objectiveValue = solver.getObjectiveValue(), storm::exceptions::InvalidAccessException);
#else #else
ASSERT_TRUE(false) << "StoRM built without Gurobi support."; ASSERT_TRUE(false) << "StoRM built without Gurobi support.";
#endif #endif
@ -189,33 +175,30 @@ TEST(GurobiLpSolver, LPInfeasible) {
TEST(GurobiLpSolver, MILPInfeasible) { TEST(GurobiLpSolver, MILPInfeasible) {
#ifdef STORM_HAVE_GUROBI #ifdef STORM_HAVE_GUROBI
storm::solver::GurobiLpSolver solver(storm::solver::LpSolver::MAXIMIZE); storm::solver::GurobiLpSolver solver(storm::solver::LpSolver::ModelSense::Maximize);
uint_fast64_t xIndex; ASSERT_NO_THROW(solver.addBinaryVariable("x", -1));
ASSERT_NO_THROW(xIndex = solver.createBinaryVariable("x", -1)); ASSERT_NO_THROW(solver.addLowerBoundedContinuousVariable("y", 0, 2));
uint_fast64_t yIndex; ASSERT_NO_THROW(solver.addLowerBoundedContinuousVariable("z", 0, 1));
ASSERT_NO_THROW(yIndex = solver.createIntegerVariable("y", storm::solver::LpSolver::VariableType::LOWER_BOUND, 0, 0, 2)); ASSERT_NO_THROW(solver.update());
uint_fast64_t zIndex; ASSERT_NO_THROW(solver.addConstraint("", storm::expressions::Expression::createDoubleVariable("x") + storm::expressions::Expression::createDoubleVariable("y") + storm::expressions::Expression::createDoubleVariable("z") <= storm::expressions::Expression::createDoubleLiteral(12)));
ASSERT_NO_THROW(zIndex = solver.createContinuousVariable("z", storm::solver::LpSolver::VariableType::LOWER_BOUND, 0, 0, 1)); ASSERT_NO_THROW(solver.addConstraint("", storm::expressions::Expression::createDoubleLiteral(0.5) * storm::expressions::Expression::createDoubleVariable("y") + storm::expressions::Expression::createDoubleVariable("z") - storm::expressions::Expression::createDoubleVariable("x") == storm::expressions::Expression::createDoubleLiteral(5)));
ASSERT_NO_THROW(solver.addConstraint("", storm::expressions::Expression::createDoubleVariable("y") - storm::expressions::Expression::createDoubleVariable("x") <= storm::expressions::Expression::createDoubleLiteral(5.5)));
ASSERT_NO_THROW(solver.update()); ASSERT_NO_THROW(solver.addConstraint("", storm::expressions::Expression::createDoubleVariable("y") > storm::expressions::Expression::createDoubleLiteral(7)));
ASSERT_NO_THROW(solver.update());
ASSERT_NO_THROW(solver.addConstraint("", {xIndex, yIndex, zIndex}, {1, 1, 1}, storm::solver::LpSolver::BoundType::LESS_EQUAL, 12));
ASSERT_NO_THROW(solver.addConstraint("", {yIndex, zIndex, xIndex}, {0.5, 1, -1}, storm::solver::LpSolver::BoundType::EQUAL, 5));
ASSERT_NO_THROW(solver.addConstraint("", {yIndex, xIndex}, {1, -1}, storm::solver::LpSolver::BoundType::LESS_EQUAL, 5.5));
ASSERT_NO_THROW(solver.addConstraint("", {yIndex}, {1}, storm::solver::LpSolver::BoundType::GREATER_EQUAL, 7));
ASSERT_NO_THROW(solver.optimize()); ASSERT_NO_THROW(solver.optimize());
ASSERT_FALSE(solver.isOptimal()); ASSERT_FALSE(solver.isOptimal());
ASSERT_FALSE(solver.isUnbounded()); ASSERT_FALSE(solver.isUnbounded());
ASSERT_TRUE(solver.isInfeasible()); ASSERT_TRUE(solver.isInfeasible());
bool xValue = false; bool xValue = false;
ASSERT_THROW(xValue = solver.getBinaryValue(xIndex), storm::exceptions::InvalidStateException); ASSERT_THROW(xValue = solver.getBinaryValue("x"), storm::exceptions::InvalidAccessException);
int_fast64_t yValue = 0; int_fast64_t yValue = 0;
ASSERT_THROW(yValue = solver.getIntegerValue(yIndex), storm::exceptions::InvalidStateException); ASSERT_THROW(yValue = solver.getIntegerValue("y"), storm::exceptions::InvalidAccessException);
double zValue = 0; double zValue = 0;
ASSERT_THROW(zValue = solver.getContinuousValue(zIndex), storm::exceptions::InvalidStateException); ASSERT_THROW(zValue = solver.getContinuousValue("z"), storm::exceptions::InvalidAccessException);
double objectiveValue = 0; double objectiveValue = 0;
ASSERT_THROW(objectiveValue = solver.getObjectiveValue(), storm::exceptions::InvalidStateException); ASSERT_THROW(objectiveValue = solver.getObjectiveValue(), storm::exceptions::InvalidAccessException);
#else #else
ASSERT_TRUE(false) << "StoRM built without Gurobi support."; ASSERT_TRUE(false) << "StoRM built without Gurobi support.";
#endif #endif
@ -223,31 +206,28 @@ TEST(GurobiLpSolver, MILPInfeasible) {
TEST(GurobiLpSolver, LPUnbounded) { TEST(GurobiLpSolver, LPUnbounded) {
#ifdef STORM_HAVE_GUROBI #ifdef STORM_HAVE_GUROBI
storm::solver::GurobiLpSolver solver(storm::solver::LpSolver::MAXIMIZE); storm::solver::GurobiLpSolver solver(storm::solver::LpSolver::ModelSense::Maximize);
uint_fast64_t xIndex; ASSERT_NO_THROW(solver.addBoundedContinuousVariable("x", 0, 1, -1));
ASSERT_NO_THROW(xIndex = solver.createContinuousVariable("x", storm::solver::LpSolver::VariableType::BOUNDED, 0, 1, -1)); ASSERT_NO_THROW(solver.addLowerBoundedContinuousVariable("y", 0, 2));
uint_fast64_t yIndex; ASSERT_NO_THROW(solver.addLowerBoundedContinuousVariable("z", 0, 1));
ASSERT_NO_THROW(yIndex = solver.createContinuousVariable("y", storm::solver::LpSolver::VariableType::LOWER_BOUND, 0, 0, 2)); ASSERT_NO_THROW(solver.update());
uint_fast64_t zIndex; ASSERT_NO_THROW(solver.addConstraint("", storm::expressions::Expression::createDoubleVariable("x") + storm::expressions::Expression::createDoubleVariable("y") - storm::expressions::Expression::createDoubleVariable("z") <= storm::expressions::Expression::createDoubleLiteral(12)));
ASSERT_NO_THROW(zIndex = solver.createContinuousVariable("z", storm::solver::LpSolver::VariableType::LOWER_BOUND, 0, 0, 1)); ASSERT_NO_THROW(solver.addConstraint("", storm::expressions::Expression::createDoubleVariable("y") - storm::expressions::Expression::createDoubleVariable("x") <= storm::expressions::Expression::createDoubleLiteral(5.5)));
ASSERT_NO_THROW(solver.update());
ASSERT_NO_THROW(solver.update());
ASSERT_NO_THROW(solver.addConstraint("", {xIndex, yIndex, zIndex}, {1, 1, -1}, storm::solver::LpSolver::BoundType::LESS_EQUAL, 12));
ASSERT_NO_THROW(solver.addConstraint("", {yIndex, xIndex}, {1, -1}, storm::solver::LpSolver::BoundType::LESS_EQUAL, 5.5));
ASSERT_NO_THROW(solver.optimize()); ASSERT_NO_THROW(solver.optimize());
ASSERT_FALSE(solver.isOptimal()); ASSERT_FALSE(solver.isOptimal());
ASSERT_TRUE(solver.isUnbounded()); ASSERT_TRUE(solver.isUnbounded());
ASSERT_FALSE(solver.isInfeasible()); ASSERT_FALSE(solver.isInfeasible());
double xValue = 0; double xValue = 0;
ASSERT_THROW(xValue = solver.getContinuousValue(xIndex), storm::exceptions::InvalidStateException); ASSERT_THROW(xValue = solver.getContinuousValue("x"), storm::exceptions::InvalidAccessException);
double yValue = 0; double yValue = 0;
ASSERT_THROW(yValue = solver.getContinuousValue(yIndex), storm::exceptions::InvalidStateException); ASSERT_THROW(yValue = solver.getContinuousValue("y"), storm::exceptions::InvalidAccessException);
double zValue = 0; double zValue = 0;
ASSERT_THROW(zValue = solver.getContinuousValue(zIndex), storm::exceptions::InvalidStateException); ASSERT_THROW(zValue = solver.getContinuousValue("z"), storm::exceptions::InvalidAccessException);
double objectiveValue = 0; double objectiveValue = 0;
ASSERT_THROW(objectiveValue = solver.getObjectiveValue(), storm::exceptions::InvalidStateException); ASSERT_THROW(objectiveValue = solver.getObjectiveValue(), storm::exceptions::InvalidAccessException);
#else #else
ASSERT_TRUE(false) << "StoRM built without Gurobi support."; ASSERT_TRUE(false) << "StoRM built without Gurobi support.";
#endif #endif
@ -255,32 +235,28 @@ TEST(GurobiLpSolver, LPUnbounded) {
TEST(GurobiLpSolver, MILPUnbounded) { TEST(GurobiLpSolver, MILPUnbounded) {
#ifdef STORM_HAVE_GUROBI #ifdef STORM_HAVE_GUROBI
storm::solver::GurobiLpSolver solver(storm::solver::LpSolver::MAXIMIZE); storm::solver::GurobiLpSolver solver(storm::solver::LpSolver::ModelSense::Maximize);
uint_fast64_t xIndex; ASSERT_NO_THROW(solver.addBinaryVariable("x", -1));
ASSERT_NO_THROW(xIndex = solver.createBinaryVariable("x", -1)); ASSERT_NO_THROW(solver.addLowerBoundedContinuousVariable("y", 0, 2));
uint_fast64_t yIndex; ASSERT_NO_THROW(solver.addLowerBoundedContinuousVariable("z", 0, 1));
ASSERT_NO_THROW(yIndex = solver.createIntegerVariable("y", storm::solver::LpSolver::VariableType::LOWER_BOUND, 0, 0, 2)); ASSERT_NO_THROW(solver.update());
uint_fast64_t zIndex;
ASSERT_NO_THROW(zIndex = solver.createContinuousVariable("z", storm::solver::LpSolver::VariableType::LOWER_BOUND, 0, 0, 1));
ASSERT_NO_THROW(solver.update());
ASSERT_NO_THROW(solver.addConstraint("", {xIndex, yIndex, zIndex}, {1, 1, -1}, storm::solver::LpSolver::BoundType::LESS_EQUAL, 12)); ASSERT_NO_THROW(solver.addConstraint("", storm::expressions::Expression::createDoubleVariable("x") + storm::expressions::Expression::createDoubleVariable("y") - storm::expressions::Expression::createDoubleVariable("z") <= storm::expressions::Expression::createDoubleLiteral(12)));
ASSERT_NO_THROW(solver.addConstraint("", {yIndex, xIndex}, {1, -1}, storm::solver::LpSolver::BoundType::LESS_EQUAL, 5.5)); ASSERT_NO_THROW(solver.addConstraint("", storm::expressions::Expression::createDoubleVariable("y") - storm::expressions::Expression::createDoubleVariable("x") <= storm::expressions::Expression::createDoubleLiteral(5.5)));
ASSERT_NO_THROW(solver.optimize()); ASSERT_NO_THROW(solver.optimize());
ASSERT_FALSE(solver.isOptimal()); ASSERT_FALSE(solver.isOptimal());
ASSERT_TRUE(solver.isUnbounded()); ASSERT_TRUE(solver.isUnbounded());
ASSERT_FALSE(solver.isInfeasible()); ASSERT_FALSE(solver.isInfeasible());
bool xValue = false; bool xValue = false;
ASSERT_THROW(xValue = solver.getBinaryValue(xIndex), storm::exceptions::InvalidStateException); ASSERT_THROW(xValue = solver.getBinaryValue("x"), storm::exceptions::InvalidAccessException);
int_fast64_t yValue = 0; int_fast64_t yValue = 0;
ASSERT_THROW(yValue = solver.getIntegerValue(yIndex), storm::exceptions::InvalidStateException); ASSERT_THROW(yValue = solver.getIntegerValue("y"), storm::exceptions::InvalidAccessException);
double zValue = 0; double zValue = 0;
ASSERT_THROW(zValue = solver.getContinuousValue(zIndex), storm::exceptions::InvalidStateException); ASSERT_THROW(zValue = solver.getContinuousValue("z"), storm::exceptions::InvalidAccessException);
double objectiveValue = 0; double objectiveValue = 0;
ASSERT_THROW(objectiveValue = solver.getObjectiveValue(), storm::exceptions::InvalidStateException); ASSERT_THROW(objectiveValue = solver.getObjectiveValue(), storm::exceptions::InvalidAccessException);
#else #else
ASSERT_TRUE(false) << "StoRM built without Gurobi support."; ASSERT_TRUE(false) << "StoRM built without Gurobi support.";
#endif #endif
} }

22
test/functional/storage/CuddDdTest.cpp

@ -307,4 +307,26 @@ TEST(CuddDd, ForwardIteratorTest) {
++numberOfValuations; ++numberOfValuations;
} }
EXPECT_EQ(9, numberOfValuations); EXPECT_EQ(9, numberOfValuations);
dd = manager->getRange("x");
dd = dd.ite(manager->getOne(), manager->getOne());
ASSERT_NO_THROW(it = dd.begin());
ASSERT_NO_THROW(ite = dd.end());
numberOfValuations = 0;
while (it != ite) {
ASSERT_NO_THROW(valuationValuePair = *it);
ASSERT_NO_THROW(++it);
++numberOfValuations;
}
EXPECT_EQ(16, numberOfValuations);
ASSERT_NO_THROW(it = dd.begin(false));
ASSERT_NO_THROW(ite = dd.end());
numberOfValuations = 0;
while (it != ite) {
ASSERT_NO_THROW(valuationValuePair = *it);
ASSERT_NO_THROW(++it);
++numberOfValuations;
}
EXPECT_EQ(1, numberOfValuations);
} }

17
test/functional/storage/ExpressionTest.cpp

@ -3,6 +3,7 @@
#include "gtest/gtest.h" #include "gtest/gtest.h"
#include "src/storage/expressions/Expression.h" #include "src/storage/expressions/Expression.h"
#include "src/storage/expressions/LinearityCheckVisitor.h"
#include "src/storage/expressions/SimpleValuation.h" #include "src/storage/expressions/SimpleValuation.h"
#include "src/exceptions/InvalidTypeException.h" #include "src/exceptions/InvalidTypeException.h"
@ -332,4 +333,20 @@ TEST(Expression, SimpleEvaluationTest) {
ASSERT_THROW(tempExpression.evaluateAsDouble(&valuation), storm::exceptions::InvalidTypeException); ASSERT_THROW(tempExpression.evaluateAsDouble(&valuation), storm::exceptions::InvalidTypeException);
ASSERT_THROW(tempExpression.evaluateAsInt(&valuation), storm::exceptions::InvalidTypeException); ASSERT_THROW(tempExpression.evaluateAsInt(&valuation), storm::exceptions::InvalidTypeException);
EXPECT_FALSE(tempExpression.evaluateAsBool(&valuation)); EXPECT_FALSE(tempExpression.evaluateAsBool(&valuation));
}
TEST(Expression, VisitorTest) {
storm::expressions::Expression threeExpression;
storm::expressions::Expression piExpression;
storm::expressions::Expression intVarExpression;
storm::expressions::Expression doubleVarExpression;
ASSERT_NO_THROW(threeExpression = storm::expressions::Expression::createIntegerLiteral(3));
ASSERT_NO_THROW(piExpression = storm::expressions::Expression::createDoubleLiteral(3.14));
ASSERT_NO_THROW(intVarExpression = storm::expressions::Expression::createIntegerVariable("y"));
ASSERT_NO_THROW(doubleVarExpression = storm::expressions::Expression::createDoubleVariable("z"));
storm::expressions::Expression tempExpression = intVarExpression + doubleVarExpression * threeExpression;
storm::expressions::LinearityCheckVisitor visitor;
EXPECT_TRUE(visitor.check(tempExpression));
} }

26
test/functional/storage/SparseMatrixTest.cpp

@ -147,7 +147,7 @@ TEST(SparseMatrix, Build) {
} }
TEST(SparseMatrix, CreationWithMovingContents) { TEST(SparseMatrix, CreationWithMovingContents) {
std::vector<std::pair<uint_fast64_t, double>> columnsAndValues; std::vector<storm::storage::MatrixEntry<double>> columnsAndValues;
columnsAndValues.emplace_back(1, 1.0); columnsAndValues.emplace_back(1, 1.0);
columnsAndValues.emplace_back(2, 1.2); columnsAndValues.emplace_back(2, 1.2);
columnsAndValues.emplace_back(0, 0.5); columnsAndValues.emplace_back(0, 0.5);
@ -540,24 +540,24 @@ TEST(SparseMatrix, Iteration) {
ASSERT_NO_THROW(matrix = matrixBuilder.build()); ASSERT_NO_THROW(matrix = matrixBuilder.build());
for (auto const& entry : matrix.getRow(4)) { for (auto const& entry : matrix.getRow(4)) {
if (entry.first == 0) { if (entry.getColumn() == 0) {
ASSERT_EQ(0.1, entry.second); ASSERT_EQ(0.1, entry.getValue());
} else if (entry.first == 1) { } else if (entry.getColumn() == 1) {
ASSERT_EQ(0.2, entry.second); ASSERT_EQ(0.2, entry.getValue());
} else if (entry.first == 3) { } else if (entry.getColumn() == 3) {
ASSERT_EQ(0.3, entry.second); ASSERT_EQ(0.3, entry.getValue());
} else { } else {
ASSERT_TRUE(false); ASSERT_TRUE(false);
} }
} }
for (storm::storage::SparseMatrix<double>::iterator it = matrix.begin(4), ite = matrix.end(4); it != ite; ++it) { for (storm::storage::SparseMatrix<double>::iterator it = matrix.begin(4), ite = matrix.end(4); it != ite; ++it) {
if (it->first == 0) { if (it->getColumn() == 0) {
ASSERT_EQ(0.1, it->second); ASSERT_EQ(0.1, it->getValue());
} else if (it->first == 1) { } else if (it->getColumn() == 1) {
ASSERT_EQ(0.2, it->second); ASSERT_EQ(0.2, it->getValue());
} else if (it->first == 3) { } else if (it->getColumn() == 3) {
ASSERT_EQ(0.3, it->second); ASSERT_EQ(0.3, it->getValue());
} else { } else {
ASSERT_TRUE(false); ASSERT_TRUE(false);
} }

4
test/performance/modelchecker/GmmxxDtmcPrctModelCheckerTest.cpp

@ -17,7 +17,7 @@ TEST(GmmxxDtmcPrctlModelCheckerTest, Crowds) {
std::shared_ptr<storm::models::Dtmc<double>> dtmc = abstractModel->as<storm::models::Dtmc<double>>(); std::shared_ptr<storm::models::Dtmc<double>> dtmc = abstractModel->as<storm::models::Dtmc<double>>();
ASSERT_EQ(dtmc->getNumberOfStates(), 2036647ull); ASSERT_EQ(dtmc->getNumberOfStates(), 2036647ull);
ASSERT_EQ(dtmc->getNumberOfTransitions(), 8973900ull); ASSERT_EQ(dtmc->getNumberOfTransitions(), 7362293ull);
storm::modelchecker::prctl::SparseDtmcPrctlModelChecker<double> mc(*dtmc, new storm::solver::GmmxxLinearEquationSolver<double>()); storm::modelchecker::prctl::SparseDtmcPrctlModelChecker<double> mc(*dtmc, new storm::solver::GmmxxLinearEquationSolver<double>());
@ -71,7 +71,7 @@ TEST(GmmxxDtmcPrctlModelCheckerTest, SynchronousLeader) {
std::shared_ptr<storm::models::Dtmc<double>> dtmc = abstractModel->as<storm::models::Dtmc<double>>(); std::shared_ptr<storm::models::Dtmc<double>> dtmc = abstractModel->as<storm::models::Dtmc<double>>();
ASSERT_EQ(dtmc->getNumberOfStates(), 1312334ull); ASSERT_EQ(dtmc->getNumberOfStates(), 1312334ull);
ASSERT_EQ(dtmc->getNumberOfTransitions(), 2886810ull); ASSERT_EQ(dtmc->getNumberOfTransitions(), 1574477ull);
storm::modelchecker::prctl::SparseDtmcPrctlModelChecker<double> mc(*dtmc, new storm::solver::GmmxxLinearEquationSolver<double>()); storm::modelchecker::prctl::SparseDtmcPrctlModelChecker<double> mc(*dtmc, new storm::solver::GmmxxLinearEquationSolver<double>());

2
test/performance/storage/SparseMatrixTest.cpp

@ -15,7 +15,7 @@ TEST(SparseMatrix, Iteration) {
for (uint_fast64_t row = 0; row < matrix.getRowCount(); ++row) { for (uint_fast64_t row = 0; row < matrix.getRowCount(); ++row) {
for (auto const& entry : matrix.getRow(row)) { for (auto const& entry : matrix.getRow(row)) {
// The following can never be true, but prevents the compiler from optimizing away the loop. // The following can never be true, but prevents the compiler from optimizing away the loop.
if (entry.first > matrix.getColumnCount()) { if (entry.getColumn() > matrix.getColumnCount()) {
ASSERT_TRUE(false); ASSERT_TRUE(false);
} }
} }

|||||||
100:0
Loading…
Cancel
Save