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());
for (auto const& entry : matrix) {
columns.emplace_back(entry.first);
values.emplace_back(entry.second);
columns.emplace_back(entry.getColumn());
values.emplace_back(entry.getValue());
}
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.
*/
struct VariableInformation {
std::unordered_map<uint_fast64_t, uint_fast64_t> labelToVariableIndexMap;
std::unordered_map<uint_fast64_t, std::list<uint_fast64_t>> stateToChoiceVariablesIndexMap;
std::unordered_map<uint_fast64_t, uint_fast64_t> initialStateToChoiceVariableIndexMap;
std::unordered_map<uint_fast64_t, uint_fast64_t> stateToProbabilityVariableIndexMap;
uint_fast64_t virtualInitialStateVariableIndex;
std::unordered_map<uint_fast64_t, uint_fast64_t> problematicStateToVariableIndexMap;
std::unordered_map<std::pair<uint_fast64_t, uint_fast64_t>, uint_fast64_t, PairHash> problematicTransitionToVariableIndexMap;
std::unordered_map<uint_fast64_t, std::string> labelToVariableMap;
std::unordered_map<uint_fast64_t, std::list<std::string>> stateToChoiceVariablesMap;
std::unordered_map<uint_fast64_t, std::string> initialStateToChoiceVariableMap;
std::unordered_map<uint_fast64_t, std::string> stateToProbabilityVariableMap;
std::string virtualInitialStateVariable;
std::unordered_map<uint_fast64_t, std::string> problematicStateToVariableMap;
std::unordered_map<std::pair<uint_fast64_t, uint_fast64_t>, std::string, PairHash> problematicTransitionToVariableMap;
uint_fast64_t numberOfVariables;
VariableInformation() : numberOfVariables(0) {}
@ -130,7 +130,7 @@ namespace storm {
bool allSuccessorsProblematic = true;
for (auto const& successorEntry : transitionMatrix.getRow(row)) {
// 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]) {
result.allRelevantLabels.insert(label);
}
@ -139,7 +139,7 @@ namespace storm {
result.relevantChoicesForRelevantStates[state].push_back(row);
}
}
if (!stateInformation.problematicStates.get(successorEntry.first)) {
if (!stateInformation.problematicStates.get(successorEntry.getColumn())) {
allSuccessorsProblematic = false;
}
}
@ -167,14 +167,15 @@ namespace storm {
* @param relevantLabels The set of relevant labels of the model.
* @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::unordered_map<uint_fast64_t, uint_fast64_t> resultingMap;
std::unordered_map<uint_fast64_t, std::string> resultingMap;
for (auto const& label : relevantLabels) {
variableNameBuffer.str("");
variableNameBuffer.clear();
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());
}
@ -187,19 +188,20 @@ namespace storm {
* @param choiceInformation The information about the choices of the model.
* @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;
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) {
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);
for (uint_fast64_t row : relevantChoicesForState) {
variableNameBuffer.str("");
variableNameBuffer.clear();
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;
}
}
@ -215,10 +217,10 @@ namespace storm {
* @param stateInformation The information about the states of the model.
* @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;
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")) {
// Only consider this initial state if it is relevant.
@ -226,7 +228,8 @@ namespace storm {
variableNameBuffer.str("");
variableNameBuffer.clear();
variableNameBuffer << "init" << initialState;
resultingMap[initialState] = solver.createBinaryVariable(variableNameBuffer.str(), 0);
resultingMap[initialState] = variableNameBuffer.str();
solver.addBinaryVariable(resultingMap[initialState]);
++numberOfVariablesCreated;
}
}
@ -240,34 +243,36 @@ namespace storm {
* @param stateInformation The information about the states in the model.
* @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;
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) {
variableNameBuffer.str("");
variableNameBuffer.clear();
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;
}
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 maximizeProbability If set to true, the objective function is constructed in a way that a
* label-minimal subsystem of maximal probability is computed.
* @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;
variableNameBuffer << "pinit";
return std::make_pair(solver.createContinuousVariable(variableNameBuffer.str(), storm::solver::LpSolver::BOUNDED, 0, 1, 0), 1);
std::string variableName = variableNameBuffer.str();
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.
* @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;
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) {
// 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.clear();
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;
}
std::list<uint_fast64_t> const& relevantChoicesForState = choiceInformation.relevantChoicesForRelevantStates.at(state);
for (uint_fast64_t row : relevantChoicesForState) {
for (auto const& successorEntry : labeledMdp.getTransitionMatrix().getRow(row)) {
if (stateInformation.relevantStates.get(successorEntry.first)) {
if (resultingMap.find(successorEntry.first) == resultingMap.end()) {
if (stateInformation.relevantStates.get(successorEntry.getColumn())) {
if (resultingMap.find(successorEntry.getColumn()) == resultingMap.end()) {
variableNameBuffer.str("");
variableNameBuffer.clear();
variableNameBuffer << "r" << successorEntry.first;
resultingMap[state] = solver.createContinuousVariable(variableNameBuffer.str(), storm::solver::LpSolver::BOUNDED, 0, 1, 0);
variableNameBuffer << "r" << successorEntry.getColumn();
resultingMap[successorEntry.getColumn()] = variableNameBuffer.str();
solver.addBoundedContinuousVariable(resultingMap[successorEntry.getColumn()], 0, 1);
++numberOfVariablesCreated;
}
}
@ -321,20 +328,21 @@ namespace storm {
* @param choiceInformation The information about the choices in the model.
* @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;
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) {
std::list<uint_fast64_t> const& relevantChoicesForState = choiceInformation.relevantChoicesForRelevantStates.at(state);
for (uint_fast64_t row : relevantChoicesForState) {
for (auto const& successorEntry : labeledMdp.getTransitionMatrix().getRow(row)) {
if (stateInformation.relevantStates.get(successorEntry.first)) {
if (stateInformation.relevantStates.get(successorEntry.getColumn())) {
variableNameBuffer.str("");
variableNameBuffer.clear();
variableNameBuffer << "t" << state << "to" << successorEntry.first;
resultingMap[std::make_pair(state, successorEntry.first)] = solver.createBinaryVariable(variableNameBuffer.str(), 0);
variableNameBuffer << "t" << state << "to" << successorEntry.getColumn();
resultingMap[std::make_pair(state, successorEntry.getColumn())] = variableNameBuffer.str();
solver.addBinaryVariable(resultingMap[std::make_pair(state, successorEntry.getColumn())]);
++numberOfVariablesCreated;
}
}
@ -358,44 +366,44 @@ namespace storm {
VariableInformation result;
// Create variables for involved labels.
std::pair<std::unordered_map<uint_fast64_t, uint_fast64_t>, uint_fast64_t> labelVariableResult = createLabelVariables(solver, choiceInformation.allRelevantLabels);
result.labelToVariableIndexMap = std::move(labelVariableResult.first);
std::pair<std::unordered_map<uint_fast64_t, std::string>, uint_fast64_t> labelVariableResult = createLabelVariables(solver, choiceInformation.allRelevantLabels);
result.labelToVariableMap = std::move(labelVariableResult.first);
result.numberOfVariables += labelVariableResult.second;
LOG4CPLUS_DEBUG(logger, "Created variables for labels.");
// 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);
result.stateToChoiceVariablesIndexMap = std::move(schedulerVariableResult.first);
std::pair<std::unordered_map<uint_fast64_t, std::list<std::string>>, uint_fast64_t> schedulerVariableResult = createSchedulerVariables(solver, stateInformation, choiceInformation);
result.stateToChoiceVariablesMap = std::move(schedulerVariableResult.first);
result.numberOfVariables += schedulerVariableResult.second;
LOG4CPLUS_DEBUG(logger, "Created variables for nondeterministic choices.");
// 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);
result.initialStateToChoiceVariableIndexMap = std::move(initialChoiceVariableResult.first);
std::pair<std::unordered_map<uint_fast64_t, std::string>, uint_fast64_t> initialChoiceVariableResult = createInitialChoiceVariables(solver, labeledMdp, stateInformation);
result.initialStateToChoiceVariableMap = std::move(initialChoiceVariableResult.first);
result.numberOfVariables += initialChoiceVariableResult.second;
LOG4CPLUS_DEBUG(logger, "Created variables for the nondeterministic choice of the initial state.");
// 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);
result.stateToProbabilityVariableIndexMap = std::move(probabilityVariableResult.first);
std::pair<std::unordered_map<uint_fast64_t, std::string>, uint_fast64_t> probabilityVariableResult = createProbabilityVariables(solver, stateInformation);
result.stateToProbabilityVariableMap = std::move(probabilityVariableResult.first);
result.numberOfVariables += probabilityVariableResult.second;
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.
std::pair<uint_fast64_t, uint_fast64_t> virtualInitialStateVariableResult = createVirtualInitialStateVariable(solver);
result.virtualInitialStateVariableIndex = virtualInitialStateVariableResult.first;
std::pair<std::string, uint_fast64_t> virtualInitialStateVariableResult = createVirtualInitialStateVariable(solver);
result.virtualInitialStateVariable = virtualInitialStateVariableResult.first;
result.numberOfVariables += virtualInitialStateVariableResult.second;
LOG4CPLUS_DEBUG(logger, "Created variables for the virtual initial state.");
// 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);
result.problematicStateToVariableIndexMap = std::move(problematicStateVariableResult.first);
std::pair<std::unordered_map<uint_fast64_t, std::string>, uint_fast64_t> problematicStateVariableResult = createProblematicStateVariables(solver, labeledMdp, stateInformation, choiceInformation);
result.problematicStateToVariableMap = std::move(problematicStateVariableResult.first);
result.numberOfVariables += problematicStateVariableResult.second;
LOG4CPLUS_DEBUG(logger, "Created variables for the problematic states.");
// 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);
result.problematicTransitionToVariableIndexMap = problematicTransitionVariableResult.first;
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.problematicTransitionToVariableMap = problematicTransitionVariableResult.first;
result.numberOfVariables += problematicTransitionVariableResult.second;
LOG4CPLUS_DEBUG(logger, "Created variables for the problematic choices.");
@ -419,7 +427,13 @@ namespace storm {
* @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) {
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;
}
@ -435,28 +449,28 @@ namespace storm {
// Assert that the policy chooses at most one action in each state of the system.
uint_fast64_t numberOfConstraintsCreated = 0;
for (auto state : stateInformation.relevantStates) {
std::list<uint_fast64_t> const& choiceVariableIndices = variableInformation.stateToChoiceVariablesIndexMap.at(state);
std::vector<uint_fast64_t> variables;
std::vector<double> coefficients(choiceVariableIndices.size(), 1);
variables.reserve(choiceVariableIndices.size());
for (auto choiceVariableIndex : choiceVariableIndices) {
variables.push_back(choiceVariableIndex);
std::list<std::string> const& choiceVariableIndices = variableInformation.stateToChoiceVariablesMap.at(state);
storm::expressions::Expression constraint = storm::expressions::Expression::createDoubleLiteral(0);
for (auto const& choiceVariable : choiceVariableIndices) {
constraint = constraint + storm::expressions::Expression::createIntegerVariable(choiceVariable);
}
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;
}
// Now assert that the virtual initial state picks exactly one initial state from the system as its
// successor state.
std::vector<uint_fast64_t> variables;
variables.reserve(variableInformation.initialStateToChoiceVariableIndexMap.size());
std::vector<double> coefficients(variableInformation.initialStateToChoiceVariableIndexMap.size(), 1);
for (auto initialStateVariableIndexPair : variableInformation.initialStateToChoiceVariableIndexMap) {
variables.push_back(initialStateVariableIndexPair.second);
storm::expressions::Expression constraint = storm::expressions::Expression::createDoubleLiteral(0);
for (auto const& initialStateVariablePair : variableInformation.initialStateToChoiceVariableMap) {
constraint = constraint + storm::expressions::Expression::createIntegerVariable(initialStateVariablePair.second);
}
constraint = constraint == storm::expressions::Expression::createDoubleLiteral(1);
solver.addConstraint("VirtualInitialStateChoosesOneInitialState", variables, coefficients, storm::solver::LpSolver::EQUAL, 1);
solver.addConstraint("VirtualInitialStateChoosesOneInitialState", constraint);
++numberOfConstraintsCreated;
return numberOfConstraintsCreated;
@ -478,13 +492,14 @@ namespace storm {
std::vector<boost::container::flat_set<uint_fast64_t>> const& choiceLabeling = labeledMdp.getChoiceLabeling();
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 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;
}
++choiceVariableIndicesIterator;
++choiceVariableIterator;
}
}
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) {
uint_fast64_t numberOfConstraintsCreated = 0;
for (auto state : stateInformation.relevantStates) {
std::list<uint_fast64_t> const& choiceVariableIndices = variableInformation.stateToChoiceVariablesIndexMap.at(state);
std::vector<double> coefficients(choiceVariableIndices.size() + 1, -1);
coefficients[0] = 1;
std::vector<uint_fast64_t> variables;
variables.reserve(variableInformation.stateToChoiceVariablesIndexMap.at(state).size() + 1);
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);
storm::expressions::Expression constraint = storm::expressions::Expression::createDoubleVariable(variableInformation.stateToProbabilityVariableMap.at(state));
for (auto const& choiceVariable : variableInformation.stateToChoiceVariablesMap.at(state)) {
constraint = constraint - storm::expressions::Expression::createIntegerVariable(choiceVariable);
}
constraint = constraint <= storm::expressions::Expression::createDoubleLiteral(0);
solver.addConstraint("ProbabilityIsZeroIfNoAction" + std::to_string(numberOfConstraintsCreated), constraint);
++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) {
uint_fast64_t numberOfConstraintsCreated = 0;
for (auto state : stateInformation.relevantStates) {
std::vector<double> coefficients;
std::vector<uint_fast64_t> variables;
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)) {
variables.clear();
coefficients.clear();
variables.push_back(variableInformation.stateToProbabilityVariableIndexMap.at(state));
coefficients.push_back(1.0);
storm::expressions::Expression constraint = storm::expressions::Expression::createDoubleVariable(variableInformation.stateToProbabilityVariableMap.at(state));
double rightHandSide = 1;
for (auto const& successorEntry : labeledMdp.getTransitionMatrix().getRow(choice)) {
if (stateInformation.relevantStates.get(successorEntry.first)) {
variables.push_back(static_cast<int>(variableInformation.stateToProbabilityVariableIndexMap.at(successorEntry.first)));
coefficients.push_back(-successorEntry.second);
} else if (psiStates.get(successorEntry.first)) {
rightHandSide += successorEntry.second;
if (stateInformation.relevantStates.get(successorEntry.getColumn())) {
constraint = constraint - storm::expressions::Expression::createDoubleLiteral(successorEntry.getValue()) * storm::expressions::Expression::createDoubleVariable(variableInformation.stateToProbabilityVariableMap.at(successorEntry.getColumn()));
} else if (psiStates.get(successorEntry.getColumn())) {
rightHandSide += successorEntry.getValue();
}
}
coefficients.push_back(1);
variables.push_back(*choiceVariableIndicesIterator);
solver.addConstraint("ReachabilityProbabilities" + std::to_string(numberOfConstraintsCreated), variables, coefficients, storm::solver::LpSolver::LESS_EQUAL, rightHandSide);
constraint = constraint + storm::expressions::Expression::createIntegerVariable(*choiceVariableIterator) <= storm::expressions::Expression::createDoubleLiteral(rightHandSide);
solver.addConstraint("ReachabilityProbabilities" + std::to_string(numberOfConstraintsCreated), constraint);
++numberOfConstraintsCreated;
++choiceVariableIndicesIterator;
++choiceVariableIterator;
}
}
// Make sure that the virtual initial state is being assigned the probability from the initial state
// that it selected as a successor state.
for (auto initialStateVariableIndexPair : variableInformation.initialStateToChoiceVariableIndexMap) {
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);
for (auto const& initialStateVariablePair : variableInformation.initialStateToChoiceVariableMap) {
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;
}
@ -587,44 +590,34 @@ namespace storm {
for (auto stateListPair : choiceInformation.problematicChoicesForProblematicStates) {
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)) {
if (relevantChoice == problematicChoice) {
break;
}
++choiceVariableIndicesIterator;
++choiceVariableIterator;
}
std::vector<uint_fast64_t> variables;
std::vector<double> coefficients;
variables.push_back(*choiceVariableIndicesIterator);
coefficients.push_back(1);
storm::expressions::Expression constraint = storm::expressions::Expression::createDoubleVariable(*choiceVariableIterator);
for (auto const& successorEntry : labeledMdp.getTransitionMatrix().getRow(problematicChoice)) {
variables.push_back(variableInformation.problematicTransitionToVariableIndexMap.at(std::make_pair(stateListPair.first, successorEntry.first)));
coefficients.push_back(-1);
constraint = constraint - storm::expressions::Expression::createDoubleVariable(variableInformation.problematicTransitionToVariableMap.at(std::make_pair(stateListPair.first, successorEntry.getColumn())));
}
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;
}
}
for (auto state : stateInformation.problematicStates) {
for (auto problematicChoice : choiceInformation.problematicChoicesForProblematicStates.at(state)) {
for (auto const& successorEntry : labeledMdp.getTransitionMatrix().getRow(state)) {
std::vector<uint_fast64_t> variables;
std::vector<double> coefficients;
variables.push_back(variableInformation.problematicStateToVariableIndexMap.at(state));
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);
for (auto const& successorEntry : labeledMdp.getTransitionMatrix().getRow(problematicChoice)) {
storm::expressions::Expression constraint = storm::expressions::Expression::createDoubleVariable(variableInformation.problematicStateToVariableMap.at(state));
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())));
constraint = constraint < storm::expressions::Expression::createDoubleLiteral(1);
solver.addConstraint("UnproblematicStateReachable" + std::to_string(numberOfConstraintsCreated), variables, coefficients, storm::solver::LpSolver::LESS, 1);
solver.addConstraint("UnproblematicStateReachable" + std::to_string(numberOfConstraintsCreated), constraint);
++numberOfConstraintsCreated;
}
}
@ -646,7 +639,8 @@ namespace storm {
uint_fast64_t numberOfConstraintsCreated = 0;
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;
}
@ -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) {
storm::storage::SparseMatrix<T> backwardTransitions = labeledMdp.getBackwardTransitions();
uint_fast64_t numberOfConstraintsCreated = 0;
std::vector<uint_fast64_t> variables;
std::vector<double> coefficients;
for (auto state : stateInformation.relevantStates) {
// 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.
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)) {
bool psiStateReachableInOneStep = false;
for (auto const& successorEntry : labeledMdp.getTransitionMatrix().getRow(choice)) {
if (psiStates.get(successorEntry.first)) {
if (psiStates.get(successorEntry.getColumn())) {
psiStateReachableInOneStep = true;
}
}
if (!psiStateReachableInOneStep) {
variables.clear();
coefficients.clear();
variables.push_back(static_cast<int>(*choiceVariableIndicesIterator));
coefficients.push_back(1);
storm::expressions::Expression constraint = storm::expressions::Expression::createDoubleVariable(*choiceVariableIterator);
for (auto const& successorEntry : labeledMdp.getTransitionMatrix().getRow(choice)) {
if (state != successorEntry.first && stateInformation.relevantStates.get(successorEntry.first)) {
std::list<uint_fast64_t> const& successorChoiceVariableIndices = variableInformation.stateToChoiceVariablesIndexMap.at(successorEntry.first);
if (state != successorEntry.getColumn() && stateInformation.relevantStates.get(successorEntry.getColumn())) {
std::list<std::string> const& successorChoiceVariableIndices = variableInformation.stateToChoiceVariablesMap.at(successorEntry.getColumn());
for (auto choiceVariableIndex : successorChoiceVariableIndices) {
variables.push_back(choiceVariableIndex);
coefficients.push_back(-1);
for (auto const& choiceVariable : successorChoiceVariableIndices) {
constraint = constraint - storm::expressions::Expression::createDoubleVariable(choiceVariable);
}
}
}
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;
}
++choiceVariableIndicesIterator;
++choiceVariableIterator;
}
// 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.
variables.clear();
coefficients.clear();
for (auto choiceVariableIndex : variableInformation.stateToChoiceVariablesIndexMap.at(state)) {
variables.push_back(choiceVariableIndex);
coefficients.push_back(1);
storm::expressions::Expression constraint = storm::expressions::Expression::createDoubleLiteral(0);
for (auto const& choiceVariable : variableInformation.stateToChoiceVariablesMap.at(state)) {
constraint = constraint + storm::expressions::Expression::createDoubleVariable(choiceVariable);
}
// Compute the set of predecessors.
std::unordered_set<uint_fast64_t> predecessors;
for (auto const& predecessorEntry : backwardTransitions.getRow(state)) {
if (state != predecessorEntry.first) {
predecessors.insert(predecessorEntry.first);
if (state != predecessorEntry.getColumn()) {
predecessors.insert(predecessorEntry.getColumn());
}
}
@ -731,13 +716,13 @@ namespace storm {
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)) {
bool choiceTargetsCurrentState = false;
// Check if the current choice targets the current state.
for (auto const& successorEntry : labeledMdp.getTransitionMatrix().getRow(relevantChoice)) {
if (state == successorEntry.first) {
if (state == successorEntry.getColumn()) {
choiceTargetsCurrentState = true;
break;
}
@ -745,45 +730,42 @@ namespace storm {
// If it does, we can add the choice to the sum.
if (choiceTargetsCurrentState) {
variables.push_back(static_cast<int>(*choiceVariableIndicesIterator));
coefficients.push_back(-1);
constraint = constraint - storm::expressions::Expression::createDoubleVariable(*choiceVariableIterator);
}
++choiceVariableIndicesIterator;
++choiceVariableIterator;
}
}
// 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.
if (labeledMdp.getLabeledStates("init").get(state)) {
variables.push_back(variableInformation.initialStateToChoiceVariableIndexMap.at(state));
coefficients.push_back(-1);
constraint = constraint - storm::expressions::Expression::createDoubleVariable(variableInformation.initialStateToChoiceVariableMap.at(state));
}
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;
}
// Assert that at least one initial state selects at least one action.
variables.clear();
coefficients.clear();
storm::expressions::Expression constraint = storm::expressions::Expression::createDoubleLiteral(0);
for (auto initialState : labeledMdp.getLabeledStates("init")) {
for (auto choiceVariableIndex : variableInformation.stateToChoiceVariablesIndexMap.at(initialState)) {
variables.push_back(choiceVariableIndex);
coefficients.push_back(1);
for (auto const& choiceVariable : variableInformation.stateToChoiceVariablesMap.at(initialState)) {
constraint = constraint + storm::expressions::Expression::createDoubleVariable(choiceVariable);
}
}
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;
// Add constraints that ensure at least one choice is selected that targets a psi state.
variables.clear();
coefficients.clear();
constraint = storm::expressions::Expression::createDoubleLiteral(0);
std::unordered_set<uint_fast64_t> predecessors;
for (auto psiState : psiStates) {
// Compute the set of predecessors.
for (auto const& predecessorEntry : backwardTransitions.getRow(psiState)) {
if (psiState != predecessorEntry.first) {
predecessors.insert(predecessorEntry.first);
if (psiState != predecessorEntry.getColumn()) {
predecessors.insert(predecessorEntry.getColumn());
}
}
}
@ -794,13 +776,13 @@ namespace storm {
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)) {
bool choiceTargetsPsiState = false;
// Check if the current choice targets the current state.
for (auto const& successorEntry : labeledMdp.getTransitionMatrix().getRow(relevantChoice)) {
if (psiStates.get(successorEntry.first)) {
if (psiStates.get(successorEntry.getColumn())) {
choiceTargetsPsiState = true;
break;
}
@ -808,14 +790,14 @@ namespace storm {
// If it does, we can add the choice to the sum.
if (choiceTargetsPsiState) {
variables.push_back(*choiceVariableIndicesIterator);
coefficients.push_back(1);
constraint = constraint + storm::expressions::Expression::createDoubleVariable(*choiceVariableIterator);
}
++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;
return numberOfConstraintsCreated;
@ -872,6 +854,9 @@ namespace storm {
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.");
}
@ -884,7 +869,7 @@ namespace storm {
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;
for (auto labelVariablePair : variableInformation.labelToVariableIndexMap) {
for (auto const& labelVariablePair : variableInformation.labelToVariableMap) {
bool labelTaken = solver.getBinaryValue(labelVariablePair.second);
if (labelTaken) {
@ -908,10 +893,10 @@ namespace storm {
std::map<uint_fast64_t, uint_fast64_t> result;
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)) {
bool choiceTaken = solver.getBinaryValue(*choiceVariableIndicesIterator);
++choiceVariableIndicesIterator;
bool choiceTaken = solver.getBinaryValue(*choiceVariableIterator);
++choiceVariableIterator;
if (choiceTaken) {
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) {
uint_fast64_t selectedInitialState = 0;
for (auto initialStateVariableIndexPair : variableInformation.initialStateToChoiceVariableIndexMap) {
bool initialStateChosen = solver.getBinaryValue(initialStateVariableIndexPair.second);
for (auto const& initialStateVariablePair : variableInformation.initialStateToChoiceVariableMap) {
bool initialStateChosen = solver.getBinaryValue(initialStateVariablePair.second);
if (initialStateChosen) {
selectedInitialState = initialStateVariableIndexPair.first;
selectedInitialState = initialStateVariablePair.first;
break;
}
}
double reachabilityProbability = solver.getContinuousValue(variableInformation.virtualInitialStateVariableIndex);
double reachabilityProbability = solver.getContinuousValue(variableInformation.virtualInitialStateVariable);
return std::make_pair(selectedInitialState, reachabilityProbability);
}
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) {
// (0) Check whether the MDP is indeed labeled.
if (!labeledMdp.hasChoiceLabeling()) {

144
src/counterexamples/PathBasedSubsystemGenerator.h

@ -69,31 +69,31 @@ public:
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.
if(trans.second != (T) 0 && !subSysStates.get(trans.first)) {
if(trans.getValue() != (T) 0 && !subSysStates.get(trans.getColumn())) {
//new state?
if(distances[trans.first].second == (T) -1) {
distances[trans.first].first = init;
distances[trans.first].second = trans.second;
if(distances[trans.getColumn()].second == (T) -1) {
distances[trans.getColumn()].first = init;
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
//And the distance can be improved by using this transition.
//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++) {
if(trans.first == range.first->first) {
if(trans.getColumn() == range.first->first) {
activeSet.erase(range.first);
break;
}
}
distances[trans.first].first = init;
distances[trans.first].second = trans.second;
distances[trans.getColumn()].first = init;
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
for(auto const& trans : transMat.getRow(activeState.first)) {
// 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
if(distances[trans.first].second == (T)-1) {
if(distances[trans.getColumn()].second == (T)-1) {
//New state discovered -> save it
distances[trans.first].first = activeState.first;
distances[trans.first].second = distance;
distances[trans.getColumn()].first = activeState.first;
distances[trans.getColumn()].second = distance;
// 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
//And the distance can be improved by using this transition.
//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++) {
if(trans.first == range.first->first) {
if(trans.getColumn() == range.first->first) {
activeSet.erase(range.first);
break;
}
}
distances[trans.first].first = activeState.first;
distances[trans.first].second = distance;
activeSet.insert(std::pair<uint_fast64_t, T>(trans.first, distance));
distances[trans.getColumn()].first = activeState.first;
distances[trans.getColumn()].second = distance;
activeSet.insert(std::pair<uint_fast64_t, T>(trans.getColumn(), distance));
}
}
}
@ -182,33 +182,33 @@ public:
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.
if(trans.second != (T) 0 && !subSysStates.get(trans.first)) {
if(trans.getValue() != (T) 0 && !subSysStates.get(trans.getColumn())) {
//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)
distances[trans.first].first = init;
distances[trans.first].second = trans.second * (itDistances[init].second == -1 ? 1 : itDistances[init].second);
distances[trans.getColumn()].first = init;
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
//And the distance can be improved by using this transition.
//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++) {
if(trans.first == range.first->first) {
if(trans.getColumn() == range.first->first) {
activeSet.erase(range.first);
break;
}
}
//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.first].second = trans.second * (itDistances[init].second == -1 ? 1 : itDistances[init].second);
distances[trans.getColumn()].first = init;
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());
// 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
// 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
for(auto const& trans : transMat.getRow(activeState.first)) {
// 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
if(distances[trans.first].second == (T)-1) {
if(distances[trans.getColumn()].second == (T)-1) {
//New state discovered -> save it
distances[trans.first].first = activeState.first;
distances[trans.first].second = distance;
distances[trans.getColumn()].first = activeState.first;
distances[trans.getColumn()].second = distance;
// 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
//And the distance can be improved by using this transition.
//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++) {
if(trans.first == range.first->first) {
if(trans.getColumn() == range.first->first) {
activeSet.erase(range.first);
break;
}
}
distances[trans.first].first = activeState.first;
distances[trans.first].second = distance;
activeSet.insert(std::pair<uint_fast64_t, T>(trans.first, distance));
distances[trans.getColumn()].first = activeState.first;
distances[trans.getColumn()].second = 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(initStates.get(*target)){
distances[*target].first = *target;
distances[*target].second = (T) 1;
distances[*target].getColumn() = *target;
distances[*target].getValue() = (T) 1;
return;
}
@ -302,19 +302,19 @@ public:
//only use if allowed and not in subsys and not terminal
if(allowedStates.get(*iter) && !subSysStates.get(*iter) && !terminalStates.get(*iter)) {
//new state?
if(distances[*iter].second == (T) -1) {
if(distances[*iter].getValue() == (T) -1) {
// save as discovered and push into active set
distances[*iter].first = *target; //successor
distances[*iter].second = transMat.getValue(*iter, *target); //prob of shortest path
distances[*iter].getColumn() = *target; //successor
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.
}
else {
// state was already discovered
// is this the better transition?
if(distances[*iter].second > transMat.getValue(*iter, *target)) {
distances[*iter].first = *target;
distances[*iter].second = transMat.getValue(*iter, *target);
if(distances[*iter].getValue() > transMat.getValue(*iter, *target)) {
distances[*iter].getColumn() = *target;
distances[*iter].getValue() = transMat.getValue(*iter, *target);
}
}
}
@ -328,19 +328,19 @@ public:
//only use if allowed and not in subsys and not terminal
if(allowedStates.get(*iter) && !subSysStates.get(*iter) && !terminalStates.get(*iter)) {
//new state?
if(distances[*iter].second == (T) -1) {
if(distances[*iter].getValue() == (T) -1) {
// save as discovered and push into active set
distances[*iter].first = *sysState; //successor
distances[*iter].second = transMat.getValue(*iter, *sysState); //prob of shortest path
distances[*iter].getColumn() = *sysState; //successor
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.
}
else {
// state was already discovered
// is this the better transition?
if(distances[*iter].second > transMat.getValue(*iter, *sysState)) {
distances[*iter].first = *sysState;
distances[*iter].second = transMat.getValue(*iter, *sysState);
if(distances[*iter].getValue() > transMat.getValue(*iter, *sysState)) {
distances[*iter].getColumn() = *sysState;
distances[*iter].getValue() = transMat.getValue(*iter, *sysState);
}
}
}
@ -355,7 +355,7 @@ public:
while(!activeSet.empty()) {
// copy here since using a reference leads to segfault
state = *(--activeSet.end());
activeState = state.first;
activeState = state.getColumn();
activeSet.erase(--activeSet.end());
//stop on the first subsys/init state
@ -368,19 +368,19 @@ public:
//only if transition is not "virtual" and no selfloop
if(*iter != activeState && transMat.getValue(*iter, activeState) != (T) 0) {
//new state?
if(distances[*iter].second == (T) -1) {
if(distances[*iter].getValue() == (T) -1) {
// save as discovered and push into active set
distances[*iter].first = activeState;
distances[*iter].second = transMat.getValue(*iter, activeState) * distances[activeState].second;
distances[*iter].getColumn() = activeState;
distances[*iter].getValue() = transMat.getValue(*iter, activeState) * distances[activeState].getValue();
activeSet.insert(std::pair<uint_fast64_t, T>(*iter, probabilities[*iter]));
}
else {
// state was already discovered
// is this the better transition?
if(distances[*iter].second < transMat.getValue(*iter, activeState) * distances[activeState].second) {
distances[*iter].first = activeState;
distances[*iter].second = transMat.getValue(*iter, activeState) * distances[activeState].second;
if(distances[*iter].getValue() < transMat.getValue(*iter, activeState) * distances[activeState].getValue()) {
distances[*iter].getColumn() = activeState;
distances[*iter].getValue() = transMat.getValue(*iter, activeState) * distances[activeState].getValue();
}
}
}
@ -389,15 +389,15 @@ public:
}
//get path probability
probability = distances[activeState].second;
probability = distances[activeState].getValue();
if(probability == (T) -1) probability = 1;
// iterate over the successors until reaching the end of the finite path
shortestPath.push_back(activeState);
activeState = distances[activeState].first;
activeState = distances[activeState].getColumn();
while(!terminalStates.get(activeState) && !subSysStates.get(activeState)) {
shortestPath.push_back(activeState);
activeState = distances[activeState].first;
activeState = distances[activeState].getColumn();
}
shortestPath.push_back(activeState);
}
@ -482,7 +482,7 @@ public:
shortestPath.push_back(bestIndex);
//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:

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());
return true;
});
});

78
src/modelchecker/csl/SparseMarkovAutomatonCslModelChecker.h

@ -103,10 +103,10 @@ namespace storm {
for (auto state : markovianNonGoalStates) {
for (auto& element : aMarkovian.getRow(rowIndex)) {
ValueType eTerm = std::exp(-exitRates[state] * delta);
if (element.first == rowIndex) {
element.second = (storm::utility::constantOne<ValueType>() - eTerm) * element.second + eTerm;
if (element.getColumn() == rowIndex) {
element.getValue() = (storm::utility::constantOne<ValueType>() - eTerm) * element.getValue() + eTerm;
} else {
element.second = (storm::utility::constantOne<ValueType>() - eTerm) * element.second;
element.getValue() = (storm::utility::constantOne<ValueType>() - eTerm) * element.getValue();
}
}
++rowIndex;
@ -116,7 +116,7 @@ namespace storm {
rowIndex = 0;
for (auto state : markovianNonGoalStates) {
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;
}
@ -133,8 +133,8 @@ namespace storm {
bMarkovianFixed.push_back(storm::utility::constantZero<ValueType>());
for (auto& element : transitionMatrix.getRowGroup(state)) {
if (goalStates.get(element.first)) {
bMarkovianFixed.back() += (1 - std::exp(-exitRates[state] * delta)) * element.second;
if (goalStates.get(element.getColumn())) {
bMarkovianFixed.back() += (1 - std::exp(-exitRates[state] * delta)) * element.getValue();
}
}
}
@ -314,13 +314,13 @@ namespace storm {
b.push_back(storm::utility::constantZero<ValueType>());
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.
sspMatrixBuilder.addNextValue(currentChoice, statesNotInMecsBeforeIndex[element.first], element.second);
sspMatrixBuilder.addNextValue(currentChoice, statesNotInMecsBeforeIndex[element.getColumn()], element.getValue());
} else {
// 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.
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>());
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.
sspMatrixBuilder.addNextValue(currentChoice, statesNotInMecsBeforeIndex[element.first], element.second);
sspMatrixBuilder.addNextValue(currentChoice, statesNotInMecsBeforeIndex[element.getColumn()], element.getValue());
} else {
// 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.
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) {
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.
std::map<uint_fast64_t, uint_fast64_t> stateToVariableIndexMap;
std::map<uint_fast64_t, std::string> stateToVariableNameMap;
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();
// Now we encode the problem as constraints.
std::vector<uint_fast64_t> variables;
std::vector<double> coefficients;
for (auto const& stateChoicesPair : mec) {
uint_fast64_t state = stateChoicesPair.first;
// Now, based on the type of the state, create a suitable constraint.
if (markovianStates.get(state)) {
variables.clear();
coefficients.clear();
variables.push_back(stateToVariableIndexMap.at(state));
coefficients.push_back(1);
storm::expressions::Expression constraint = storm::expressions::Expression::createDoubleVariable(stateToVariableNameMap.at(state));
for (auto element : transitionMatrix.getRow(nondeterministicChoiceIndices[state])) {
variables.push_back(stateToVariableIndexMap.at(element.first));
coefficients.push_back(-element.second);
constraint = constraint - storm::expressions::Expression::createDoubleVariable(stateToVariableNameMap.at(element.getColumn()));
}
variables.push_back(lraValueVariableIndex);
coefficients.push_back(storm::utility::constantOne<ValueType>() / exitRates[state]);
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 + storm::expressions::Expression::createDoubleLiteral(storm::utility::constantOne<ValueType>() / exitRates[state]) * storm::expressions::Expression::createDoubleVariable("k");
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) {
constraint = constraint <= rightHandSide;
} else {
constraint = constraint >= rightHandSide;
}
solver->addConstraint("state" + std::to_string(state), constraint);
} 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
// and the sum ranges over all states s'.
for (auto choice : stateChoicesPair.second) {
variables.clear();
coefficients.clear();
variables.push_back(stateToVariableIndexMap.at(state));
coefficients.push_back(1);
storm::expressions::Expression constraint = storm::expressions::Expression::createDoubleVariable(stateToVariableNameMap.at(state));
for (auto element : transitionMatrix.getRow(choice)) {
variables.push_back(stateToVariableIndexMap.at(element.first));
coefficients.push_back(-element.second);
constraint = constraint - storm::expressions::Expression::createDoubleVariable(stateToVariableNameMap.at(element.getColumn()));
}
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();
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) {
typename storm::storage::SparseMatrix<T>::const_rows row = this->transitionMatrix.getRow(i);
for (auto const& transition : row) {
if (transition.second != storm::utility::constantZero<T>()) {
if (subsystem == nullptr || subsystem->get(transition.first)) {
outStream << "\t" << i << " -> " << transition.first << " [ label= \"" << transition.second << "\" ];" << std::endl;
if (transition.getValue() != storm::utility::constantZero<T>()) {
if (subsystem == nullptr || subsystem->get(transition.getColumn())) {
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.
*/
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.
for (auto const& transition : row) {
if (subsystem == nullptr || subsystem->get(transition.first)) {
outStream << "\t\"" << state << "c" << choice << "\" -> " << transition.first << " [ label= \"" << transition.second << "\" ]";
if (subsystem == nullptr || subsystem->get(transition.getColumn())) {
outStream << "\t\"" << state << "c" << choice << "\" -> " << transition.getColumn() << " [ label= \"" << transition.getValue() << "\" ]";
// If we were given a scheduler to highlight, we do so now.
if (scheduler != nullptr) {

12
src/models/Dtmc.h

@ -170,7 +170,7 @@ public:
for(uint_fast64_t row = 0; row < origMat.getRowCount(); ++row) {
if(subSysStates.get(row)){
for(auto const& entry : origMat.getRow(row)) {
if(subSysStates.get(entry.first)) {
if(subSysStates.get(entry.getColumn())) {
subSysTransitionCount++;
}
}
@ -198,10 +198,10 @@ public:
if(subSysStates.get(row)){
// Transfer transitions
for(auto& entry : origMat.getRow(row)) {
if(subSysStates.get(entry.first)) {
newMatBuilder.addNextValue(newRow, stateMapping[entry.first], entry.second);
if(subSysStates.get(entry.getColumn())) {
newMatBuilder.addNextValue(newRow, stateMapping[entry.getColumn()], entry.getValue());
} else {
rest += entry.second;
rest += entry.getValue();
}
}
@ -251,8 +251,8 @@ public:
if(subSysStates.get(row)){
// Transfer transition rewards
for(auto& entry : this->getTransitionRewardMatrix().getRow(row)) {
if(subSysStates.get(entry.first)) {
newTransRewardsBuilder.addNextValue(newRow, stateMapping[entry.first], entry.second);
if(subSysStates.get(entry.getColumn())) {
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 (auto const& entry : this->transitionMatrix.getRow(row)) {
newTransitionMatrixBuilder.addNextValue(currentChoice, entry.first, entry.second);
newTransitionMatrixBuilder.addNextValue(currentChoice, entry.getColumn(), entry.getValue());
}
++currentChoice;
}
@ -220,8 +220,8 @@ namespace storm {
// Now draw all probabilitic arcs that belong to this nondeterminstic choice.
for (auto const& transition : row) {
if (subsystem == nullptr || subsystem->get(transition.first)) {
outStream << "\t\"" << state << "c" << choice << "\" -> " << transition.first << " [ label= \"" << transition.second << "\" ]";
if (subsystem == nullptr || subsystem->get(transition.getColumn())) {
outStream << "\t\"" << state << "c" << choice << "\" -> " << transition.getColumn() << " [ label= \"" << transition.getValue() << "\" ]";
// If we were given a scheduler to highlight, we do so now.
if (scheduler != nullptr) {
@ -237,8 +237,8 @@ namespace storm {
} else {
// In this case we are emitting a Markovian choice, so draw the arrows directly to the target states.
for (auto const& transition : row) {
if (subsystem == nullptr || subsystem->get(transition.first)) {
outStream << "\t\"" << state << "\" -> " << transition.first << " [ label= \"" << transition.second << " (" << this->exitRates[state] << ")\" ]";
if (subsystem == nullptr || subsystem->get(transition.getColumn())) {
outStream << "\t\"" << state << "\" -> " << transition.getColumn() << " [ label= \"" << transition.getValue() << " (" << this->exitRates[state] << ")\" ]";
}
}
}
@ -259,7 +259,7 @@ namespace storm {
void turnRatesToProbabilities() {
for (auto state : this->markovianStates) {
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 "src/exceptions/InvalidStateException.h"
#include "src/settings/Settings.h"
#include "log4cplus/logger.h"
#include "log4cplus/loggingmacros.h"
#include "src/storage/expressions/LinearCoefficientVisitor.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 {
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 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.
lp = glp_create_prob();
@ -38,11 +37,11 @@ namespace storm {
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.
}
GlpkLpSolver::GlpkLpSolver() : GlpkLpSolver("", MINIMIZE) {
GlpkLpSolver::GlpkLpSolver() : GlpkLpSolver("", ModelSense::Minimize) {
// Intentionally left empty.
}
@ -56,76 +55,120 @@ namespace storm {
glp_free_env();
}
uint_fast64_t GlpkLpSolver::createContinuousVariable(std::string const& name, VariableType const& variableType, double lowerBound, double upperBound, double objectiveFunctionCoefficient) {
glp_add_cols(this->lp, 1);
glp_set_col_name(this->lp, nextVariableIndex, name.c_str());
switch (variableType) {
case LpSolver::BOUNDED:
glp_set_col_bnds(lp, nextVariableIndex, GLP_DB, lowerBound, upperBound);
break;
case LpSolver::UNBOUNDED:
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;
void GlpkLpSolver::addBoundedContinuousVariable(std::string const& name, double lowerBound, double upperBound, double objectiveFunctionCoefficient) {
this->addVariable(name, GLP_CV, GLP_DB, lowerBound, upperBound, objectiveFunctionCoefficient);
}
void GlpkLpSolver::addLowerBoundedContinuousVariable(std::string const& name, double lowerBound, double objectiveFunctionCoefficient) {
this->addVariable(name, GLP_CV, GLP_LO, lowerBound, 0, objectiveFunctionCoefficient);
}
void GlpkLpSolver::addUpperBoundedContinuousVariable(std::string const& name, double upperBound, double objectiveFunctionCoefficient) {
this->addVariable(name, GLP_CV, GLP_UP, 0, upperBound, objectiveFunctionCoefficient);
}
uint_fast64_t GlpkLpSolver::createIntegerVariable(std::string const& name, VariableType const& variableType, double lowerBound, double upperBound, double objectiveFunctionCoefficient) {
uint_fast64_t index = this->createContinuousVariable(name, variableType, lowerBound, upperBound, objectiveFunctionCoefficient);
glp_set_col_kind(this->lp, index, GLP_IV);
void GlpkLpSolver::addUnboundedContinuousVariable(std::string const& name, double objectiveFunctionCoefficient) {
this->addVariable(name, GLP_CV, GLP_FR, 0, 0, objectiveFunctionCoefficient);
}
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;
return index;
}
uint_fast64_t GlpkLpSolver::createBinaryVariable(std::string const& name, double objectiveFunctionCoefficient) {
uint_fast64_t index = this->createContinuousVariable(name, UNBOUNDED, 0, 1, objectiveFunctionCoefficient);
glp_set_col_kind(this->lp, index, GLP_BV);
void GlpkLpSolver::addBinaryVariable(std::string const& name, double objectiveFunctionCoefficient) {
this->addVariable(name, GLP_BV, GLP_FR, 0, 0, objectiveFunctionCoefficient);
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 {
// 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) {
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.";
}
void GlpkLpSolver::addConstraint(std::string const& name, storm::expressions::Expression const& constraint) {
// Add the row that will represent this constraint.
glp_add_rows(this->lp, 1);
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.
switch (boundType) {
case LESS:
glp_set_row_bnds(this->lp, nextConstraintIndex, GLP_UP, 0, rightHandSideValue - storm::settings::Settings::getInstance()->getOptionByLongName("precision").getArgument(0).getValueAsDouble());
switch (constraint.getOperator()) {
case storm::expressions::OperatorType::Less:
glp_set_row_bnds(this->lp, nextConstraintIndex, GLP_UP, 0, rightCoefficients.second - storm::settings::Settings::getInstance()->getOptionByLongName("glpkinttol").getArgument(0).getValueAsDouble());
break;
case LESS_EQUAL:
glp_set_row_bnds(this->lp, nextConstraintIndex, GLP_UP, 0, rightHandSideValue);
case storm::expressions::OperatorType::LessOrEqual:
glp_set_row_bnds(this->lp, nextConstraintIndex, GLP_UP, 0, rightCoefficients.second);
break;
case GREATER:
glp_set_row_bnds(this->lp, nextConstraintIndex, GLP_LO, rightHandSideValue + storm::settings::Settings::getInstance()->getOptionByLongName("precision").getArgument(0).getValueAsDouble(), 0);
case storm::expressions::OperatorType::Greater:
glp_set_row_bnds(this->lp, nextConstraintIndex, GLP_LO, rightCoefficients.second + storm::settings::Settings::getInstance()->getOptionByLongName("glpkinttol").getArgument(0).getValueAsDouble(), 0);
break;
case GREATER_EQUAL:
glp_set_row_bnds(this->lp, nextConstraintIndex, GLP_LO, rightHandSideValue, 0);
case storm::expressions::OperatorType::GreaterOrEqual:
glp_set_row_bnds(this->lp, nextConstraintIndex, GLP_LO, rightCoefficients.second, 0);
break;
case EQUAL:
glp_set_row_bnds(this->lp, nextConstraintIndex, GLP_FX, rightHandSideValue, rightHandSideValue);
case storm::expressions::OperatorType::Equal:
glp_set_row_bnds(this->lp, nextConstraintIndex, GLP_FX, rightCoefficients.second, rightCoefficients.second);
break;
default:
LOG_ASSERT(false, "Illegal operator in LP solver constraint.");
}
// Record the variables and coefficients in the coefficient matrix.
@ -143,13 +186,13 @@ namespace storm {
this->isUnboundedFlag = false;
// 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());
int error = 0;
if (this->modelContainsIntegerVariables) {
glp_iocp* parameters = new glp_iocp;
glp_iocp* parameters = new glp_iocp();
glp_init_iocp(parameters);
parameters->presolve = GLP_ON;
parameters->tol_int = storm::settings::Settings::getInstance()->getOptionByLongName("glpkinttol").getArgument(0).getValueAsDouble();
@ -171,11 +214,7 @@ namespace storm {
error = glp_simplex(this->lp, nullptr);
}
if (error != 0) {
LOG4CPLUS_ERROR(logger, "Unable to optimize glpk model (" << error << ").");
throw storm::exceptions::InvalidStateException() << "Unable to optimize glpk model (" << error << ").";
}
LOG_THROW(error == 0, storm::exceptions::InvalidStateException, "Unable to optimize glpk model (" << error << ").");
this->currentModelHasBeenOptimized = true;
}
@ -217,103 +256,75 @@ namespace storm {
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->isInfeasible()) {
LOG4CPLUS_ERROR(logger, "Unable to get glpk solution from infeasible model.");
throw storm::exceptions::InvalidStateException() << "Unable to get Gurobi solution from infeasible 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.";
}
LOG_THROW(!this->isInfeasible(), storm::exceptions::InvalidAccessException, "Unable to get glpk solution from infeasible model.");
LOG_THROW(!this->isUnbounded(), storm::exceptions::InvalidAccessException, "Unable to get glpk solution from unbounded model.");
LOG_THROW(false, storm::exceptions::InvalidAccessException, "Unable to get glpk 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;
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 {
value = glp_get_col_prim(this->lp, static_cast<int>(variableIndex));
}
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 << ").";
value = glp_get_col_prim(this->lp, static_cast<int>(variableIndexPair->second));
}
return static_cast<int_fast64_t>(value);
return value;
}
bool GlpkLpSolver::getBinaryValue(uint_fast64_t variableIndex) const {
int_fast64_t GlpkLpSolver::getIntegerValue(std::string const& name) const {
if (!this->isOptimal()) {
if (this->isInfeasible()) {
LOG4CPLUS_ERROR(logger, "Unable to get glpk solution from infeasible model.");
throw storm::exceptions::InvalidStateException() << "Unable to get Gurobi solution from infeasible 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.";
}
LOG_THROW(!this->isInfeasible(), storm::exceptions::InvalidAccessException, "Unable to get glpk solution from infeasible model.");
LOG_THROW(!this->isUnbounded(), storm::exceptions::InvalidAccessException, "Unable to get glpk solution from unbounded model.");
LOG_THROW(false, storm::exceptions::InvalidAccessException, "Unable to get glpk 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;
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 {
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()) {
// 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 binary variable in Gurobi solution (" << value << ").");
throw storm::exceptions::InvalidStateException() << "Illegal value for binary variable in Gurobi solution (" << value << ").";
}
// Now check the desired precision was actually achieved.
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 << ").");
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->isInfeasible()) {
LOG4CPLUS_ERROR(logger, "Unable to get glpk solution from infeasible model.");
throw storm::exceptions::InvalidStateException() << "Unable to get Gurobi solution from infeasible 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.";
}
LOG_THROW(!this->isInfeasible(), storm::exceptions::InvalidAccessException, "Unable to get glpk solution from infeasible model.");
LOG_THROW(!this->isUnbounded(), storm::exceptions::InvalidAccessException, "Unable to get glpk solution from unbounded model.");
LOG_THROW(false, storm::exceptions::InvalidAccessException, "Unable to get glpk 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;
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 {
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 {
if (!this->isOptimal()) {
if (this->isInfeasible()) {
LOG4CPLUS_ERROR(logger, "Unable to get glpk solution from infeasible model.");
throw storm::exceptions::InvalidStateException() << "Unable to get Gurobi solution from infeasible 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.";
}
LOG_THROW(!this->isInfeasible(), storm::exceptions::InvalidAccessException, "Unable to get glpk solution from infeasible model.");
LOG_THROW(!this->isUnbounded(), storm::exceptions::InvalidAccessException, "Unable to get glpk solution from unbounded model.");
LOG_THROW(false, storm::exceptions::InvalidAccessException, "Unable to get glpk solution from unoptimized model.");
}
double value = 0;

97
src/solver/GlpkLpSolver.h

@ -14,7 +14,6 @@
namespace storm {
namespace solver {
#ifdef STORM_HAVE_GLPK
/*!
* A class that implements the LpSolver interface using glpk as the background solver.
*/
@ -56,34 +55,66 @@ namespace storm {
*/
virtual ~GlpkLpSolver();
virtual uint_fast64_t createContinuousVariable(std::string const& name, VariableType const& variableType, double lowerBound, double upperBound, double objectiveFunctionCoefficient) override;
virtual uint_fast64_t createIntegerVariable(std::string const& name, VariableType const& variableType, double lowerBound, double upperBound, double objectiveFunctionCoefficient) override;
virtual uint_fast64_t createBinaryVariable(std::string const& name, double objectiveFunctionCoefficient) override;
// Methods to add continuous variables.
virtual void addBoundedContinuousVariable(std::string const& name, double lowerBound, double upperBound, double objectiveFunctionCoefficient = 0) 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 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 bool isInfeasible() const override;
virtual bool isUnbounded() const override;
virtual bool isOptimal() const override;
virtual int_fast64_t getIntegerValue(uint_fast64_t variableIndex) const override;
virtual bool getBinaryValue(uint_fast64_t variableIndex) const override;
virtual double getContinuousValue(uint_fast64_t variableIndex) const override;
// Methods to retrieve values of variables and the objective function in the optimal solutions.
virtual double getContinuousValue(std::string const& name) 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;
// Methods to print the LP problem to a file.
virtual void writeModelToFile(std::string const& filename) const override;
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.
glp_prob* lp;
// A counter that keeps track of the next free variable index.
uint_fast64_t nextVariableIndex;
// A mapping from variable names to their indices.
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.
uint_fast64_t nextConstraintIndex;
// A counter used for getting the next constraint index.
int nextConstraintIndex;
// A flag storing whether the model is an LP or an MILP.
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.";
}
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.";
}
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.";
}
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.";
}
@ -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.";
}
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.";
}
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.";
}
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.";
}
@ -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.";
}
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.";
}
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.";
}
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.";
}

386
src/solver/GurobiLpSolver.cpp

@ -3,13 +3,12 @@
#ifdef STORM_HAVE_GUROBI
#include <numeric>
#include "src/exceptions/InvalidStateException.h"
#include "src/settings/Settings.h"
#include "src/storage/expressions/LinearCoefficientVisitor.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/InvalidStateException.h"
#include "src/exceptions/InvalidAccessException.h"
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());
@ -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.
}
@ -51,7 +50,7 @@ namespace storm {
// Intentionally left empty.
}
GurobiLpSolver::GurobiLpSolver() : GurobiLpSolver("", MINIMIZE) {
GurobiLpSolver::GurobiLpSolver() : GurobiLpSolver("", ModelSense::Minimize) {
// 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.
error = GRBsetintparam(env, "OutputFlag", storm::settings::Settings::getInstance()->isSet("debug") || storm::settings::Settings::getInstance()->isSet("gurobioutput") ? 1 : 0);
if (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 << ").";
}
LOG_THROW(error == 0, 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.
error = GRBsetintparam(env, "Threads", storm::settings::Settings::getInstance()->getOptionByLongName("gurobithreads").getArgument(0).getValueAsUnsignedInteger());
if (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 << ").";
}
LOG_THROW(error == 0, 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.
error = GRBsetdblparam(env, "IntFeasTol", storm::settings::Settings::getInstance()->getOptionByLongName("gurobiinttol").getArgument(0).getValueAsDouble());
if (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 << ").";
}
LOG_THROW(error == 0, storm::exceptions::InvalidStateException, "Unable to set Gurobi Parameter IntFeasTol (" << GRBgeterrormsg(env) << ", error code " << error << ").");
}
void GurobiLpSolver::update() const {
int error = GRBupdatemodel(model);
if (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 << ").";
}
LOG_THROW(error == 0, storm::exceptions::InvalidStateException, "Unable to update Gurobi model (" << GRBgeterrormsg(env) << ", error code " << error << ").");
// Since the model changed, we erase the optimality flag.
this->currentModelHasBeenOptimized = false;
}
uint_fast64_t GurobiLpSolver::createContinuousVariable(std::string const& name, VariableType const& variableType, double lowerBound, double upperBound, double objectiveFunctionCoefficient) {
int error = 0;
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;
void GurobiLpSolver::addBoundedContinuousVariable(std::string const& name, double lowerBound, double upperBound, double objectiveFunctionCoefficient) {
this->addVariable(name, GRB_CONTINUOUS, lowerBound, upperBound, objectiveFunctionCoefficient);
}
uint_fast64_t GurobiLpSolver::createIntegerVariable(std::string const& name, VariableType const& variableType, double lowerBound, double upperBound, double objectiveFunctionCoefficient) {
int error = 0;
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;
}
void GurobiLpSolver::addLowerBoundedContinuousVariable(std::string const& name, double lowerBound, double objectiveFunctionCoefficient) {
this->addVariable(name, GRB_CONTINUOUS, lowerBound, GRB_INFINITY, 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::addUpperBoundedContinuousVariable(std::string const& name, double upperBound, double objectiveFunctionCoefficient) {
this->addVariable(name, GRB_CONTINUOUS, -GRB_INFINITY, upperBound, objectiveFunctionCoefficient);
}
void GurobiLpSolver::addUnboundedContinuousVariable(std::string const& name, double objectiveFunctionCoefficient) {
this->addVariable(name, GRB_CONTINUOUS, -GRB_INFINITY, GRB_INFINITY, objectiveFunctionCoefficient);
}
uint_fast64_t GurobiLpSolver::createBinaryVariable(std::string const& name, double objectiveFunctionCoefficient) {
int error = GRBaddvar(model, 0, nullptr, nullptr, objectiveFunctionCoefficient, 0.0, 1.0, GRB_BINARY, name.c_str());
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::addBoundedIntegerVariable(std::string const& name, double lowerBound, double upperBound, double objectiveFunctionCoefficient) {
this->addVariable(name, GRB_INTEGER, lowerBound, upperBound, objectiveFunctionCoefficient);
}
void GurobiLpSolver::addConstraint(std::string const& name, std::vector<uint_fast64_t> const& variables, std::vector<double> const& coefficients, BoundType const& boundType, double rightHandSideValue) {
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.";
}
void GurobiLpSolver::addLowerBoundedIntegerVariable(std::string const& name, double lowerBound, double objectiveFunctionCoefficient) {
this->addVariable(name, GRB_INTEGER, lowerBound, GRB_INFINITY, objectiveFunctionCoefficient);
}
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
// variables and coefficients and eliminated duplicates by adding the coefficients.
// Check for valid variable type.
LOG_ASSERT(variableType == GRB_CONTINUOUS || variableType == GRB_INTEGER || variableType == GRB_BINARY, "Illegal type '" << variableType << "' for Gurobi variable.");
// We start by sorting both vectors.
std::vector<uint_fast64_t> sortedVariables(variables);
std::vector<double> sortedCoefficients(coefficients);
std::vector<uint_fast64_t> permutation(variables.size());
std::iota(permutation.begin(), permutation.end(), 0);
std::sort(permutation.begin(), permutation.end(), [&] (uint_fast64_t i, uint_fast64_t j) { return variables[i] < variables[j]; } );
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]; } );
// Finally, create the actual variable.
int error = 0;
error = GRBaddvar(model, 0, nullptr, nullptr, objectiveFunctionCoefficient, lowerBound, upperBound, variableType, name.c_str());
LOG_THROW(error == 0, storm::exceptions::InvalidStateException, "Could not create binary Gurobi variable (" << GRBgeterrormsg(env) << ", error code " << error << ").");
this->variableNameToIndexMap.emplace(name, nextVariableIndex);
++nextVariableIndex;
}
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::vector<int> uniqueVariables;
std::vector<double> uniqueCoefficients;
for (uint_fast64_t i = 0; i < sortedVariables.size(); ++i) {
if (!uniqueVariables.empty() && uniqueVariables.back() == sortedVariables[i]) {
uniqueCoefficients.back() += sortedCoefficients[i];
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 {
uniqueVariables.push_back(static_cast<int>(sortedVariables[i]));
uniqueCoefficients.push_back(sortedCoefficients[i]);
leftCoefficients.first.addDoubleIdentifier(identifier, -rightCoefficients.first.getDoubleValue(identifier));
}
}
rightCoefficients.second -= leftCoefficients.second;
bool strictBound = boundType == LESS || boundType == GREATER;
char sense = boundType == LESS || boundType == LESS_EQUAL ? GRB_LESS_EQUAL : boundType == EQUAL ? GRB_EQUAL : GRB_GREATER_EQUAL;
// If the constraint enforces a strict bound, we need to do some tweaking of the right-hand side value, because Gurobi only supports
// non-strict bounds.
if (strictBound) {
if (boundType == LESS) {
rightHandSideValue -= storm::settings::Settings::getInstance()->getOptionByLongName("precision").getArgument(0).getValueAsDouble();
} else if (boundType == GREATER) {
rightHandSideValue += storm::settings::Settings::getInstance()->getOptionByLongName("precision").getArgument(0).getValueAsDouble();
}
// 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));
}
int error = GRBaddconstr(model, uniqueVariables.size(), uniqueVariables.data(), uniqueCoefficients.data(), sense, rightHandSideValue, name == "" ? nullptr : name.c_str());
if (error) {
LOG4CPLUS_ERROR(logger, "Unable to assert Gurobi constraint (" << GRBgeterrormsg(env) << ", error code " << error << ").");
throw storm::exceptions::InvalidStateException() << "Unable to assert Gurobi constraint (" << GRBgeterrormsg(env) << ", error code " << error << ").";
// Determine the type of the constraint and add it properly.
int error = 0;
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 {
@ -212,18 +190,12 @@ namespace storm {
this->update();
// Set the most recently set model sense.
int error = GRBsetintattr(model, "ModelSense", this->getModelSense() == MINIMIZE ? 1 : -1);
if (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 << ").";
}
int error = GRBsetintattr(model, "ModelSense", this->getModelSense() == ModelSense::Minimize ? 1 : -1);
LOG_THROW(error == 0, storm::exceptions::InvalidStateException, "Unable to set Gurobi model sense (" << GRBgeterrormsg(env) << ", error code " << error << ").");
// Then we actually optimize the model.
error = GRBoptimize(model);
if (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 << ").";
}
LOG_THROW(error == 0, storm::exceptions::InvalidStateException, "Unable to optimize Gurobi model (" << GRBgeterrormsg(env) << ", error code " << error << ").");
this->currentModelHasBeenOptimized = true;
}
@ -236,34 +208,21 @@ namespace storm {
int optimalityStatus = 0;
int error = GRBgetintattr(model, GRB_INT_ATTR_STATUS, &optimalityStatus);
if (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 << ").";
}
LOG_THROW(error == 0, 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
// it is, we need to perform an extra step.
if (optimalityStatus == GRB_INF_OR_UNBD) {
std::cout << "here" << std::endl;
error = GRBsetintparam(GRBgetenv(model), GRB_INT_PAR_DUALREDUCTIONS, 0);
if (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 << ").";
}
LOG_THROW(error == 0, storm::exceptions::InvalidStateException, "Unable to set Gurobi parameter (" << GRBgeterrormsg(env) << ", error code " << error << ").");
this->optimize();
error = GRBgetintattr(model, GRB_INT_ATTR_STATUS, &optimalityStatus);
if (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 << ").";
}
LOG_THROW(error == 0, 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);
if (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 << ").";
}
LOG_THROW(error == 0, storm::exceptions::InvalidStateException, "Unable to set Gurobi parameter (" << GRBgeterrormsg(env) << ", error code " << error << ").");
}
return optimalityStatus == GRB_INFEASIBLE;
@ -277,33 +236,21 @@ namespace storm {
int optimalityStatus = 0;
int error = GRBgetintattr(model, GRB_INT_ATTR_STATUS, &optimalityStatus);
if (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 << ").";
}
LOG_THROW(error == 0, 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
// it is, we need to perform an extra step.
if (optimalityStatus == GRB_INF_OR_UNBD) {
error = GRBsetintparam(GRBgetenv(model), GRB_INT_PAR_DUALREDUCTIONS, 0);
if (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 << ").";
}
LOG_THROW(error == 0, storm::exceptions::InvalidStateException, "Unable to set Gurobi parameter (" << GRBgeterrormsg(env) << ", error code " << error << ").");
this->optimize();
error = GRBgetintattr(model, GRB_INT_ATTR_STATUS, &optimalityStatus);
if (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 << ").";
}
LOG_THROW(error == 0, 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);
if (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 << ").";
}
LOG_THROW(error == 0, storm::exceptions::InvalidStateException, "Unable to set Gurobi parameter (" << GRBgeterrormsg(env) << ", error code " << error << ").");
}
return optimalityStatus == GRB_UNBOUNDED;
@ -316,120 +263,79 @@ namespace storm {
int optimalityStatus = 0;
int error = GRBgetintattr(model, GRB_INT_ATTR_STATUS, &optimalityStatus);
if (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 << ").";
}
LOG_THROW(error == 0, storm::exceptions::InvalidStateException, "Unable to retrieve optimization status of Gurobi model (" << GRBgeterrormsg(env) << ", error code " << error << ").");
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->isInfeasible()) {
LOG4CPLUS_ERROR(logger, "Unable to get Gurobi solution from infeasible model (" << GRBgeterrormsg(env) << ").");
throw storm::exceptions::InvalidStateException() << "Unable to get Gurobi solution from infeasible 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) << ").";
}
LOG_THROW(!this->isInfeasible(), storm::exceptions::InvalidAccessException, "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) << ").");
LOG_THROW(false, storm::exceptions::InvalidAccessException, "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 << ").";
}
auto variableIndexPair = this->variableNameToIndexMap.find(name);
LOG_THROW(variableIndexPair != this->variableNameToIndexMap.end(), storm::exceptions::InvalidAccessException, "Accessing value of unknown variable '" << name << "'.");
if (std::abs(value - static_cast<int>(value)) <= storm::settings::Settings::getInstance()->getOptionByLongName("gurobiinttol").getArgument(0).getValueAsDouble()) {
// Nothing to do in this case.
} else if (std::abs(value) > storm::settings::Settings::getInstance()->getOptionByLongName("gurobiinttol").getArgument(0).getValueAsDouble()) {
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 << ").";
}
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 << ").");
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->isInfeasible()) {
LOG4CPLUS_ERROR(logger, "Unable to get Gurobi solution from infeasible model (" << GRBgeterrormsg(env) << ").");
throw storm::exceptions::InvalidStateException() << "Unable to get Gurobi solution from infeasible 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 << ").";
LOG_THROW(!this->isInfeasible(), storm::exceptions::InvalidAccessException, "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) << ").");
LOG_THROW(false, storm::exceptions::InvalidAccessException, "Unable to get Gurobi solution from unoptimized model (" << GRBgeterrormsg(env) << ").");
}
if (std::abs(value - 1) <= storm::settings::Settings::getInstance()->getOptionByLongName("gurobiinttol").getArgument(0).getValueAsDouble()) {
// Nothing to do in this case.
} 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 << ").";
}
auto variableIndexPair = this->variableNameToIndexMap.find(name);
LOG_THROW(variableIndexPair != this->variableNameToIndexMap.end(), storm::exceptions::InvalidAccessException, "Accessing value of unknown variable '" << name << "'.");
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->isInfeasible()) {
LOG4CPLUS_ERROR(logger, "Unable to get Gurobi solution from infeasible model (" << GRBgeterrormsg(env) << ").");
throw storm::exceptions::InvalidStateException() << "Unable to get Gurobi solution from infeasible 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) << ").";
}
LOG_THROW(!this->isInfeasible(), storm::exceptions::InvalidAccessException, "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) << ").");
LOG_THROW(false, storm::exceptions::InvalidAccessException, "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;
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 << ").";
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 << ").");
if (value > 0.5) {
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 {
if (!this->isOptimal()) {
if (this->isInfeasible()) {
LOG4CPLUS_ERROR(logger, "Unable to get Gurobi solution from infeasible model (" << GRBgeterrormsg(env) << ").");
throw storm::exceptions::InvalidStateException() << "Unable to get Gurobi solution from infeasible 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) << ").";
}
LOG_THROW(!this->isInfeasible(), storm::exceptions::InvalidAccessException, "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) << ").");
LOG_THROW(false, storm::exceptions::InvalidAccessException, "Unable to get Gurobi solution from unoptimized model (" << GRBgeterrormsg(env) << ").");
}
double value = 0;
int error = GRBgetdblattr(model, GRB_DBL_ATTR_OBJVAL, &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 << ").";
}
LOG_THROW(error == 0, storm::exceptions::InvalidStateException, "Unable to get Gurobi solution (" << GRBgeterrormsg(env) << ", error code " << error << ").");
return value;
}

94
src/solver/GurobiLpSolver.h

@ -60,23 +60,40 @@ namespace storm {
*/
virtual ~GurobiLpSolver();
virtual uint_fast64_t createContinuousVariable(std::string const& name, VariableType const& variableType, double lowerBound, double upperBound, double objectiveFunctionCoefficient) override;
virtual uint_fast64_t createIntegerVariable(std::string const& name, VariableType const& variableType, double lowerBound, double upperBound, double objectiveFunctionCoefficient) override;
virtual uint_fast64_t createBinaryVariable(std::string const& name, double objectiveFunctionCoefficient) override;
// Methods to add continuous variables.
virtual void addBoundedContinuousVariable(std::string const& name, double lowerBound, double upperBound, double objectiveFunctionCoefficient = 0) 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 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 bool isInfeasible() const override;
virtual bool isUnbounded() const override;
virtual bool isOptimal() const override;
virtual int_fast64_t getIntegerValue(uint_fast64_t variableIndex) const override;
virtual bool getBinaryValue(uint_fast64_t variableIndex) const override;
virtual double getContinuousValue(uint_fast64_t variableIndex) const override;
// Methods to retrieve values of variables and the objective function in the optimal solutions.
virtual double getContinuousValue(std::string const& name) 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;
// Methods to print the LP problem to a file.
virtual void writeModelToFile(std::string const& filename) const override;
private:
@ -85,14 +102,28 @@ namespace storm {
*/
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.
GRBenv* env;
// The Gurobi model.
GRBmodel* model;
// A counter that keeps track of the next free variable index.
uint_fast64_t nextVariableIndex;
// The index of the next variable.
int nextVariableIndex;
// A mapping from variable names to their indices.
std::map<std::string, int> variableNameToIndexMap;
};
#else
// 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.";
}
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.";
}
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.";
}
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.";
}
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.";
}
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.";
}
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.";
}
@ -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.";
}
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.";
}
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.";
}
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.";
}
@ -175,7 +225,7 @@ namespace storm {
}
};
#endif
}
}

170
src/solver/LpSolver.h

@ -5,42 +5,25 @@
#include <vector>
#include <cstdint>
#include "src/storage/expressions/Expression.h"
namespace storm {
namespace solver {
/*!
* An interface that captures the functionality of an LP solver.
*/
class LpSolver {
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.
enum ModelSense {
MINIMIZE,
MAXIMIZE
enum class ModelSense {
Minimize,
Maximize
};
/*!
* 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.
}
@ -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 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
* function. If 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.
* function. If omitted (or set to zero), the variable is irrelevant for the objective value.
*/
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 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
* function. If 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.
* function. If omitted (or set to zero), the variable is irrelevant for the objective value.
*/
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 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
* function. If 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.
* function. If omitted (or set to zero), the variable is irrelevant for the objective value.
*/
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>
@ -109,18 +139,13 @@ namespace storm {
virtual void update() const = 0;
/*!
* Adds a constraint of the form
* a_1*x_1 + ... + a_n*x_n op c
* to the LP problem.
* Adds a the given constraint to the LP problem.
*
* @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 coefficients A vector of coefficients that define the a_1, ..., a_n. The i-ith entry specifies the
* 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.
* @param constraint An expression that represents the constraint. The given constraint must be a linear
* (in)equality over the registered variables.
*/
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
@ -154,34 +179,31 @@ namespace storm {
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.
*
* @param variableIndex The index of the integer variable whose value to query. If this index does not
* belong to a previously declared integer variable, the behaviour is undefined.
* @param name The name of the variable whose integer value (in the optimal solution) to retrieve.
* @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.
*
* @param variableIndex The index of the binary variable whose value to query. If this index does not
* belong to a previously declared binary variable, the behaviour is undefined.
* @param name The name of the variable whose binary (boolean) value (in the optimal solution) to retrieve.
* @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.
*
* @param variableIndex The index of the continuous variable whose value to query. If this index does not
* belong to a previously declared continuous variable, the behaviour is undefined.
* @param name The name of the variable whose continuous value (in the optimal solution) to retrieve.
* @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

8
src/storage/MaximalEndComponentDecomposition.cpp

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

158
src/storage/SparseMatrix.cpp

@ -17,6 +17,41 @@ extern log4cplus::Logger logger;
namespace storm {
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>
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();
@ -168,7 +203,7 @@ namespace storm {
void SparseMatrixBuilder<T>::prepareInternalStorage() {
// Only allocate the memory for the matrix contents if the dimensions of the matrix are already known.
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);
} else {
rowIndications.push_back(0);
@ -218,17 +253,17 @@ namespace storm {
}
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.
}
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.
}
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
other.rowCount = 0;
other.columnCount = 0;
@ -236,13 +271,21 @@ namespace storm {
}
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) {
// Intentionally left empty.
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) {
for (auto const& element : *this) {
if (element.getValue() != storm::utility::constantZero<T>()) {
++this->nonzeroEntryCount;
}
}
}
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)) {
// Intentionally left empty.
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)) {
for (auto const& element : *this) {
if (element.getValue() != storm::utility::constantZero<T>()) {
++this->nonzeroEntryCount;
}
}
}
template<typename T>
@ -252,6 +295,7 @@ namespace storm {
rowCount = other.rowCount;
columnCount = other.columnCount;
entryCount = other.entryCount;
nonzeroEntryCount = other.nonzeroEntryCount;
columnsAndValues = other.columnsAndValues;
rowIndications = other.rowIndications;
@ -268,6 +312,7 @@ namespace storm {
rowCount = other.rowCount;
columnCount = other.columnCount;
entryCount = other.entryCount;
nonzeroEntryCount = other.nonzeroEntryCount;
columnsAndValues = std::move(other.columnsAndValues);
rowIndications = std::move(other.rowIndications);
@ -294,17 +339,17 @@ namespace storm {
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) {
// 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;
}
while (it2 != ite2 && it2->second == storm::utility::constantZero<T>()) {
while (it2 != ite2 && it2->getValue() == storm::utility::constantZero<T>()) {
++it2;
}
if ((it1 == ite1) || (it2 == ite2)) {
equalityResult = (it1 == ite1) ^ (it2 == ite2);
break;
} else {
if (it1->first != it2->first || it1->second != it2->second) {
if (it1->getColumn() != it2->getColumn() || it1->getValue() != it2->getValue()) {
equalityResult = false;
break;
}
@ -330,6 +375,11 @@ namespace storm {
return entryCount;
}
template<typename T>
uint_fast64_t SparseMatrix<T>::getNonzeroEntryCount() const {
return nonzeroEntryCount;
}
template<typename T>
uint_fast64_t SparseMatrix<T>::getRowGroupCount() const {
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
// one given by the parameter and set all subsequent elements of this row to zero.
columnValuePtr->first = column;
columnValuePtr->second = storm::utility::constantOne<T>();
columnValuePtr->getColumn() = column;
columnValuePtr->getValue() = storm::utility::constantOne<T>();
++columnValuePtr;
for (; columnValuePtr != columnValuePtrEnd; ++columnValuePtr) {
columnValuePtr->first = 0;
columnValuePtr->second = storm::utility::constantZero<T>();
columnValuePtr->getColumn() = 0;
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 result(0);
for (const_iterator it = this->begin(row), ite = this->end(row); it != ite; ++it) {
if (constraint.get(it->first)) {
result += it->second;
if (constraint.get(it->getColumn())) {
result += it->getValue();
}
}
return result;
@ -442,10 +492,10 @@ namespace storm {
bool foundDiagonalElement = false;
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;
if (index == it->first) {
if (index == it->getColumn()) {
foundDiagonalElement = true;
}
}
@ -492,14 +542,14 @@ namespace storm {
bool insertedDiagonalElement = false;
for (const_iterator it = this->begin(i), ite = this->end(i); it != ite; ++it) {
if (columnConstraint.get(it->first)) {
if (index == it->first) {
if (columnConstraint.get(it->getColumn())) {
if (index == it->getColumn()) {
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>());
insertedDiagonalElement = true;
}
matrixBuilder.addNextValue(rowCount, bitsSetBeforeIndex[it->first], it->second);
matrixBuilder.addNextValue(rowCount, bitsSetBeforeIndex[it->getColumn()], it->getValue());
}
}
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.
bool foundDiagonalElement = false;
for (const_iterator it = this->begin(rowToCopy), ite = this->end(rowToCopy); it != ite; ++it) {
if (it->first == rowGroupIndex) {
if (it->getColumn() == rowGroupIndex) {
foundDiagonalElement = true;
}
++subEntries;
@ -547,13 +597,13 @@ namespace storm {
// there is no entry yet.
bool insertedDiagonalElement = false;
for (const_iterator it = this->begin(rowToCopy), ite = this->end(rowToCopy); it != ite; ++it) {
if (it->first == rowGroupIndex) {
if (it->getColumn() == rowGroupIndex) {
insertedDiagonalElement = true;
} else if (insertDiagonalEntries && !insertedDiagonalElement && it->first > rowGroupIndex) {
} else if (insertDiagonalEntries && !insertedDiagonalElement && it->getColumn() > rowGroupIndex) {
matrixBuilder.addNextValue(rowGroupIndex, rowGroupIndex, storm::utility::constantZero<T>());
insertedDiagonalElement = true;
}
matrixBuilder.addNextValue(rowGroupIndex, it->first, it->second);
matrixBuilder.addNextValue(rowGroupIndex, it->getColumn(), it->getValue());
}
if (insertDiagonalEntries && !insertedDiagonalElement) {
matrixBuilder.addNextValue(rowGroupIndex, rowGroupIndex, storm::utility::constantZero<T>());
@ -571,13 +621,13 @@ namespace storm {
uint_fast64_t entryCount = this->getEntryCount();
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.
for (uint_fast64_t group = 0; group < columnCount; ++group) {
for (auto const& transition : joinGroups ? this->getRowGroup(group) : this->getRow(group)) {
if (transition.second != storm::utility::constantZero<T>()) {
++rowIndications[transition.first + 1];
if (transition.getValue() != storm::utility::constantZero<T>()) {
++rowIndications[transition.getColumn() + 1];
}
}
}
@ -595,9 +645,9 @@ namespace storm {
// Now we are ready to actually fill in the values of the transposed matrix.
for (uint_fast64_t group = 0; group < columnCount; ++group) {
for (auto const& transition : joinGroups ? this->getRowGroup(group) : this->getRow(group)) {
if (transition.second != storm::utility::constantZero<T>()) {
columnsAndValues[nextIndices[transition.first]] = std::make_pair(group, transition.second);
nextIndices[transition.first]++;
if (transition.getValue() != storm::utility::constantZero<T>()) {
columnsAndValues[nextIndices[transition.getColumn()]] = std::make_pair(group, transition.getValue());
nextIndices[transition.getColumn()]++;
}
}
}
@ -626,8 +676,8 @@ namespace storm {
bool foundDiagonalElement = false;
for (uint_fast64_t group = 0; group < this->getRowGroupCount(); ++group) {
for (auto& entry : this->getRowGroup(group)) {
if (entry.first == group) {
entry.second = one - entry.second;
if (entry.getColumn() == group) {
entry.getValue() = one - entry.getValue();
foundDiagonalElement = true;
}
}
@ -644,8 +694,8 @@ namespace storm {
// 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 (auto& entry : this->getRowGroup(group)) {
if (entry.first != group) {
entry.second = -entry.second;
if (entry.getColumn() != group) {
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.
for (uint_fast64_t group = 0; group < this->getRowGroupCount(); ++group) {
for (auto& entry : this->getRowGroup(group)) {
if (entry.first == group) {
entry.second = storm::utility::constantZero<T>();
if (entry.getColumn() == group) {
entry.getValue() = storm::utility::constantZero<T>();
}
}
}
@ -680,9 +730,9 @@ namespace storm {
// to invert the entry.
T diagonalValue = storm::utility::constantZero<T>();
for (const_iterator it = this->begin(rowNumber), ite = this->end(rowNumber); it != ite; ++it) {
if (it->first == rowNumber) {
diagonalValue += it->second;
} else if (it->first > rowNumber) {
if (it->getColumn() == rowNumber) {
diagonalValue += it->getValue();
} else if (it->getColumn() > rowNumber) {
break;
}
}
@ -701,13 +751,13 @@ namespace storm {
// add the result to the corresponding position in the vector.
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) {
if (it1->first < it2->first) {
if (it1->getColumn() < it2->getColumn()) {
continue;
} else {
// 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
// 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;
}
}
@ -735,7 +785,7 @@ namespace storm {
*resultIterator = storm::utility::constantZero<T>();
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>();
for (ite = this->begin() + *(rowIterator + 1); it != ite; ++it) {
*resultIterator += it->second * vector[it->first];
*resultIterator += it->getValue() * vector[it->getColumn()];
}
}
#endif
@ -761,7 +811,7 @@ namespace storm {
uint_fast64_t size = sizeof(*this);
// 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.
size += sizeof(uint_fast64_t) * rowIndications.capacity();
@ -833,7 +883,7 @@ namespace storm {
T SparseMatrix<T>::getRowSum(uint_fast64_t row) const {
T sum = storm::utility::constantZero<T>();
for (const_iterator it = this->begin(row), ite = this->end(row); it != ite; ++it) {
sum += it->second;
sum += it->getValue();
}
return sum;
}
@ -849,10 +899,10 @@ namespace storm {
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) {
// 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;
}
if (it2 == ite2 || it1->first != it2->first) {
if (it2 == ite2 || it1->getColumn() != it2->getColumn()) {
return false;
}
}
@ -879,8 +929,8 @@ namespace storm {
out << i << "\t(\t";
uint_fast64_t currentRealIndex = 0;
while (currentRealIndex < matrix.columnCount) {
if (nextIndex < matrix.rowIndications[i + 1] && currentRealIndex == matrix.columnsAndValues[nextIndex].first) {
out << matrix.columnsAndValues[nextIndex].second << "\t";
if (nextIndex < matrix.rowIndications[i + 1] && currentRealIndex == matrix.columnsAndValues[nextIndex].getColumn()) {
out << matrix.columnsAndValues[nextIndex].getValue() << "\t";
++nextIndex;
} else {
out << "0\t";
@ -915,10 +965,12 @@ namespace storm {
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 SparseMatrix<double>;
template std::ostream& operator<<(std::ostream& out, SparseMatrix<double> const& matrix);
template class MatrixEntry<int>;
template class SparseMatrixBuilder<int>;
template class SparseMatrix<int>;
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/utility/constants.h"
#include "src/utility/OsDetection.h"
#include "src/exceptions/InvalidArgumentException.h"
#include "src/exceptions/OutOfRangeException.h"
@ -27,6 +28,83 @@ namespace storm {
// Forward declare matrix class.
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.
*/
@ -128,7 +206,7 @@ namespace storm {
bool storagePreallocated;
// 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
// 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::StormAdapter;
typedef typename std::vector<std::pair<uint_fast64_t, T>>::iterator iterator;
typedef typename std::vector<std::pair<uint_fast64_t, T>>::const_iterator const_iterator;
typedef typename std::vector<MatrixEntry<T>>::iterator iterator;
typedef typename std::vector<MatrixEntry<T>>::const_iterator const_iterator;
/*!
* 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 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.
@ -294,7 +372,7 @@ namespace storm {
* @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.
*/
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.
@ -339,6 +417,13 @@ namespace storm {
*/
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.
*
@ -651,8 +736,11 @@ namespace storm {
// The number of entries in the matrix.
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.
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
// 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.
for(; successorIt != model.getRows(currentState).end(); ++successorIt) {
// 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);
}
// 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.
if (subsystem.get(successorIt->first)) {
if (!visitedStates.get(successorIt->first)) {
if (subsystem.get(successorIt->getColumn())) {
if (!visitedStates.get(successorIt->getColumn())) {
// Save current iterator position so we can continue where we left off later.
recursionIteratorStack.pop_back();
recursionIteratorStack.push_back(successorIt);
// Put unvisited successor on top of our recursion stack and remember that.
recursionStateStack.push_back(successorIt->first);
statesInStack[successorIt->first] = true;
recursionStateStack.push_back(successorIt->getColumn());
statesInStack[successorIt->getColumn()] = true;
// 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.
goto recursionStepForward;
recursionStepBackward:
lowlinks[currentState] = std::min(lowlinks[currentState], lowlinks[successorIt->first]);
} else if (tarjanStackStates.get(successorIt->first)) {
lowlinks[currentState] = std::min(lowlinks[currentState], lowlinks[successorIt->getColumn()]);
} else if (tarjanStackStates.get(successorIt->getColumn())) {
// 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) {
for (auto const& state : scc) {
for (auto const& successor : model.getRows(state)) {
if (scc.find(successor.first) == scc.end()) {
if (scc.find(successor.getColumn()) == scc.end()) {
isBottomScc = false;
break;
}

8
src/storage/dd/CuddDd.cpp

@ -473,15 +473,15 @@ namespace storm {
return this->ddManager;
}
DdForwardIterator<DdType::CUDD> Dd<DdType::CUDD>::begin() const {
DdForwardIterator<DdType::CUDD> Dd<DdType::CUDD>::begin(bool enumerateDontCareMetaVariables) const {
int* cube;
double 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 {
return DdForwardIterator<DdType::CUDD>(this->getDdManager(), nullptr, nullptr, 0, true, nullptr);
DdForwardIterator<DdType::CUDD> Dd<DdType::CUDD>::end(bool enumerateDontCareMetaVariables) const {
return DdForwardIterator<DdType::CUDD>(this->getDdManager(), nullptr, nullptr, 0, true, nullptr, enumerateDontCareMetaVariables);
}
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.
*
* @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.
*/
DdForwardIterator<DdType::CUDD> begin() const;
DdForwardIterator<DdType::CUDD> begin(bool enumerateDontCareMetaVariables = true) const;
/*!
* 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.
*/
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);
private:

48
src/storage/dd/CuddDdForwardIterator.cpp

@ -5,7 +5,11 @@
namespace storm {
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
// scratch.
if (!this->isAtEnd) {
@ -49,6 +53,7 @@ namespace storm {
}
DdForwardIterator<DdType::CUDD>::~DdForwardIterator() {
// We free the pointers sind Cudd allocates them using malloc rather than new/delete.
if (this->cube != nullptr) {
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
// valuations later.
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);
if (metaVariable.getType() == DdMetaVariable<DdType::CUDD>::MetaVariableType::Bool) {
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) {
currentValuation.setBooleanValue(metaVariableName, true);
metaVariableAppearsInCube = true;
if (!currentValuation.containsBooleanIdentifier(metaVariableName)) {
currentValuation.addBooleanIdentifier(metaVariableName, true);
} else {
currentValuation.setBooleanValue(metaVariableName, true);
}
} 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 {
int_fast64_t intValue = 0;
for (uint_fast64_t bitIndex = 0; bitIndex < metaVariable.getNumberOfDdVariables(); ++bitIndex) {
if (cube[metaVariable.getDdVariables()[bitIndex].getCuddAdd().NodeReadIndex()] == 0) {
// Leave bit unset.
metaVariableAppearsInCube = true;
} else if (cube[metaVariable.getDdVariables()[bitIndex].getCuddAdd().NodeReadIndex()] == 1) {
intValue |= 1ull << (metaVariable.getNumberOfDdVariables() - bitIndex - 1);
metaVariableAppearsInCube = true;
} else {
// Temporarily leave bit unset so we can iterate trough the other option later.
// 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>;
// Default-instantiate the constructor.
DdForwardIterator() = default;
DdForwardIterator();
// Forbid copy-construction and copy assignment, because ownership of the internal pointer is unclear then.
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
* more.
* @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.
@ -114,6 +116,10 @@ namespace storm {
// The set of meta variables appearing in the DD.
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.
// This is needed, because cubes may represent many assignments (if they have don't care variables).
uint_fast64_t cubeCounter;

23
src/storage/dd/CuddDdManager.cpp

@ -32,7 +32,7 @@ bool CuddOptionsRegistered = storm::settings::Settings::registerNewModule([] (st
namespace storm {
namespace dd {
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());
}
@ -224,6 +224,10 @@ namespace storm {
Cudd& DdManager<DdType::CUDD>::getCuddManager() {
return this->cuddManager;
}
Cudd const& DdManager<DdType::CUDD>::getCuddManager() const {
return this->cuddManager;
}
std::vector<std::string> DdManager<DdType::CUDD>::getDdVariableNames() const {
// First, we initialize a list DD variables and their names.
@ -246,5 +250,22 @@ namespace storm {
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;
/*!
* 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:
/*!
* Retrieves a list of names of the DD variables in the order of their index.
@ -153,6 +172,13 @@ namespace storm {
*/
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.
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.");
}
OperatorType BaseExpression::getOperator() const {
LOG_THROW(false, storm::exceptions::InvalidAccessException, "Unable to access operator of non-function application expression.");
}
bool BaseExpression::containsVariables() const {
return false;
}
@ -69,18 +73,12 @@ namespace storm {
return false;
}
std::shared_ptr<BaseExpression const> BaseExpression::getSharedPointer() const {
return this->shared_from_this();
bool BaseExpression::isFunctionApplication() const {
return false;
}
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;
std::shared_ptr<BaseExpression const> BaseExpression::getSharedPointer() const {
return this->shared_from_this();
}
std::ostream& operator<<(std::ostream& stream, BaseExpression const& expression) {

26
src/storage/expressions/BaseExpression.h

@ -7,20 +7,15 @@
#include <map>
#include <iostream>
#include "src/storage/expressions/ExpressionReturnType.h"
#include "src/storage/expressions/Valuation.h"
#include "src/storage/expressions/ExpressionVisitor.h"
#include "src/storage/expressions/OperatorType.h"
#include "src/exceptions/InvalidArgumentException.h"
#include "src/utility/OsDetection.h"
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);
namespace expressions {
/*!
* The base class of all expression classes.
*/
@ -97,6 +92,14 @@ namespace storm {
*/
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.
*
@ -132,6 +135,13 @@ namespace storm {
*/
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.
*

10
src/storage/expressions/BinaryBooleanFunctionExpression.cpp

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

6
src/storage/expressions/BinaryExpression.cpp

@ -9,6 +9,10 @@ namespace storm {
// Intentionally left empty.
}
bool BinaryExpression::isFunctionApplication() const {
return true;
}
bool BinaryExpression::containsVariables() const {
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 {
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();
} else {
return this->getSecondOperand();

1
src/storage/expressions/BinaryExpression.h

@ -30,6 +30,7 @@ namespace storm {
virtual ~BinaryExpression() = default;
// Override base class methods.
virtual bool isFunctionApplication() const override;
virtual bool containsVariables() const override;
virtual uint_fast64_t getArity() 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;
}
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 {
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;
// Override base class methods.
virtual storm::expressions::OperatorType getOperator() const override;
virtual int_fast64_t evaluateAsInt(Valuation const* valuation = nullptr) const override;
virtual double evaluateAsDouble(Valuation const* valuation = nullptr) 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) {
// 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 {
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;
// Override base class methods.
virtual storm::expressions::OperatorType getOperator() const override;
virtual bool evaluateAsBool(Valuation const* valuation = nullptr) const override;
virtual std::shared_ptr<BaseExpression const> simplify() 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/IdentifierSubstitutionVisitor.h"
#include "src/storage/expressions/TypeCheckVisitor.h"
#include "src/storage/expressions/LinearityCheckVisitor.h"
#include "src/storage/expressions/Expressions.h"
#include "src/exceptions/InvalidTypeException.h"
#include "src/exceptions/ExceptionMacros.h"
@ -16,27 +17,27 @@ namespace storm {
}
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 {
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 {
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 {
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 {
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 {
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 {
@ -55,6 +56,14 @@ namespace storm {
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 {
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 {
return *this->expressionPtr;
}

38
src/storage/expressions/Expression.h

@ -6,6 +6,7 @@
#include <unordered_map>
#include "src/storage/expressions/BaseExpression.h"
#include "src/storage/expressions/ExpressionVisitor.h"
#include "src/utility/OsDetection.h"
namespace storm {
@ -157,6 +158,21 @@ namespace storm {
*/
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.
*
@ -215,6 +231,21 @@ namespace storm {
*/
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.
*
@ -271,6 +302,13 @@ namespace storm {
*/
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);
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>
Expression IdentifierSubstitutionVisitor<MapType>::substitute(BaseExpression const* expression) {
expression->accept(this);
Expression IdentifierSubstitutionVisitor<MapType>::substitute(Expression const& expression) {
expression.getBaseExpression().accept(this);
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
* 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(BinaryBooleanFunctionExpression const* expression) override;

30
src/storage/expressions/IfThenElseExpression.cpp

@ -1,11 +1,41 @@
#include "src/storage/expressions/IfThenElseExpression.h"
#include "src/exceptions/ExceptionMacros.h"
#include "src/exceptions/InvalidAccessException.h"
namespace storm {
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) {
// 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 conditionValue = this->condition->evaluateAsBool(valuation);
if (conditionValue) {

5
src/storage/expressions/IfThenElseExpression.h

@ -27,6 +27,11 @@ namespace storm {
virtual ~IfThenElseExpression() = default;
// 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 int_fast64_t evaluateAsInt(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 <set>
#include <boost/functional/hash.hpp>
#include "src/exceptions/ExceptionMacros.h"
#include "src/exceptions/InvalidArgumentException.h"
#include "src/exceptions/InvalidAccessException.h"
namespace storm {
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 {
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) {
LOG_THROW(this->booleanIdentifierToIndexMap->find(name) == this->booleanIdentifierToIndexMap->end(), storm::exceptions::InvalidArgumentException, "Boolean identifier '" << name << "' already registered.");
this->booleanIdentifierToIndexMap->emplace(name, this->booleanValues.size());
this->booleanValues.push_back(initialValue);
LOG_THROW(this->identifierToValueMap.find(name) == this->identifierToValueMap.end(), storm::exceptions::InvalidArgumentException, "Identifier '" << name << "' already registered.");
this->identifierToValueMap.emplace(name, 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.");
this->integerIdentifierToIndexMap->emplace(name, this->integerValues.size());
this->integerValues.push_back(initialValue);
LOG_THROW(this->identifierToValueMap.find(name) == this->identifierToValueMap.end(), storm::exceptions::InvalidArgumentException, "Identifier '" << name << "' already registered.");
this->identifierToValueMap.emplace(name, 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.");
this->doubleIdentifierToIndexMap->emplace(name, this->doubleValues.size());
this->doubleValues.push_back(initialValue);
LOG_THROW(this->identifierToValueMap.find(name) == this->identifierToValueMap.end(), storm::exceptions::InvalidArgumentException, "Identifier '" << name << "' already registered.");
this->identifierToValueMap.emplace(name, initialValue);
}
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) {
this->integerValues[this->integerIdentifierToIndexMap->at(name)] = value;
this->identifierToValueMap[name] = 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 {
auto const& nameIndexPair = this->booleanIdentifierToIndexMap->find(name);
return this->booleanValues[nameIndexPair->second];
auto nameValuePair = this->identifierToValueMap.find(name);
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 {
auto const& nameIndexPair = this->integerIdentifierToIndexMap->find(name);
return this->integerValues[nameIndexPair->second];
auto nameValuePair = this->identifierToValueMap.find(name);
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 {
auto const& nameIndexPair = this->doubleIdentifierToIndexMap->find(name);
return this->doubleValues[nameIndexPair->second];
auto nameValuePair = this->identifierToValueMap.find(name);
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) {
stream << "valuation { bool [";
if (!valuation.booleanValues.empty()) {
for (uint_fast64_t i = 0; i < valuation.booleanValues.size() - 1; ++i) {
stream << valuation.booleanValues[i] << ", ";
std::size_t SimpleValuation::getNumberOfIdentifiers() const {
return this->identifierToValueMap.size();
}
std::set<std::string> SimpleValuation::getIdentifiers() const {
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 [";
if (!valuation.integerValues.empty()) {
for (uint_fast64_t i = 0; i < valuation.integerValues.size() - 1; ++i) {
stream << valuation.integerValues[i] << ", ";
return result;
}
std::set<std::string> SimpleValuation::getDoubleIdentifiers() const {
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 [";
if (!valuation.doubleValues.empty()) {
for (uint_fast64_t i = 0; i < valuation.doubleValues.size() - 1; ++i) {
stream << valuation.doubleValues[i] << ", ";
return result;
}
std::ostream& operator<<(std::ostream& stream, SimpleValuation const& valuation) {
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;
}
std::size_t SimpleValuationPointerHash::operator()(SimpleValuation* valuation) const {
size_t seed = 0;
for (auto const& value : valuation->booleanValues) {
boost::hash_combine<bool>(seed, value);
}
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);
for (auto const& nameValuePair : valuation->identifierToValueMap) {
boost::hash_combine(seed, nameValuePair.first);
boost::hash_combine(seed, nameValuePair.second);
}
return seed;
}
@ -107,21 +171,7 @@ namespace storm {
}
bool SimpleValuationPointerLess::operator()(SimpleValuation* valuation1, SimpleValuation* valuation2) const {
// Compare boolean variables.
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;
}
return valuation1->identifierToValueMap < valuation2->identifierToValueMap;
}
}
}

52
src/storage/expressions/SimpleValuation.h

@ -1,12 +1,12 @@
#ifndef STORM_STORAGE_EXPRESSIONS_SIMPLEVALUATION_H_
#define STORM_STORAGE_EXPRESSIONS_SIMPLEVALUATION_H_
#include <memory>
#include <vector>
#include <unordered_map>
#include <boost/container/flat_map.hpp>
#include <boost/variant.hpp>
#include <iostream>
#include "src/storage/expressions/Valuation.h"
#include "src/storage/expressions/ExpressionReturnType.h"
#include "src/utility/OsDetection.h"
namespace storm {
@ -16,12 +16,8 @@ namespace storm {
friend class SimpleValuationPointerHash;
friend class SimpleValuationPointerLess;
/*!
* Creates a simple valuation without any identifiers.
*/
SimpleValuation();
// Instantiate some constructors and assignments with their default implementations.
SimpleValuation() = default;
SimpleValuation(SimpleValuation const&) = default;
SimpleValuation& operator=(SimpleValuation const&) = default;
#ifndef WINDOWS
@ -83,7 +79,30 @@ namespace storm {
*/
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.
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 int_fast64_t getIntegerValue(std::string const& name) const override;
virtual double getDoubleValue(std::string const& name) const override;
@ -92,22 +111,7 @@ namespace storm {
private:
// 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;
// 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;
boost::container::flat_map<std::string, boost::variant<bool, int_fast64_t, double>> identifierToValueMap;
};
/*!

4
src/storage/expressions/SubstitutionVisitor.cpp

@ -13,8 +13,8 @@ namespace storm {
}
template<typename MapType>
Expression SubstitutionVisitor<MapType>::substitute(BaseExpression const* expression) {
expression->accept(this);
Expression SubstitutionVisitor<MapType>::substitute(Expression const& expression) {
expression.getBaseExpression().accept(this);
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
* 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(BinaryBooleanFunctionExpression const* expression) override;

4
src/storage/expressions/TypeCheckVisitor.cpp

@ -12,8 +12,8 @@ namespace storm {
}
template<typename MapType>
void TypeCheckVisitor<MapType>::check(BaseExpression const* expression) {
expression->accept(this);
void TypeCheckVisitor<MapType>::check(Expression const& expression) {
expression.getBaseExpression().accept(this);
}
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.
*/
void check(BaseExpression const* expression);
void check(Expression const& expression);
virtual void visit(IfThenElseExpression 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;
}
storm::expressions::OperatorType UnaryBooleanFunctionExpression::getOperator() const {
switch (this->getOperatorType()) {
case OperatorType::Not: return storm::expressions::OperatorType::Not;
}
}
bool UnaryBooleanFunctionExpression::evaluateAsBool(Valuation const* valuation) const {
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;
// Override base class methods.
virtual storm::expressions::OperatorType getOperator() const override;
virtual bool evaluateAsBool(Valuation const* valuation = nullptr) const override;
virtual std::shared_ptr<BaseExpression const> simplify() const override;
virtual void accept(ExpressionVisitor* visitor) const override;

4
src/storage/expressions/UnaryExpression.cpp

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

1
src/storage/expressions/UnaryExpression.h

@ -26,6 +26,7 @@ namespace storm {
virtual ~UnaryExpression() = default;
// Override base class methods.
virtual bool isFunctionApplication() const override;
virtual bool containsVariables() const override;
virtual uint_fast64_t getArity() 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;
}
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 {
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;
// Override base class methods.
virtual storm::expressions::OperatorType getOperator() const override;
virtual int_fast64_t evaluateAsInt(Valuation const* valuation = nullptr) const override;
virtual double evaluateAsDouble(Valuation const* valuation = nullptr) 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_
#include <string>
#include <set>
namespace storm {
namespace expressions {
@ -34,6 +35,66 @@ namespace storm {
* @return The value of the double identifier.
*/
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() {
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 (this->getInitialConstruct().getInitialStatesExpression().isFalse()) {
storm::expressions::Expression newInitialExpression = storm::expressions::Expression::createTrue();

28
src/utility/counterexamples.h

@ -36,8 +36,8 @@ namespace storm {
// for (auto state : psiStates) {
// analysisInformation[state] = boost::container::flat_set<uint_fast64_t>();
// for (auto const& predecessorEntry : backwardTransitions.getRow(state)) {
// if (predecessorEntry.first != state && !psiStates.get(predecessorEntry.first)) {
// worklist.push(std::make_pair(predecessorEntry.first, state));
// if (predecessorEntry.getColumn() != state && !psiStates.get(predecessorEntry.getColumn())) {
// worklist.push(std::make_pair(predecessorEntry.getColumn(), state));
// }
// }
// }
@ -57,7 +57,7 @@ namespace storm {
// bool choiceTargetsTargetState = false;
//
// for (auto& entry : transitionMatrix.getRow(currentChoice)) {
// if (entry.first == targetState) {
// if (entry.getColumn() == targetState) {
// choiceTargetsTargetState = true;
// break;
// }
@ -79,8 +79,8 @@ namespace storm {
// if (analysisInformation[currentState].size() != analysisInformationSizeBefore) {
// for (auto& predecessorEntry : backwardTransitions.getRow(currentState)) {
// // Only put the predecessor in the worklist if it's not already a target state.
// if (!psiStates.get(predecessorEntry.first)) {
// worklist.push(std::make_pair(predecessorEntry.first, currentState));
// if (!psiStates.get(predecessorEntry.getColumn())) {
// worklist.push(std::make_pair(predecessorEntry.getColumn(), currentState));
// }
// }
// }
@ -96,9 +96,9 @@ namespace storm {
for (auto state : psiStates) {
analysisInformation[state] = boost::container::flat_set<uint_fast64_t>();
for (auto const& predecessorEntry : backwardTransitions.getRow(state)) {
if (predecessorEntry.first != state && !statesInWorkList.get(predecessorEntry.first) && !psiStates.get(predecessorEntry.first)) {
worklist.push(predecessorEntry.first);
statesInWorkList.set(predecessorEntry.first);
if (predecessorEntry.getColumn() != state && !statesInWorkList.get(predecessorEntry.getColumn()) && !psiStates.get(predecessorEntry.getColumn())) {
worklist.push(predecessorEntry.getColumn());
statesInWorkList.set(predecessorEntry.getColumn());
markedStates.set(state);
}
}
@ -116,7 +116,7 @@ namespace storm {
bool modifiedChoice = false;
for (auto const& entry : transitionMatrix.getRow(currentChoice)) {
if (markedStates.get(entry.first)) {
if (markedStates.get(entry.getColumn())) {
modifiedChoice = true;
break;
}
@ -127,9 +127,9 @@ namespace storm {
// and the choice labels.
if (modifiedChoice) {
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;
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()));
analysisInformation[currentState] = std::move(tmpIntersection);
}
@ -142,9 +142,9 @@ namespace storm {
if (analysisInformation[currentState].size() != analysisInformationSizeBefore) {
for (auto const& predecessorEntry : backwardTransitions.getRow(currentState)) {
// Only put the predecessor in the worklist if it's not already a target state.
if (!psiStates.get(predecessorEntry.first) && !statesInWorkList.get(predecessorEntry.first)) {
worklist.push(predecessorEntry.first);
statesInWorkList.set(predecessorEntry.first);
if (!psiStates.get(predecessorEntry.getColumn()) && !statesInWorkList.get(predecessorEntry.getColumn())) {
worklist.push(predecessorEntry.getColumn());
statesInWorkList.set(predecessorEntry.getColumn());
}
}
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) {
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 (!useStepBound) {
statesWithProbabilityGreater0.set(entryIt->first, true);
stack.push_back(entryIt->first);
statesWithProbabilityGreater0.set(entryIt->getColumn(), true);
stack.push_back(entryIt->getColumn());
} 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.
remainingSteps[entryIt->first] = currentStepBound - 1;
statesWithProbabilityGreater0.set(entryIt->first, true);
stack.push_back(entryIt->first);
remainingSteps[entryIt->getColumn()] = currentStepBound - 1;
statesWithProbabilityGreater0.set(entryIt->getColumn(), true);
stack.push_back(entryIt->getColumn());
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) {
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 (!useStepBound) {
statesWithProbabilityGreater0.set(entryIt->first, true);
stack.push_back(entryIt->first);
statesWithProbabilityGreater0.set(entryIt->getColumn(), true);
stack.push_back(entryIt->getColumn());
} 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.
remainingSteps[entryIt->first] = currentStepBound - 1;
statesWithProbabilityGreater0.set(entryIt->first, true);
stack.push_back(entryIt->first);
remainingSteps[entryIt->getColumn()] = currentStepBound - 1;
statesWithProbabilityGreater0.set(entryIt->getColumn(), true);
stack.push_back(entryIt->getColumn());
stepStack.push_back(currentStepBound - 1);
}
}
@ -290,13 +290,13 @@ namespace storm {
stack.pop_back();
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
// 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;
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;
break;
}
@ -306,8 +306,8 @@ namespace storm {
// add it to the set of states for the next iteration and perform a backward search from
// that state.
if (allSuccessorsInCurrentStates) {
nextStates.set(predecessorEntryIt->first, true);
stack.push_back(predecessorEntryIt->first);
nextStates.set(predecessorEntryIt->getColumn(), true);
stack.push_back(predecessorEntryIt->getColumn());
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) {
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
// nondeterministic choice.
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;
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;
break;
}
@ -424,13 +424,13 @@ namespace storm {
if (addToStatesWithProbabilityGreater0) {
// If we don't have a bound on the number of steps to take, just add the state to the stack.
if (!useStepBound) {
statesWithProbabilityGreater0.set(predecessorEntryIt->first, true);
stack.push_back(predecessorEntryIt->first);
statesWithProbabilityGreater0.set(predecessorEntryIt->getColumn(), true);
stack.push_back(predecessorEntryIt->getColumn());
} 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.
remainingSteps[predecessorEntryIt->first] = currentStepBound - 1;
statesWithProbabilityGreater0.set(predecessorEntryIt->first, true);
stack.push_back(predecessorEntryIt->first);
remainingSteps[predecessorEntryIt->getColumn()] = currentStepBound - 1;
statesWithProbabilityGreater0.set(predecessorEntryIt->getColumn(), true);
stack.push_back(predecessorEntryIt->getColumn());
stepStack.push_back(currentStepBound - 1);
}
}
@ -501,12 +501,12 @@ namespace storm {
stack.pop_back();
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
// nondeterminstic choices.
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) {
if (!currentStates.get(successorEntryIt->first)) {
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->getColumn())) {
allSuccessorsInCurrentStatesForAllChoices = false;
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
// that state.
if (allSuccessorsInCurrentStatesForAllChoices) {
nextStates.set(predecessorEntryIt->first, true);
stack.push_back(predecessorEntryIt->first);
nextStates.set(predecessorEntryIt->getColumn(), true);
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.
typename storm::storage::SparseMatrix<T>::const_rows selectedRow = transitionMatrix.getRow(choice);
for (auto const& entry : selectedRow) {
matrixBuilder.addNextValue(state, entry.first, entry.second);
matrixBuilder.addNextValue(state, entry.getColumn(), entry.getValue());
}
} else {
// 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>>();
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>());
@ -74,7 +74,7 @@ TEST(GmmxxDtmcPrctlModelCheckerTest, Crowds) {
std::shared_ptr<storm::models::Dtmc<double>> dtmc = abstractModel->as<storm::models::Dtmc<double>>();
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>());
@ -119,7 +119,7 @@ TEST(GmmxxDtmcPrctlModelCheckerTest, SynchronousLeader) {
std::shared_ptr<storm::models::Dtmc<double>> dtmc = abstractModel->as<storm::models::Dtmc<double>>();
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>());

12
test/functional/parser/AutoParserTest.cpp

@ -24,7 +24,7 @@ TEST(AutoParserTest, BasicParsing) {
// Test if parsed correctly.
ASSERT_EQ(storm::models::DTMC, modelPtr->getType());
ASSERT_EQ(12, modelPtr->getNumberOfStates());
ASSERT_EQ(32, modelPtr->getNumberOfTransitions());
ASSERT_EQ(26, modelPtr->getNumberOfTransitions());
ASSERT_EQ(1, modelPtr->getInitialStates().getNumberOfSetBits());
ASSERT_TRUE(modelPtr->hasAtomicProposition("three"));
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");
ASSERT_EQ(storm::models::DTMC, modelPtr->getType());
ASSERT_EQ(12, modelPtr->getNumberOfStates());
ASSERT_EQ(32, modelPtr->getNumberOfTransitions());
ASSERT_EQ(26, modelPtr->getNumberOfTransitions());
// Ctmc
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");
ASSERT_EQ(storm::models::CTMC, modelPtr->getType());
ASSERT_EQ(12, modelPtr->getNumberOfStates());
ASSERT_EQ(31, modelPtr->getNumberOfTransitions());
ASSERT_EQ(26, modelPtr->getNumberOfTransitions());
// Mdp
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");
ASSERT_EQ(storm::models::MDP, modelPtr->getType());
ASSERT_EQ(12, modelPtr->getNumberOfStates());
ASSERT_EQ(36, modelPtr->getNumberOfTransitions());
ASSERT_EQ(28, modelPtr->getNumberOfTransitions());
// 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.
@ -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");
ASSERT_EQ(storm::models::CTMDP, modelPtr->getType());
ASSERT_EQ(12, modelPtr->getNumberOfStates());
ASSERT_EQ(36, modelPtr->getNumberOfTransitions());
ASSERT_EQ(28, modelPtr->getNumberOfTransitions());
// MA
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");
ASSERT_EQ(storm::models::MA, modelPtr->getType());
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"));
ASSERT_EQ(8, dtmc.getNumberOfStates());
ASSERT_EQ(21, dtmc.getNumberOfTransitions());
ASSERT_EQ(16, dtmc.getNumberOfTransitions());
ASSERT_EQ(2, dtmc.getInitialStates().getNumberOfSetBits());
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"));
ASSERT_EQ(8, ctmc.getNumberOfStates());
ASSERT_EQ(21, ctmc.getNumberOfTransitions());
ASSERT_EQ(16, ctmc.getNumberOfTransitions());
ASSERT_EQ(2, ctmc.getInitialStates().getNumberOfSetBits());
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.
storm::storage::SparseMatrix<double>::const_iterator cIter = transitionMatrix.begin(0);
ASSERT_EQ(0, cIter->first);
ASSERT_EQ(0, cIter->second);
ASSERT_EQ(0, cIter->getColumn());
ASSERT_EQ(0, cIter->getValue());
cIter++;
ASSERT_EQ(1, cIter->first);
ASSERT_EQ(1, cIter->second);
ASSERT_EQ(1, cIter->getColumn());
ASSERT_EQ(1, cIter->getValue());
cIter++;
ASSERT_EQ(1, cIter->first);
ASSERT_EQ(0, cIter->second);
ASSERT_EQ(1, cIter->getColumn());
ASSERT_EQ(0, cIter->getValue());
cIter++;
ASSERT_EQ(2, cIter->first);
ASSERT_EQ(0.5, cIter->second);
ASSERT_EQ(2, cIter->getColumn());
ASSERT_EQ(0.5, cIter->getValue());
cIter++;
ASSERT_EQ(3, cIter->first);
ASSERT_EQ(0.5, cIter->second);
ASSERT_EQ(3, cIter->getColumn());
ASSERT_EQ(0.5, cIter->getValue());
cIter++;
ASSERT_EQ(2, cIter->first);
ASSERT_EQ(0, cIter->second);
ASSERT_EQ(2, cIter->getColumn());
ASSERT_EQ(0, cIter->getValue());
cIter++;
ASSERT_EQ(3, cIter->first);
ASSERT_EQ(0.4, cIter->second);
ASSERT_EQ(3, cIter->getColumn());
ASSERT_EQ(0.4, cIter->getValue());
cIter++;
ASSERT_EQ(4, cIter->first);
ASSERT_EQ(0.4, cIter->second);
ASSERT_EQ(4, cIter->getColumn());
ASSERT_EQ(0.4, cIter->getValue());
cIter++;
ASSERT_EQ(5, cIter->first);
ASSERT_EQ(0.2, cIter->second);
ASSERT_EQ(5, cIter->getColumn());
ASSERT_EQ(0.2, cIter->getValue());
cIter++;
ASSERT_EQ(3, cIter->first);
ASSERT_EQ(1, cIter->second);
ASSERT_EQ(3, cIter->getColumn());
ASSERT_EQ(1, cIter->getValue());
cIter++;
ASSERT_EQ(3, cIter->first);
ASSERT_EQ(1, cIter->second);
ASSERT_EQ(3, cIter->getColumn());
ASSERT_EQ(1, cIter->getValue());
cIter++;
ASSERT_EQ(4, cIter->first);
ASSERT_EQ(0, cIter->second);
ASSERT_EQ(4, cIter->getColumn());
ASSERT_EQ(0, cIter->getValue());
cIter++;
ASSERT_EQ(3, cIter->first);
ASSERT_EQ(0.1, cIter->second);
ASSERT_EQ(3, cIter->getColumn());
ASSERT_EQ(0.1, cIter->getValue());
cIter++;
ASSERT_EQ(4, cIter->first);
ASSERT_EQ(0.1, cIter->second);
ASSERT_EQ(4, cIter->getColumn());
ASSERT_EQ(0.1, cIter->getValue());
cIter++;
ASSERT_EQ(5, cIter->first);
ASSERT_EQ(0.1, cIter->second);
ASSERT_EQ(5, cIter->getColumn());
ASSERT_EQ(0.1, cIter->getValue());
cIter++;
ASSERT_EQ(6, cIter->first);
ASSERT_EQ(0.7, cIter->second);
ASSERT_EQ(6, cIter->getColumn());
ASSERT_EQ(0.7, cIter->getValue());
cIter++;
ASSERT_EQ(0, cIter->first);
ASSERT_EQ(0.9, cIter->second);
ASSERT_EQ(0, cIter->getColumn());
ASSERT_EQ(0.9, cIter->getValue());
cIter++;
ASSERT_EQ(5, cIter->first);
ASSERT_EQ(0, cIter->second);
ASSERT_EQ(5, cIter->getColumn());
ASSERT_EQ(0, cIter->getValue());
cIter++;
ASSERT_EQ(6, cIter->first);
ASSERT_EQ(0.1, cIter->second);
ASSERT_EQ(6, cIter->getColumn());
ASSERT_EQ(0.1, cIter->getValue());
cIter++;
ASSERT_EQ(6, cIter->first);
ASSERT_EQ(0.224653, cIter->second);
ASSERT_EQ(6, cIter->getColumn());
ASSERT_EQ(0.224653, cIter->getValue());
cIter++;
ASSERT_EQ(7, cIter->first);
ASSERT_EQ(0.775347, cIter->second);
ASSERT_EQ(7, cIter->getColumn());
ASSERT_EQ(0.775347, cIter->getValue());
}
TEST(DeterministicSparseTransitionParserTest, BasicTransitionsRewardsParsing) {
@ -112,56 +112,56 @@ TEST(DeterministicSparseTransitionParserTest, BasicTransitionsRewardsParsing) {
// Test every entry of the matrix.
storm::storage::SparseMatrix<double>::const_iterator cIter = rewardMatrix.begin(0);
ASSERT_EQ(1, cIter->first);
ASSERT_EQ(10, cIter->second);
ASSERT_EQ(1, cIter->getColumn());
ASSERT_EQ(10, cIter->getValue());
cIter++;
ASSERT_EQ(2, cIter->first);
ASSERT_EQ(5, cIter->second);
ASSERT_EQ(2, cIter->getColumn());
ASSERT_EQ(5, cIter->getValue());
cIter++;
ASSERT_EQ(3, cIter->first);
ASSERT_EQ(5.5, cIter->second);
ASSERT_EQ(3, cIter->getColumn());
ASSERT_EQ(5.5, cIter->getValue());
cIter++;
ASSERT_EQ(3, cIter->first);
ASSERT_EQ(21.4, cIter->second);
ASSERT_EQ(3, cIter->getColumn());
ASSERT_EQ(21.4, cIter->getValue());
cIter++;
ASSERT_EQ(4, cIter->first);
ASSERT_EQ(4, cIter->second);
ASSERT_EQ(4, cIter->getColumn());
ASSERT_EQ(4, cIter->getValue());
cIter++;
ASSERT_EQ(5, cIter->first);
ASSERT_EQ(2, cIter->second);
ASSERT_EQ(5, cIter->getColumn());
ASSERT_EQ(2, cIter->getValue());
cIter++;
ASSERT_EQ(3, cIter->first);
ASSERT_EQ(1, cIter->second);
ASSERT_EQ(3, cIter->getColumn());
ASSERT_EQ(1, cIter->getValue());
cIter++;
ASSERT_EQ(3, cIter->first);
ASSERT_EQ(1, cIter->second);
ASSERT_EQ(3, cIter->getColumn());
ASSERT_EQ(1, cIter->getValue());
cIter++;
ASSERT_EQ(3, cIter->first);
ASSERT_EQ(0.1, cIter->second);
ASSERT_EQ(3, cIter->getColumn());
ASSERT_EQ(0.1, cIter->getValue());
cIter++;
ASSERT_EQ(4, cIter->first);
ASSERT_EQ(1.1, cIter->second);
ASSERT_EQ(4, cIter->getColumn());
ASSERT_EQ(1.1, cIter->getValue());
cIter++;
ASSERT_EQ(5, cIter->first);
ASSERT_EQ(9.5, cIter->second);
ASSERT_EQ(5, cIter->getColumn());
ASSERT_EQ(9.5, cIter->getValue());
cIter++;
ASSERT_EQ(6, cIter->first);
ASSERT_EQ(6.7, cIter->second);
ASSERT_EQ(6, cIter->getColumn());
ASSERT_EQ(6.7, cIter->getValue());
cIter++;
ASSERT_EQ(0, cIter->first);
ASSERT_EQ(1, cIter->second);
ASSERT_EQ(0, cIter->getColumn());
ASSERT_EQ(1, cIter->getValue());
cIter++;
ASSERT_EQ(5, cIter->first);
ASSERT_EQ(0, cIter->second);
ASSERT_EQ(5, cIter->getColumn());
ASSERT_EQ(0, cIter->getValue());
cIter++;
ASSERT_EQ(6, cIter->first);
ASSERT_EQ(12, cIter->second);
ASSERT_EQ(6, cIter->getColumn());
ASSERT_EQ(12, cIter->getValue());
cIter++;
ASSERT_EQ(6, cIter->first);
ASSERT_EQ(35.224653, cIter->second);
ASSERT_EQ(6, cIter->getColumn());
ASSERT_EQ(35.224653, cIter->getValue());
cIter++;
ASSERT_EQ(7, cIter->first);
ASSERT_EQ(9.875347, cIter->second);
ASSERT_EQ(7, cIter->getColumn());
ASSERT_EQ(9.875347, cIter->getValue());
}
@ -201,17 +201,17 @@ TEST(DeterministicSparseTransitionParserTest, FixDeadlocks) {
ASSERT_EQ(23, transitionMatrix.getEntryCount());
storm::storage::SparseMatrix<double>::const_iterator cIter = transitionMatrix.begin(7);
ASSERT_EQ(7, cIter->first);
ASSERT_EQ(1, cIter->second);
ASSERT_EQ(7, cIter->getColumn());
ASSERT_EQ(1, cIter->getValue());
cIter++;
ASSERT_EQ(6, cIter->first);
ASSERT_EQ(0.224653, cIter->second);
ASSERT_EQ(6, cIter->getColumn());
ASSERT_EQ(0.224653, cIter->getValue());
cIter++;
ASSERT_EQ(7, cIter->first);
ASSERT_EQ(0.775347, cIter->second);
ASSERT_EQ(7, cIter->getColumn());
ASSERT_EQ(0.775347, cIter->getValue());
cIter++;
ASSERT_EQ(8, cIter->first);
ASSERT_EQ(0, cIter->second);
ASSERT_EQ(8, cIter->getColumn());
ASSERT_EQ(0, cIter->getValue());
}
TEST(DeterministicSparseTransitionParserTest, DontFixDeadlocks) {

48
test/functional/parser/MarkovAutomatonSparseTransitionParserTest.cpp

@ -79,29 +79,29 @@ TEST(MarkovAutomatonSparseTransitionParserTest, BasicParsing) {
// Finally, test the transition matrix itself.
storm::storage::SparseMatrix<double>::const_iterator cIter = transitionMatrix.begin(0);
ASSERT_EQ(2, cIter->second);
ASSERT_EQ(2, cIter->getValue());
cIter++;
ASSERT_EQ(1, cIter->second);
ASSERT_EQ(1, cIter->getValue());
cIter++;
ASSERT_EQ(1, cIter->second);
ASSERT_EQ(1, cIter->getValue());
cIter++;
ASSERT_EQ(2, cIter->second);
ASSERT_EQ(2, cIter->getValue());
cIter++;
ASSERT_EQ(4, cIter->second);
ASSERT_EQ(4, cIter->getValue());
cIter++;
ASSERT_EQ(8, cIter->second);
ASSERT_EQ(8, cIter->getValue());
cIter++;
ASSERT_EQ(0.5, cIter->second);
ASSERT_EQ(0.5, cIter->getValue());
cIter++;
ASSERT_EQ(0.5, cIter->second);
ASSERT_EQ(0.5, cIter->getValue());
cIter++;
ASSERT_EQ(1, cIter->second);
ASSERT_EQ(1, cIter->getValue());
cIter++;
ASSERT_EQ(0.5, cIter->second);
ASSERT_EQ(0.5, cIter->getValue());
cIter++;
ASSERT_EQ(0.5, cIter->second);
ASSERT_EQ(0.5, cIter->getValue());
cIter++;
ASSERT_EQ(1, cIter->second);
ASSERT_EQ(1, cIter->getValue());
cIter++;
ASSERT_EQ(transitionMatrix.end(), cIter);
}
@ -157,29 +157,29 @@ TEST(MarkovAutomatonSparseTransitionParserTest, Whitespaces) {
// Finally, test the transition matrix itself.
storm::storage::SparseMatrix<double>::const_iterator cIter = transitionMatrix.begin(0);
ASSERT_EQ(2, cIter->second);
ASSERT_EQ(2, cIter->getValue());
cIter++;
ASSERT_EQ(1, cIter->second);
ASSERT_EQ(1, cIter->getValue());
cIter++;
ASSERT_EQ(1, cIter->second);
ASSERT_EQ(1, cIter->getValue());
cIter++;
ASSERT_EQ(2, cIter->second);
ASSERT_EQ(2, cIter->getValue());
cIter++;
ASSERT_EQ(4, cIter->second);
ASSERT_EQ(4, cIter->getValue());
cIter++;
ASSERT_EQ(8, cIter->second);
ASSERT_EQ(8, cIter->getValue());
cIter++;
ASSERT_EQ(0.5, cIter->second);
ASSERT_EQ(0.5, cIter->getValue());
cIter++;
ASSERT_EQ(0.5, cIter->second);
ASSERT_EQ(0.5, cIter->getValue());
cIter++;
ASSERT_EQ(1, cIter->second);
ASSERT_EQ(1, cIter->getValue());
cIter++;
ASSERT_EQ(0.5, cIter->second);
ASSERT_EQ(0.5, cIter->getValue());
cIter++;
ASSERT_EQ(0.5, cIter->second);
ASSERT_EQ(0.5, cIter->getValue());
cIter++;
ASSERT_EQ(1, cIter->second);
ASSERT_EQ(1, cIter->getValue());
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.
storm::storage::SparseMatrix<double>::const_iterator cIter = result.begin(0);
ASSERT_EQ(0, cIter->first);
ASSERT_EQ(0.9, cIter->second);
ASSERT_EQ(0, cIter->getColumn());
ASSERT_EQ(0.9, cIter->getValue());
cIter++;
ASSERT_EQ(1, cIter->first);
ASSERT_EQ(0.1, cIter->second);
ASSERT_EQ(1, cIter->getColumn());
ASSERT_EQ(0.1, cIter->getValue());
cIter++;
ASSERT_EQ(1, cIter->first);
ASSERT_EQ(0.2, cIter->second);
ASSERT_EQ(1, cIter->getColumn());
ASSERT_EQ(0.2, cIter->getValue());
cIter++;
ASSERT_EQ(2, cIter->first);
ASSERT_EQ(0.2, cIter->second);
ASSERT_EQ(2, cIter->getColumn());
ASSERT_EQ(0.2, cIter->getValue());
cIter++;
ASSERT_EQ(3, cIter->first);
ASSERT_EQ(0.2, cIter->second);
ASSERT_EQ(3, cIter->getColumn());
ASSERT_EQ(0.2, cIter->getValue());
cIter++;
ASSERT_EQ(4, cIter->first);
ASSERT_EQ(0.2, cIter->second);
ASSERT_EQ(4, cIter->getColumn());
ASSERT_EQ(0.2, cIter->getValue());
cIter++;
ASSERT_EQ(5, cIter->first);
ASSERT_EQ(0.2, cIter->second);
ASSERT_EQ(5, cIter->getColumn());
ASSERT_EQ(0.2, cIter->getValue());
cIter++;
ASSERT_EQ(5, cIter->first);
ASSERT_EQ(1, cIter->second);
ASSERT_EQ(5, cIter->getColumn());
ASSERT_EQ(1, cIter->getValue());
cIter++;
ASSERT_EQ(0, cIter->first);
ASSERT_EQ(0.1, cIter->second);
ASSERT_EQ(0, cIter->getColumn());
ASSERT_EQ(0.1, cIter->getValue());
cIter++;
ASSERT_EQ(4, cIter->first);
ASSERT_EQ(0.9, cIter->second);
ASSERT_EQ(4, cIter->getColumn());
ASSERT_EQ(0.9, cIter->getValue());
cIter++;
ASSERT_EQ(2, cIter->first);
ASSERT_EQ(1, cIter->second);
ASSERT_EQ(2, cIter->getColumn());
ASSERT_EQ(1, cIter->getValue());
cIter++;
ASSERT_EQ(2, cIter->first);
ASSERT_EQ(0.5, cIter->second);
ASSERT_EQ(2, cIter->getColumn());
ASSERT_EQ(0.5, cIter->getValue());
cIter++;
ASSERT_EQ(3, cIter->first);
ASSERT_EQ(0.5, cIter->second);
ASSERT_EQ(3, cIter->getColumn());
ASSERT_EQ(0.5, cIter->getValue());
cIter++;
ASSERT_EQ(2, cIter->first);
ASSERT_EQ(1, cIter->second);
ASSERT_EQ(2, cIter->getColumn());
ASSERT_EQ(1, cIter->getValue());
cIter++;
ASSERT_EQ(2, cIter->first);
ASSERT_EQ(0.001, cIter->second);
ASSERT_EQ(2, cIter->getColumn());
ASSERT_EQ(0.001, cIter->getValue());
cIter++;
ASSERT_EQ(3, cIter->first);
ASSERT_EQ(0.999, cIter->second);
ASSERT_EQ(3, cIter->getColumn());
ASSERT_EQ(0.999, cIter->getValue());
cIter++;
ASSERT_EQ(1, cIter->first);
ASSERT_EQ(0.7, cIter->second);
ASSERT_EQ(1, cIter->getColumn());
ASSERT_EQ(0.7, cIter->getValue());
cIter++;
ASSERT_EQ(4, cIter->first);
ASSERT_EQ(0.3, cIter->second);
ASSERT_EQ(4, cIter->getColumn());
ASSERT_EQ(0.3, cIter->getValue());
cIter++;
ASSERT_EQ(1, cIter->first);
ASSERT_EQ(0.2, cIter->second);
ASSERT_EQ(1, cIter->getColumn());
ASSERT_EQ(0.2, cIter->getValue());
cIter++;
ASSERT_EQ(4, cIter->first);
ASSERT_EQ(0.2, cIter->second);
ASSERT_EQ(4, cIter->getColumn());
ASSERT_EQ(0.2, cIter->getValue());
cIter++;
ASSERT_EQ(5, cIter->first);
ASSERT_EQ(0.6, cIter->second);
ASSERT_EQ(5, cIter->getColumn());
ASSERT_EQ(0.6, cIter->getValue());
cIter++;
ASSERT_EQ(5, cIter->first);
ASSERT_EQ(1, cIter->second);
ASSERT_EQ(5, cIter->getColumn());
ASSERT_EQ(1, cIter->getValue());
}
TEST(NondeterministicSparseTransitionParserTest, BasicTransitionsRewardsParsing) {
@ -128,56 +128,56 @@ TEST(NondeterministicSparseTransitionParserTest, BasicTransitionsRewardsParsing)
// Test every entry of the matrix.
storm::storage::SparseMatrix<double>::const_iterator cIter = result.begin(0);
ASSERT_EQ(0, cIter->first);
ASSERT_EQ(1, cIter->second);
ASSERT_EQ(0, cIter->getColumn());
ASSERT_EQ(1, cIter->getValue());
cIter++;
ASSERT_EQ(1, cIter->first);
ASSERT_EQ(30, cIter->second);
ASSERT_EQ(1, cIter->getColumn());
ASSERT_EQ(30, cIter->getValue());
cIter++;
ASSERT_EQ(1, cIter->first);
ASSERT_EQ(15.2, cIter->second);
ASSERT_EQ(1, cIter->getColumn());
ASSERT_EQ(15.2, cIter->getValue());
cIter++;
ASSERT_EQ(2, cIter->first);
ASSERT_EQ(75, cIter->second);
ASSERT_EQ(2, cIter->getColumn());
ASSERT_EQ(75, cIter->getValue());
cIter++;
ASSERT_EQ(5, cIter->first);
ASSERT_EQ(2.45, cIter->second);
ASSERT_EQ(5, cIter->getColumn());
ASSERT_EQ(2.45, cIter->getValue());
cIter++;
ASSERT_EQ(5, cIter->first);
ASSERT_EQ(1, cIter->second);
ASSERT_EQ(5, cIter->getColumn());
ASSERT_EQ(1, cIter->getValue());
cIter++;
ASSERT_EQ(0, cIter->first);
ASSERT_EQ(0.114, cIter->second);
ASSERT_EQ(0, cIter->getColumn());
ASSERT_EQ(0.114, cIter->getValue());
cIter++;
ASSERT_EQ(4, cIter->first);
ASSERT_EQ(90, cIter->second);
ASSERT_EQ(4, cIter->getColumn());
ASSERT_EQ(90, cIter->getValue());
cIter++;
ASSERT_EQ(2, cIter->first);
ASSERT_EQ(1, cIter->second);
ASSERT_EQ(2, cIter->getColumn());
ASSERT_EQ(1, cIter->getValue());
cIter++;
ASSERT_EQ(2, cIter->first);
ASSERT_EQ(55, cIter->second);
ASSERT_EQ(2, cIter->getColumn());
ASSERT_EQ(55, cIter->getValue());
cIter++;
ASSERT_EQ(3, cIter->first);
ASSERT_EQ(87, cIter->second);
ASSERT_EQ(3, cIter->getColumn());
ASSERT_EQ(87, cIter->getValue());
cIter++;
ASSERT_EQ(2, cIter->first);
ASSERT_EQ(13, cIter->second);
ASSERT_EQ(2, cIter->getColumn());
ASSERT_EQ(13, cIter->getValue());
cIter++;
ASSERT_EQ(3, cIter->first);
ASSERT_EQ(999, cIter->second);
ASSERT_EQ(3, cIter->getColumn());
ASSERT_EQ(999, cIter->getValue());
cIter++;
ASSERT_EQ(1, cIter->first);
ASSERT_EQ(0.7, cIter->second);
ASSERT_EQ(1, cIter->getColumn());
ASSERT_EQ(0.7, cIter->getValue());
cIter++;
ASSERT_EQ(4, cIter->first);
ASSERT_EQ(0.3, cIter->second);
ASSERT_EQ(4, cIter->getColumn());
ASSERT_EQ(0.3, cIter->getValue());
cIter++;
ASSERT_EQ(1, cIter->first);
ASSERT_EQ(0.1, cIter->second);
ASSERT_EQ(1, cIter->getColumn());
ASSERT_EQ(0.1, cIter->getValue());
cIter++;
ASSERT_EQ(5, cIter->first);
ASSERT_EQ(6, cIter->second);
ASSERT_EQ(5, cIter->getColumn());
ASSERT_EQ(6, cIter->getValue());
}
TEST(NondeterministicSparseTransitionParserTest, Whitespaces) {
@ -224,26 +224,26 @@ TEST(NondeterministicSparseTransitionParserTest, FixDeadlocks) {
storm::storage::SparseMatrix<double>::const_iterator cIter = result.begin(8);
ASSERT_EQ(1, cIter->first);
ASSERT_EQ(0.7, cIter->second);
ASSERT_EQ(1, cIter->getColumn());
ASSERT_EQ(0.7, cIter->getValue());
cIter++;
ASSERT_EQ(4, cIter->first);
ASSERT_EQ(0.3, cIter->second);
ASSERT_EQ(4, cIter->getColumn());
ASSERT_EQ(0.3, cIter->getValue());
cIter++;
ASSERT_EQ(5, cIter->first);
ASSERT_EQ(1, cIter->second);
ASSERT_EQ(5, cIter->getColumn());
ASSERT_EQ(1, cIter->getValue());
cIter++;
ASSERT_EQ(1, cIter->first);
ASSERT_EQ(0.2, cIter->second);
ASSERT_EQ(1, cIter->getColumn());
ASSERT_EQ(0.2, cIter->getValue());
cIter++;
ASSERT_EQ(4, cIter->first);
ASSERT_EQ(0.2, cIter->second);
ASSERT_EQ(4, cIter->getColumn());
ASSERT_EQ(0.2, cIter->getValue());
cIter++;
ASSERT_EQ(5, cIter->first);
ASSERT_EQ(0.6, cIter->second);
ASSERT_EQ(5, cIter->getColumn());
ASSERT_EQ(0.6, cIter->getValue());
cIter++;
ASSERT_EQ(5, cIter->first);
ASSERT_EQ(1, cIter->second);
ASSERT_EQ(5, cIter->getColumn());
ASSERT_EQ(1, cIter->getValue());
}

243
test/functional/solver/GlpkLpSolverTest.cpp

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

240
test/functional/solver/GurobiLpSolverTest.cpp

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

22
test/functional/storage/CuddDdTest.cpp

@ -307,4 +307,26 @@ TEST(CuddDd, ForwardIteratorTest) {
++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 "src/storage/expressions/Expression.h"
#include "src/storage/expressions/LinearityCheckVisitor.h"
#include "src/storage/expressions/SimpleValuation.h"
#include "src/exceptions/InvalidTypeException.h"
@ -332,4 +333,20 @@ TEST(Expression, SimpleEvaluationTest) {
ASSERT_THROW(tempExpression.evaluateAsDouble(&valuation), storm::exceptions::InvalidTypeException);
ASSERT_THROW(tempExpression.evaluateAsInt(&valuation), storm::exceptions::InvalidTypeException);
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) {
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(2, 1.2);
columnsAndValues.emplace_back(0, 0.5);
@ -540,24 +540,24 @@ TEST(SparseMatrix, Iteration) {
ASSERT_NO_THROW(matrix = matrixBuilder.build());
for (auto const& entry : matrix.getRow(4)) {
if (entry.first == 0) {
ASSERT_EQ(0.1, entry.second);
} else if (entry.first == 1) {
ASSERT_EQ(0.2, entry.second);
} else if (entry.first == 3) {
ASSERT_EQ(0.3, entry.second);
if (entry.getColumn() == 0) {
ASSERT_EQ(0.1, entry.getValue());
} else if (entry.getColumn() == 1) {
ASSERT_EQ(0.2, entry.getValue());
} else if (entry.getColumn() == 3) {
ASSERT_EQ(0.3, entry.getValue());
} else {
ASSERT_TRUE(false);
}
}
for (storm::storage::SparseMatrix<double>::iterator it = matrix.begin(4), ite = matrix.end(4); it != ite; ++it) {
if (it->first == 0) {
ASSERT_EQ(0.1, it->second);
} else if (it->first == 1) {
ASSERT_EQ(0.2, it->second);
} else if (it->first == 3) {
ASSERT_EQ(0.3, it->second);
if (it->getColumn() == 0) {
ASSERT_EQ(0.1, it->getValue());
} else if (it->getColumn() == 1) {
ASSERT_EQ(0.2, it->getValue());
} else if (it->getColumn() == 3) {
ASSERT_EQ(0.3, it->getValue());
} else {
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>>();
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>());
@ -71,7 +71,7 @@ TEST(GmmxxDtmcPrctlModelCheckerTest, SynchronousLeader) {
std::shared_ptr<storm::models::Dtmc<double>> dtmc = abstractModel->as<storm::models::Dtmc<double>>();
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>());

2
test/performance/storage/SparseMatrixTest.cpp

@ -15,7 +15,7 @@ TEST(SparseMatrix, Iteration) {
for (uint_fast64_t row = 0; row < matrix.getRowCount(); ++row) {
for (auto const& entry : matrix.getRow(row)) {
// 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);
}
}

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