From dc88830acd9af07d171b5536286445259deb6043 Mon Sep 17 00:00:00 2001 From: Jip Spel Date: Fri, 3 Aug 2018 12:45:27 +0200 Subject: [PATCH 001/178] First try --- src/storm-pars-cli/storm-pars.cpp | 41 ++- src/storm-pars/analysis/Lattice.cpp | 171 ++++++++++++ src/storm-pars/analysis/Lattice.h | 94 +++++++ src/storm-pars/analysis/Transformer.cpp | 249 ++++++++++++++++++ src/storm-pars/analysis/Transformer.h | 55 ++++ .../settings/modules/ParametricSettings.cpp | 6 +- .../settings/modules/ParametricSettings.h | 2 + 7 files changed, 615 insertions(+), 3 deletions(-) create mode 100644 src/storm-pars/analysis/Lattice.cpp create mode 100644 src/storm-pars/analysis/Lattice.h create mode 100644 src/storm-pars/analysis/Transformer.cpp create mode 100644 src/storm-pars/analysis/Transformer.h diff --git a/src/storm-pars-cli/storm-pars.cpp b/src/storm-pars-cli/storm-pars.cpp index badcb0212..38d1c6975 100644 --- a/src/storm-pars-cli/storm-pars.cpp +++ b/src/storm-pars-cli/storm-pars.cpp @@ -3,6 +3,8 @@ #include "storm-pars/settings/ParsSettings.h" #include "storm-pars/settings/modules/ParametricSettings.h" #include "storm-pars/settings/modules/RegionSettings.h" +#include "storm-pars/analysis/Lattice.h" +#include "storm-pars/analysis/Transformer.h" #include "storm/settings/SettingsManager.h" #include "storm/api/storm.h" @@ -455,7 +457,9 @@ namespace storm { } STORM_LOG_THROW(model || input.properties.empty(), storm::exceptions::InvalidSettingsException, "No input model."); - + + // TODO: Shift this to after preprocessing? + if (model) { auto preprocessingResult = storm::pars::preprocessModel(model, input); if (preprocessingResult.second) { @@ -463,7 +467,40 @@ namespace storm { model->printModelInformationToStream(std::cout); } } - + + + if (parSettings.isMonotonicityAnalysisSet()) { + // Do something more fancy. + std::cout << "Hello, Jip" << std::endl; + std::shared_ptr> sparseModel = model->as>(); + + storm::storage::SparseMatrix matrix = sparseModel.get()->getTransitionMatrix(); + + storm::storage::BitVector initialStates = sparseModel.get()->getInitialStates(); + + std::vector> formulas = storm::api::extractFormulasFromProperties(input.properties); + + STORM_LOG_THROW((*(formulas[0])).isProbabilityOperatorFormula() && (*(formulas[0])).asProbabilityOperatorFormula().getSubformula().isUntilFormula(), storm::exceptions::NotSupportedException, "Expecting until formula"); + // Check that formulas[0] is actually a ProbabilityOperator ... + // Check that formulas[0]->asProbabilityOperator().subformula() is an EventuallyFormula.. + // Compute phiStates, psiStates via formulas[0]....subformula().as..().subformula + storm::modelchecker::SparsePropositionalModelChecker> propositionalChecker(*sparseModel); + storm::storage::BitVector phiStates = propositionalChecker.check((*(formulas[0])).asProbabilityOperatorFormula().getSubformula().asUntilFormula().getLeftSubformula())->asExplicitQualitativeCheckResult().getTruthValuesVector(); + storm::storage::BitVector psiStates = propositionalChecker.check((*(formulas[0])).asProbabilityOperatorFormula().getSubformula().asUntilFormula().getRightSubformula())->asExplicitQualitativeCheckResult().getTruthValuesVector(); //right + // get the maybeStates + std::pair statesWithProbability01 = storm::utility::graph::performProb01(sparseModel.get()->getBackwardTransitions(), phiStates, psiStates); + + model.get()->printModelInformationToStream(std::cout); + + storm::storage::BitVector topStates = statesWithProbability01.second; + storm::storage::BitVector bottomStates = statesWithProbability01.first; + storm::analysis::Lattice* lattice = storm::analysis::Transformer::toLattice(matrix, initialStates, topStates, bottomStates, sparseModel.get()->getNumberOfStates()); + lattice->toString(std::cout); + return; + } + + + std::vector> regions = parseRegions(model); std::string samplesAsString = parSettings.getSamples(); SampleInformation samples; diff --git a/src/storm-pars/analysis/Lattice.cpp b/src/storm-pars/analysis/Lattice.cpp new file mode 100644 index 000000000..c5c13f825 --- /dev/null +++ b/src/storm-pars/analysis/Lattice.cpp @@ -0,0 +1,171 @@ +// +// Created by Jip Spel on 24.07.18. +// + +#include +#include "Lattice.h" +namespace storm { + namespace analysis { + Lattice::Lattice(Node *topNode, Node *bottomNode, uint_fast64_t numberOfStates) { + Node *top = new Node(); + top->states = topNode->states; + Node *bottom = new Node(); + bottom->states = bottomNode->states; + top->below.push_back(bottom); + bottom->above.push_back(top); + nodes = std::vector({top, bottom}); +// addedStates.insert(addedStates.end(), top->states.begin(), top->states.end()); +// addedStates.insert(addedStates.end(), bottom->states.begin(), bottom->states.end()); + this->numberOfStates = numberOfStates; + } + + void Lattice::addBetween(uint_fast64_t state, Node *above, Node *below) { + Node *newNode = new Node(); + newNode->states = storm::storage::BitVector(numberOfStates); + newNode->states.set(state); + newNode->above = std::vector({above}); + newNode->below = std::vector({below}); + remove(&(below->above), above); + remove(&(above->below), below); + (below->above).push_back(newNode); + above->below.push_back(newNode); + nodes.push_back(newNode); +// addedStates.push_back(state); + } + + void Lattice::addToNode(uint_fast64_t state, Node *node) { + node->states.set(state); +// addedStates.push_back(state); + } + + int Lattice::compare(uint_fast64_t state1, uint_fast64_t state2) { + Node *node1 = getNode(state1); + Node *node2 = getNode(state2); + + if (node1 == node2) { + return 0; + } + + if (above(node1, node2)) { + return 1; + } + + if (below(node1, node2)) { + return 2; + } + + return -1; + } + + Lattice::Node *Lattice::getNode(uint_fast64_t stateNumber) { + Node *node; + for (auto itr = nodes.begin(); itr != nodes.end(); ++itr) { + storm::storage::BitVector states = (*itr)->states; + + if (states[stateNumber]) return (*itr); + } + return node; + } + + void Lattice::toString(std::ostream &out) { + for (auto itr = nodes.begin(); itr != nodes.end(); ++itr) { + Node *node = *itr; + out << "Node: {"; + uint_fast64_t index = node->states.getNextSetIndex(0); + while (index < numberOfStates) { + out << index; + index = node->states.getNextSetIndex(index+1); + if (index < numberOfStates) { + out << ", "; + } + } + out << "}" << std::endl; + out << " Address: " << node << std::endl; + out << " Above: {"; + for (auto itr2 = node->above.begin(); itr2 != node->above.end(); ++itr2) { + Node *above = *itr2; + out << "{"; + index = above->states.getNextSetIndex(0); + while (index < numberOfStates) { + out << index; + index = above->states.getNextSetIndex(index+1); + if (index < numberOfStates) { + out << ", "; + } + } + + out << "}"; + if (itr2 + 1 != node->above.end()) { + out << ", "; + } + } + out << "}" << std::endl; + + out << " Below: {"; + for (auto itr2 = node->below.begin(); itr2 != node->below.end(); ++itr2) { + Node *below = *itr2; + out << "{"; + index = below->states.getNextSetIndex(0); + while (index < numberOfStates) { + out << index; + index = below->states.getNextSetIndex(index+1); + if (index < numberOfStates) { + out << ", "; + } + } + + out << "}"; + if (itr2 + 1 != node->below.end()) { + out << ", "; + } + } + out << "}" << std::endl; + } + } + + bool Lattice::above(Node *node1, Node *node2) { + if (node1->below.empty()) { + return false; + } + + if (std::find(node1->below.begin(), node1->below.end(), node2) != node1->below.end()) { + return true; + } + + bool result = false; + for (auto itr = node1->below.begin(); node1->below.end() != itr; ++itr) { + result |= above(*itr, node2); + } + return result; + } + + bool Lattice::below(Node *node1, Node *node2) { + if (node1->above.empty()) { + return false; + } + + if (std::find(node1->above.begin(), node1->above.end(), node2) != node1->above.end()) { + return true; + } + + bool result = false; + for (auto itr = node1->above.begin(); node1->above.end() != itr; ++itr) { + result |= below(*itr, node2); + } + return result; + } + + void Lattice::remove(std::vector *nodes, Node *node) { + auto index = std::find(nodes->begin(), nodes->end(), node); + if (index != nodes->end()) { + nodes->erase(index); + } + }; + + void Lattice::setStates(std::vector states, Node *node) { + for (auto itr = states.begin(); itr < states.end(); ++itr) { + node->states.set(*itr); + } + } + } +} diff --git a/src/storm-pars/analysis/Lattice.h b/src/storm-pars/analysis/Lattice.h new file mode 100644 index 000000000..e80ab7035 --- /dev/null +++ b/src/storm-pars/analysis/Lattice.h @@ -0,0 +1,94 @@ +// +// Created by Jip Spel on 24.07.18. +// + +#ifndef LATTICE_LATTICE_H +#define LATTICE_LATTICE_H + +#include +#include + +#include "storm/storage/BitVector.h" + +namespace storm { + namespace analysis { + class Lattice { + + public: + struct Node { + storm::storage::BitVector states; + std::vector above; + std::vector below; + }; + + /*! + * Constructs a lattice with the given top node and bottom node. + * + * @param topNode The top node of the resulting lattice. + * @param bottomNode The bottom node of the resulting lattice. + */ + Lattice(Node *topNode, Node *bottomNode, uint_fast64_t numberOfStates); + + /*! + * Adds a node with the given state below node1 and above node2. + * @param state The given state. + * @param node1 The pointer to the node below which a new node is added. + * @param node2 The pointer to the node above which a new node is added. + */ + void addBetween(uint_fast64_t state, Node *node1, Node *node2); + + /*! + * Adds state to the states of the given node. + * @param state The state which is added. + * @param node The pointer to the node to which state is added. + */ + void addToNode(uint_fast64_t state, Node *node); + + /*! + * Compares the level of the nodes of the states. + * Behaviour unknown when one or more of the states doesnot occur at any Node in the Lattice. + * @param state1 The first state. + * @param state2 The second state. + * @return 0 if the nodes are on the same level; + * 1 if the node of the first state is closer to top then the node of the second state; + * 2 if the node of the second state is closer to top then the node of the first state; + * -1 if it is unclear from the structure of the lattice how the nodes relate. + */ + int compare(uint_fast64_t state1, uint_fast64_t state2); + + /*! + * Retrieves the pointer to a Node at which the state occurs. + * Behaviour unknown when state does not exists at any Node in the Lattice. + * + * @param state The number of the state. + * + * @return The pointer to the node of the state. + */ + Node *getNode(uint_fast64_t state); + + /*! + * Prints a string representation of the lattice to std::cout. + * + * @param out The stream to output to. + */ + void toString(std::ostream &out); + +// std::vector addedStates; + + private: + std::vector nodes; + + uint_fast64_t numberOfStates; + + bool above(Node *, Node *); + + bool below(Node *, Node *); + + void remove(std::vector *nodes, Node *node); + + void setStates(std::vector states, Node *node); + + }; + } +} +#endif //LATTICE_LATTICE_H diff --git a/src/storm-pars/analysis/Transformer.cpp b/src/storm-pars/analysis/Transformer.cpp new file mode 100644 index 000000000..a87a8d19e --- /dev/null +++ b/src/storm-pars/analysis/Transformer.cpp @@ -0,0 +1,249 @@ +// +// Created by Jip Spel on 26.07.18. +// + +#include "Transformer.h" +namespace storm { + namespace analysis { + Lattice *Transformer::toLattice(storm::storage::SparseMatrix matrix, + storm::storage::BitVector const &initialStates, + storm::storage::BitVector topStates, + storm::storage::BitVector bottomStates, uint_fast64_t numberOfStates) { + // Transform the transition matrix into a vector containing the states with the state to which the transition goes. + std::vector stateVector = toStateVector(matrix, initialStates); + + // Start creating the Lattice. + Lattice::Node top = {topStates}; + Lattice::Node bottom = {bottomStates}; + Lattice *lattice = new Lattice(&top, &bottom, numberOfStates); + storm::storage::BitVector oldStates(numberOfStates); + // Create a copy of the states already present in the lattice. + storm::storage::BitVector seenStates = topStates|=bottomStates; + + matrix.printAsMatlabMatrix(std::cout); + + while (oldStates != seenStates) { + // As long as new states are discovered, continue. + oldStates = storm::storage::BitVector(seenStates); + + for (auto itr = stateVector.begin(); itr != stateVector.end(); ++itr) { + // Iterate over all states + State *currentState = *itr; + + if (!seenStates[currentState->stateNumber] + && seenStates[currentState->successor1] + && seenStates[currentState->successor2]) { + + // Check if the current state number has not been added, but its successors have been added. + if (currentState->successor1 == currentState->successor2) { + // If there is only one successor, the state should be added to the same Node as its successor + lattice->addToNode(currentState->stateNumber, lattice->getNode(currentState->successor1)); + // Add stateNumber to the set with seen states. + seenStates.set(currentState->stateNumber); + } else { + // Otherwise, check how the two states compare, and add if the comparison is possible. + uint_fast64_t successor1 = currentState->successor1; + uint_fast64_t successor2 = currentState->successor2; + int compareResult = lattice->compare(successor1, successor2); + if (compareResult == 1) { + //TODO dit in een aparte methode doen + Lattice::Node *above = lattice->getNode(successor1); + Lattice::Node *below = lattice->getNode(successor2); + std::vector states1 = above->below; + std::vector states2 = below->above; + bool added = false; + for (auto itr1 = states1.begin(); itr1 < states1.end(); ++itr1) { + for (auto itr2 = states2.begin(); itr2 < states2.end(); ++itr2) { + if ((*itr1)->states == (*itr2)->states) { + storm::RationalFunction prob1 = getProbability(currentState->stateNumber, successor1, matrix); + storm::RationalFunction prob2 = getProbability(currentState->stateNumber, successor2, matrix); + if (prob1 != storm::RationalFunction(1) + && prob2 != storm::RationalFunction(1) + && getProbability((*itr1)->states, above->states, matrix) == prob1 + && getProbability((*itr1)->states, below->states, matrix) == prob2) { + + std::cout << "Van: " << currentState-> stateNumber << " naar: " << successor1 << std::endl; + std::cout << prob1 << std::endl; + std::cout << "Van: " << currentState-> stateNumber << " naar: " << successor2 << std::endl; + std::cout << prob2 << std::endl; + + lattice->addToNode(currentState->stateNumber, (*itr1)); + seenStates.set(currentState->stateNumber); + added = true; + } + } + + } + } + + if (!added) { + // successor 1 is closer to top than successor 2 + lattice->addBetween(currentState->stateNumber, lattice->getNode(successor1), + lattice->getNode(successor2)); + // Add stateNumber to the set with seen states. + seenStates.set(currentState->stateNumber); + } + } else if (compareResult == 2) { + //TODO dit in een aparte methode doen + // als er in de below van successor 2 en de above van succesor 1 een overlap is met een state, dan moet je kijken naar de kans + Lattice::Node *above = lattice->getNode(successor2); + Lattice::Node *below = lattice->getNode(successor1); + std::vector states1 = above->below; + std::vector states2 = below->above; + bool added = false; + for (auto itr1 = states1.begin(); itr1 < states1.end(); ++itr1) { + for (auto itr2 = states2.begin(); itr2 < states2.end(); ++itr2) { + if ((*itr1)->states == (*itr2)->states) { + storm::RationalFunction prob1 = getProbability(currentState->stateNumber, successor2, matrix); + storm::RationalFunction prob2 = getProbability(currentState->stateNumber, successor1, matrix); + if (prob1 != storm::RationalFunction(1) + && prob2 != storm::RationalFunction(1) + && getProbability((*itr1)->states, above->states, matrix) == prob1 + && getProbability((*itr1)->states, below->states, matrix) == prob2) { + + std::cout << "Van: " << currentState-> stateNumber << " naar: " << successor2 << std::endl; + std::cout << prob1 << std::endl; + std::cout << "Van: " << currentState-> stateNumber << " naar: " << successor1 << std::endl; + std::cout << prob2 << std::endl; + + lattice->addToNode(currentState->stateNumber, (*itr1)); + seenStates.set(currentState->stateNumber); + added = true; + } + } + } + } + + if (!added) { + // successor 2 is closer to top than successor 1 + lattice->addBetween(currentState->stateNumber, lattice->getNode(successor2), + lattice->getNode(successor1)); + // Add stateNumber to the set with seen states. + seenStates.set(currentState->stateNumber); + } + + + + + } else if (compareResult == 0) { + // the successors are at the same level + lattice->addToNode(currentState->stateNumber, lattice->getNode(successor1)); + // Add stateNumber to the set with seen states. + seenStates.set(currentState->stateNumber); + } else { + // TODO: what to do? + STORM_LOG_DEBUG("Failed to add" << currentState->stateNumber << "\n"); + } + + } + } + } + + } + + return lattice; + } + + std::vector + Transformer::toStateVector(storm::storage::SparseMatrix transitionMatrix, + storm::storage::BitVector const &initialStates) { + std::vector < State *> states = std::vector({}); + std::vector stack(initialStates.begin(), initialStates.end()); + std::vector seenStates(initialStates.begin(), initialStates.end()); + uint_fast64_t currentState; + + while (!stack.empty()) { + currentState = stack.back(); + stack.pop_back(); + std::vector successorStates(0, 2); + + // Assume there are at most 2 successors + for (auto const &successor : transitionMatrix.getRowGroup(currentState)) { + if (!storm::utility::isZero(successor.getValue())) { + // Only explore the state if the transition was actually there. + uint_fast64_t successorNumber = successor.getColumn(); + if (std::find(seenStates.begin(), seenStates.end(), successorNumber) == seenStates.end()) { + stack.push_back(successorNumber); + seenStates.push_back(successorNumber); + } + successorStates.push_back(successorNumber); + } + } + + State *state = new State(); + state->stateNumber = currentState; + state->successor1 = successorStates.back(); + successorStates.pop_back(); + if (!successorStates.empty()) { + state->successor2 = successorStates.back(); + successorStates.pop_back(); + } else { + state->successor2 = state->successor1; + } + states.push_back(state); + } + return states; + } + + void Transformer::print(storm::storage::BitVector vector, std::string message) { + uint_fast64_t index = vector.getNextSetIndex(0); + std::cout << message <<": {"; + while (index < vector.size()) { + std::cout << index; + index = vector.getNextSetIndex(index+1); + if (index < vector.size()) { + std::cout << ", "; + } + } + std::cout << "}" << std::endl; + } + + std::vector Transformer::getNumbers(storm::storage::BitVector vector) { + std::vector result = std::vector({}); + uint_fast64_t index = vector.getNextSetIndex(0); + while (index < vector.size()) { + result.push_back(index); + index = vector.getNextSetIndex(index+1); + + } + return result; + } + + storm::RationalFunction Transformer::getProbability(storm::storage::BitVector state, storm::storage::BitVector successor, storm::storage::SparseMatrix matrix) { + std::vector successorNumbers = getNumbers(successor); + storm::RationalFunction result = storm::RationalFunction(1); + for (auto itr = successorNumbers.begin(); itr < successorNumbers.end() && result == storm::RationalFunction(1); ++itr) { + result = getProbability(state, (*itr), matrix); + } + return result; + } + + storm::RationalFunction Transformer::getProbability(storm::storage::BitVector state, uint_fast64_t successor, storm::storage::SparseMatrix matrix) { + std::vector stateNumbers = getNumbers(state); + storm::RationalFunction result = storm::RationalFunction(1); + for (auto itr = stateNumbers.begin(); itr < stateNumbers.end() && result == storm::RationalFunction(1); ++itr) { + result = getProbability((*itr), successor, matrix); + } + return result; + } + + storm::RationalFunction Transformer::getProbability(uint_fast64_t state, uint_fast64_t successor, storm::storage::SparseMatrix matrix) { + storm::RationalFunction result = storm::RationalFunction(1); + // Iterate over all row groups. + auto row = matrix.getRow(state); + + for (auto itr = row.begin(); itr < row.end() && result == storm::RationalFunction(1); ++itr) { + if ((*itr).getColumn() == successor) { + std::cout << "Tralala" << std::endl; + // TODO: nog checken dat ie wel met state te doen heeft + result = (*itr).getValue(); + std::cout << "Van: " << state << " naar: " << successor << std::endl; + std::cout << result << std::endl; + } + + } + + return result; + } + } +} diff --git a/src/storm-pars/analysis/Transformer.h b/src/storm-pars/analysis/Transformer.h new file mode 100644 index 000000000..d584227f2 --- /dev/null +++ b/src/storm-pars/analysis/Transformer.h @@ -0,0 +1,55 @@ +// +// Created by Jip Spel on 26.07.18. +// + +#ifndef LATTICE_BUILDER_H +#define LATTICE_BUILDER_H + +#include "storm/storage/BitVector.h" +#include "storm/storage/SparseMatrix.h" +#include "Lattice.h" +namespace storm { + namespace analysis { + class Transformer { + public: + struct State { + uint_fast64_t stateNumber; + uint_fast64_t successor1; + uint_fast64_t successor2; + }; + + /*! + * Returns the pointer to the Lattice constructed from the given transitionMatrix, + * BitVector of initialStates, vector with the top states and vector with the bottom states. + * Assumes that every state has at least one and at most two outgoing transitions. + * + * @param matrix The transition matrix. + * @param initialStates The BitVector containing the initialStates. + * @param topStates Vector containing the numbers of the top states. + * @param bottomStates Vector containing the numbers of the bottom states. + * + * @return The lattice ordering of the states. + */ + static Lattice *toLattice(storm::storage::SparseMatrix matrix, + storm::storage::BitVector const &initialStates, + storm::storage::BitVector topStates, + storm::storage::BitVector bottomStates, uint_fast64_t numberOfStates); + + private: + static std::vector + toStateVector(storm::storage::SparseMatrix transitionMatrix, + storm::storage::BitVector const &initialStates); + + static void print(storm::storage::BitVector vector, std::string message); + + static std::vector getNumbers(storm::storage::BitVector vector); + + static storm::RationalFunction getProbability(storm::storage::BitVector state, storm::storage::BitVector successor, storm::storage::SparseMatrix matrix); + + static storm::RationalFunction getProbability(storm::storage::BitVector state, uint_fast64_t successor, storm::storage::SparseMatrix matrix); + + static storm::RationalFunction getProbability(uint_fast64_t state, uint_fast64_t successor, storm::storage::SparseMatrix matrix); + }; + } +} +#endif //LATTICE_BUILDER_H diff --git a/src/storm-pars/settings/modules/ParametricSettings.cpp b/src/storm-pars/settings/modules/ParametricSettings.cpp index 7ecbd6166..ef64acb94 100644 --- a/src/storm-pars/settings/modules/ParametricSettings.cpp +++ b/src/storm-pars/settings/modules/ParametricSettings.cpp @@ -65,7 +65,11 @@ namespace storm { bool ParametricSettings::isSampleExactSet() const { return this->getOption(sampleExactOptionName).getHasOptionBeenSet(); } - + + bool ParametricSettings::isMonotonicityAnalysisSet() const { + // TODO: Make this dependent on the input. + return true; + } } // namespace modules } // namespace settings } // namespace storm diff --git a/src/storm-pars/settings/modules/ParametricSettings.h b/src/storm-pars/settings/modules/ParametricSettings.h index 1f10a4b35..0fa167409 100644 --- a/src/storm-pars/settings/modules/ParametricSettings.h +++ b/src/storm-pars/settings/modules/ParametricSettings.h @@ -63,6 +63,8 @@ namespace storm { * Retrieves whether samples are to be computed exactly. */ bool isSampleExactSet() const; + + bool isMonotonicityAnalysisSet() const; const static std::string moduleName; From 2827da84ee8638ce788049e61ddd92e740f3fa45 Mon Sep 17 00:00:00 2001 From: Jip Spel Date: Fri, 3 Aug 2018 13:12:38 +0200 Subject: [PATCH 002/178] Add TODOs --- src/storm-pars-cli/storm-pars.cpp | 17 +++++++++----- src/storm-pars/analysis/Lattice.cpp | 9 +++---- src/storm-pars/analysis/Transformer.cpp | 31 ++++++++----------------- 3 files changed, 26 insertions(+), 31 deletions(-) diff --git a/src/storm-pars-cli/storm-pars.cpp b/src/storm-pars-cli/storm-pars.cpp index 38d1c6975..9a73ee0d5 100644 --- a/src/storm-pars-cli/storm-pars.cpp +++ b/src/storm-pars-cli/storm-pars.cpp @@ -481,21 +481,26 @@ namespace storm { std::vector> formulas = storm::api::extractFormulasFromProperties(input.properties); STORM_LOG_THROW((*(formulas[0])).isProbabilityOperatorFormula() && (*(formulas[0])).asProbabilityOperatorFormula().getSubformula().isUntilFormula(), storm::exceptions::NotSupportedException, "Expecting until formula"); - // Check that formulas[0] is actually a ProbabilityOperator ... - // Check that formulas[0]->asProbabilityOperator().subformula() is an EventuallyFormula.. - // Compute phiStates, psiStates via formulas[0]....subformula().as..().subformula storm::modelchecker::SparsePropositionalModelChecker> propositionalChecker(*sparseModel); storm::storage::BitVector phiStates = propositionalChecker.check((*(formulas[0])).asProbabilityOperatorFormula().getSubformula().asUntilFormula().getLeftSubformula())->asExplicitQualitativeCheckResult().getTruthValuesVector(); storm::storage::BitVector psiStates = propositionalChecker.check((*(formulas[0])).asProbabilityOperatorFormula().getSubformula().asUntilFormula().getRightSubformula())->asExplicitQualitativeCheckResult().getTruthValuesVector(); //right // get the maybeStates std::pair statesWithProbability01 = storm::utility::graph::performProb01(sparseModel.get()->getBackwardTransitions(), phiStates, psiStates); - model.get()->printModelInformationToStream(std::cout); - storm::storage::BitVector topStates = statesWithProbability01.second; storm::storage::BitVector bottomStates = statesWithProbability01.first; storm::analysis::Lattice* lattice = storm::analysis::Transformer::toLattice(matrix, initialStates, topStates, bottomStates, sparseModel.get()->getNumberOfStates()); - lattice->toString(std::cout); + + // TODO: Analyse lattice with transition matrix + // Where do the parameters occur? + // initially incr.Boolean and decr.Boolean true + // At every occurence as long as either incr.Boolean or decr.Boolean true + // --> check if monotonic + // --> yes --> check position in lattice + // --> if incr. set incr.Boolean = incr.Boolean && true, decr.Boolean = false; + // --> if decr. set incr.Boolean = false, decr.Boolean = decr.Boolean && true; + // --> no --> set both booleans to false + // --> set both incr.bool and decr.bool to false return; } diff --git a/src/storm-pars/analysis/Lattice.cpp b/src/storm-pars/analysis/Lattice.cpp index c5c13f825..77f4e83f8 100644 --- a/src/storm-pars/analysis/Lattice.cpp +++ b/src/storm-pars/analysis/Lattice.cpp @@ -58,6 +58,7 @@ namespace storm { } Lattice::Node *Lattice::getNode(uint_fast64_t stateNumber) { + // TODO: might return nullptr, what to do with it? Node *node; for (auto itr = nodes.begin(); itr != nodes.end(); ++itr) { storm::storage::BitVector states = (*itr)->states; @@ -79,8 +80,8 @@ namespace storm { out << ", "; } } - out << "}" << std::endl; - out << " Address: " << node << std::endl; + out << "}" << "\n"; + out << " Address: " << node << "\n"; out << " Above: {"; for (auto itr2 = node->above.begin(); itr2 != node->above.end(); ++itr2) { Node *above = *itr2; @@ -99,7 +100,7 @@ namespace storm { out << ", "; } } - out << "}" << std::endl; + out << "}" << "\n"; out << " Below: {"; for (auto itr2 = node->below.begin(); itr2 != node->below.end(); ++itr2) { @@ -119,7 +120,7 @@ namespace storm { out << ", "; } } - out << "}" << std::endl; + out << "}" << "\n"; } } diff --git a/src/storm-pars/analysis/Transformer.cpp b/src/storm-pars/analysis/Transformer.cpp index a87a8d19e..9a2baba53 100644 --- a/src/storm-pars/analysis/Transformer.cpp +++ b/src/storm-pars/analysis/Transformer.cpp @@ -1,7 +1,7 @@ // // Created by Jip Spel on 26.07.18. // - +// TODO: Use templates #include "Transformer.h" namespace storm { namespace analysis { @@ -9,19 +9,19 @@ namespace storm { storm::storage::BitVector const &initialStates, storm::storage::BitVector topStates, storm::storage::BitVector bottomStates, uint_fast64_t numberOfStates) { + // TODO: take SparseModel as input // Transform the transition matrix into a vector containing the states with the state to which the transition goes. std::vector stateVector = toStateVector(matrix, initialStates); - // Start creating the Lattice. + // TODO: not initializing all fields of Lattice::Node yet, what to do? + // Start creating the Lattice Lattice::Node top = {topStates}; Lattice::Node bottom = {bottomStates}; Lattice *lattice = new Lattice(&top, &bottom, numberOfStates); storm::storage::BitVector oldStates(numberOfStates); // Create a copy of the states already present in the lattice. storm::storage::BitVector seenStates = topStates|=bottomStates; - - matrix.printAsMatlabMatrix(std::cout); - + while (oldStates != seenStates) { // As long as new states are discovered, continue. oldStates = storm::storage::BitVector(seenStates); @@ -46,7 +46,7 @@ namespace storm { uint_fast64_t successor2 = currentState->successor2; int compareResult = lattice->compare(successor1, successor2); if (compareResult == 1) { - //TODO dit in een aparte methode doen + // TODO: create seperate method or change compareResult method? Lattice::Node *above = lattice->getNode(successor1); Lattice::Node *below = lattice->getNode(successor2); std::vector states1 = above->below; @@ -61,12 +61,6 @@ namespace storm { && prob2 != storm::RationalFunction(1) && getProbability((*itr1)->states, above->states, matrix) == prob1 && getProbability((*itr1)->states, below->states, matrix) == prob2) { - - std::cout << "Van: " << currentState-> stateNumber << " naar: " << successor1 << std::endl; - std::cout << prob1 << std::endl; - std::cout << "Van: " << currentState-> stateNumber << " naar: " << successor2 << std::endl; - std::cout << prob2 << std::endl; - lattice->addToNode(currentState->stateNumber, (*itr1)); seenStates.set(currentState->stateNumber); added = true; @@ -101,11 +95,6 @@ namespace storm { && getProbability((*itr1)->states, above->states, matrix) == prob1 && getProbability((*itr1)->states, below->states, matrix) == prob2) { - std::cout << "Van: " << currentState-> stateNumber << " naar: " << successor2 << std::endl; - std::cout << prob1 << std::endl; - std::cout << "Van: " << currentState-> stateNumber << " naar: " << successor1 << std::endl; - std::cout << prob2 << std::endl; - lattice->addToNode(currentState->stateNumber, (*itr1)); seenStates.set(currentState->stateNumber); added = true; @@ -147,6 +136,7 @@ namespace storm { std::vector Transformer::toStateVector(storm::storage::SparseMatrix transitionMatrix, storm::storage::BitVector const &initialStates) { + // TODO: Remove this, unnecessary std::vector < State *> states = std::vector({}); std::vector stack(initialStates.begin(), initialStates.end()); std::vector seenStates(initialStates.begin(), initialStates.end()); @@ -186,6 +176,8 @@ namespace storm { } void Transformer::print(storm::storage::BitVector vector, std::string message) { + // TODO: Remove this, unnecessary + uint_fast64_t index = vector.getNextSetIndex(0); std::cout << message <<": {"; while (index < vector.size()) { @@ -199,6 +191,7 @@ namespace storm { } std::vector Transformer::getNumbers(storm::storage::BitVector vector) { + // TODO: Remove this, unnecessary std::vector result = std::vector({}); uint_fast64_t index = vector.getNextSetIndex(0); while (index < vector.size()) { @@ -234,11 +227,7 @@ namespace storm { for (auto itr = row.begin(); itr < row.end() && result == storm::RationalFunction(1); ++itr) { if ((*itr).getColumn() == successor) { - std::cout << "Tralala" << std::endl; - // TODO: nog checken dat ie wel met state te doen heeft result = (*itr).getValue(); - std::cout << "Van: " << state << " naar: " << successor << std::endl; - std::cout << result << std::endl; } } From baf5cbb0741bcfb9b55d1b089b2096495223b1e8 Mon Sep 17 00:00:00 2001 From: Jip Spel Date: Mon, 13 Aug 2018 11:14:00 +0200 Subject: [PATCH 003/178] Remove superfluous methods --- src/storm-pars/analysis/Lattice.cpp | 4 --- src/storm-pars/analysis/Transformer.cpp | 41 +++++-------------------- src/storm-pars/analysis/Transformer.h | 4 --- 3 files changed, 8 insertions(+), 41 deletions(-) diff --git a/src/storm-pars/analysis/Lattice.cpp b/src/storm-pars/analysis/Lattice.cpp index 77f4e83f8..393079afb 100644 --- a/src/storm-pars/analysis/Lattice.cpp +++ b/src/storm-pars/analysis/Lattice.cpp @@ -14,8 +14,6 @@ namespace storm { top->below.push_back(bottom); bottom->above.push_back(top); nodes = std::vector({top, bottom}); -// addedStates.insert(addedStates.end(), top->states.begin(), top->states.end()); -// addedStates.insert(addedStates.end(), bottom->states.begin(), bottom->states.end()); this->numberOfStates = numberOfStates; } @@ -30,12 +28,10 @@ namespace storm { (below->above).push_back(newNode); above->below.push_back(newNode); nodes.push_back(newNode); -// addedStates.push_back(state); } void Lattice::addToNode(uint_fast64_t state, Node *node) { node->states.set(state); -// addedStates.push_back(state); } int Lattice::compare(uint_fast64_t state1, uint_fast64_t state2) { diff --git a/src/storm-pars/analysis/Transformer.cpp b/src/storm-pars/analysis/Transformer.cpp index 9a2baba53..183a0412c 100644 --- a/src/storm-pars/analysis/Transformer.cpp +++ b/src/storm-pars/analysis/Transformer.cpp @@ -175,47 +175,22 @@ namespace storm { return states; } - void Transformer::print(storm::storage::BitVector vector, std::string message) { - // TODO: Remove this, unnecessary - - uint_fast64_t index = vector.getNextSetIndex(0); - std::cout << message <<": {"; - while (index < vector.size()) { - std::cout << index; - index = vector.getNextSetIndex(index+1); - if (index < vector.size()) { - std::cout << ", "; - } - } - std::cout << "}" << std::endl; - } - - std::vector Transformer::getNumbers(storm::storage::BitVector vector) { - // TODO: Remove this, unnecessary - std::vector result = std::vector({}); - uint_fast64_t index = vector.getNextSetIndex(0); - while (index < vector.size()) { - result.push_back(index); - index = vector.getNextSetIndex(index+1); - - } - return result; - } - storm::RationalFunction Transformer::getProbability(storm::storage::BitVector state, storm::storage::BitVector successor, storm::storage::SparseMatrix matrix) { - std::vector successorNumbers = getNumbers(successor); storm::RationalFunction result = storm::RationalFunction(1); - for (auto itr = successorNumbers.begin(); itr < successorNumbers.end() && result == storm::RationalFunction(1); ++itr) { - result = getProbability(state, (*itr), matrix); + uint_fast64_t index = successor.getNextSetIndex(0); + while (index < successor.size() && result == storm::RationalFunction(1)) { + result = getProbability(state, index, matrix); + index = successor.getNextSetIndex(index+1); } return result; } storm::RationalFunction Transformer::getProbability(storm::storage::BitVector state, uint_fast64_t successor, storm::storage::SparseMatrix matrix) { - std::vector stateNumbers = getNumbers(state); storm::RationalFunction result = storm::RationalFunction(1); - for (auto itr = stateNumbers.begin(); itr < stateNumbers.end() && result == storm::RationalFunction(1); ++itr) { - result = getProbability((*itr), successor, matrix); + uint_fast64_t index = state.getNextSetIndex(0); + while (index < state.size() && result == storm::RationalFunction(1)) { + result = getProbability(index, successor, matrix); + index = state.getNextSetIndex(index+1); } return result; } diff --git a/src/storm-pars/analysis/Transformer.h b/src/storm-pars/analysis/Transformer.h index d584227f2..65ecd859a 100644 --- a/src/storm-pars/analysis/Transformer.h +++ b/src/storm-pars/analysis/Transformer.h @@ -40,10 +40,6 @@ namespace storm { toStateVector(storm::storage::SparseMatrix transitionMatrix, storm::storage::BitVector const &initialStates); - static void print(storm::storage::BitVector vector, std::string message); - - static std::vector getNumbers(storm::storage::BitVector vector); - static storm::RationalFunction getProbability(storm::storage::BitVector state, storm::storage::BitVector successor, storm::storage::SparseMatrix matrix); static storm::RationalFunction getProbability(storm::storage::BitVector state, uint_fast64_t successor, storm::storage::SparseMatrix matrix); From 116dbc8bba56b7718419f080ecfaa98ec196652e Mon Sep 17 00:00:00 2001 From: Jip Spel Date: Mon, 13 Aug 2018 11:34:08 +0200 Subject: [PATCH 004/178] Refactor constructor Lattice --- src/storm-pars/analysis/Lattice.cpp | 7 ++++--- src/storm-pars/analysis/Lattice.h | 3 ++- src/storm-pars/analysis/Transformer.cpp | 5 +---- 3 files changed, 7 insertions(+), 8 deletions(-) diff --git a/src/storm-pars/analysis/Lattice.cpp b/src/storm-pars/analysis/Lattice.cpp index 393079afb..a3fa9b8dc 100644 --- a/src/storm-pars/analysis/Lattice.cpp +++ b/src/storm-pars/analysis/Lattice.cpp @@ -6,11 +6,12 @@ #include "Lattice.h" namespace storm { namespace analysis { - Lattice::Lattice(Node *topNode, Node *bottomNode, uint_fast64_t numberOfStates) { + Lattice::Lattice(storm::storage::BitVector topStates, + storm::storage::BitVector bottomStates, uint_fast64_t numberOfStates) { Node *top = new Node(); - top->states = topNode->states; + top->states = topStates; Node *bottom = new Node(); - bottom->states = bottomNode->states; + bottom->states = bottomStates; top->below.push_back(bottom); bottom->above.push_back(top); nodes = std::vector({top, bottom}); diff --git a/src/storm-pars/analysis/Lattice.h b/src/storm-pars/analysis/Lattice.h index e80ab7035..6b5e6d32c 100644 --- a/src/storm-pars/analysis/Lattice.h +++ b/src/storm-pars/analysis/Lattice.h @@ -27,7 +27,8 @@ namespace storm { * @param topNode The top node of the resulting lattice. * @param bottomNode The bottom node of the resulting lattice. */ - Lattice(Node *topNode, Node *bottomNode, uint_fast64_t numberOfStates); + Lattice(storm::storage::BitVector topStates, + storm::storage::BitVector bottomStates, uint_fast64_t numberOfStates); /*! * Adds a node with the given state below node1 and above node2. diff --git a/src/storm-pars/analysis/Transformer.cpp b/src/storm-pars/analysis/Transformer.cpp index 183a0412c..5cf39bb97 100644 --- a/src/storm-pars/analysis/Transformer.cpp +++ b/src/storm-pars/analysis/Transformer.cpp @@ -13,11 +13,8 @@ namespace storm { // Transform the transition matrix into a vector containing the states with the state to which the transition goes. std::vector stateVector = toStateVector(matrix, initialStates); - // TODO: not initializing all fields of Lattice::Node yet, what to do? // Start creating the Lattice - Lattice::Node top = {topStates}; - Lattice::Node bottom = {bottomStates}; - Lattice *lattice = new Lattice(&top, &bottom, numberOfStates); + Lattice *lattice = new Lattice(topStates, bottomStates, numberOfStates); storm::storage::BitVector oldStates(numberOfStates); // Create a copy of the states already present in the lattice. storm::storage::BitVector seenStates = topStates|=bottomStates; From 9f8aa986cec64ffaa596190c7ed4892bc0c1b2db Mon Sep 17 00:00:00 2001 From: Jip Spel Date: Mon, 13 Aug 2018 13:44:54 +0200 Subject: [PATCH 005/178] Refactor creating State vector --- src/storm-pars/analysis/Transformer.cpp | 71 +++++++++---------------- src/storm-pars/analysis/Transformer.h | 6 +-- 2 files changed, 27 insertions(+), 50 deletions(-) diff --git a/src/storm-pars/analysis/Transformer.cpp b/src/storm-pars/analysis/Transformer.cpp index 5cf39bb97..da16af00e 100644 --- a/src/storm-pars/analysis/Transformer.cpp +++ b/src/storm-pars/analysis/Transformer.cpp @@ -11,7 +11,30 @@ namespace storm { storm::storage::BitVector bottomStates, uint_fast64_t numberOfStates) { // TODO: take SparseModel as input // Transform the transition matrix into a vector containing the states with the state to which the transition goes. - std::vector stateVector = toStateVector(matrix, initialStates); + std::vector stateVector = std::vector({}); + + for (uint_fast64_t i = 0; i < numberOfStates; ++i) { + State* state = new State(); + state->stateNumber = i; + state->successor1 = numberOfStates; + state->successor2 = numberOfStates; + + auto row = matrix.getRow(i); + for (auto itr = row.begin(); itr < row.end() && state->successor2 == numberOfStates; ++itr) { + if ((*itr).getValue() != storm::RationalFunction(1)) { + if (state->successor1 == numberOfStates) { + state->successor1 = (*itr).getColumn(); + } else { + state->successor2 = (*itr).getColumn(); + } + } else { + state-> successor1 = (*itr).getColumn(); + state-> successor2 = (*itr).getColumn(); + } + } + stateVector.push_back(state); + } + // Start creating the Lattice Lattice *lattice = new Lattice(topStates, bottomStates, numberOfStates); @@ -48,7 +71,6 @@ namespace storm { Lattice::Node *below = lattice->getNode(successor2); std::vector states1 = above->below; std::vector states2 = below->above; - bool added = false; for (auto itr1 = states1.begin(); itr1 < states1.end(); ++itr1) { for (auto itr2 = states2.begin(); itr2 < states2.end(); ++itr2) { if ((*itr1)->states == (*itr2)->states) { @@ -60,14 +82,13 @@ namespace storm { && getProbability((*itr1)->states, below->states, matrix) == prob2) { lattice->addToNode(currentState->stateNumber, (*itr1)); seenStates.set(currentState->stateNumber); - added = true; } } } } - if (!added) { + if (!seenStates.get(currentState->stateNumber)) { // successor 1 is closer to top than successor 2 lattice->addBetween(currentState->stateNumber, lattice->getNode(successor1), lattice->getNode(successor2)); @@ -130,48 +151,6 @@ namespace storm { return lattice; } - std::vector - Transformer::toStateVector(storm::storage::SparseMatrix transitionMatrix, - storm::storage::BitVector const &initialStates) { - // TODO: Remove this, unnecessary - std::vector < State *> states = std::vector({}); - std::vector stack(initialStates.begin(), initialStates.end()); - std::vector seenStates(initialStates.begin(), initialStates.end()); - uint_fast64_t currentState; - - while (!stack.empty()) { - currentState = stack.back(); - stack.pop_back(); - std::vector successorStates(0, 2); - - // Assume there are at most 2 successors - for (auto const &successor : transitionMatrix.getRowGroup(currentState)) { - if (!storm::utility::isZero(successor.getValue())) { - // Only explore the state if the transition was actually there. - uint_fast64_t successorNumber = successor.getColumn(); - if (std::find(seenStates.begin(), seenStates.end(), successorNumber) == seenStates.end()) { - stack.push_back(successorNumber); - seenStates.push_back(successorNumber); - } - successorStates.push_back(successorNumber); - } - } - - State *state = new State(); - state->stateNumber = currentState; - state->successor1 = successorStates.back(); - successorStates.pop_back(); - if (!successorStates.empty()) { - state->successor2 = successorStates.back(); - successorStates.pop_back(); - } else { - state->successor2 = state->successor1; - } - states.push_back(state); - } - return states; - } - storm::RationalFunction Transformer::getProbability(storm::storage::BitVector state, storm::storage::BitVector successor, storm::storage::SparseMatrix matrix) { storm::RationalFunction result = storm::RationalFunction(1); uint_fast64_t index = successor.getNextSetIndex(0); diff --git a/src/storm-pars/analysis/Transformer.h b/src/storm-pars/analysis/Transformer.h index 65ecd859a..1d3bf64a1 100644 --- a/src/storm-pars/analysis/Transformer.h +++ b/src/storm-pars/analysis/Transformer.h @@ -5,6 +5,7 @@ #ifndef LATTICE_BUILDER_H #define LATTICE_BUILDER_H +#include #include "storm/storage/BitVector.h" #include "storm/storage/SparseMatrix.h" #include "Lattice.h" @@ -36,15 +37,12 @@ namespace storm { storm::storage::BitVector bottomStates, uint_fast64_t numberOfStates); private: - static std::vector - toStateVector(storm::storage::SparseMatrix transitionMatrix, - storm::storage::BitVector const &initialStates); - static storm::RationalFunction getProbability(storm::storage::BitVector state, storm::storage::BitVector successor, storm::storage::SparseMatrix matrix); static storm::RationalFunction getProbability(storm::storage::BitVector state, uint_fast64_t successor, storm::storage::SparseMatrix matrix); static storm::RationalFunction getProbability(uint_fast64_t state, uint_fast64_t successor, storm::storage::SparseMatrix matrix); + }; } } From c1758b8ea15dffcb6713f5a50912671c10d16cee Mon Sep 17 00:00:00 2001 From: Jip Spel Date: Tue, 14 Aug 2018 09:06:34 +0200 Subject: [PATCH 006/178] Remove duplicate code --- src/storm-pars/analysis/Transformer.cpp | 56 +++++-------------------- 1 file changed, 11 insertions(+), 45 deletions(-) diff --git a/src/storm-pars/analysis/Transformer.cpp b/src/storm-pars/analysis/Transformer.cpp index da16af00e..6bcae81a9 100644 --- a/src/storm-pars/analysis/Transformer.cpp +++ b/src/storm-pars/analysis/Transformer.cpp @@ -35,7 +35,6 @@ namespace storm { stateVector.push_back(state); } - // Start creating the Lattice Lattice *lattice = new Lattice(topStates, bottomStates, numberOfStates); storm::storage::BitVector oldStates(numberOfStates); @@ -43,7 +42,7 @@ namespace storm { storm::storage::BitVector seenStates = topStates|=bottomStates; while (oldStates != seenStates) { - // As long as new states are discovered, continue. + // As long as new states are added to the lattice, continue. oldStates = storm::storage::BitVector(seenStates); for (auto itr = stateVector.begin(); itr != stateVector.end(); ++itr) { @@ -65,8 +64,16 @@ namespace storm { uint_fast64_t successor1 = currentState->successor1; uint_fast64_t successor2 = currentState->successor2; int compareResult = lattice->compare(successor1, successor2); - if (compareResult == 1) { - // TODO: create seperate method or change compareResult method? + if (compareResult == 1 || compareResult == 2) { + + if (compareResult == 2) { + // swap + auto temp = successor1; + successor1 = successor2; + successor2 = temp; + } + // Additional check, if states have the same probability of reaching a given next state, + // then they should be at the same node Lattice::Node *above = lattice->getNode(successor1); Lattice::Node *below = lattice->getNode(successor2); std::vector states1 = above->below; @@ -84,7 +91,6 @@ namespace storm { seenStates.set(currentState->stateNumber); } } - } } @@ -95,43 +101,6 @@ namespace storm { // Add stateNumber to the set with seen states. seenStates.set(currentState->stateNumber); } - } else if (compareResult == 2) { - //TODO dit in een aparte methode doen - // als er in de below van successor 2 en de above van succesor 1 een overlap is met een state, dan moet je kijken naar de kans - Lattice::Node *above = lattice->getNode(successor2); - Lattice::Node *below = lattice->getNode(successor1); - std::vector states1 = above->below; - std::vector states2 = below->above; - bool added = false; - for (auto itr1 = states1.begin(); itr1 < states1.end(); ++itr1) { - for (auto itr2 = states2.begin(); itr2 < states2.end(); ++itr2) { - if ((*itr1)->states == (*itr2)->states) { - storm::RationalFunction prob1 = getProbability(currentState->stateNumber, successor2, matrix); - storm::RationalFunction prob2 = getProbability(currentState->stateNumber, successor1, matrix); - if (prob1 != storm::RationalFunction(1) - && prob2 != storm::RationalFunction(1) - && getProbability((*itr1)->states, above->states, matrix) == prob1 - && getProbability((*itr1)->states, below->states, matrix) == prob2) { - - lattice->addToNode(currentState->stateNumber, (*itr1)); - seenStates.set(currentState->stateNumber); - added = true; - } - } - } - } - - if (!added) { - // successor 2 is closer to top than successor 1 - lattice->addBetween(currentState->stateNumber, lattice->getNode(successor2), - lattice->getNode(successor1)); - // Add stateNumber to the set with seen states. - seenStates.set(currentState->stateNumber); - } - - - - } else if (compareResult == 0) { // the successors are at the same level lattice->addToNode(currentState->stateNumber, lattice->getNode(successor1)); @@ -141,13 +110,10 @@ namespace storm { // TODO: what to do? STORM_LOG_DEBUG("Failed to add" << currentState->stateNumber << "\n"); } - } } } - } - return lattice; } From 2c4d5c0d3fecbe12d5b2adb742f1629497c8aa5c Mon Sep 17 00:00:00 2001 From: Jip Spel Date: Tue, 14 Aug 2018 10:21:14 +0200 Subject: [PATCH 007/178] Delete Transfomer class --- src/storm-pars-cli/storm-pars.cpp | 186 ++++++++++++++++++++++-- src/storm-pars/analysis/Transformer.cpp | 155 -------------------- src/storm-pars/analysis/Transformer.h | 49 ------- 3 files changed, 173 insertions(+), 217 deletions(-) delete mode 100644 src/storm-pars/analysis/Transformer.cpp delete mode 100644 src/storm-pars/analysis/Transformer.h diff --git a/src/storm-pars-cli/storm-pars.cpp b/src/storm-pars-cli/storm-pars.cpp index 9a73ee0d5..470699988 100644 --- a/src/storm-pars-cli/storm-pars.cpp +++ b/src/storm-pars-cli/storm-pars.cpp @@ -4,7 +4,6 @@ #include "storm-pars/settings/modules/ParametricSettings.h" #include "storm-pars/settings/modules/RegionSettings.h" #include "storm-pars/analysis/Lattice.h" -#include "storm-pars/analysis/Transformer.h" #include "storm/settings/SettingsManager.h" #include "storm/api/storm.h" @@ -47,6 +46,12 @@ namespace storm { bool graphPreserving; bool exact; }; + + struct State { + uint_fast64_t stateNumber; + uint_fast64_t successor1; + uint_fast64_t successor2; + }; template std::vector> parseRegions(std::shared_ptr const& model) { @@ -429,13 +434,168 @@ namespace storm { storm::pars::verifyRegionsWithSparseEngine(model, input, regions); } } - + template void verifyParametricModel(std::shared_ptr const& model, SymbolicInput const& input, std::vector> const& regions, SampleInformation const& samples) { STORM_LOG_ASSERT(model->isSparseModel(), "Unexpected model type."); storm::pars::verifyWithSparseEngine(model->as>(), input, regions, samples); } - + + + template + ValueType getProbability(uint_fast64_t state, uint_fast64_t successor, storm::storage::SparseMatrix matrix) { + ValueType result = ValueType(1); + // Iterate over all row groups. + auto row = matrix.getRow(state); + + for (auto itr = row.begin(); itr < row.end() && result == ValueType(1); ++itr) { + if ((*itr).getColumn() == successor) { + result = (*itr).getValue(); + } + + } + + return result; + } + + template + ValueType getProbability(storm::storage::BitVector state, uint_fast64_t successor, storm::storage::SparseMatrix matrix) { + ValueType result = ValueType(1); + uint_fast64_t index = state.getNextSetIndex(0); + while (index < state.size() && result == ValueType(1)) { + result = getProbability(index, successor, matrix); + index = state.getNextSetIndex(index+1); + } + return result; + } + + template + ValueType getProbability(storm::storage::BitVector state, storm::storage::BitVector successor, storm::storage::SparseMatrix matrix) { + ValueType result = ValueType(1); + uint_fast64_t index = successor.getNextSetIndex(0); + while (index < successor.size() && result == ValueType(1)) { + result = getProbability(state, index, matrix); + index = successor.getNextSetIndex(index+1); + } + return result; + } + + template + storm::analysis::Lattice* toLattice(std::shared_ptr> model, + storm::storage::BitVector topStates, + storm::storage::BitVector bottomStates) { + storm::storage::SparseMatrix matrix = model.get()->getTransitionMatrix(); + storm::storage::BitVector initialStates = model.get()->getInitialStates(); + uint_fast64_t numberOfStates = model.get()->getNumberOfStates(); + + // Transform the transition matrix into a vector containing the states with the state to which the transition goes. + std::vector stateVector = std::vector({}); + for (uint_fast64_t i = 0; i < numberOfStates; ++i) { + State* state = new State(); + state->stateNumber = i; + state->successor1 = numberOfStates; + state->successor2 = numberOfStates; + + auto row = matrix.getRow(i); + for (auto itr = row.begin(); itr < row.end() && state->successor2 == numberOfStates; ++itr) { + if ((*itr).getValue() != ValueType(1)) { + if (state->successor1 == numberOfStates) { + state->successor1 = (*itr).getColumn(); + } else { + state->successor2 = (*itr).getColumn(); + } + } else { + state-> successor1 = (*itr).getColumn(); + state-> successor2 = (*itr).getColumn(); + } + } + stateVector.push_back(state); + } + + // Start creating the Lattice + storm::analysis::Lattice *lattice = new storm::analysis::Lattice(topStates, bottomStates, numberOfStates); + storm::storage::BitVector oldStates(numberOfStates); + // Create a copy of the states already present in the lattice. + storm::storage::BitVector seenStates = topStates|=bottomStates; + + while (oldStates != seenStates) { + // As long as new states are added to the lattice, continue. + oldStates = storm::storage::BitVector(seenStates); + + for (auto itr = stateVector.begin(); itr != stateVector.end(); ++itr) { + // Iterate over all states + State *currentState = *itr; + + if (!seenStates[currentState->stateNumber] + && seenStates[currentState->successor1] + && seenStates[currentState->successor2]) { + + // Check if the current state number has not been added, but its successors have been added. + if (currentState->successor1 == currentState->successor2) { + // If there is only one successor, the state should be added to the same Node as its successor + lattice->addToNode(currentState->stateNumber, lattice->getNode(currentState->successor1)); + // Add stateNumber to the set with seen states. + seenStates.set(currentState->stateNumber); + } else { + // Otherwise, check how the two states compare, and add if the comparison is possible. + uint_fast64_t successor1 = currentState->successor1; + uint_fast64_t successor2 = currentState->successor2; + int compareResult = lattice->compare(successor1, successor2); + if (compareResult == 1 || compareResult == 2) { + + if (compareResult == 2) { + // swap + auto temp = successor1; + successor1 = successor2; + successor2 = temp; + } + // Additional check, if states have the same probability of reaching a given next state, + // then they should be at the same node + // TODO: can this be removed, e.g. adding a step to preprocessing, making this superfluous + storm::analysis::Lattice::Node *above = lattice->getNode(successor1); + storm::analysis::Lattice::Node *below = lattice->getNode(successor2); + std::vector states1 = above->below; + std::vector states2 = below->above; + for (auto itr1 = states1.begin(); itr1 < states1.end(); ++itr1) { + for (auto itr2 = states2.begin(); itr2 < states2.end(); ++itr2) { + if ((*itr1)->states == (*itr2)->states) { + ValueType prob1 = getProbability(currentState->stateNumber, successor1, matrix); + ValueType prob2 = getProbability(currentState->stateNumber, successor2, matrix); + if (prob1 != ValueType(1) + && prob2 != ValueType(1) + && getProbability((*itr1)->states, above->states, matrix) == prob1 + && getProbability((*itr1)->states, below->states, matrix) == prob2) { + lattice->addToNode(currentState->stateNumber, (*itr1)); + seenStates.set(currentState->stateNumber); + } + } + } + } + + if (!seenStates.get(currentState->stateNumber)) { + // successor 1 is closer to top than successor 2 + lattice->addBetween(currentState->stateNumber, lattice->getNode(successor1), + lattice->getNode(successor2)); + // Add stateNumber to the set with seen states. + seenStates.set(currentState->stateNumber); + } + } else if (compareResult == 0) { + // the successors are at the same level + lattice->addToNode(currentState->stateNumber, lattice->getNode(successor1)); + // Add stateNumber to the set with seen states. + seenStates.set(currentState->stateNumber); + } else { + // TODO: what to do? + STORM_LOG_DEBUG("Failed to add" << currentState->stateNumber << "\n"); + } + } + } + } + } + return lattice; + } + + template void processInputWithValueTypeAndDdlib(SymbolicInput& input) { auto coreSettings = storm::settings::getModule(); @@ -458,8 +618,6 @@ namespace storm { STORM_LOG_THROW(model || input.properties.empty(), storm::exceptions::InvalidSettingsException, "No input model."); - // TODO: Shift this to after preprocessing? - if (model) { auto preprocessingResult = storm::pars::preprocessModel(model, input); if (preprocessingResult.second) { @@ -472,24 +630,24 @@ namespace storm { if (parSettings.isMonotonicityAnalysisSet()) { // Do something more fancy. std::cout << "Hello, Jip" << std::endl; - std::shared_ptr> sparseModel = model->as>(); - - storm::storage::SparseMatrix matrix = sparseModel.get()->getTransitionMatrix(); - - storm::storage::BitVector initialStates = sparseModel.get()->getInitialStates(); + std::shared_ptr> sparseModel = model->as>(); std::vector> formulas = storm::api::extractFormulasFromProperties(input.properties); STORM_LOG_THROW((*(formulas[0])).isProbabilityOperatorFormula() && (*(formulas[0])).asProbabilityOperatorFormula().getSubformula().isUntilFormula(), storm::exceptions::NotSupportedException, "Expecting until formula"); storm::modelchecker::SparsePropositionalModelChecker> propositionalChecker(*sparseModel); storm::storage::BitVector phiStates = propositionalChecker.check((*(formulas[0])).asProbabilityOperatorFormula().getSubformula().asUntilFormula().getLeftSubformula())->asExplicitQualitativeCheckResult().getTruthValuesVector(); storm::storage::BitVector psiStates = propositionalChecker.check((*(formulas[0])).asProbabilityOperatorFormula().getSubformula().asUntilFormula().getRightSubformula())->asExplicitQualitativeCheckResult().getTruthValuesVector(); //right - // get the maybeStates - std::pair statesWithProbability01 = storm::utility::graph::performProb01(sparseModel.get()->getBackwardTransitions(), phiStates, psiStates); + // Get the maybeStates + std::pair statesWithProbability01 = storm::utility::graph::performProb01(sparseModel.get()->getBackwardTransitions(), phiStates, psiStates); storm::storage::BitVector topStates = statesWithProbability01.second; storm::storage::BitVector bottomStates = statesWithProbability01.first; - storm::analysis::Lattice* lattice = storm::analysis::Transformer::toLattice(matrix, initialStates, topStates, bottomStates, sparseModel.get()->getNumberOfStates()); + + // Transform to LatticeLattice + storm::analysis::Lattice* lattice = toLattice(sparseModel, topStates, bottomStates); + lattice->toString(std::cout); + std::cout << "Bye, Jip" << std::endl; // TODO: Analyse lattice with transition matrix // Where do the parameters occur? @@ -528,6 +686,8 @@ namespace storm { verifyParametricModel(model, input, regions, samples); } } + + void processOptions() { // Start by setting some urgent options (log levels, resources, etc.) diff --git a/src/storm-pars/analysis/Transformer.cpp b/src/storm-pars/analysis/Transformer.cpp deleted file mode 100644 index 6bcae81a9..000000000 --- a/src/storm-pars/analysis/Transformer.cpp +++ /dev/null @@ -1,155 +0,0 @@ -// -// Created by Jip Spel on 26.07.18. -// -// TODO: Use templates -#include "Transformer.h" -namespace storm { - namespace analysis { - Lattice *Transformer::toLattice(storm::storage::SparseMatrix matrix, - storm::storage::BitVector const &initialStates, - storm::storage::BitVector topStates, - storm::storage::BitVector bottomStates, uint_fast64_t numberOfStates) { - // TODO: take SparseModel as input - // Transform the transition matrix into a vector containing the states with the state to which the transition goes. - std::vector stateVector = std::vector({}); - - for (uint_fast64_t i = 0; i < numberOfStates; ++i) { - State* state = new State(); - state->stateNumber = i; - state->successor1 = numberOfStates; - state->successor2 = numberOfStates; - - auto row = matrix.getRow(i); - for (auto itr = row.begin(); itr < row.end() && state->successor2 == numberOfStates; ++itr) { - if ((*itr).getValue() != storm::RationalFunction(1)) { - if (state->successor1 == numberOfStates) { - state->successor1 = (*itr).getColumn(); - } else { - state->successor2 = (*itr).getColumn(); - } - } else { - state-> successor1 = (*itr).getColumn(); - state-> successor2 = (*itr).getColumn(); - } - } - stateVector.push_back(state); - } - - // Start creating the Lattice - Lattice *lattice = new Lattice(topStates, bottomStates, numberOfStates); - storm::storage::BitVector oldStates(numberOfStates); - // Create a copy of the states already present in the lattice. - storm::storage::BitVector seenStates = topStates|=bottomStates; - - while (oldStates != seenStates) { - // As long as new states are added to the lattice, continue. - oldStates = storm::storage::BitVector(seenStates); - - for (auto itr = stateVector.begin(); itr != stateVector.end(); ++itr) { - // Iterate over all states - State *currentState = *itr; - - if (!seenStates[currentState->stateNumber] - && seenStates[currentState->successor1] - && seenStates[currentState->successor2]) { - - // Check if the current state number has not been added, but its successors have been added. - if (currentState->successor1 == currentState->successor2) { - // If there is only one successor, the state should be added to the same Node as its successor - lattice->addToNode(currentState->stateNumber, lattice->getNode(currentState->successor1)); - // Add stateNumber to the set with seen states. - seenStates.set(currentState->stateNumber); - } else { - // Otherwise, check how the two states compare, and add if the comparison is possible. - uint_fast64_t successor1 = currentState->successor1; - uint_fast64_t successor2 = currentState->successor2; - int compareResult = lattice->compare(successor1, successor2); - if (compareResult == 1 || compareResult == 2) { - - if (compareResult == 2) { - // swap - auto temp = successor1; - successor1 = successor2; - successor2 = temp; - } - // Additional check, if states have the same probability of reaching a given next state, - // then they should be at the same node - Lattice::Node *above = lattice->getNode(successor1); - Lattice::Node *below = lattice->getNode(successor2); - std::vector states1 = above->below; - std::vector states2 = below->above; - for (auto itr1 = states1.begin(); itr1 < states1.end(); ++itr1) { - for (auto itr2 = states2.begin(); itr2 < states2.end(); ++itr2) { - if ((*itr1)->states == (*itr2)->states) { - storm::RationalFunction prob1 = getProbability(currentState->stateNumber, successor1, matrix); - storm::RationalFunction prob2 = getProbability(currentState->stateNumber, successor2, matrix); - if (prob1 != storm::RationalFunction(1) - && prob2 != storm::RationalFunction(1) - && getProbability((*itr1)->states, above->states, matrix) == prob1 - && getProbability((*itr1)->states, below->states, matrix) == prob2) { - lattice->addToNode(currentState->stateNumber, (*itr1)); - seenStates.set(currentState->stateNumber); - } - } - } - } - - if (!seenStates.get(currentState->stateNumber)) { - // successor 1 is closer to top than successor 2 - lattice->addBetween(currentState->stateNumber, lattice->getNode(successor1), - lattice->getNode(successor2)); - // Add stateNumber to the set with seen states. - seenStates.set(currentState->stateNumber); - } - } else if (compareResult == 0) { - // the successors are at the same level - lattice->addToNode(currentState->stateNumber, lattice->getNode(successor1)); - // Add stateNumber to the set with seen states. - seenStates.set(currentState->stateNumber); - } else { - // TODO: what to do? - STORM_LOG_DEBUG("Failed to add" << currentState->stateNumber << "\n"); - } - } - } - } - } - return lattice; - } - - storm::RationalFunction Transformer::getProbability(storm::storage::BitVector state, storm::storage::BitVector successor, storm::storage::SparseMatrix matrix) { - storm::RationalFunction result = storm::RationalFunction(1); - uint_fast64_t index = successor.getNextSetIndex(0); - while (index < successor.size() && result == storm::RationalFunction(1)) { - result = getProbability(state, index, matrix); - index = successor.getNextSetIndex(index+1); - } - return result; - } - - storm::RationalFunction Transformer::getProbability(storm::storage::BitVector state, uint_fast64_t successor, storm::storage::SparseMatrix matrix) { - storm::RationalFunction result = storm::RationalFunction(1); - uint_fast64_t index = state.getNextSetIndex(0); - while (index < state.size() && result == storm::RationalFunction(1)) { - result = getProbability(index, successor, matrix); - index = state.getNextSetIndex(index+1); - } - return result; - } - - storm::RationalFunction Transformer::getProbability(uint_fast64_t state, uint_fast64_t successor, storm::storage::SparseMatrix matrix) { - storm::RationalFunction result = storm::RationalFunction(1); - // Iterate over all row groups. - auto row = matrix.getRow(state); - - for (auto itr = row.begin(); itr < row.end() && result == storm::RationalFunction(1); ++itr) { - if ((*itr).getColumn() == successor) { - result = (*itr).getValue(); - } - - } - - return result; - } - } -} diff --git a/src/storm-pars/analysis/Transformer.h b/src/storm-pars/analysis/Transformer.h deleted file mode 100644 index 1d3bf64a1..000000000 --- a/src/storm-pars/analysis/Transformer.h +++ /dev/null @@ -1,49 +0,0 @@ -// -// Created by Jip Spel on 26.07.18. -// - -#ifndef LATTICE_BUILDER_H -#define LATTICE_BUILDER_H - -#include -#include "storm/storage/BitVector.h" -#include "storm/storage/SparseMatrix.h" -#include "Lattice.h" -namespace storm { - namespace analysis { - class Transformer { - public: - struct State { - uint_fast64_t stateNumber; - uint_fast64_t successor1; - uint_fast64_t successor2; - }; - - /*! - * Returns the pointer to the Lattice constructed from the given transitionMatrix, - * BitVector of initialStates, vector with the top states and vector with the bottom states. - * Assumes that every state has at least one and at most two outgoing transitions. - * - * @param matrix The transition matrix. - * @param initialStates The BitVector containing the initialStates. - * @param topStates Vector containing the numbers of the top states. - * @param bottomStates Vector containing the numbers of the bottom states. - * - * @return The lattice ordering of the states. - */ - static Lattice *toLattice(storm::storage::SparseMatrix matrix, - storm::storage::BitVector const &initialStates, - storm::storage::BitVector topStates, - storm::storage::BitVector bottomStates, uint_fast64_t numberOfStates); - - private: - static storm::RationalFunction getProbability(storm::storage::BitVector state, storm::storage::BitVector successor, storm::storage::SparseMatrix matrix); - - static storm::RationalFunction getProbability(storm::storage::BitVector state, uint_fast64_t successor, storm::storage::SparseMatrix matrix); - - static storm::RationalFunction getProbability(uint_fast64_t state, uint_fast64_t successor, storm::storage::SparseMatrix matrix); - - }; - } -} -#endif //LATTICE_BUILDER_H From 1364ec8729b15dc836c89d8e631fdd193dccd7d7 Mon Sep 17 00:00:00 2001 From: Jip Spel Date: Wed, 15 Aug 2018 17:03:26 +0200 Subject: [PATCH 008/178] Clean up --- src/storm-pars-cli/storm-pars.cpp | 100 +++++++++++++--------------- src/storm-pars/analysis/Lattice.cpp | 46 ++++--------- src/storm-pars/analysis/Lattice.h | 4 +- 3 files changed, 60 insertions(+), 90 deletions(-) diff --git a/src/storm-pars-cli/storm-pars.cpp b/src/storm-pars-cli/storm-pars.cpp index 470699988..931ac740d 100644 --- a/src/storm-pars-cli/storm-pars.cpp +++ b/src/storm-pars-cli/storm-pars.cpp @@ -511,12 +511,11 @@ namespace storm { } stateVector.push_back(state); } - // Start creating the Lattice storm::analysis::Lattice *lattice = new storm::analysis::Lattice(topStates, bottomStates, numberOfStates); storm::storage::BitVector oldStates(numberOfStates); // Create a copy of the states already present in the lattice. - storm::storage::BitVector seenStates = topStates|=bottomStates; + storm::storage::BitVector seenStates = topStates|= bottomStates; while (oldStates != seenStates) { // As long as new states are added to the lattice, continue. @@ -530,65 +529,60 @@ namespace storm { && seenStates[currentState->successor1] && seenStates[currentState->successor2]) { - // Check if the current state number has not been added, but its successors have been added. - if (currentState->successor1 == currentState->successor2) { - // If there is only one successor, the state should be added to the same Node as its successor - lattice->addToNode(currentState->stateNumber, lattice->getNode(currentState->successor1)); - // Add stateNumber to the set with seen states. - seenStates.set(currentState->stateNumber); - } else { - // Otherwise, check how the two states compare, and add if the comparison is possible. - uint_fast64_t successor1 = currentState->successor1; - uint_fast64_t successor2 = currentState->successor2; - int compareResult = lattice->compare(successor1, successor2); - if (compareResult == 1 || compareResult == 2) { - - if (compareResult == 2) { - // swap - auto temp = successor1; - successor1 = successor2; - successor2 = temp; - } - // Additional check, if states have the same probability of reaching a given next state, - // then they should be at the same node - // TODO: can this be removed, e.g. adding a step to preprocessing, making this superfluous - storm::analysis::Lattice::Node *above = lattice->getNode(successor1); - storm::analysis::Lattice::Node *below = lattice->getNode(successor2); - std::vector states1 = above->below; - std::vector states2 = below->above; - for (auto itr1 = states1.begin(); itr1 < states1.end(); ++itr1) { - for (auto itr2 = states2.begin(); itr2 < states2.end(); ++itr2) { - if ((*itr1)->states == (*itr2)->states) { - ValueType prob1 = getProbability(currentState->stateNumber, successor1, matrix); - ValueType prob2 = getProbability(currentState->stateNumber, successor2, matrix); - if (prob1 != ValueType(1) - && prob2 != ValueType(1) - && getProbability((*itr1)->states, above->states, matrix) == prob1 - && getProbability((*itr1)->states, below->states, matrix) == prob2) { - lattice->addToNode(currentState->stateNumber, (*itr1)); - seenStates.set(currentState->stateNumber); - } + + // Otherwise, check how the two states compare, and add if the comparison is possible. + uint_fast64_t successor1 = currentState->successor1; + uint_fast64_t successor2 = currentState->successor2; + int compareResult = lattice->compare(successor1, successor2); + if (compareResult == 1 || compareResult == 2) { + // getNode will not return nullptr, as compare already checked this + if (compareResult == 2) { + // swap + auto temp = successor1; + successor1 = successor2; + successor2 = temp; + } + // Additional check, if states have the same probability of reaching a given next state, + // then they should be at the same node + // TODO: can this be removed, e.g. adding a step to preprocessing, making this superfluous + // TODO: 1 prob. and same probs to same states should be removed from matrix + storm::analysis::Lattice::Node *above = lattice->getNode(successor1); + storm::analysis::Lattice::Node *below = lattice->getNode(successor2); + std::vector states1 = above->below; + std::vector states2 = below->above; + for (auto itr1 = states1.begin(); itr1 < states1.end(); ++itr1) { + for (auto itr2 = states2.begin(); itr2 < states2.end(); ++itr2) { + if ((*itr1)->states == (*itr2)->states) { + ValueType prob1 = getProbability(currentState->stateNumber, successor1, matrix); + ValueType prob2 = getProbability(currentState->stateNumber, successor2, matrix); + if (prob1 != ValueType(1) + && prob2 != ValueType(1) + && getProbability((*itr1)->states, above->states, matrix) == prob1 + && getProbability((*itr1)->states, below->states, matrix) == prob2) { + lattice->addToNode(currentState->stateNumber, (*itr1)); + seenStates.set(currentState->stateNumber); } } } + } - if (!seenStates.get(currentState->stateNumber)) { - // successor 1 is closer to top than successor 2 - lattice->addBetween(currentState->stateNumber, lattice->getNode(successor1), - lattice->getNode(successor2)); - // Add stateNumber to the set with seen states. - seenStates.set(currentState->stateNumber); - } - } else if (compareResult == 0) { - // the successors are at the same level - lattice->addToNode(currentState->stateNumber, lattice->getNode(successor1)); + if (!seenStates.get(currentState->stateNumber)) { + // successor 1 is closer to top than successor 2 + lattice->addBetween(currentState->stateNumber, lattice->getNode(successor1), + lattice->getNode(successor2)); // Add stateNumber to the set with seen states. seenStates.set(currentState->stateNumber); - } else { - // TODO: what to do? - STORM_LOG_DEBUG("Failed to add" << currentState->stateNumber << "\n"); } + } else if (compareResult == 0) { + // the successors are at the same level + lattice->addToNode(currentState->stateNumber, lattice->getNode(successor1)); + // Add stateNumber to the set with seen states. + seenStates.set(currentState->stateNumber); + } else { + // TODO: what to do? + STORM_LOG_DEBUG("Failed to add" << currentState->stateNumber << "\n"); } + } } } diff --git a/src/storm-pars/analysis/Lattice.cpp b/src/storm-pars/analysis/Lattice.cpp index a3fa9b8dc..8023fd835 100644 --- a/src/storm-pars/analysis/Lattice.cpp +++ b/src/storm-pars/analysis/Lattice.cpp @@ -39,23 +39,24 @@ namespace storm { Node *node1 = getNode(state1); Node *node2 = getNode(state2); - if (node1 == node2) { - return 0; - } + if (node1 != nullptr && node2 != nullptr) { + if (node1 == node2) { + return 0; + } - if (above(node1, node2)) { - return 1; - } + if (above(node1, node2)) { + return 1; + } - if (below(node1, node2)) { - return 2; + if (above(node2, node1)) { + return 2; + } } return -1; } Lattice::Node *Lattice::getNode(uint_fast64_t stateNumber) { - // TODO: might return nullptr, what to do with it? Node *node; for (auto itr = nodes.begin(); itr != nodes.end(); ++itr) { storm::storage::BitVector states = (*itr)->states; @@ -122,37 +123,14 @@ namespace storm { } bool Lattice::above(Node *node1, Node *node2) { - if (node1->below.empty()) { - return false; - } - - if (std::find(node1->below.begin(), node1->below.end(), node2) != node1->below.end()) { - return true; - } + bool result = !node1->below.empty() && std::find(node1->below.begin(), node1->below.end(), node2) != node1->below.end(); - bool result = false; - for (auto itr = node1->below.begin(); node1->below.end() != itr; ++itr) { + for (auto itr = node1->below.begin(); !result && node1->below.end() != itr; ++itr) { result |= above(*itr, node2); } return result; } - bool Lattice::below(Node *node1, Node *node2) { - if (node1->above.empty()) { - return false; - } - - if (std::find(node1->above.begin(), node1->above.end(), node2) != node1->above.end()) { - return true; - } - - bool result = false; - for (auto itr = node1->above.begin(); node1->above.end() != itr; ++itr) { - result |= below(*itr, node2); - } - return result; - } - void Lattice::remove(std::vector *nodes, Node *node) { auto index = std::find(nodes->begin(), nodes->end(), node); if (index != nodes->end()) { diff --git a/src/storm-pars/analysis/Lattice.h b/src/storm-pars/analysis/Lattice.h index 6b5e6d32c..14b7b341b 100644 --- a/src/storm-pars/analysis/Lattice.h +++ b/src/storm-pars/analysis/Lattice.h @@ -63,7 +63,7 @@ namespace storm { * * @param state The number of the state. * - * @return The pointer to the node of the state. + * @return The pointer to the node of the state, nullptr if the node does not exist */ Node *getNode(uint_fast64_t state); @@ -83,8 +83,6 @@ namespace storm { bool above(Node *, Node *); - bool below(Node *, Node *); - void remove(std::vector *nodes, Node *node); void setStates(std::vector states, Node *node); From b782d80a26910147534dccd7e8c29fac5d212d15 Mon Sep 17 00:00:00 2001 From: Jip Spel Date: Thu, 16 Aug 2018 11:04:01 +0200 Subject: [PATCH 009/178] Changed nodes implementation in Lattice --- src/storm-pars/analysis/Lattice.cpp | 105 +++++++++++++++------------- 1 file changed, 58 insertions(+), 47 deletions(-) diff --git a/src/storm-pars/analysis/Lattice.cpp b/src/storm-pars/analysis/Lattice.cpp index 8023fd835..f710f2fbb 100644 --- a/src/storm-pars/analysis/Lattice.cpp +++ b/src/storm-pars/analysis/Lattice.cpp @@ -8,17 +8,28 @@ namespace storm { namespace analysis { Lattice::Lattice(storm::storage::BitVector topStates, storm::storage::BitVector bottomStates, uint_fast64_t numberOfStates) { + Node *top = new Node(); top->states = topStates; Node *bottom = new Node(); bottom->states = bottomStates; top->below.push_back(bottom); bottom->above.push_back(top); - nodes = std::vector({top, bottom}); + + nodes = std::vector(numberOfStates); + for (auto i = topStates.getNextSetIndex(0); i < numberOfStates; i = topStates.getNextSetIndex(i+1)) { + nodes.at(i) = top; + + } + for (auto i = bottomStates.getNextSetIndex(0); i < numberOfStates; i = bottomStates.getNextSetIndex(i+1)) { + nodes.at(i) = bottom; + } this->numberOfStates = numberOfStates; + } void Lattice::addBetween(uint_fast64_t state, Node *above, Node *below) { + std::cout << "Adding: " << state << std::endl; Node *newNode = new Node(); newNode->states = storm::storage::BitVector(numberOfStates); newNode->states.set(state); @@ -28,11 +39,12 @@ namespace storm { remove(&(above->below), below); (below->above).push_back(newNode); above->below.push_back(newNode); - nodes.push_back(newNode); + nodes.at(state) = newNode; } void Lattice::addToNode(uint_fast64_t state, Node *node) { node->states.set(state); + nodes.at(state) = node; } int Lattice::compare(uint_fast64_t state1, uint_fast64_t state2) { @@ -57,68 +69,67 @@ namespace storm { } Lattice::Node *Lattice::getNode(uint_fast64_t stateNumber) { - Node *node; - for (auto itr = nodes.begin(); itr != nodes.end(); ++itr) { - storm::storage::BitVector states = (*itr)->states; - - if (states[stateNumber]) return (*itr); - } - return node; + return nodes.at(stateNumber); } void Lattice::toString(std::ostream &out) { + std::vector printedNodes = std::vector({}); for (auto itr = nodes.begin(); itr != nodes.end(); ++itr) { - Node *node = *itr; - out << "Node: {"; - uint_fast64_t index = node->states.getNextSetIndex(0); - while (index < numberOfStates) { - out << index; - index = node->states.getNextSetIndex(index+1); - if (index < numberOfStates) { - out << ", "; - } - } - out << "}" << "\n"; - out << " Address: " << node << "\n"; - out << " Above: {"; - for (auto itr2 = node->above.begin(); itr2 != node->above.end(); ++itr2) { - Node *above = *itr2; - out << "{"; - index = above->states.getNextSetIndex(0); + + if (std::find(printedNodes.begin(), printedNodes.end(), (*itr)) == printedNodes.end()) { + Node *node = *itr; + printedNodes.push_back(*itr); + out << "Node: {"; + uint_fast64_t index = node->states.getNextSetIndex(0); while (index < numberOfStates) { out << index; - index = above->states.getNextSetIndex(index+1); + index = node->states.getNextSetIndex(index + 1); if (index < numberOfStates) { out << ", "; } } + out << "}" << "\n"; + out << " Address: " << node << "\n"; + out << " Above: {"; + for (auto itr2 = node->above.begin(); itr2 != node->above.end(); ++itr2) { + Node *above = *itr2; + out << "{"; + index = above->states.getNextSetIndex(0); + while (index < numberOfStates) { + out << index; + index = above->states.getNextSetIndex(index + 1); + if (index < numberOfStates) { + out << ", "; + } + } - out << "}"; - if (itr2 + 1 != node->above.end()) { - out << ", "; - } - } - out << "}" << "\n"; - - out << " Below: {"; - for (auto itr2 = node->below.begin(); itr2 != node->below.end(); ++itr2) { - Node *below = *itr2; - out << "{"; - index = below->states.getNextSetIndex(0); - while (index < numberOfStates) { - out << index; - index = below->states.getNextSetIndex(index+1); - if (index < numberOfStates) { + out << "}"; + if (itr2 + 1 != node->above.end()) { out << ", "; } } + out << "}" << "\n"; + + out << " Below: {"; + for (auto itr2 = node->below.begin(); itr2 != node->below.end(); ++itr2) { + Node *below = *itr2; + out << "{"; + index = below->states.getNextSetIndex(0); + while (index < numberOfStates) { + out << index; + index = below->states.getNextSetIndex(index + 1); + if (index < numberOfStates) { + out << ", "; + } + } - out << "}"; - if (itr2 + 1 != node->below.end()) { - out << ", "; + out << "}"; + if (itr2 + 1 != node->below.end()) { + out << ", "; + } } + out << "}" << "\n"; } - out << "}" << "\n"; } } From aa630ce62b79bdd9e4a624914a5e03268f4ad88e Mon Sep 17 00:00:00 2001 From: Jip Spel Date: Thu, 16 Aug 2018 14:25:38 +0200 Subject: [PATCH 010/178] Monotone increasing in all parameters implemented --- src/storm-pars-cli/storm-pars.cpp | 46 +++++++++++++++++++++++-------- 1 file changed, 35 insertions(+), 11 deletions(-) diff --git a/src/storm-pars-cli/storm-pars.cpp b/src/storm-pars-cli/storm-pars.cpp index 931ac740d..11d6a98bb 100644 --- a/src/storm-pars-cli/storm-pars.cpp +++ b/src/storm-pars-cli/storm-pars.cpp @@ -641,18 +641,42 @@ namespace storm { // Transform to LatticeLattice storm::analysis::Lattice* lattice = toLattice(sparseModel, topStates, bottomStates); lattice->toString(std::cout); - std::cout << "Bye, Jip" << std::endl; - // TODO: Analyse lattice with transition matrix - // Where do the parameters occur? - // initially incr.Boolean and decr.Boolean true - // At every occurence as long as either incr.Boolean or decr.Boolean true - // --> check if monotonic - // --> yes --> check position in lattice - // --> if incr. set incr.Boolean = incr.Boolean && true, decr.Boolean = false; - // --> if decr. set incr.Boolean = false, decr.Boolean = decr.Boolean && true; - // --> no --> set both booleans to false - // --> set both incr.bool and decr.bool to false + bool monotoneInAll = true; + + storm::storage::SparseMatrix matrix = sparseModel.get()->getTransitionMatrix(); + for (uint_fast64_t i = 0; i < sparseModel.get()->getNumberOfStates(); ++i) { + // go over all rows + auto row = matrix.getRow(i); + + + auto first = (*row.begin()); + if (first.getValue() != ValueType(1)) { + auto second = (* (row.begin() + 1)); + + auto val = first.getValue(); + auto vars = val.gatherVariables(); + for (auto itr = vars.begin(); itr != vars.end(); ++itr) { + auto derivative = val.derivative(*itr); + STORM_LOG_THROW(derivative.isConstant(), storm::exceptions::NotSupportedException, "Expecting probability to have at most degree 1"); + auto compare = lattice->compare(first.getColumn(), second.getColumn()); + if (compare == 1) { + monotoneInAll &=derivative.constantPart() >= 0; + } else if (compare == 2) { + monotoneInAll &=derivative.constantPart() <= 0; + } else { + monotoneInAll = false; + } + } + } + + + } + if (monotoneInAll) { + std::cout << "Monotone increasing in all parameters" << std::endl; + } + // TODO: split into monotonicity in different parameters + std::cout << "Bye, Jip" << std::endl; return; } From 9bc402a20b46deb48ae5df5d418fc4b08278db1f Mon Sep 17 00:00:00 2001 From: Jip Spel Date: Fri, 17 Aug 2018 10:04:37 +0200 Subject: [PATCH 011/178] Remove states with transition with probability 1 from model --- src/storm-pars-cli/storm-pars.cpp | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/src/storm-pars-cli/storm-pars.cpp b/src/storm-pars-cli/storm-pars.cpp index 11d6a98bb..f97c67c8b 100644 --- a/src/storm-pars-cli/storm-pars.cpp +++ b/src/storm-pars-cli/storm-pars.cpp @@ -1,4 +1,6 @@ +#include +#include #include "storm-pars/api/storm-pars.h" #include "storm-pars/settings/ParsSettings.h" #include "storm-pars/settings/modules/ParametricSettings.h" @@ -612,6 +614,7 @@ namespace storm { STORM_LOG_THROW(model || input.properties.empty(), storm::exceptions::InvalidSettingsException, "No input model."); + if (model) { auto preprocessingResult = storm::pars::preprocessModel(model, input); if (preprocessingResult.second) { @@ -624,9 +627,21 @@ namespace storm { if (parSettings.isMonotonicityAnalysisSet()) { // Do something more fancy. std::cout << "Hello, Jip" << std::endl; + auto testModel = (model->as>()); + // TODO: check if it is a Dtmc + auto simplifier = storm::transformer::SparseParametricDtmcSimplifier>(*testModel); + - std::shared_ptr> sparseModel = model->as>(); std::vector> formulas = storm::api::extractFormulasFromProperties(input.properties); + STORM_LOG_THROW(formulas.begin()!=formulas.end(), storm::exceptions::NotSupportedException, "Only one formula at the time supported"); + + if (!simplifier.simplify(*(formulas[0]))) { + STORM_LOG_THROW(false, storm::exceptions::UnexpectedException, "Simplifying the model was not successfull."); + } + + + std::shared_ptr> sparseModel = simplifier.getSimplifiedModel();//->as>(); +// formulas = std::vector>({simplifier.getSimplifiedFormula()});//storm::api::extractFormulasFromProperties(input.properties); STORM_LOG_THROW((*(formulas[0])).isProbabilityOperatorFormula() && (*(formulas[0])).asProbabilityOperatorFormula().getSubformula().isUntilFormula(), storm::exceptions::NotSupportedException, "Expecting until formula"); storm::modelchecker::SparsePropositionalModelChecker> propositionalChecker(*sparseModel); From 8c3fb65ef9a8214b07813161dcfa5f539dbe0a3e Mon Sep 17 00:00:00 2001 From: Jip Spel Date: Fri, 17 Aug 2018 10:48:01 +0200 Subject: [PATCH 012/178] Simplify before preprocessing --- src/storm-pars-cli/storm-pars.cpp | 93 +++++++++++++++---------------- 1 file changed, 46 insertions(+), 47 deletions(-) diff --git a/src/storm-pars-cli/storm-pars.cpp b/src/storm-pars-cli/storm-pars.cpp index f97c67c8b..5506247a7 100644 --- a/src/storm-pars-cli/storm-pars.cpp +++ b/src/storm-pars-cli/storm-pars.cpp @@ -499,18 +499,15 @@ namespace storm { state->successor2 = numberOfStates; auto row = matrix.getRow(i); - for (auto itr = row.begin(); itr < row.end() && state->successor2 == numberOfStates; ++itr) { - if ((*itr).getValue() != ValueType(1)) { - if (state->successor1 == numberOfStates) { - state->successor1 = (*itr).getColumn(); - } else { - state->successor2 = (*itr).getColumn(); - } - } else { - state-> successor1 = (*itr).getColumn(); - state-> successor2 = (*itr).getColumn(); - } + //TODO assert that there are at most two successors + if ((*(row.begin())).getValue() != ValueType(1)) { + state->successor1 = (*(row.begin())).getColumn(); + state->successor2 = (*(++row.begin())).getColumn(); + } else { + state-> successor1 = (*(row.begin())).getColumn(); + state-> successor2 = (*(row.begin())).getColumn(); } + stateVector.push_back(state); } // Start creating the Lattice @@ -548,25 +545,25 @@ namespace storm { // then they should be at the same node // TODO: can this be removed, e.g. adding a step to preprocessing, making this superfluous // TODO: 1 prob. and same probs to same states should be removed from matrix - storm::analysis::Lattice::Node *above = lattice->getNode(successor1); - storm::analysis::Lattice::Node *below = lattice->getNode(successor2); - std::vector states1 = above->below; - std::vector states2 = below->above; - for (auto itr1 = states1.begin(); itr1 < states1.end(); ++itr1) { - for (auto itr2 = states2.begin(); itr2 < states2.end(); ++itr2) { - if ((*itr1)->states == (*itr2)->states) { - ValueType prob1 = getProbability(currentState->stateNumber, successor1, matrix); - ValueType prob2 = getProbability(currentState->stateNumber, successor2, matrix); - if (prob1 != ValueType(1) - && prob2 != ValueType(1) - && getProbability((*itr1)->states, above->states, matrix) == prob1 - && getProbability((*itr1)->states, below->states, matrix) == prob2) { - lattice->addToNode(currentState->stateNumber, (*itr1)); - seenStates.set(currentState->stateNumber); - } - } - } - } +// storm::analysis::Lattice::Node *above = lattice->getNode(successor1); +// storm::analysis::Lattice::Node *below = lattice->getNode(successor2); +// std::vector states1 = above->below; +// std::vector states2 = below->above; +// for (auto itr1 = states1.begin(); itr1 < states1.end(); ++itr1) { +// for (auto itr2 = states2.begin(); itr2 < states2.end(); ++itr2) { +// if ((*itr1)->states == (*itr2)->states) { +// ValueType prob1 = getProbability(currentState->stateNumber, successor1, matrix); +// ValueType prob2 = getProbability(currentState->stateNumber, successor2, matrix); +// if (prob1 != ValueType(1) +// && prob2 != ValueType(1) +// && getProbability((*itr1)->states, above->states, matrix) == prob1 +// && getProbability((*itr1)->states, below->states, matrix) == prob2) { +// lattice->addToNode(currentState->stateNumber, (*itr1)); +// seenStates.set(currentState->stateNumber); +// } +// } +// } +// } if (!seenStates.get(currentState->stateNumber)) { // successor 1 is closer to top than successor 2 @@ -614,6 +611,21 @@ namespace storm { STORM_LOG_THROW(model || input.properties.empty(), storm::exceptions::InvalidSettingsException, "No input model."); + if (parSettings.isMonotonicityAnalysisSet()) { + std::cout << "Hello, Jip1" << std::endl; + auto consideredModel = (model->as>()); + // TODO: check if it is a Dtmc + auto simplifier = storm::transformer::SparseParametricDtmcSimplifier>(*consideredModel); + + std::vector> formulas = storm::api::extractFormulasFromProperties(input.properties); + STORM_LOG_THROW(formulas.begin()!=formulas.end(), storm::exceptions::NotSupportedException, "Only one formula at the time supported"); + + if (!simplifier.simplify(*(formulas[0]))) { + STORM_LOG_THROW(false, storm::exceptions::UnexpectedException, "Simplifying the model was not successfull."); + } + model = simplifier.getSimplifiedModel(); + std::cout << "Bye, Jip1" << std::endl; + } if (model) { auto preprocessingResult = storm::pars::preprocessModel(model, input); @@ -623,25 +635,12 @@ namespace storm { } } - if (parSettings.isMonotonicityAnalysisSet()) { // Do something more fancy. - std::cout << "Hello, Jip" << std::endl; - auto testModel = (model->as>()); - // TODO: check if it is a Dtmc - auto simplifier = storm::transformer::SparseParametricDtmcSimplifier>(*testModel); - + std::cout << "Hello, Jip2" << std::endl; + std::shared_ptr> sparseModel = model->as>(); std::vector> formulas = storm::api::extractFormulasFromProperties(input.properties); - STORM_LOG_THROW(formulas.begin()!=formulas.end(), storm::exceptions::NotSupportedException, "Only one formula at the time supported"); - - if (!simplifier.simplify(*(formulas[0]))) { - STORM_LOG_THROW(false, storm::exceptions::UnexpectedException, "Simplifying the model was not successfull."); - } - - - std::shared_ptr> sparseModel = simplifier.getSimplifiedModel();//->as>(); -// formulas = std::vector>({simplifier.getSimplifiedFormula()});//storm::api::extractFormulasFromProperties(input.properties); STORM_LOG_THROW((*(formulas[0])).isProbabilityOperatorFormula() && (*(formulas[0])).asProbabilityOperatorFormula().getSubformula().isUntilFormula(), storm::exceptions::NotSupportedException, "Expecting until formula"); storm::modelchecker::SparsePropositionalModelChecker> propositionalChecker(*sparseModel); @@ -652,13 +651,13 @@ namespace storm { std::pair statesWithProbability01 = storm::utility::graph::performProb01(sparseModel.get()->getBackwardTransitions(), phiStates, psiStates); storm::storage::BitVector topStates = statesWithProbability01.second; storm::storage::BitVector bottomStates = statesWithProbability01.first; - + // Transform to LatticeLattice storm::analysis::Lattice* lattice = toLattice(sparseModel, topStates, bottomStates); lattice->toString(std::cout); + // Monotonicity? bool monotoneInAll = true; - storm::storage::SparseMatrix matrix = sparseModel.get()->getTransitionMatrix(); for (uint_fast64_t i = 0; i < sparseModel.get()->getNumberOfStates(); ++i) { // go over all rows From 5f6a894a324a87be8552c9a1693b391ef2d5744a Mon Sep 17 00:00:00 2001 From: Jip Spel Date: Fri, 17 Aug 2018 10:57:03 +0200 Subject: [PATCH 013/178] Clean up --- src/storm-pars-cli/storm-pars.cpp | 80 ++++--------------------------- 1 file changed, 8 insertions(+), 72 deletions(-) diff --git a/src/storm-pars-cli/storm-pars.cpp b/src/storm-pars-cli/storm-pars.cpp index 5506247a7..6f67ca435 100644 --- a/src/storm-pars-cli/storm-pars.cpp +++ b/src/storm-pars-cli/storm-pars.cpp @@ -443,45 +443,6 @@ namespace storm { storm::pars::verifyWithSparseEngine(model->as>(), input, regions, samples); } - - template - ValueType getProbability(uint_fast64_t state, uint_fast64_t successor, storm::storage::SparseMatrix matrix) { - ValueType result = ValueType(1); - // Iterate over all row groups. - auto row = matrix.getRow(state); - - for (auto itr = row.begin(); itr < row.end() && result == ValueType(1); ++itr) { - if ((*itr).getColumn() == successor) { - result = (*itr).getValue(); - } - - } - - return result; - } - - template - ValueType getProbability(storm::storage::BitVector state, uint_fast64_t successor, storm::storage::SparseMatrix matrix) { - ValueType result = ValueType(1); - uint_fast64_t index = state.getNextSetIndex(0); - while (index < state.size() && result == ValueType(1)) { - result = getProbability(index, successor, matrix); - index = state.getNextSetIndex(index+1); - } - return result; - } - - template - ValueType getProbability(storm::storage::BitVector state, storm::storage::BitVector successor, storm::storage::SparseMatrix matrix) { - ValueType result = ValueType(1); - uint_fast64_t index = successor.getNextSetIndex(0); - while (index < successor.size() && result == ValueType(1)) { - result = getProbability(state, index, matrix); - index = successor.getNextSetIndex(index+1); - } - return result; - } - template storm::analysis::Lattice* toLattice(std::shared_ptr> model, storm::storage::BitVector topStates, @@ -541,37 +502,12 @@ namespace storm { successor1 = successor2; successor2 = temp; } - // Additional check, if states have the same probability of reaching a given next state, - // then they should be at the same node - // TODO: can this be removed, e.g. adding a step to preprocessing, making this superfluous - // TODO: 1 prob. and same probs to same states should be removed from matrix -// storm::analysis::Lattice::Node *above = lattice->getNode(successor1); -// storm::analysis::Lattice::Node *below = lattice->getNode(successor2); -// std::vector states1 = above->below; -// std::vector states2 = below->above; -// for (auto itr1 = states1.begin(); itr1 < states1.end(); ++itr1) { -// for (auto itr2 = states2.begin(); itr2 < states2.end(); ++itr2) { -// if ((*itr1)->states == (*itr2)->states) { -// ValueType prob1 = getProbability(currentState->stateNumber, successor1, matrix); -// ValueType prob2 = getProbability(currentState->stateNumber, successor2, matrix); -// if (prob1 != ValueType(1) -// && prob2 != ValueType(1) -// && getProbability((*itr1)->states, above->states, matrix) == prob1 -// && getProbability((*itr1)->states, below->states, matrix) == prob2) { -// lattice->addToNode(currentState->stateNumber, (*itr1)); -// seenStates.set(currentState->stateNumber); -// } -// } -// } -// } - - if (!seenStates.get(currentState->stateNumber)) { - // successor 1 is closer to top than successor 2 - lattice->addBetween(currentState->stateNumber, lattice->getNode(successor1), - lattice->getNode(successor2)); - // Add stateNumber to the set with seen states. - seenStates.set(currentState->stateNumber); - } + + // successor 1 is closer to top than successor 2 + lattice->addBetween(currentState->stateNumber, lattice->getNode(successor1), + lattice->getNode(successor2)); + // Add stateNumber to the set with seen states. + seenStates.set(currentState->stateNumber); } else if (compareResult == 0) { // the successors are at the same level lattice->addToNode(currentState->stateNumber, lattice->getNode(successor1)); @@ -651,7 +587,7 @@ namespace storm { std::pair statesWithProbability01 = storm::utility::graph::performProb01(sparseModel.get()->getBackwardTransitions(), phiStates, psiStates); storm::storage::BitVector topStates = statesWithProbability01.second; storm::storage::BitVector bottomStates = statesWithProbability01.first; - + // Transform to LatticeLattice storm::analysis::Lattice* lattice = toLattice(sparseModel, topStates, bottomStates); lattice->toString(std::cout); @@ -690,7 +626,7 @@ namespace storm { std::cout << "Monotone increasing in all parameters" << std::endl; } // TODO: split into monotonicity in different parameters - std::cout << "Bye, Jip" << std::endl; + std::cout << "Bye, Jip2" << std::endl; return; } From c6e6331db29a606742d3d5c73afde340af9c19c7 Mon Sep 17 00:00:00 2001 From: Jip Spel Date: Fri, 17 Aug 2018 11:47:52 +0200 Subject: [PATCH 014/178] Move creation of Lattice to Lattice class --- src/storm-pars-cli/storm-pars.cpp | 89 +---------------------- src/storm-pars/analysis/Lattice.cpp | 9 ++- src/storm-pars/analysis/Lattice.h | 109 +++++++++++++++++++++++++++- 3 files changed, 114 insertions(+), 93 deletions(-) diff --git a/src/storm-pars-cli/storm-pars.cpp b/src/storm-pars-cli/storm-pars.cpp index 6f67ca435..ab240471f 100644 --- a/src/storm-pars-cli/storm-pars.cpp +++ b/src/storm-pars-cli/storm-pars.cpp @@ -49,11 +49,7 @@ namespace storm { bool exact; }; - struct State { - uint_fast64_t stateNumber; - uint_fast64_t successor1; - uint_fast64_t successor2; - }; + template std::vector> parseRegions(std::shared_ptr const& model) { @@ -443,86 +439,7 @@ namespace storm { storm::pars::verifyWithSparseEngine(model->as>(), input, regions, samples); } - template - storm::analysis::Lattice* toLattice(std::shared_ptr> model, - storm::storage::BitVector topStates, - storm::storage::BitVector bottomStates) { - storm::storage::SparseMatrix matrix = model.get()->getTransitionMatrix(); - storm::storage::BitVector initialStates = model.get()->getInitialStates(); - uint_fast64_t numberOfStates = model.get()->getNumberOfStates(); - - // Transform the transition matrix into a vector containing the states with the state to which the transition goes. - std::vector stateVector = std::vector({}); - for (uint_fast64_t i = 0; i < numberOfStates; ++i) { - State* state = new State(); - state->stateNumber = i; - state->successor1 = numberOfStates; - state->successor2 = numberOfStates; - - auto row = matrix.getRow(i); - //TODO assert that there are at most two successors - if ((*(row.begin())).getValue() != ValueType(1)) { - state->successor1 = (*(row.begin())).getColumn(); - state->successor2 = (*(++row.begin())).getColumn(); - } else { - state-> successor1 = (*(row.begin())).getColumn(); - state-> successor2 = (*(row.begin())).getColumn(); - } - stateVector.push_back(state); - } - // Start creating the Lattice - storm::analysis::Lattice *lattice = new storm::analysis::Lattice(topStates, bottomStates, numberOfStates); - storm::storage::BitVector oldStates(numberOfStates); - // Create a copy of the states already present in the lattice. - storm::storage::BitVector seenStates = topStates|= bottomStates; - - while (oldStates != seenStates) { - // As long as new states are added to the lattice, continue. - oldStates = storm::storage::BitVector(seenStates); - - for (auto itr = stateVector.begin(); itr != stateVector.end(); ++itr) { - // Iterate over all states - State *currentState = *itr; - - if (!seenStates[currentState->stateNumber] - && seenStates[currentState->successor1] - && seenStates[currentState->successor2]) { - - - // Otherwise, check how the two states compare, and add if the comparison is possible. - uint_fast64_t successor1 = currentState->successor1; - uint_fast64_t successor2 = currentState->successor2; - int compareResult = lattice->compare(successor1, successor2); - if (compareResult == 1 || compareResult == 2) { - // getNode will not return nullptr, as compare already checked this - if (compareResult == 2) { - // swap - auto temp = successor1; - successor1 = successor2; - successor2 = temp; - } - - // successor 1 is closer to top than successor 2 - lattice->addBetween(currentState->stateNumber, lattice->getNode(successor1), - lattice->getNode(successor2)); - // Add stateNumber to the set with seen states. - seenStates.set(currentState->stateNumber); - } else if (compareResult == 0) { - // the successors are at the same level - lattice->addToNode(currentState->stateNumber, lattice->getNode(successor1)); - // Add stateNumber to the set with seen states. - seenStates.set(currentState->stateNumber); - } else { - // TODO: what to do? - STORM_LOG_DEBUG("Failed to add" << currentState->stateNumber << "\n"); - } - - } - } - } - return lattice; - } template @@ -589,12 +506,12 @@ namespace storm { storm::storage::BitVector bottomStates = statesWithProbability01.first; // Transform to LatticeLattice - storm::analysis::Lattice* lattice = toLattice(sparseModel, topStates, bottomStates); + storm::storage::SparseMatrix matrix = sparseModel.get()->getTransitionMatrix(); + storm::analysis::Lattice* lattice = storm::analysis::Lattice::toLattice(matrix, topStates, bottomStates); lattice->toString(std::cout); // Monotonicity? bool monotoneInAll = true; - storm::storage::SparseMatrix matrix = sparseModel.get()->getTransitionMatrix(); for (uint_fast64_t i = 0; i < sparseModel.get()->getNumberOfStates(); ++i) { // go over all rows auto row = matrix.getRow(i); diff --git a/src/storm-pars/analysis/Lattice.cpp b/src/storm-pars/analysis/Lattice.cpp index f710f2fbb..3f0f8da3f 100644 --- a/src/storm-pars/analysis/Lattice.cpp +++ b/src/storm-pars/analysis/Lattice.cpp @@ -9,9 +9,9 @@ namespace storm { Lattice::Lattice(storm::storage::BitVector topStates, storm::storage::BitVector bottomStates, uint_fast64_t numberOfStates) { - Node *top = new Node(); + top = new Node(); top->states = topStates; - Node *bottom = new Node(); + bottom = new Node(); bottom->states = bottomStates; top->below.push_back(bottom); bottom->above.push_back(top); @@ -29,7 +29,6 @@ namespace storm { } void Lattice::addBetween(uint_fast64_t state, Node *above, Node *below) { - std::cout << "Adding: " << state << std::endl; Node *newNode = new Node(); newNode->states = storm::storage::BitVector(numberOfStates); newNode->states.set(state); @@ -47,6 +46,10 @@ namespace storm { nodes.at(state) = node; } + void Lattice::add(uint_fast64_t state) { + addBetween(state, top, bottom); + } + int Lattice::compare(uint_fast64_t state1, uint_fast64_t state2) { Node *node1 = getNode(state1); Node *node2 = getNode(state2); diff --git a/src/storm-pars/analysis/Lattice.h b/src/storm-pars/analysis/Lattice.h index 14b7b341b..f6617871e 100644 --- a/src/storm-pars/analysis/Lattice.h +++ b/src/storm-pars/analysis/Lattice.h @@ -8,7 +8,10 @@ #include #include +#include "storm/models/sparse/Model.h" #include "storm/storage/BitVector.h" +#include "storm/storage/SparseMatrix.h" + namespace storm { namespace analysis { @@ -33,18 +36,24 @@ namespace storm { /*! * Adds a node with the given state below node1 and above node2. * @param state The given state. - * @param node1 The pointer to the node below which a new node is added. - * @param node2 The pointer to the node above which a new node is added. + * @param node1 The pointer to the node below which a new node (with state) is added + * @param node2 The pointer to the node above which a new node (with state) is added */ void addBetween(uint_fast64_t state, Node *node1, Node *node2); /*! * Adds state to the states of the given node. * @param state The state which is added. - * @param node The pointer to the node to which state is added. + * @param node The pointer to the node to which state is added, should not be nullptr. */ void addToNode(uint_fast64_t state, Node *node); + /*! + * Adds state between the top and bottom node of the lattice + * @param state The given state + */ + void add(uint_fast64_t state); + /*! * Compares the level of the nodes of the states. * Behaviour unknown when one or more of the states doesnot occur at any Node in the Lattice. @@ -74,11 +83,103 @@ namespace storm { */ void toString(std::ostream &out); -// std::vector addedStates; + /*! + * Creates a Lattice based on the transition matrix, topStates of the Lattice and bottomStates of the Lattice + * @tparam ValueType Type of the probabilities + * @param matrix The transition matrix. + * @param topStates Set of topStates of the Lattice. + * @param bottomStates Set of bottomStates of the Lattice. + * @return pointer to the created Lattice. + */ + template + static Lattice* toLattice(storm::storage::SparseMatrix matrix, + storm::storage::BitVector topStates, + storm::storage::BitVector bottomStates) { + uint_fast64_t numberOfStates = matrix.getColumnCount(); + + // Transform the transition matrix into a vector containing the states with the state to which the transition goes. + std::vector stateVector = std::vector({}); + for (uint_fast64_t i = 0; i < numberOfStates; ++i) { + State* state = new State(); + state->stateNumber = i; + + auto row = matrix.getRow(i); + //TODO assert that there are at most two successors + if ((*(row.begin())).getValue() != ValueType(1)) { + state->successor1 = (*(row.begin())).getColumn(); + state->successor2 = (*(++row.begin())).getColumn(); + } else { + state-> successor1 = (*(row.begin())).getColumn(); + state-> successor2 = (*(row.begin())).getColumn(); + } + + stateVector.push_back(state); + } + // Start creating the Lattice + storm::analysis::Lattice *lattice = new storm::analysis::Lattice(topStates, bottomStates, numberOfStates); + storm::storage::BitVector oldStates(numberOfStates); + // Create a copy of the states already present in the lattice. + storm::storage::BitVector seenStates = topStates|= bottomStates; + + while (oldStates != seenStates) { + // As long as new states are added to the lattice, continue. + oldStates = storm::storage::BitVector(seenStates); + + for (auto itr = stateVector.begin(); itr != stateVector.end(); ++itr) { + // Iterate over all states + State *currentState = *itr; + + if (!seenStates[currentState->stateNumber] + && seenStates[currentState->successor1] + && seenStates[currentState->successor2]) { + + + // Otherwise, check how the two states compare, and add if the comparison is possible. + uint_fast64_t successor1 = currentState->successor1; + uint_fast64_t successor2 = currentState->successor2; + int compareResult = lattice->compare(successor1, successor2); + if (compareResult == 1) { + // successor 1 is closer to top than successor 2 + lattice->addBetween(currentState->stateNumber, lattice->getNode(successor1), + lattice->getNode(successor2)); + // Add stateNumber to the set with seen states. + seenStates.set(currentState->stateNumber); + } else if (compareResult == 2) { + // successor 2 is closer to top than successor 1 + lattice->addBetween(currentState->stateNumber, lattice->getNode(successor2), + lattice->getNode(successor1)); + // Add stateNumber to the set with seen states. + seenStates.set(currentState->stateNumber); + } else if (compareResult == 0) { + // the successors are at the same level + lattice->addToNode(currentState->stateNumber, lattice->getNode(successor1)); + // Add stateNumber to the set with seen states. + seenStates.set(currentState->stateNumber); + } else { + // TODO: is this what we want? + lattice->add(currentState->stateNumber); + } + + } + } + } + + return lattice; + } private: + struct State { + uint_fast64_t stateNumber; + uint_fast64_t successor1; + uint_fast64_t successor2; + }; + std::vector nodes; + Node * top; + + Node * bottom; + uint_fast64_t numberOfStates; bool above(Node *, Node *); From 1536aeab4712336b5bf391399f8fbdc2b8aa0c57 Mon Sep 17 00:00:00 2001 From: Jip Spel Date: Fri, 17 Aug 2018 12:01:19 +0200 Subject: [PATCH 015/178] Add keep track of time --- src/storm-pars-cli/storm-pars.cpp | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/storm-pars-cli/storm-pars.cpp b/src/storm-pars-cli/storm-pars.cpp index ab240471f..d700ef4cd 100644 --- a/src/storm-pars-cli/storm-pars.cpp +++ b/src/storm-pars-cli/storm-pars.cpp @@ -466,6 +466,7 @@ namespace storm { if (parSettings.isMonotonicityAnalysisSet()) { std::cout << "Hello, Jip1" << std::endl; + storm::utility::Stopwatch simplifyingWatch(true); auto consideredModel = (model->as>()); // TODO: check if it is a Dtmc auto simplifier = storm::transformer::SparseParametricDtmcSimplifier>(*consideredModel); @@ -477,6 +478,9 @@ namespace storm { STORM_LOG_THROW(false, storm::exceptions::UnexpectedException, "Simplifying the model was not successfull."); } model = simplifier.getSimplifiedModel(); + simplifyingWatch.stop(); + STORM_PRINT(std::endl << "Time for model simplification: " << simplifyingWatch << "." << std::endl << std::endl); + model->printModelInformationToStream(std::cout); std::cout << "Bye, Jip1" << std::endl; } @@ -491,7 +495,7 @@ namespace storm { if (parSettings.isMonotonicityAnalysisSet()) { // Do something more fancy. std::cout << "Hello, Jip2" << std::endl; - + storm::utility::Stopwatch latticeWatch(true); std::shared_ptr> sparseModel = model->as>(); std::vector> formulas = storm::api::extractFormulasFromProperties(input.properties); @@ -508,9 +512,14 @@ namespace storm { // Transform to LatticeLattice storm::storage::SparseMatrix matrix = sparseModel.get()->getTransitionMatrix(); storm::analysis::Lattice* lattice = storm::analysis::Lattice::toLattice(matrix, topStates, bottomStates); + + latticeWatch.stop(); + STORM_PRINT(std::endl << "Time for lattice creation: " << latticeWatch << "." << std::endl << std::endl); lattice->toString(std::cout); // Monotonicity? + storm::utility::Stopwatch monotonicityWatch(true); + bool monotoneInAll = true; for (uint_fast64_t i = 0; i < sparseModel.get()->getNumberOfStates(); ++i) { // go over all rows @@ -539,6 +548,8 @@ namespace storm { } + monotonicityWatch.stop(); + STORM_PRINT(std::endl << "Time for monotonicity: " << monotonicityWatch << "." << std::endl << std::endl); if (monotoneInAll) { std::cout << "Monotone increasing in all parameters" << std::endl; } From 39b8ac6c18cdc98c325771bd96a16d4653695441 Mon Sep 17 00:00:00 2001 From: Jip Spel Date: Fri, 17 Aug 2018 14:01:24 +0200 Subject: [PATCH 016/178] Analyse monotonicity for each variable --- src/storm-pars-cli/storm-pars.cpp | 37 +++++++++++++++++++++++-------- 1 file changed, 28 insertions(+), 9 deletions(-) diff --git a/src/storm-pars-cli/storm-pars.cpp b/src/storm-pars-cli/storm-pars.cpp index d700ef4cd..b7ed5da29 100644 --- a/src/storm-pars-cli/storm-pars.cpp +++ b/src/storm-pars-cli/storm-pars.cpp @@ -49,8 +49,6 @@ namespace storm { bool exact; }; - - template std::vector> parseRegions(std::shared_ptr const& model) { std::vector> result; @@ -519,8 +517,10 @@ namespace storm { // Monotonicity? storm::utility::Stopwatch monotonicityWatch(true); + // Map with for each variable bool whether it is monotonic or not (assume montone increasing) + std::map varsMonotoneIncr; + std::map varsMonotoneDecr; - bool monotoneInAll = true; for (uint_fast64_t i = 0; i < sparseModel.get()->getNumberOfStates(); ++i) { // go over all rows auto row = matrix.getRow(i); @@ -536,12 +536,19 @@ namespace storm { auto derivative = val.derivative(*itr); STORM_LOG_THROW(derivative.isConstant(), storm::exceptions::NotSupportedException, "Expecting probability to have at most degree 1"); auto compare = lattice->compare(first.getColumn(), second.getColumn()); + if (varsMonotoneIncr.find(*itr) == varsMonotoneIncr.end()) { + varsMonotoneIncr[*itr] = true; + varsMonotoneDecr[*itr] = true; + } if (compare == 1) { - monotoneInAll &=derivative.constantPart() >= 0; + varsMonotoneIncr.find(*itr)->second &=derivative.constantPart() >= 0; + varsMonotoneDecr.find(*itr)->second &=derivative.constantPart() <= 0; } else if (compare == 2) { - monotoneInAll &=derivative.constantPart() <= 0; + varsMonotoneIncr.find(*itr)->second &= derivative.constantPart() <= 0; + varsMonotoneDecr.find(*itr)->second &= derivative.constantPart() >= 0; } else { - monotoneInAll = false; + varsMonotoneIncr.find(*itr)->second = false; + varsMonotoneDecr.find(*itr)->second = false; } } } @@ -550,10 +557,22 @@ namespace storm { } monotonicityWatch.stop(); STORM_PRINT(std::endl << "Time for monotonicity: " << monotonicityWatch << "." << std::endl << std::endl); - if (monotoneInAll) { - std::cout << "Monotone increasing in all parameters" << std::endl; + + for (auto itr = varsMonotoneIncr.begin(); itr != varsMonotoneIncr.end(); ++itr) { + if (itr->second) { + std::cout << "Monotone increasing in: " << itr->first << std::endl; + } else { + std::cout << "Not monotone increasing in: " << itr->first << std::endl; + } } - // TODO: split into monotonicity in different parameters + for (auto itr = varsMonotoneDecr.begin(); itr != varsMonotoneDecr.end(); ++itr) { + if (itr->second) { + std::cout << "Monotone decreasing in: " << itr->first << std::endl; + } else { + std::cout << "Not monotone decreasing in: " << itr->first << std::endl; + } + } + std::cout << "Bye, Jip2" << std::endl; return; } From 0116837956d2920735cd526330944a7357e4e287 Mon Sep 17 00:00:00 2001 From: Jip Spel Date: Mon, 20 Aug 2018 10:57:14 +0200 Subject: [PATCH 017/178] Check dtmc or mdp for simplification --- src/storm-pars-cli/storm-pars.cpp | 42 ++++++++++++++++++++----------- 1 file changed, 28 insertions(+), 14 deletions(-) diff --git a/src/storm-pars-cli/storm-pars.cpp b/src/storm-pars-cli/storm-pars.cpp index b7ed5da29..b62a8cb2b 100644 --- a/src/storm-pars-cli/storm-pars.cpp +++ b/src/storm-pars-cli/storm-pars.cpp @@ -1,5 +1,5 @@ -#include +#include #include #include "storm-pars/api/storm-pars.h" #include "storm-pars/settings/ParsSettings.h" @@ -437,9 +437,6 @@ namespace storm { storm::pars::verifyWithSparseEngine(model->as>(), input, regions, samples); } - - - template void processInputWithValueTypeAndDdlib(SymbolicInput& input) { auto coreSettings = storm::settings::getModule(); @@ -465,17 +462,32 @@ namespace storm { if (parSettings.isMonotonicityAnalysisSet()) { std::cout << "Hello, Jip1" << std::endl; storm::utility::Stopwatch simplifyingWatch(true); - auto consideredModel = (model->as>()); - // TODO: check if it is a Dtmc - auto simplifier = storm::transformer::SparseParametricDtmcSimplifier>(*consideredModel); + if (model->isOfType(storm::models::ModelType::Dtmc)) { + auto consideredModel = (model->as>()); + auto simplifier = storm::transformer::SparseParametricDtmcSimplifier>(*consideredModel); - std::vector> formulas = storm::api::extractFormulasFromProperties(input.properties); - STORM_LOG_THROW(formulas.begin()!=formulas.end(), storm::exceptions::NotSupportedException, "Only one formula at the time supported"); + std::vector> formulas = storm::api::extractFormulasFromProperties(input.properties); + STORM_LOG_THROW(formulas.begin()!=formulas.end(), storm::exceptions::NotSupportedException, "Only one formula at the time supported"); - if (!simplifier.simplify(*(formulas[0]))) { - STORM_LOG_THROW(false, storm::exceptions::UnexpectedException, "Simplifying the model was not successfull."); + if (!simplifier.simplify(*(formulas[0]))) { + STORM_LOG_THROW(false, storm::exceptions::UnexpectedException, "Simplifying the model was not successfull."); + } + model = simplifier.getSimplifiedModel(); + } else if (model->isOfType(storm::models::ModelType::Mdp)) { + auto consideredModel = (model->as>()); + auto simplifier = storm::transformer::SparseParametricMdpSimplifier>(*consideredModel); + + std::vector> formulas = storm::api::extractFormulasFromProperties(input.properties); + STORM_LOG_THROW(formulas.begin()!=formulas.end(), storm::exceptions::NotSupportedException, "Only one formula at the time supported"); + + if (!simplifier.simplify(*(formulas[0]))) { + STORM_LOG_THROW(false, storm::exceptions::UnexpectedException, "Simplifying the model was not successfull."); + } + model = simplifier.getSimplifiedModel(); + } else { + STORM_LOG_THROW(false, storm::exceptions::InvalidOperationException, "Unable to perform parameterLifting on the provided model type."); } - model = simplifier.getSimplifiedModel(); + simplifyingWatch.stop(); STORM_PRINT(std::endl << "Time for model simplification: " << simplifyingWatch << "." << std::endl << std::endl); model->printModelInformationToStream(std::cout); @@ -491,9 +503,9 @@ namespace storm { } if (parSettings.isMonotonicityAnalysisSet()) { - // Do something more fancy. std::cout << "Hello, Jip2" << std::endl; storm::utility::Stopwatch latticeWatch(true); + std::shared_ptr> sparseModel = model->as>(); std::vector> formulas = storm::api::extractFormulasFromProperties(input.properties); @@ -535,11 +547,13 @@ namespace storm { for (auto itr = vars.begin(); itr != vars.end(); ++itr) { auto derivative = val.derivative(*itr); STORM_LOG_THROW(derivative.isConstant(), storm::exceptions::NotSupportedException, "Expecting probability to have at most degree 1"); - auto compare = lattice->compare(first.getColumn(), second.getColumn()); + if (varsMonotoneIncr.find(*itr) == varsMonotoneIncr.end()) { varsMonotoneIncr[*itr] = true; varsMonotoneDecr[*itr] = true; } + + auto compare = lattice->compare(first.getColumn(), second.getColumn()); if (compare == 1) { varsMonotoneIncr.find(*itr)->second &=derivative.constantPart() >= 0; varsMonotoneDecr.find(*itr)->second &=derivative.constantPart() <= 0; From 1af5670750f4890ab50ad4f17e7d7bd879be34ef Mon Sep 17 00:00:00 2001 From: Jip Spel Date: Mon, 20 Aug 2018 11:12:03 +0200 Subject: [PATCH 018/178] Throw error when bisimulation not set, change output monotonicity --- src/storm-pars-cli/storm-pars.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/storm-pars-cli/storm-pars.cpp b/src/storm-pars-cli/storm-pars.cpp index b62a8cb2b..a13f245bf 100644 --- a/src/storm-pars-cli/storm-pars.cpp +++ b/src/storm-pars-cli/storm-pars.cpp @@ -461,6 +461,7 @@ namespace storm { if (parSettings.isMonotonicityAnalysisSet()) { std::cout << "Hello, Jip1" << std::endl; + STORM_LOG_THROW(storm::settings::getModule().isBisimulationSet(), storm::exceptions::InvalidSettingsException, "Monotonicity analysis requires bisimulation"); storm::utility::Stopwatch simplifyingWatch(true); if (model->isOfType(storm::models::ModelType::Dtmc)) { auto consideredModel = (model->as>()); @@ -576,14 +577,14 @@ namespace storm { if (itr->second) { std::cout << "Monotone increasing in: " << itr->first << std::endl; } else { - std::cout << "Not monotone increasing in: " << itr->first << std::endl; + std::cout << "Do not know if monotone increasing in: " << itr->first << std::endl; } } for (auto itr = varsMonotoneDecr.begin(); itr != varsMonotoneDecr.end(); ++itr) { if (itr->second) { std::cout << "Monotone decreasing in: " << itr->first << std::endl; } else { - std::cout << "Not monotone decreasing in: " << itr->first << std::endl; + std::cout << "Do not know if monotone decreasing in: " << itr->first << std::endl; } } From 6ac0782a186305fbc78594f384a663a0c8b5e5b2 Mon Sep 17 00:00:00 2001 From: Jip Spel Date: Mon, 20 Aug 2018 11:43:56 +0200 Subject: [PATCH 019/178] Remove need for bisimulation --- src/storm-pars-cli/storm-pars.cpp | 2 +- src/storm-pars/analysis/Lattice.h | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/storm-pars-cli/storm-pars.cpp b/src/storm-pars-cli/storm-pars.cpp index a13f245bf..13767907a 100644 --- a/src/storm-pars-cli/storm-pars.cpp +++ b/src/storm-pars-cli/storm-pars.cpp @@ -461,7 +461,7 @@ namespace storm { if (parSettings.isMonotonicityAnalysisSet()) { std::cout << "Hello, Jip1" << std::endl; - STORM_LOG_THROW(storm::settings::getModule().isBisimulationSet(), storm::exceptions::InvalidSettingsException, "Monotonicity analysis requires bisimulation"); +// STORM_LOG_THROW(storm::settings::getModule().isBisimulationSet(), storm::exceptions::InvalidSettingsException, "Monotonicity analysis requires bisimulation"); storm::utility::Stopwatch simplifyingWatch(true); if (model->isOfType(storm::models::ModelType::Dtmc)) { auto consideredModel = (model->as>()); diff --git a/src/storm-pars/analysis/Lattice.h b/src/storm-pars/analysis/Lattice.h index f6617871e..69f8fd4aa 100644 --- a/src/storm-pars/analysis/Lattice.h +++ b/src/storm-pars/analysis/Lattice.h @@ -143,22 +143,20 @@ namespace storm { lattice->addBetween(currentState->stateNumber, lattice->getNode(successor1), lattice->getNode(successor2)); // Add stateNumber to the set with seen states. - seenStates.set(currentState->stateNumber); } else if (compareResult == 2) { // successor 2 is closer to top than successor 1 lattice->addBetween(currentState->stateNumber, lattice->getNode(successor2), lattice->getNode(successor1)); // Add stateNumber to the set with seen states. - seenStates.set(currentState->stateNumber); } else if (compareResult == 0) { // the successors are at the same level lattice->addToNode(currentState->stateNumber, lattice->getNode(successor1)); // Add stateNumber to the set with seen states. - seenStates.set(currentState->stateNumber); } else { // TODO: is this what we want? lattice->add(currentState->stateNumber); } + seenStates.set(currentState->stateNumber); } } From e83dad09638dcbc7bb550bc684ee69a3c50afee2 Mon Sep 17 00:00:00 2001 From: Jip Spel Date: Mon, 20 Aug 2018 17:15:46 +0200 Subject: [PATCH 020/178] Add check on amount of formulas, fix typo --- src/storm-pars-cli/storm-pars.cpp | 7 +++++-- src/storm-pars/analysis/Lattice.h | 1 - 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/storm-pars-cli/storm-pars.cpp b/src/storm-pars-cli/storm-pars.cpp index 13767907a..5b38cf1f4 100644 --- a/src/storm-pars-cli/storm-pars.cpp +++ b/src/storm-pars-cli/storm-pars.cpp @@ -507,11 +507,14 @@ namespace storm { std::cout << "Hello, Jip2" << std::endl; storm::utility::Stopwatch latticeWatch(true); - std::shared_ptr> sparseModel = model->as>(); std::vector> formulas = storm::api::extractFormulasFromProperties(input.properties); + STORM_LOG_THROW((++formulas.begin()) == formulas.end(), storm::exceptions::NotSupportedException, "Only one formula allowed for monotonicity analysis"); STORM_LOG_THROW((*(formulas[0])).isProbabilityOperatorFormula() && (*(formulas[0])).asProbabilityOperatorFormula().getSubformula().isUntilFormula(), storm::exceptions::NotSupportedException, "Expecting until formula"); + + std::shared_ptr> sparseModel = model->as>(); storm::modelchecker::SparsePropositionalModelChecker> propositionalChecker(*sparseModel); + storm::storage::BitVector phiStates = propositionalChecker.check((*(formulas[0])).asProbabilityOperatorFormula().getSubformula().asUntilFormula().getLeftSubformula())->asExplicitQualitativeCheckResult().getTruthValuesVector(); storm::storage::BitVector psiStates = propositionalChecker.check((*(formulas[0])).asProbabilityOperatorFormula().getSubformula().asUntilFormula().getRightSubformula())->asExplicitQualitativeCheckResult().getTruthValuesVector(); //right @@ -520,7 +523,7 @@ namespace storm { storm::storage::BitVector topStates = statesWithProbability01.second; storm::storage::BitVector bottomStates = statesWithProbability01.first; - // Transform to LatticeLattice + // Transform to Lattice storm::storage::SparseMatrix matrix = sparseModel.get()->getTransitionMatrix(); storm::analysis::Lattice* lattice = storm::analysis::Lattice::toLattice(matrix, topStates, bottomStates); diff --git a/src/storm-pars/analysis/Lattice.h b/src/storm-pars/analysis/Lattice.h index 69f8fd4aa..e3e9f5246 100644 --- a/src/storm-pars/analysis/Lattice.h +++ b/src/storm-pars/analysis/Lattice.h @@ -133,7 +133,6 @@ namespace storm { && seenStates[currentState->successor1] && seenStates[currentState->successor2]) { - // Otherwise, check how the two states compare, and add if the comparison is possible. uint_fast64_t successor1 = currentState->successor1; uint_fast64_t successor2 = currentState->successor2; From 383814681d409a17c73a087e3155efd2be1371dd Mon Sep 17 00:00:00 2001 From: Jip Spel Date: Tue, 21 Aug 2018 09:20:28 +0200 Subject: [PATCH 021/178] One map with pair of bool instead of two maps for monotonicity --- src/storm-pars-cli/storm-pars.cpp | 33 ++++++++++++++----------------- 1 file changed, 15 insertions(+), 18 deletions(-) diff --git a/src/storm-pars-cli/storm-pars.cpp b/src/storm-pars-cli/storm-pars.cpp index 5b38cf1f4..7dbeb0e6c 100644 --- a/src/storm-pars-cli/storm-pars.cpp +++ b/src/storm-pars-cli/storm-pars.cpp @@ -533,9 +533,8 @@ namespace storm { // Monotonicity? storm::utility::Stopwatch monotonicityWatch(true); - // Map with for each variable bool whether it is monotonic or not (assume montone increasing) - std::map varsMonotoneIncr; - std::map varsMonotoneDecr; + // Map with for each variable bool pair whether it is monotone increasing (first) or monotone decreasing (second) + std::map> varsMonotone; for (uint_fast64_t i = 0; i < sparseModel.get()->getNumberOfStates(); ++i) { // go over all rows @@ -552,21 +551,22 @@ namespace storm { auto derivative = val.derivative(*itr); STORM_LOG_THROW(derivative.isConstant(), storm::exceptions::NotSupportedException, "Expecting probability to have at most degree 1"); - if (varsMonotoneIncr.find(*itr) == varsMonotoneIncr.end()) { - varsMonotoneIncr[*itr] = true; - varsMonotoneDecr[*itr] = true; + if (varsMonotone.find(*itr) == varsMonotone.end()) { + varsMonotone[*itr].first = true; + varsMonotone[*itr].second = true; } auto compare = lattice->compare(first.getColumn(), second.getColumn()); + std::pair* value = &varsMonotone.find(*itr)->second; if (compare == 1) { - varsMonotoneIncr.find(*itr)->second &=derivative.constantPart() >= 0; - varsMonotoneDecr.find(*itr)->second &=derivative.constantPart() <= 0; + value->first &=derivative.constantPart() >= 0; + value->second &=derivative.constantPart() <= 0; } else if (compare == 2) { - varsMonotoneIncr.find(*itr)->second &= derivative.constantPart() <= 0; - varsMonotoneDecr.find(*itr)->second &= derivative.constantPart() >= 0; + value->first &=derivative.constantPart() <= 0; + value->second &=derivative.constantPart() >= 0; } else { - varsMonotoneIncr.find(*itr)->second = false; - varsMonotoneDecr.find(*itr)->second = false; + value->first = false; + value->second = false; } } } @@ -575,16 +575,13 @@ namespace storm { } monotonicityWatch.stop(); STORM_PRINT(std::endl << "Time for monotonicity: " << monotonicityWatch << "." << std::endl << std::endl); - - for (auto itr = varsMonotoneIncr.begin(); itr != varsMonotoneIncr.end(); ++itr) { - if (itr->second) { + for (auto itr = varsMonotone.begin(); itr != varsMonotone.end(); ++itr) { + if (itr->second.first) { std::cout << "Monotone increasing in: " << itr->first << std::endl; } else { std::cout << "Do not know if monotone increasing in: " << itr->first << std::endl; } - } - for (auto itr = varsMonotoneDecr.begin(); itr != varsMonotoneDecr.end(); ++itr) { - if (itr->second) { + if (itr->second.second) { std::cout << "Monotone decreasing in: " << itr->first << std::endl; } else { std::cout << "Do not know if monotone decreasing in: " << itr->first << std::endl; From 1aa8f409cba718b0d71aa3f77f7938c4b93d2f40 Mon Sep 17 00:00:00 2001 From: Jip Spel Date: Tue, 21 Aug 2018 11:32:08 +0200 Subject: [PATCH 022/178] Change error messages + add new ones --- src/storm-pars-cli/storm-pars.cpp | 7 ++++--- src/storm-pars/analysis/Lattice.cpp | 4 ++-- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/storm-pars-cli/storm-pars.cpp b/src/storm-pars-cli/storm-pars.cpp index 7dbeb0e6c..8ac1cac18 100644 --- a/src/storm-pars-cli/storm-pars.cpp +++ b/src/storm-pars-cli/storm-pars.cpp @@ -523,6 +523,8 @@ namespace storm { storm::storage::BitVector topStates = statesWithProbability01.second; storm::storage::BitVector bottomStates = statesWithProbability01.first; + STORM_LOG_THROW(topStates.begin() != topStates.end(), storm::exceptions::NotImplementedException, "Formula yields to no 1 states"); + STORM_LOG_THROW(bottomStates.begin() != bottomStates.end(), storm::exceptions::NotImplementedException, "Formula yields to no zero states"); // Transform to Lattice storm::storage::SparseMatrix matrix = sparseModel.get()->getTransitionMatrix(); storm::analysis::Lattice* lattice = storm::analysis::Lattice::toLattice(matrix, topStates, bottomStates); @@ -540,16 +542,15 @@ namespace storm { // go over all rows auto row = matrix.getRow(i); - auto first = (*row.begin()); if (first.getValue() != ValueType(1)) { - auto second = (* (row.begin() + 1)); + auto second = (*(++row.begin())); auto val = first.getValue(); auto vars = val.gatherVariables(); for (auto itr = vars.begin(); itr != vars.end(); ++itr) { auto derivative = val.derivative(*itr); - STORM_LOG_THROW(derivative.isConstant(), storm::exceptions::NotSupportedException, "Expecting probability to have at most degree 1"); + STORM_LOG_THROW(derivative.isConstant(), storm::exceptions::NotSupportedException, "Expecting derivative to be constant"); if (varsMonotone.find(*itr) == varsMonotone.end()) { varsMonotone[*itr].first = true; diff --git a/src/storm-pars/analysis/Lattice.cpp b/src/storm-pars/analysis/Lattice.cpp index 3f0f8da3f..038b18e4f 100644 --- a/src/storm-pars/analysis/Lattice.cpp +++ b/src/storm-pars/analysis/Lattice.cpp @@ -34,8 +34,8 @@ namespace storm { newNode->states.set(state); newNode->above = std::vector({above}); newNode->below = std::vector({below}); - remove(&(below->above), above); - remove(&(above->below), below); +// remove(&(below->above), above); +// remove(&(above->below), below); (below->above).push_back(newNode); above->below.push_back(newNode); nodes.at(state) = newNode; From 92bd07c9c5c9fc3b2d7d618bbfe2ba30ec566461 Mon Sep 17 00:00:00 2001 From: Jip Spel Date: Tue, 21 Aug 2018 13:21:21 +0200 Subject: [PATCH 023/178] Allow monotonicity analysis on both Until and Eventually formulas --- src/storm-pars-cli/storm-pars.cpp | 15 ++++++++++++--- src/storm-pars/analysis/Lattice.cpp | 4 ++-- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/src/storm-pars-cli/storm-pars.cpp b/src/storm-pars-cli/storm-pars.cpp index 8ac1cac18..7437f10ea 100644 --- a/src/storm-pars-cli/storm-pars.cpp +++ b/src/storm-pars-cli/storm-pars.cpp @@ -510,13 +510,22 @@ namespace storm { std::vector> formulas = storm::api::extractFormulasFromProperties(input.properties); STORM_LOG_THROW((++formulas.begin()) == formulas.end(), storm::exceptions::NotSupportedException, "Only one formula allowed for monotonicity analysis"); - STORM_LOG_THROW((*(formulas[0])).isProbabilityOperatorFormula() && (*(formulas[0])).asProbabilityOperatorFormula().getSubformula().isUntilFormula(), storm::exceptions::NotSupportedException, "Expecting until formula"); + STORM_LOG_THROW((*(formulas[0])).isProbabilityOperatorFormula() + && ((*(formulas[0])).asProbabilityOperatorFormula().getSubformula().isUntilFormula() + || (*(formulas[0])).asProbabilityOperatorFormula().getSubformula().isEventuallyFormula()), storm::exceptions::NotSupportedException, "Expecting until formula"); std::shared_ptr> sparseModel = model->as>(); storm::modelchecker::SparsePropositionalModelChecker> propositionalChecker(*sparseModel); - storm::storage::BitVector phiStates = propositionalChecker.check((*(formulas[0])).asProbabilityOperatorFormula().getSubformula().asUntilFormula().getLeftSubformula())->asExplicitQualitativeCheckResult().getTruthValuesVector(); - storm::storage::BitVector psiStates = propositionalChecker.check((*(formulas[0])).asProbabilityOperatorFormula().getSubformula().asUntilFormula().getRightSubformula())->asExplicitQualitativeCheckResult().getTruthValuesVector(); //right + storm::storage::BitVector phiStates; + storm::storage::BitVector psiStates; + if ((*(formulas[0])).asProbabilityOperatorFormula().getSubformula().isUntilFormula()) { + phiStates = propositionalChecker.check((*(formulas[0])).asProbabilityOperatorFormula().getSubformula().asUntilFormula().getLeftSubformula())->asExplicitQualitativeCheckResult().getTruthValuesVector(); + psiStates = propositionalChecker.check((*(formulas[0])).asProbabilityOperatorFormula().getSubformula().asUntilFormula().getRightSubformula())->asExplicitQualitativeCheckResult().getTruthValuesVector(); + } else { + phiStates = storm::storage::BitVector(sparseModel.get()->getNumberOfStates(), true); + psiStates = propositionalChecker.check((*(formulas[0])).asProbabilityOperatorFormula().getSubformula().asEventuallyFormula().getSubformula())->asExplicitQualitativeCheckResult().getTruthValuesVector(); + } // Get the maybeStates std::pair statesWithProbability01 = storm::utility::graph::performProb01(sparseModel.get()->getBackwardTransitions(), phiStates, psiStates); diff --git a/src/storm-pars/analysis/Lattice.cpp b/src/storm-pars/analysis/Lattice.cpp index 038b18e4f..3f0f8da3f 100644 --- a/src/storm-pars/analysis/Lattice.cpp +++ b/src/storm-pars/analysis/Lattice.cpp @@ -34,8 +34,8 @@ namespace storm { newNode->states.set(state); newNode->above = std::vector({above}); newNode->below = std::vector({below}); -// remove(&(below->above), above); -// remove(&(above->below), below); + remove(&(below->above), above); + remove(&(above->below), below); (below->above).push_back(newNode); above->below.push_back(newNode); nodes.at(state) = newNode; From da691c8102a1eb22c0f8f061e4fb0e0bf65fd358 Mon Sep 17 00:00:00 2001 From: Jip Spel Date: Tue, 21 Aug 2018 14:23:46 +0200 Subject: [PATCH 024/178] Add .dot representation for lattice --- src/storm-pars-cli/storm-pars.cpp | 7 +++++- src/storm-pars/analysis/Lattice.cpp | 39 +++++++++++++++++++++++++++++ src/storm-pars/analysis/Lattice.h | 8 +++--- 3 files changed, 50 insertions(+), 4 deletions(-) diff --git a/src/storm-pars-cli/storm-pars.cpp b/src/storm-pars-cli/storm-pars.cpp index 7437f10ea..7ff92ca34 100644 --- a/src/storm-pars-cli/storm-pars.cpp +++ b/src/storm-pars-cli/storm-pars.cpp @@ -540,7 +540,12 @@ namespace storm { latticeWatch.stop(); STORM_PRINT(std::endl << "Time for lattice creation: " << latticeWatch << "." << std::endl << std::endl); - lattice->toString(std::cout); + + ofstream myfile; + myfile.open ("output.dot"); + lattice->toDotFile(myfile); + myfile.close(); + // Monotonicity? storm::utility::Stopwatch monotonicityWatch(true); diff --git a/src/storm-pars/analysis/Lattice.cpp b/src/storm-pars/analysis/Lattice.cpp index 3f0f8da3f..1c4fe63c7 100644 --- a/src/storm-pars/analysis/Lattice.cpp +++ b/src/storm-pars/analysis/Lattice.cpp @@ -136,6 +136,45 @@ namespace storm { } } + void Lattice::toDotFile(std::ostream &out) { + out << "digraph \"Lattice\" {" << std::endl; + + // print all nodes + std::vector printed; + out << "\t" << "node [shape=ellipse]" << std::endl; + for (auto itr = nodes.begin(); itr != nodes.end(); ++itr) { + if (find(printed.begin(), printed.end(), (*itr)) == printed.end()) { + out << "\t\"" << (*itr) << "\" [label = \""; + uint_fast64_t index = (*itr)->states.getNextSetIndex(0); + while (index < numberOfStates) { + out << index; + index = (*itr)->states.getNextSetIndex(index + 1); + if (index < numberOfStates) { + out << ", "; + } + } + + out << "\"]" << std::endl; + printed.push_back(*itr); + } + } + + // print arcs + printed.clear(); + for (auto itr = nodes.begin(); itr != nodes.end(); ++itr) { + if (find(printed.begin(), printed.end(), (*itr)) == printed.end()) { + auto below = (*itr)->below; + for (auto itr2 = below.begin(); itr2 != below.end(); ++itr2) { + out << "\t\"" << (*itr) << "\" -> \"" << (*itr2) << "\";" << std::endl; + } + printed.push_back(*itr); + } + } + + out << "}" << std::endl; + + + } bool Lattice::above(Node *node1, Node *node2) { bool result = !node1->below.empty() && std::find(node1->below.begin(), node1->below.end(), node2) != node1->below.end(); diff --git a/src/storm-pars/analysis/Lattice.h b/src/storm-pars/analysis/Lattice.h index e3e9f5246..34242fe75 100644 --- a/src/storm-pars/analysis/Lattice.h +++ b/src/storm-pars/analysis/Lattice.h @@ -83,6 +83,8 @@ namespace storm { */ void toString(std::ostream &out); + void toDotFile(std::ostream &out); + /*! * Creates a Lattice based on the transition matrix, topStates of the Lattice and bottomStates of the Lattice * @tparam ValueType Type of the probabilities @@ -171,11 +173,11 @@ namespace storm { uint_fast64_t successor2; }; - std::vector nodes; + std::vector nodes; - Node * top; + Node* top; - Node * bottom; + Node* bottom; uint_fast64_t numberOfStates; From 128d428fcc8b4d0b61393977c762113693005d8e Mon Sep 17 00:00:00 2001 From: Jip Spel Date: Tue, 21 Aug 2018 16:16:23 +0200 Subject: [PATCH 025/178] Add .dot representation for mc --- src/storm-pars-cli/storm-pars.cpp | 45 +++++++++++++++++++++++++++++-- 1 file changed, 43 insertions(+), 2 deletions(-) diff --git a/src/storm-pars-cli/storm-pars.cpp b/src/storm-pars-cli/storm-pars.cpp index 7ff92ca34..b7da6c37e 100644 --- a/src/storm-pars-cli/storm-pars.cpp +++ b/src/storm-pars-cli/storm-pars.cpp @@ -542,7 +542,7 @@ namespace storm { STORM_PRINT(std::endl << "Time for lattice creation: " << latticeWatch << "." << std::endl << std::endl); ofstream myfile; - myfile.open ("output.dot"); + myfile.open ("lattice.dot"); lattice->toDotFile(myfile); myfile.close(); @@ -552,6 +552,16 @@ namespace storm { // Map with for each variable bool pair whether it is monotone increasing (first) or monotone decreasing (second) std::map> varsMonotone; + myfile.open ("mc.dot"); + myfile << "digraph \"MC\" {" << std::endl; + myfile << "\t" << "node [shape=ellipse]" << std::endl; + // print all nodes + for (uint_fast64_t i = 0; i < sparseModel.get()->getNumberOfStates(); ++i) { + myfile << "\t\"" << i << "\" [label = \"" << i << "\"]" << std::endl; + } + + + for (uint_fast64_t i = 0; i < sparseModel.get()->getNumberOfStates(); ++i) { // go over all rows auto row = matrix.getRow(i); @@ -559,7 +569,7 @@ namespace storm { auto first = (*row.begin()); if (first.getValue() != ValueType(1)) { auto second = (*(++row.begin())); - + string color = ""; auto val = first.getValue(); auto vars = val.gatherVariables(); for (auto itr = vars.begin(); itr != vars.end(); ++itr) { @@ -573,6 +583,7 @@ namespace storm { auto compare = lattice->compare(first.getColumn(), second.getColumn()); std::pair* value = &varsMonotone.find(*itr)->second; + std::pair old = *value; if (compare == 1) { value->first &=derivative.constantPart() >= 0; value->second &=derivative.constantPart() <= 0; @@ -583,11 +594,41 @@ namespace storm { value->first = false; value->second = false; } + if ((value->first != old.first) && (value->second != old.second)) { + color = "color = red, "; + } else if ((value->first != old.first)) { + myfile << "\t edge[style=dashed];" << std::endl; + color = "color = blue, "; + } else if ((value->second != old.second)) { + myfile << "\t edge[style=dotted];" << std::endl; + color = "color = blue, "; + } } + myfile << "\t" << i << " -> " << first.getColumn() << "[" << color << "label=\"" << first.getValue() << "\"];" + << std::endl; + myfile << "\t" << i << " -> " << second.getColumn() << "[" << color << "label=\"" << second.getValue() << "\"];" + << std::endl; + myfile << "\t edge[style=\"\"];" << std::endl; + } else { + myfile << "\t" << i << " -> " << first.getColumn() << "[label=\"" << first.getValue() << "\"];" + << std::endl; } } + + myfile << "\tsubgraph legend {" << std::endl; +// myfile << "\t\trank=\"source\";" << std::endl; + myfile << "\t\tnode [color=white];" << std::endl; + myfile << "\t\tedge [style=invis];" << std::endl; + myfile << "\t\tedge [style=invis];" << std::endl; + myfile << "\t\tt0 [label=\"incr+decr false\", fontcolor=red];" << std::endl; + myfile << "\t\tt1 [label=\"incr false (dashed)\", fontcolor=blue];" << std::endl; + myfile << "\t\tt2 [label=\"decr false (dotted)\", fontcolor=blue];" << std::endl; + + myfile << "\t}" << std::endl; + myfile << "}" << std::endl; + myfile.close(); monotonicityWatch.stop(); STORM_PRINT(std::endl << "Time for monotonicity: " << monotonicityWatch << "." << std::endl << std::endl); for (auto itr = varsMonotone.begin(); itr != varsMonotone.end(); ++itr) { From 905f6fc970b3cfd6b26ab94be049184376a00cba Mon Sep 17 00:00:00 2001 From: Jip Spel Date: Wed, 22 Aug 2018 09:17:31 +0200 Subject: [PATCH 026/178] Create lattice from model and formulas --- src/storm-pars-cli/storm-pars.cpp | 43 +++++-------------------------- src/storm-pars/analysis/Lattice.h | 39 +++++++++++++++++++++++++--- 2 files changed, 42 insertions(+), 40 deletions(-) diff --git a/src/storm-pars-cli/storm-pars.cpp b/src/storm-pars-cli/storm-pars.cpp index b7da6c37e..7bf13cc18 100644 --- a/src/storm-pars-cli/storm-pars.cpp +++ b/src/storm-pars-cli/storm-pars.cpp @@ -461,7 +461,7 @@ namespace storm { if (parSettings.isMonotonicityAnalysisSet()) { std::cout << "Hello, Jip1" << std::endl; -// STORM_LOG_THROW(storm::settings::getModule().isBisimulationSet(), storm::exceptions::InvalidSettingsException, "Monotonicity analysis requires bisimulation"); + // Simplify the model storm::utility::Stopwatch simplifyingWatch(true); if (model->isOfType(storm::models::ModelType::Dtmc)) { auto consideredModel = (model->as>()); @@ -486,7 +486,7 @@ namespace storm { } model = simplifier.getSimplifiedModel(); } else { - STORM_LOG_THROW(false, storm::exceptions::InvalidOperationException, "Unable to perform parameterLifting on the provided model type."); + STORM_LOG_THROW(false, storm::exceptions::InvalidOperationException, "Unable to perform monotonicity analysis on the provided model type."); } simplifyingWatch.stop(); @@ -508,35 +508,10 @@ namespace storm { storm::utility::Stopwatch latticeWatch(true); std::vector> formulas = storm::api::extractFormulasFromProperties(input.properties); - - STORM_LOG_THROW((++formulas.begin()) == formulas.end(), storm::exceptions::NotSupportedException, "Only one formula allowed for monotonicity analysis"); - STORM_LOG_THROW((*(formulas[0])).isProbabilityOperatorFormula() - && ((*(formulas[0])).asProbabilityOperatorFormula().getSubformula().isUntilFormula() - || (*(formulas[0])).asProbabilityOperatorFormula().getSubformula().isEventuallyFormula()), storm::exceptions::NotSupportedException, "Expecting until formula"); - std::shared_ptr> sparseModel = model->as>(); - storm::modelchecker::SparsePropositionalModelChecker> propositionalChecker(*sparseModel); - - storm::storage::BitVector phiStates; - storm::storage::BitVector psiStates; - if ((*(formulas[0])).asProbabilityOperatorFormula().getSubformula().isUntilFormula()) { - phiStates = propositionalChecker.check((*(formulas[0])).asProbabilityOperatorFormula().getSubformula().asUntilFormula().getLeftSubformula())->asExplicitQualitativeCheckResult().getTruthValuesVector(); - psiStates = propositionalChecker.check((*(formulas[0])).asProbabilityOperatorFormula().getSubformula().asUntilFormula().getRightSubformula())->asExplicitQualitativeCheckResult().getTruthValuesVector(); - } else { - phiStates = storm::storage::BitVector(sparseModel.get()->getNumberOfStates(), true); - psiStates = propositionalChecker.check((*(formulas[0])).asProbabilityOperatorFormula().getSubformula().asEventuallyFormula().getSubformula())->asExplicitQualitativeCheckResult().getTruthValuesVector(); - } - - // Get the maybeStates - std::pair statesWithProbability01 = storm::utility::graph::performProb01(sparseModel.get()->getBackwardTransitions(), phiStates, psiStates); - storm::storage::BitVector topStates = statesWithProbability01.second; - storm::storage::BitVector bottomStates = statesWithProbability01.first; - STORM_LOG_THROW(topStates.begin() != topStates.end(), storm::exceptions::NotImplementedException, "Formula yields to no 1 states"); - STORM_LOG_THROW(bottomStates.begin() != bottomStates.end(), storm::exceptions::NotImplementedException, "Formula yields to no zero states"); // Transform to Lattice - storm::storage::SparseMatrix matrix = sparseModel.get()->getTransitionMatrix(); - storm::analysis::Lattice* lattice = storm::analysis::Lattice::toLattice(matrix, topStates, bottomStates); + storm::analysis::Lattice* lattice = storm::analysis::Lattice::toLattice(sparseModel, formulas); latticeWatch.stop(); STORM_PRINT(std::endl << "Time for lattice creation: " << latticeWatch << "." << std::endl << std::endl); @@ -561,7 +536,7 @@ namespace storm { } - + storm::storage::SparseMatrix matrix = sparseModel.get()->getTransitionMatrix(); for (uint_fast64_t i = 0; i < sparseModel.get()->getNumberOfStates(); ++i) { // go over all rows auto row = matrix.getRow(i); @@ -618,13 +593,11 @@ namespace storm { } myfile << "\tsubgraph legend {" << std::endl; -// myfile << "\t\trank=\"source\";" << std::endl; myfile << "\t\tnode [color=white];" << std::endl; myfile << "\t\tedge [style=invis];" << std::endl; - myfile << "\t\tedge [style=invis];" << std::endl; - myfile << "\t\tt0 [label=\"incr+decr false\", fontcolor=red];" << std::endl; - myfile << "\t\tt1 [label=\"incr false (dashed)\", fontcolor=blue];" << std::endl; - myfile << "\t\tt2 [label=\"decr false (dotted)\", fontcolor=blue];" << std::endl; + myfile << "\t\tt0 [label=\"incr? and decr?\", fontcolor=red];" << std::endl; + myfile << "\t\tt1 [label=\"incr? (dashed)\", fontcolor=blue];" << std::endl; + myfile << "\t\tt2 [label=\"decr? (dotted)\", fontcolor=blue];" << std::endl; myfile << "\t}" << std::endl; myfile << "}" << std::endl; @@ -648,8 +621,6 @@ namespace storm { return; } - - std::vector> regions = parseRegions(model); std::string samplesAsString = parSettings.getSamples(); SampleInformation samples; diff --git a/src/storm-pars/analysis/Lattice.h b/src/storm-pars/analysis/Lattice.h index 34242fe75..8248b74d9 100644 --- a/src/storm-pars/analysis/Lattice.h +++ b/src/storm-pars/analysis/Lattice.h @@ -7,10 +7,16 @@ #include #include +#include +#include #include "storm/models/sparse/Model.h" #include "storm/storage/BitVector.h" #include "storm/storage/SparseMatrix.h" +#include "storm/utility/macros.h" +#include "storm/utility/graph.h" +#include "storm/exceptions/NotImplementedException.h" +#include "storm/exceptions/NotSupportedException.h" namespace storm { @@ -94,10 +100,35 @@ namespace storm { * @return pointer to the created Lattice. */ template - static Lattice* toLattice(storm::storage::SparseMatrix matrix, - storm::storage::BitVector topStates, - storm::storage::BitVector bottomStates) { - uint_fast64_t numberOfStates = matrix.getColumnCount(); + static Lattice* toLattice(std::shared_ptr> sparseModel, std::vector> formulas) { + STORM_LOG_THROW((++formulas.begin()) == formulas.end(), storm::exceptions::NotSupportedException, "Only one formula allowed for monotonicity analysis"); + STORM_LOG_THROW((*(formulas[0])).isProbabilityOperatorFormula() + && ((*(formulas[0])).asProbabilityOperatorFormula().getSubformula().isUntilFormula() + || (*(formulas[0])).asProbabilityOperatorFormula().getSubformula().isEventuallyFormula()), storm::exceptions::NotSupportedException, "Expecting until formula"); + + uint_fast64_t numberOfStates = sparseModel.get()->getNumberOfStates(); + + storm::modelchecker::SparsePropositionalModelChecker> propositionalChecker(*sparseModel); + storm::storage::BitVector phiStates; + storm::storage::BitVector psiStates; + if ((*(formulas[0])).asProbabilityOperatorFormula().getSubformula().isUntilFormula()) { + phiStates = propositionalChecker.check((*(formulas[0])).asProbabilityOperatorFormula().getSubformula().asUntilFormula().getLeftSubformula())->asExplicitQualitativeCheckResult().getTruthValuesVector(); + psiStates = propositionalChecker.check((*(formulas[0])).asProbabilityOperatorFormula().getSubformula().asUntilFormula().getRightSubformula())->asExplicitQualitativeCheckResult().getTruthValuesVector(); + } else { + phiStates = storm::storage::BitVector(numberOfStates, true); + psiStates = propositionalChecker.check((*(formulas[0])).asProbabilityOperatorFormula().getSubformula().asEventuallyFormula().getSubformula())->asExplicitQualitativeCheckResult().getTruthValuesVector(); + } + + // Get the maybeStates + std::pair statesWithProbability01 = storm::utility::graph::performProb01(sparseModel.get()->getBackwardTransitions(), phiStates, psiStates); + storm::storage::BitVector topStates = statesWithProbability01.second; + storm::storage::BitVector bottomStates = statesWithProbability01.first; + + STORM_LOG_THROW(topStates.begin() != topStates.end(), storm::exceptions::NotImplementedException, "Formula yields to no 1 states"); + STORM_LOG_THROW(bottomStates.begin() != bottomStates.end(), storm::exceptions::NotImplementedException, "Formula yields to no zero states"); + + // Transform to Lattice + auto matrix = sparseModel.get()->getTransitionMatrix(); // Transform the transition matrix into a vector containing the states with the state to which the transition goes. std::vector stateVector = std::vector({}); From 1bce5935faf4076e6607a4726209d4d5c2705a84 Mon Sep 17 00:00:00 2001 From: Jip Spel Date: Wed, 22 Aug 2018 09:38:26 +0200 Subject: [PATCH 027/178] Update documentation --- src/storm-pars/analysis/Lattice.h | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/storm-pars/analysis/Lattice.h b/src/storm-pars/analysis/Lattice.h index 8248b74d9..8324a75d2 100644 --- a/src/storm-pars/analysis/Lattice.h +++ b/src/storm-pars/analysis/Lattice.h @@ -94,9 +94,8 @@ namespace storm { /*! * Creates a Lattice based on the transition matrix, topStates of the Lattice and bottomStates of the Lattice * @tparam ValueType Type of the probabilities - * @param matrix The transition matrix. - * @param topStates Set of topStates of the Lattice. - * @param bottomStates Set of bottomStates of the Lattice. + * @param model The pointer to the model + * @param formulas Vector with pointer to formula * @return pointer to the created Lattice. */ template From 8bbf4b454380fefe8bdbaa401f1f743c44773caa Mon Sep 17 00:00:00 2001 From: Jip Spel Date: Thu, 23 Aug 2018 10:11:30 +0200 Subject: [PATCH 028/178] Change vector to set, add error message if more than two successors for one state, add documentation --- src/storm-pars/analysis/Lattice.cpp | 28 ++++++++++------------------ src/storm-pars/analysis/Lattice.h | 23 ++++++++++++++--------- 2 files changed, 24 insertions(+), 27 deletions(-) diff --git a/src/storm-pars/analysis/Lattice.cpp b/src/storm-pars/analysis/Lattice.cpp index 1c4fe63c7..4bc2819ca 100644 --- a/src/storm-pars/analysis/Lattice.cpp +++ b/src/storm-pars/analysis/Lattice.cpp @@ -8,13 +8,12 @@ namespace storm { namespace analysis { Lattice::Lattice(storm::storage::BitVector topStates, storm::storage::BitVector bottomStates, uint_fast64_t numberOfStates) { - top = new Node(); top->states = topStates; bottom = new Node(); bottom->states = bottomStates; - top->below.push_back(bottom); - bottom->above.push_back(top); + top->below.insert(bottom); + bottom->above.insert(top); nodes = std::vector(numberOfStates); for (auto i = topStates.getNextSetIndex(0); i < numberOfStates; i = topStates.getNextSetIndex(i+1)) { @@ -32,12 +31,12 @@ namespace storm { Node *newNode = new Node(); newNode->states = storm::storage::BitVector(numberOfStates); newNode->states.set(state); - newNode->above = std::vector({above}); - newNode->below = std::vector({below}); - remove(&(below->above), above); - remove(&(above->below), below); - (below->above).push_back(newNode); - above->below.push_back(newNode); + newNode->above = std::set({above}); + newNode->below = std::set({below}); + below->above.erase(above); + above->below.erase(below); + (below->above).insert(newNode); + above->below.insert(newNode); nodes.at(state) = newNode; } @@ -107,7 +106,7 @@ namespace storm { } out << "}"; - if (itr2 + 1 != node->above.end()) { + if ((++itr2) != node->above.end()) { out << ", "; } } @@ -127,7 +126,7 @@ namespace storm { } out << "}"; - if (itr2 + 1 != node->below.end()) { + if ((++itr2) != node->below.end()) { out << ", "; } } @@ -184,13 +183,6 @@ namespace storm { return result; } - void Lattice::remove(std::vector *nodes, Node *node) { - auto index = std::find(nodes->begin(), nodes->end(), node); - if (index != nodes->end()) { - nodes->erase(index); - } - }; - void Lattice::setStates(std::vector states, Node *node) { for (auto itr = states.begin(); itr < states.end(); ++itr) { node->states.set(*itr); diff --git a/src/storm-pars/analysis/Lattice.h b/src/storm-pars/analysis/Lattice.h index 8324a75d2..643dc16b6 100644 --- a/src/storm-pars/analysis/Lattice.h +++ b/src/storm-pars/analysis/Lattice.h @@ -26,8 +26,8 @@ namespace storm { public: struct Node { storm::storage::BitVector states; - std::vector above; - std::vector below; + std::set above; + std::set below; }; /*! @@ -83,12 +83,17 @@ namespace storm { Node *getNode(uint_fast64_t state); /*! - * Prints a string representation of the lattice to std::cout. + * Prints a string representation of the lattice to the output stream. * * @param out The stream to output to. */ void toString(std::ostream &out); + /*! + * Prints a dot representation of the lattice to the output stream. + * + * @param out The stream to output to. + */ void toDotFile(std::ostream &out); /*! @@ -136,11 +141,14 @@ namespace storm { state->stateNumber = i; auto row = matrix.getRow(i); - //TODO assert that there are at most two successors + + if ((*(row.begin())).getValue() != ValueType(1)) { + STORM_LOG_THROW((row.begin() + 2) == row.end(), storm::exceptions::NotSupportedException, "Only two outgoing transitions per state allowed"); state->successor1 = (*(row.begin())).getColumn(); state->successor2 = (*(++row.begin())).getColumn(); } else { + state-> successor1 = (*(row.begin())).getColumn(); state-> successor2 = (*(row.begin())).getColumn(); } @@ -169,20 +177,19 @@ namespace storm { uint_fast64_t successor1 = currentState->successor1; uint_fast64_t successor2 = currentState->successor2; int compareResult = lattice->compare(successor1, successor2); + Node* node1 = lattice->getNode(successor1); + Node* node2 = lattice->getNode(successor2); if (compareResult == 1) { // successor 1 is closer to top than successor 2 lattice->addBetween(currentState->stateNumber, lattice->getNode(successor1), lattice->getNode(successor2)); - // Add stateNumber to the set with seen states. } else if (compareResult == 2) { // successor 2 is closer to top than successor 1 lattice->addBetween(currentState->stateNumber, lattice->getNode(successor2), lattice->getNode(successor1)); - // Add stateNumber to the set with seen states. } else if (compareResult == 0) { // the successors are at the same level lattice->addToNode(currentState->stateNumber, lattice->getNode(successor1)); - // Add stateNumber to the set with seen states. } else { // TODO: is this what we want? lattice->add(currentState->stateNumber); @@ -213,8 +220,6 @@ namespace storm { bool above(Node *, Node *); - void remove(std::vector *nodes, Node *node); - void setStates(std::vector states, Node *node); }; From 915a8b24ec88a0765697d05a0f936583c8ba2434 Mon Sep 17 00:00:00 2001 From: Jip Spel Date: Thu, 23 Aug 2018 10:11:59 +0200 Subject: [PATCH 029/178] Remove superfluous vars --- src/storm-pars/analysis/Lattice.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/storm-pars/analysis/Lattice.h b/src/storm-pars/analysis/Lattice.h index 643dc16b6..d37fea695 100644 --- a/src/storm-pars/analysis/Lattice.h +++ b/src/storm-pars/analysis/Lattice.h @@ -177,8 +177,6 @@ namespace storm { uint_fast64_t successor1 = currentState->successor1; uint_fast64_t successor2 = currentState->successor2; int compareResult = lattice->compare(successor1, successor2); - Node* node1 = lattice->getNode(successor1); - Node* node2 = lattice->getNode(successor2); if (compareResult == 1) { // successor 1 is closer to top than successor 2 lattice->addBetween(currentState->stateNumber, lattice->getNode(successor1), From 6f8787b6f0998d9ecece8a94ffaf2797a46b8a61 Mon Sep 17 00:00:00 2001 From: Jip Spel Date: Thu, 23 Aug 2018 14:02:01 +0200 Subject: [PATCH 030/178] Add one possible solution for critical states --- src/storm-pars-cli/storm-pars.cpp | 220 +++++++++++++++++++--------- src/storm-pars/analysis/Lattice.cpp | 8 + src/storm-pars/analysis/Lattice.h | 8 + 3 files changed, 166 insertions(+), 70 deletions(-) diff --git a/src/storm-pars-cli/storm-pars.cpp b/src/storm-pars-cli/storm-pars.cpp index 7bf13cc18..ba15457a4 100644 --- a/src/storm-pars-cli/storm-pars.cpp +++ b/src/storm-pars-cli/storm-pars.cpp @@ -437,6 +437,90 @@ namespace storm { storm::pars::verifyWithSparseEngine(model->as>(), input, regions, samples); } + template + std::map> analyseMonotonicity(storm::analysis::Lattice* lattice, storm::storage::SparseMatrix matrix) { + //TODO: Seperate cpp file with this and criticalstatefinding/handling + std::map> varsMonotone; + ofstream myfile; + myfile.open ("mc.dot"); + myfile << "digraph \"MC\" {" << std::endl; + myfile << "\t" << "node [shape=ellipse]" << std::endl; + // print all nodes + for (uint_fast64_t i = 0; i < matrix.getColumnCount(); ++i) { + myfile << "\t\"" << i << "\" [label = \"" << i << "\"]" << std::endl; + } + + + for (uint_fast64_t i = 0; i < matrix.getColumnCount(); ++i) { + // go over all rows + auto row = matrix.getRow(i); + + auto first = (*row.begin()); + if (first.getValue() != ValueType(1)) { + auto second = (*(++row.begin())); + string color = ""; + auto val = first.getValue(); + auto vars = val.gatherVariables(); + for (auto itr = vars.begin(); itr != vars.end(); ++itr) { + auto derivative = val.derivative(*itr); + STORM_LOG_THROW(derivative.isConstant(), storm::exceptions::NotSupportedException, "Expecting derivative to be constant"); + + if (varsMonotone.find(*itr) == varsMonotone.end()) { + varsMonotone[*itr].first = true; + varsMonotone[*itr].second = true; + } + + auto compare = lattice->compare(first.getColumn(), second.getColumn()); + std::pair* value = &varsMonotone.find(*itr)->second; + std::pair old = *value; + if (compare == 1) { + value->first &=derivative.constantPart() >= 0; + value->second &=derivative.constantPart() <= 0; + } else if (compare == 2) { + value->first &=derivative.constantPart() <= 0; + value->second &=derivative.constantPart() >= 0; + } else if (compare == 0) { + STORM_LOG_THROW(false, storm::exceptions::UnexpectedException, "Don't know what is happening, something in monotonicity checking went wrong"); + } else { + value->first = false; + value->second = false; + } + if ((value->first != old.first) && (value->second != old.second)) { + color = "color = red, "; + } else if ((value->first != old.first)) { + myfile << "\t edge[style=dashed];" << std::endl; + color = "color = blue, "; + } else if ((value->second != old.second)) { + myfile << "\t edge[style=dotted];" << std::endl; + color = "color = blue, "; + } + } + myfile << "\t" << i << " -> " << first.getColumn() << "[" << color << "label=\"" << first.getValue() << "\"];" + << std::endl; + myfile << "\t" << i << " -> " << second.getColumn() << "[" << color << "label=\"" << second.getValue() << "\"];" + << std::endl; + myfile << "\t edge[style=\"\"];" << std::endl; + } else { + myfile << "\t" << i << " -> " << first.getColumn() << "[label=\"" << first.getValue() << "\"];" + << std::endl; + } + + + } + + myfile << "\tsubgraph legend {" << std::endl; + myfile << "\t\tnode [color=white];" << std::endl; + myfile << "\t\tedge [style=invis];" << std::endl; + myfile << "\t\tt0 [label=\"incr? and decr?\", fontcolor=red];" << std::endl; + myfile << "\t\tt1 [label=\"incr? (dashed)\", fontcolor=blue];" << std::endl; + myfile << "\t\tt2 [label=\"decr? (dotted)\", fontcolor=blue];" << std::endl; + + myfile << "\t}" << std::endl; + myfile << "}" << std::endl; + myfile.close(); + return varsMonotone; + }; + template void processInputWithValueTypeAndDdlib(SymbolicInput& input) { auto coreSettings = storm::settings::getModule(); @@ -516,31 +600,14 @@ namespace storm { latticeWatch.stop(); STORM_PRINT(std::endl << "Time for lattice creation: " << latticeWatch << "." << std::endl << std::endl); - ofstream myfile; - myfile.open ("lattice.dot"); - lattice->toDotFile(myfile); - myfile.close(); - - - // Monotonicity? - storm::utility::Stopwatch monotonicityWatch(true); - // Map with for each variable bool pair whether it is monotone increasing (first) or monotone decreasing (second) - std::map> varsMonotone; - - myfile.open ("mc.dot"); - myfile << "digraph \"MC\" {" << std::endl; - myfile << "\t" << "node [shape=ellipse]" << std::endl; - // print all nodes - for (uint_fast64_t i = 0; i < sparseModel.get()->getNumberOfStates(); ++i) { - myfile << "\t\"" << i << "\" [label = \"" << i << "\"]" << std::endl; - } - - + // CriticalStates storm::storage::SparseMatrix matrix = sparseModel.get()->getTransitionMatrix(); + //TODO: seperate class + storm::utility::Stopwatch criticalStatesWatch(true); + storm::storage::BitVector criticalStates = storm::storage::BitVector(sparseModel.get()->getNumberOfStates()); for (uint_fast64_t i = 0; i < sparseModel.get()->getNumberOfStates(); ++i) { - // go over all rows - auto row = matrix.getRow(i); + auto row = matrix.getRow(i); auto first = (*row.begin()); if (first.getValue() != ValueType(1)) { auto second = (*(++row.begin())); @@ -548,62 +615,77 @@ namespace storm { auto val = first.getValue(); auto vars = val.gatherVariables(); for (auto itr = vars.begin(); itr != vars.end(); ++itr) { - auto derivative = val.derivative(*itr); - STORM_LOG_THROW(derivative.isConstant(), storm::exceptions::NotSupportedException, "Expecting derivative to be constant"); + auto compare = lattice->compare(first.getColumn(), second.getColumn()); + if (compare != 1 && compare != 2 && compare !=0) { + auto rowFirst = matrix.getRow(first.getColumn()); + while ((*rowFirst.begin()).getValue() == ValueType(1)) { + rowFirst = matrix.getRow((*rowFirst.begin()).getColumn()); + } - if (varsMonotone.find(*itr) == varsMonotone.end()) { - varsMonotone[*itr].first = true; - varsMonotone[*itr].second = true; - } + auto rowSecond = matrix.getRow(second.getColumn()); + while ((*rowSecond.begin()).getValue() == ValueType(1)) { + rowSecond = matrix.getRow((*rowSecond.begin()).getColumn()); + } - auto compare = lattice->compare(first.getColumn(), second.getColumn()); - std::pair* value = &varsMonotone.find(*itr)->second; - std::pair old = *value; - if (compare == 1) { - value->first &=derivative.constantPart() >= 0; - value->second &=derivative.constantPart() <= 0; - } else if (compare == 2) { - value->first &=derivative.constantPart() <= 0; - value->second &=derivative.constantPart() >= 0; - } else { - value->first = false; - value->second = false; - } - if ((value->first != old.first) && (value->second != old.second)) { - color = "color = red, "; - } else if ((value->first != old.first)) { - myfile << "\t edge[style=dashed];" << std::endl; - color = "color = blue, "; - } else if ((value->second != old.second)) { - myfile << "\t edge[style=dotted];" << std::endl; - color = "color = blue, "; + auto succF1 = *rowFirst.begin(); + auto succF2 = *(++rowFirst.begin()); + auto compareF = lattice->compare(succF1.getColumn(), succF2.getColumn()); + ValueType valF; + ValueType valS; + if (compareF == 1) { + valF = succF1.getValue(); + } else if (compareF == 2) { + valF = succF2.getValue(); + } else { + continue; + } + + auto succS1 = *rowSecond.begin(); + auto succS2 = *(++rowSecond.begin()); + auto compareS = lattice->compare(succS1.getColumn(), succS2.getColumn()); + if (compareS == 1) { + valS = succS1.getValue(); + } else if (compareS == 2) { + valS = succS2.getValue(); + } else { + continue; + } + + storm::RationalFunction diff = valF-valS; + auto vars = diff.gatherVariables(); + for (auto varsItr = vars.begin(); varsItr != vars.end(); ++varsItr) { + ValueType derivative = diff.derivative(*varsItr); + if (derivative.isConstant()) { + std::map sub0; + sub0.emplace(*varsItr, storm::utility::convertNumber(std::string("0"))); + std::map sub1; + sub1.emplace(*varsItr, storm::utility::convertNumber(std::string("1"))); + if (diff.evaluate(sub0) >= 0 && diff.evaluate(sub1) >= 0) { + lattice->addRelation(lattice->getNode(first.getColumn()), lattice->getNode(i), lattice->getNode(second.getColumn())); + } else if (diff.evaluate(sub0) <= 0 && diff.evaluate(sub1) <= 0) { + lattice->addRelation(lattice->getNode(second.getColumn()), lattice->getNode(i), lattice->getNode(first.getColumn())); + } + } + } } } - myfile << "\t" << i << " -> " << first.getColumn() << "[" << color << "label=\"" << first.getValue() << "\"];" - << std::endl; - myfile << "\t" << i << " -> " << second.getColumn() << "[" << color << "label=\"" << second.getValue() << "\"];" - << std::endl; - myfile << "\t edge[style=\"\"];" << std::endl; - } else { - myfile << "\t" << i << " -> " << first.getColumn() << "[label=\"" << first.getValue() << "\"];" - << std::endl; - } - + } } - myfile << "\tsubgraph legend {" << std::endl; - myfile << "\t\tnode [color=white];" << std::endl; - myfile << "\t\tedge [style=invis];" << std::endl; - myfile << "\t\tt0 [label=\"incr? and decr?\", fontcolor=red];" << std::endl; - myfile << "\t\tt1 [label=\"incr? (dashed)\", fontcolor=blue];" << std::endl; - myfile << "\t\tt2 [label=\"decr? (dotted)\", fontcolor=blue];" << std::endl; - - myfile << "\t}" << std::endl; - myfile << "}" << std::endl; + criticalStatesWatch.stop(); + STORM_PRINT(std::endl << "Time for critical states checking: " << criticalStatesWatch << "." << std::endl << std::endl); + ofstream myfile; + myfile.open ("lattice.dot"); + lattice->toDotFile(myfile); myfile.close(); + + // Monotonicity? + storm::utility::Stopwatch monotonicityWatch(true); + std::map> varsMonotone = analyseMonotonicity(lattice, matrix); monotonicityWatch.stop(); STORM_PRINT(std::endl << "Time for monotonicity: " << monotonicityWatch << "." << std::endl << std::endl); + for (auto itr = varsMonotone.begin(); itr != varsMonotone.end(); ++itr) { if (itr->second.first) { std::cout << "Monotone increasing in: " << itr->first << std::endl; @@ -643,8 +725,6 @@ namespace storm { verifyParametricModel(model, input, regions, samples); } } - - void processOptions() { // Start by setting some urgent options (log levels, resources, etc.) diff --git a/src/storm-pars/analysis/Lattice.cpp b/src/storm-pars/analysis/Lattice.cpp index 4bc2819ca..9602ab5a0 100644 --- a/src/storm-pars/analysis/Lattice.cpp +++ b/src/storm-pars/analysis/Lattice.cpp @@ -49,6 +49,14 @@ namespace storm { addBetween(state, top, bottom); } + void Lattice::addRelation(storm::analysis::Lattice::Node *above, storm::analysis::Lattice::Node *between, + storm::analysis::Lattice::Node *below) { + above->below.insert(between); + between->above.insert(above); + between->below.insert(below); + below->above.insert(between); + } + int Lattice::compare(uint_fast64_t state1, uint_fast64_t state2) { Node *node1 = getNode(state1); Node *node2 = getNode(state2); diff --git a/src/storm-pars/analysis/Lattice.h b/src/storm-pars/analysis/Lattice.h index d37fea695..e3c8f0104 100644 --- a/src/storm-pars/analysis/Lattice.h +++ b/src/storm-pars/analysis/Lattice.h @@ -60,6 +60,14 @@ namespace storm { */ void add(uint_fast64_t state); + /*! + * Adds a new relation to the lattice + * @param above The node closest to the top Node of the Lattice. + * @param between The node between above and below. + * @param below The node closest to the bottom Node of the Lattice. + */ + void addRelation(Node* above, Node* between, Node* below); + /*! * Compares the level of the nodes of the states. * Behaviour unknown when one or more of the states doesnot occur at any Node in the Lattice. From 80cf0982a97878d98bb8f052150225622e5463fd Mon Sep 17 00:00:00 2001 From: Jip Spel Date: Fri, 24 Aug 2018 09:39:07 +0200 Subject: [PATCH 031/178] WIP: parameter lifting --- src/storm-pars-cli/storm-pars.cpp | 67 +++++++++++++++++++++++------ src/storm-pars/analysis/Lattice.cpp | 1 + 2 files changed, 55 insertions(+), 13 deletions(-) diff --git a/src/storm-pars-cli/storm-pars.cpp b/src/storm-pars-cli/storm-pars.cpp index ba15457a4..61b0c9505 100644 --- a/src/storm-pars-cli/storm-pars.cpp +++ b/src/storm-pars-cli/storm-pars.cpp @@ -1,6 +1,6 @@ -#include -#include +#include "storm-pars/transformer/SparseParametricMdpSimplifier.h" +#include "storm-pars/transformer/SparseParametricDtmcSimplifier.h" #include "storm-pars/api/storm-pars.h" #include "storm-pars/settings/ParsSettings.h" #include "storm-pars/settings/modules/ParametricSettings.h" @@ -17,8 +17,11 @@ #include "storm/utility/initialize.h" #include "storm/utility/Stopwatch.h" #include "storm/utility/macros.h" +#include "storm-pars/api/region.h" #include "storm-pars/modelchecker/instantiation/SparseCtmcInstantiationModelChecker.h" +#include "storm-pars/modelchecker/region/SparseParameterLiftingModelChecker.h" +#include "storm-pars/modelchecker/region/SparseDtmcParameterLiftingModelChecker.h" #include "storm/settings/modules/GeneralSettings.h" #include "storm/settings/modules/CoreSettings.h" @@ -617,6 +620,33 @@ namespace storm { for (auto itr = vars.begin(); itr != vars.end(); ++itr) { auto compare = lattice->compare(first.getColumn(), second.getColumn()); if (compare != 1 && compare != 2 && compare !=0) { + + if (storm::utility::parameterlifting::validateParameterLiftingSound(*(sparseModel.get()), *((formulas[0]).get()))) { + //TODO: parameterlifting gebruiken om te kijken op kans op =) vanuit first.getCOlumn() en second.getColumn() + // als vanuit first.getColumn() >= second.getColumn() voor =) dan lattice->addRelation(lattice->getNode(first.getColumn()), + // lattice->getNode(i), + // lattice->getNode(second.getColumn())); + // als vanuit second.getColumn() >= first.getColumn() voor =) dan lattice->addRelation(lattice->getNode(second.getColumn()), + // lattice->getNode(i), + // lattice->getNode(first.getColumn())); + + + auto modelParameters = storm::models::sparse::getProbabilityParameters(*sparseModel); + auto rewParameters = storm::models::sparse::getRewardParameters(*sparseModel); + modelParameters.insert(rewParameters.begin(), rewParameters.end()); + +// auto regionChecker = storm::api::initializeParameterLiftingRegionModelChecker(Environment(), sparseModel, storm::api::createTask(formulas[0], true)); +// +// //start testing +// auto allSatRegion=storm::api::parseRegion("0.7<=pL<=0.9,0.75<=pK<=0.95", modelParameters); +// auto exBothRegion=storm::api::parseRegion("0.4<=pL<=0.65,0.75<=pK<=0.95", modelParameters); +// auto allVioRegion=storm::api::parseRegion("0.1<=pL<=0.73,0.2<=pK<=0.715", modelParameters); +// if (storm::modelchecker::RegionResult::AllSat == regionChecker->analyzeRegion(Environment(), allSatRegion, storm::modelchecker::RegionResultHypothesis::Unknown, storm::modelchecker::RegionResult::Unknown, true)) { +// std::cout << "Tralalala" << std::endl; +// } + } + + auto rowFirst = matrix.getRow(first.getColumn()); while ((*rowFirst.begin()).getValue() == ValueType(1)) { rowFirst = matrix.getRow((*rowFirst.begin()).getColumn()); @@ -653,17 +683,28 @@ namespace storm { storm::RationalFunction diff = valF-valS; auto vars = diff.gatherVariables(); - for (auto varsItr = vars.begin(); varsItr != vars.end(); ++varsItr) { - ValueType derivative = diff.derivative(*varsItr); - if (derivative.isConstant()) { - std::map sub0; - sub0.emplace(*varsItr, storm::utility::convertNumber(std::string("0"))); - std::map sub1; - sub1.emplace(*varsItr, storm::utility::convertNumber(std::string("1"))); - if (diff.evaluate(sub0) >= 0 && diff.evaluate(sub1) >= 0) { - lattice->addRelation(lattice->getNode(first.getColumn()), lattice->getNode(i), lattice->getNode(second.getColumn())); - } else if (diff.evaluate(sub0) <= 0 && diff.evaluate(sub1) <= 0) { - lattice->addRelation(lattice->getNode(second.getColumn()), lattice->getNode(i), lattice->getNode(first.getColumn())); + if (vars.size() == 1) { + for (auto varsItr = vars.begin(); varsItr != vars.end(); ++varsItr) { + ValueType derivative = diff.derivative(*varsItr); + if (derivative.isConstant()) { + std::map sub0; + sub0.emplace(*varsItr, + storm::utility::convertNumber( + std::string("0"))); + std::map sub1; + sub1.emplace(*varsItr, + storm::utility::convertNumber( + std::string("1"))); + if (diff.evaluate(sub0) >= 0 && diff.evaluate(sub1) >= 0) { + lattice->addRelation(lattice->getNode(first.getColumn()), + lattice->getNode(i), + lattice->getNode(second.getColumn())); + } else if (diff.evaluate(sub0) <= 0 && diff.evaluate(sub1) <= 0) { + lattice->addRelation(lattice->getNode(second.getColumn()), + lattice->getNode(i), + lattice->getNode(first.getColumn())); + } + } } } diff --git a/src/storm-pars/analysis/Lattice.cpp b/src/storm-pars/analysis/Lattice.cpp index 9602ab5a0..66c3af007 100644 --- a/src/storm-pars/analysis/Lattice.cpp +++ b/src/storm-pars/analysis/Lattice.cpp @@ -61,6 +61,7 @@ namespace storm { Node *node1 = getNode(state1); Node *node2 = getNode(state2); + // TODO: Wat als above(node1, node2) en above(node2, node1), dan moeten ze samengevoegd? if (node1 != nullptr && node2 != nullptr) { if (node1 == node2) { return 0; From d2e754c302bf4ab76c1e2ff5aae5e659a4eca792 Mon Sep 17 00:00:00 2001 From: Jip Spel Date: Mon, 27 Aug 2018 09:58:26 +0200 Subject: [PATCH 032/178] Replace transformation to State Vector with transformation in map --- src/storm-pars/analysis/Lattice.h | 65 ++++++++++++++----------------- 1 file changed, 30 insertions(+), 35 deletions(-) diff --git a/src/storm-pars/analysis/Lattice.h b/src/storm-pars/analysis/Lattice.h index e3c8f0104..698b2d058 100644 --- a/src/storm-pars/analysis/Lattice.h +++ b/src/storm-pars/analysis/Lattice.h @@ -142,66 +142,67 @@ namespace storm { // Transform to Lattice auto matrix = sparseModel.get()->getTransitionMatrix(); - // Transform the transition matrix into a vector containing the states with the state to which the transition goes. - std::vector stateVector = std::vector({}); + std::map stateMap; for (uint_fast64_t i = 0; i < numberOfStates; ++i) { - State* state = new State(); - state->stateNumber = i; + stateMap[i] = storm::storage::BitVector(numberOfStates, false); auto row = matrix.getRow(i); - - - if ((*(row.begin())).getValue() != ValueType(1)) { - STORM_LOG_THROW((row.begin() + 2) == row.end(), storm::exceptions::NotSupportedException, "Only two outgoing transitions per state allowed"); - state->successor1 = (*(row.begin())).getColumn(); - state->successor2 = (*(++row.begin())).getColumn(); - } else { - - state-> successor1 = (*(row.begin())).getColumn(); - state-> successor2 = (*(row.begin())).getColumn(); + for (auto rowItr = row.begin(); rowItr != row.end(); ++rowItr) { + stateMap[i].set(rowItr->getColumn(), true); } - - stateVector.push_back(state); + // TODO: allow more than 2 transitions + STORM_LOG_THROW(stateMap[i].getNumberOfSetBits() <= 2, storm::exceptions::NotSupportedException, "Only two outgoing transitions per state allowed"); } + // Start creating the Lattice storm::analysis::Lattice *lattice = new storm::analysis::Lattice(topStates, bottomStates, numberOfStates); storm::storage::BitVector oldStates(numberOfStates); // Create a copy of the states already present in the lattice. storm::storage::BitVector seenStates = topStates|= bottomStates; + matrix.printAsMatlabMatrix(std::cout); while (oldStates != seenStates) { // As long as new states are added to the lattice, continue. oldStates = storm::storage::BitVector(seenStates); - for (auto itr = stateVector.begin(); itr != stateVector.end(); ++itr) { + for (auto stateItr = stateMap.begin(); stateItr != stateMap.end(); ++stateItr) { // Iterate over all states - State *currentState = *itr; + auto stateNumber = stateItr->first; + storm::storage::BitVector successors = stateItr->second; - if (!seenStates[currentState->stateNumber] - && seenStates[currentState->successor1] - && seenStates[currentState->successor2]) { + // Check if current state has not been added yet, and all successors have + bool check = !seenStates[stateNumber]; + for (auto succIndex = successors.getNextSetIndex(0); check && succIndex != numberOfStates; succIndex = successors.getNextSetIndex(++succIndex)) { + check &= seenStates[succIndex]; + } + + if (check && successors.getNumberOfSetBits() == 1) { + // As there is only one successor the current state and its successor must be at the same nodes. + lattice->addToNode(stateNumber, lattice->getNode(successors.getNextSetIndex(0))); + seenStates.set(stateNumber); + } else if (check && successors.getNumberOfSetBits() > 1) { + // TODO: allow more than 2 transitions // Otherwise, check how the two states compare, and add if the comparison is possible. - uint_fast64_t successor1 = currentState->successor1; - uint_fast64_t successor2 = currentState->successor2; + uint_fast64_t successor1 = successors.getNextSetIndex(0); + uint_fast64_t successor2 = successors.getNextSetIndex(successor1 + 1); int compareResult = lattice->compare(successor1, successor2); if (compareResult == 1) { // successor 1 is closer to top than successor 2 - lattice->addBetween(currentState->stateNumber, lattice->getNode(successor1), + lattice->addBetween(stateNumber, lattice->getNode(successor1), lattice->getNode(successor2)); } else if (compareResult == 2) { // successor 2 is closer to top than successor 1 - lattice->addBetween(currentState->stateNumber, lattice->getNode(successor2), + lattice->addBetween(stateNumber, lattice->getNode(successor2), lattice->getNode(successor1)); } else if (compareResult == 0) { // the successors are at the same level - lattice->addToNode(currentState->stateNumber, lattice->getNode(successor1)); + lattice->addToNode(stateNumber, lattice->getNode(successor1)); } else { // TODO: is this what we want? - lattice->add(currentState->stateNumber); + lattice->add(stateNumber); } - seenStates.set(currentState->stateNumber); - + seenStates.set(stateNumber); } } } @@ -210,12 +211,6 @@ namespace storm { } private: - struct State { - uint_fast64_t stateNumber; - uint_fast64_t successor1; - uint_fast64_t successor2; - }; - std::vector nodes; Node* top; From ee8971c608599a8de14c3278365df7e4dee54d6e Mon Sep 17 00:00:00 2001 From: Jip Spel Date: Mon, 27 Aug 2018 10:22:22 +0200 Subject: [PATCH 033/178] Clean up --- src/storm-pars/analysis/Lattice.cpp | 9 +-------- src/storm-pars/analysis/Lattice.h | 9 +++------ 2 files changed, 4 insertions(+), 14 deletions(-) diff --git a/src/storm-pars/analysis/Lattice.cpp b/src/storm-pars/analysis/Lattice.cpp index 66c3af007..b2fa043e7 100644 --- a/src/storm-pars/analysis/Lattice.cpp +++ b/src/storm-pars/analysis/Lattice.cpp @@ -180,9 +180,8 @@ namespace storm { } out << "}" << std::endl; - - } + bool Lattice::above(Node *node1, Node *node2) { bool result = !node1->below.empty() && std::find(node1->below.begin(), node1->below.end(), node2) != node1->below.end(); @@ -191,11 +190,5 @@ namespace storm { } return result; } - - void Lattice::setStates(std::vector states, Node *node) { - for (auto itr = states.begin(); itr < states.end(); ++itr) { - node->states.set(*itr); - } - } } } diff --git a/src/storm-pars/analysis/Lattice.h b/src/storm-pars/analysis/Lattice.h index 698b2d058..03147431e 100644 --- a/src/storm-pars/analysis/Lattice.h +++ b/src/storm-pars/analysis/Lattice.h @@ -150,17 +150,17 @@ namespace storm { for (auto rowItr = row.begin(); rowItr != row.end(); ++rowItr) { stateMap[i].set(rowItr->getColumn(), true); } - // TODO: allow more than 2 transitions + // TODO: allow more than 2 transitions? or fix this in preprocessing? STORM_LOG_THROW(stateMap[i].getNumberOfSetBits() <= 2, storm::exceptions::NotSupportedException, "Only two outgoing transitions per state allowed"); } // Start creating the Lattice storm::analysis::Lattice *lattice = new storm::analysis::Lattice(topStates, bottomStates, numberOfStates); storm::storage::BitVector oldStates(numberOfStates); + // Create a copy of the states already present in the lattice. storm::storage::BitVector seenStates = topStates|= bottomStates; - matrix.printAsMatlabMatrix(std::cout); while (oldStates != seenStates) { // As long as new states are added to the lattice, continue. oldStates = storm::storage::BitVector(seenStates); @@ -181,7 +181,7 @@ namespace storm { lattice->addToNode(stateNumber, lattice->getNode(successors.getNextSetIndex(0))); seenStates.set(stateNumber); } else if (check && successors.getNumberOfSetBits() > 1) { - // TODO: allow more than 2 transitions + // TODO: allow more than 2 transitions? // Otherwise, check how the two states compare, and add if the comparison is possible. uint_fast64_t successor1 = successors.getNextSetIndex(0); @@ -220,9 +220,6 @@ namespace storm { uint_fast64_t numberOfStates; bool above(Node *, Node *); - - void setStates(std::vector states, Node *node); - }; } } From e7dc7acf8ef21677ad1a097543b66735a11b855e Mon Sep 17 00:00:00 2001 From: Jip Spel Date: Mon, 27 Aug 2018 14:13:10 +0200 Subject: [PATCH 034/178] Cleanup --- src/storm-pars-cli/storm-pars.cpp | 57 ++++++++++++++++++++----------- 1 file changed, 37 insertions(+), 20 deletions(-) diff --git a/src/storm-pars-cli/storm-pars.cpp b/src/storm-pars-cli/storm-pars.cpp index 61b0c9505..0159a9af4 100644 --- a/src/storm-pars-cli/storm-pars.cpp +++ b/src/storm-pars-cli/storm-pars.cpp @@ -1,36 +1,50 @@ -#include "storm-pars/transformer/SparseParametricMdpSimplifier.h" -#include "storm-pars/transformer/SparseParametricDtmcSimplifier.h" + +#include "storm-cli-utilities/cli.h" +#include "storm-cli-utilities/model-handling.h" + +#include "storm-pars/analysis/Lattice.h" + #include "storm-pars/api/storm-pars.h" +#include "storm-pars/api/region.h" + +#include "storm-pars/modelchecker/instantiation/SparseCtmcInstantiationModelChecker.h" +#include "storm-pars/modelchecker/region/SparseParameterLiftingModelChecker.h" +#include "storm-pars/modelchecker/region/SparseDtmcParameterLiftingModelChecker.h" + #include "storm-pars/settings/ParsSettings.h" #include "storm-pars/settings/modules/ParametricSettings.h" #include "storm-pars/settings/modules/RegionSettings.h" -#include "storm-pars/analysis/Lattice.h" -#include "storm/settings/SettingsManager.h" +#include "storm-pars/transformer/SparseParametricMdpSimplifier.h" +#include "storm-pars/transformer/SparseParametricDtmcSimplifier.h" + #include "storm/api/storm.h" -#include "storm-cli-utilities/cli.h" -#include "storm-cli-utilities/model-handling.h" + +#include "storm/exceptions/BaseException.h" +#include "storm/exceptions/InvalidSettingsException.h" +#include "storm/exceptions/InvalidSettingsException.h" +#include "storm/exceptions/NotSupportedException.h" + #include "storm/models/ModelBase.h" + +#include "storm/settings/SettingsManager.h" + +#include "storm/solver/stateelimination/PrioritizedStateEliminator.h" + +#include "storm/storage/StronglyConnectedComponentDecomposition.h" #include "storm/storage/SymbolicModelDescription.h" + #include "storm/utility/file.h" #include "storm/utility/initialize.h" #include "storm/utility/Stopwatch.h" #include "storm/utility/macros.h" -#include "storm-pars/api/region.h" - -#include "storm-pars/modelchecker/instantiation/SparseCtmcInstantiationModelChecker.h" -#include "storm-pars/modelchecker/region/SparseParameterLiftingModelChecker.h" -#include "storm-pars/modelchecker/region/SparseDtmcParameterLiftingModelChecker.h" #include "storm/settings/modules/GeneralSettings.h" #include "storm/settings/modules/CoreSettings.h" #include "storm/settings/modules/IOSettings.h" #include "storm/settings/modules/BisimulationSettings.h" -#include "storm/exceptions/BaseException.h" -#include "storm/exceptions/InvalidSettingsException.h" -#include "storm/exceptions/NotSupportedException.h" namespace storm { namespace pars { @@ -592,20 +606,24 @@ namespace storm { if (parSettings.isMonotonicityAnalysisSet()) { std::cout << "Hello, Jip2" << std::endl; - storm::utility::Stopwatch latticeWatch(true); - std::vector> formulas = storm::api::extractFormulasFromProperties(input.properties); std::shared_ptr> sparseModel = model->as>(); // Transform to Lattice + storm::utility::Stopwatch latticeWatch(true); storm::analysis::Lattice* lattice = storm::analysis::Lattice::toLattice(sparseModel, formulas); - latticeWatch.stop(); STORM_PRINT(std::endl << "Time for lattice creation: " << latticeWatch << "." << std::endl << std::endl); + ofstream myfile; + myfile.open ("lattice.dot"); + lattice->toDotFile(myfile); + myfile.close(); + // CriticalStates + //TODO: what if states not found in lattice/cyclic thingie storm::storage::SparseMatrix matrix = sparseModel.get()->getTransitionMatrix(); - //TODO: seperate class + //TODO: separate class storm::utility::Stopwatch criticalStatesWatch(true); storm::storage::BitVector criticalStates = storm::storage::BitVector(sparseModel.get()->getNumberOfStates()); for (uint_fast64_t i = 0; i < sparseModel.get()->getNumberOfStates(); ++i) { @@ -704,7 +722,6 @@ namespace storm { lattice->getNode(i), lattice->getNode(first.getColumn())); } - } } } @@ -716,11 +733,11 @@ namespace storm { criticalStatesWatch.stop(); STORM_PRINT(std::endl << "Time for critical states checking: " << criticalStatesWatch << "." << std::endl << std::endl); - ofstream myfile; myfile.open ("lattice.dot"); lattice->toDotFile(myfile); myfile.close(); + // Monotonicity? storm::utility::Stopwatch monotonicityWatch(true); std::map> varsMonotone = analyseMonotonicity(lattice, matrix); From 5aec480a1ed98e0e9fc8cc049f998f61097ea205 Mon Sep 17 00:00:00 2001 From: Jip Spel Date: Tue, 28 Aug 2018 12:35:34 +0200 Subject: [PATCH 035/178] Clean up --- src/storm-pars-cli/storm-pars.cpp | 128 +----------------------------- 1 file changed, 4 insertions(+), 124 deletions(-) diff --git a/src/storm-pars-cli/storm-pars.cpp b/src/storm-pars-cli/storm-pars.cpp index 0159a9af4..fd7fd0988 100644 --- a/src/storm-pars-cli/storm-pars.cpp +++ b/src/storm-pars-cli/storm-pars.cpp @@ -521,8 +521,6 @@ namespace storm { myfile << "\t" << i << " -> " << first.getColumn() << "[label=\"" << first.getValue() << "\"];" << std::endl; } - - } myfile << "\tsubgraph legend {" << std::endl; @@ -615,129 +613,11 @@ namespace storm { latticeWatch.stop(); STORM_PRINT(std::endl << "Time for lattice creation: " << latticeWatch << "." << std::endl << std::endl); ofstream myfile; - myfile.open ("lattice.dot"); - lattice->toDotFile(myfile); - myfile.close(); - - - // CriticalStates - //TODO: what if states not found in lattice/cyclic thingie - storm::storage::SparseMatrix matrix = sparseModel.get()->getTransitionMatrix(); - //TODO: separate class - storm::utility::Stopwatch criticalStatesWatch(true); - storm::storage::BitVector criticalStates = storm::storage::BitVector(sparseModel.get()->getNumberOfStates()); - for (uint_fast64_t i = 0; i < sparseModel.get()->getNumberOfStates(); ++i) { - - auto row = matrix.getRow(i); - auto first = (*row.begin()); - if (first.getValue() != ValueType(1)) { - auto second = (*(++row.begin())); - string color = ""; - auto val = first.getValue(); - auto vars = val.gatherVariables(); - for (auto itr = vars.begin(); itr != vars.end(); ++itr) { - auto compare = lattice->compare(first.getColumn(), second.getColumn()); - if (compare != 1 && compare != 2 && compare !=0) { - - if (storm::utility::parameterlifting::validateParameterLiftingSound(*(sparseModel.get()), *((formulas[0]).get()))) { - //TODO: parameterlifting gebruiken om te kijken op kans op =) vanuit first.getCOlumn() en second.getColumn() - // als vanuit first.getColumn() >= second.getColumn() voor =) dan lattice->addRelation(lattice->getNode(first.getColumn()), - // lattice->getNode(i), - // lattice->getNode(second.getColumn())); - // als vanuit second.getColumn() >= first.getColumn() voor =) dan lattice->addRelation(lattice->getNode(second.getColumn()), - // lattice->getNode(i), - // lattice->getNode(first.getColumn())); - - - auto modelParameters = storm::models::sparse::getProbabilityParameters(*sparseModel); - auto rewParameters = storm::models::sparse::getRewardParameters(*sparseModel); - modelParameters.insert(rewParameters.begin(), rewParameters.end()); - -// auto regionChecker = storm::api::initializeParameterLiftingRegionModelChecker(Environment(), sparseModel, storm::api::createTask(formulas[0], true)); -// -// //start testing -// auto allSatRegion=storm::api::parseRegion("0.7<=pL<=0.9,0.75<=pK<=0.95", modelParameters); -// auto exBothRegion=storm::api::parseRegion("0.4<=pL<=0.65,0.75<=pK<=0.95", modelParameters); -// auto allVioRegion=storm::api::parseRegion("0.1<=pL<=0.73,0.2<=pK<=0.715", modelParameters); -// if (storm::modelchecker::RegionResult::AllSat == regionChecker->analyzeRegion(Environment(), allSatRegion, storm::modelchecker::RegionResultHypothesis::Unknown, storm::modelchecker::RegionResult::Unknown, true)) { -// std::cout << "Tralalala" << std::endl; -// } - } - - - auto rowFirst = matrix.getRow(first.getColumn()); - while ((*rowFirst.begin()).getValue() == ValueType(1)) { - rowFirst = matrix.getRow((*rowFirst.begin()).getColumn()); - } - - auto rowSecond = matrix.getRow(second.getColumn()); - while ((*rowSecond.begin()).getValue() == ValueType(1)) { - rowSecond = matrix.getRow((*rowSecond.begin()).getColumn()); - } - auto succF1 = *rowFirst.begin(); - auto succF2 = *(++rowFirst.begin()); - auto compareF = lattice->compare(succF1.getColumn(), succF2.getColumn()); - ValueType valF; - ValueType valS; - if (compareF == 1) { - valF = succF1.getValue(); - } else if (compareF == 2) { - valF = succF2.getValue(); - } else { - continue; - } - - auto succS1 = *rowSecond.begin(); - auto succS2 = *(++rowSecond.begin()); - auto compareS = lattice->compare(succS1.getColumn(), succS2.getColumn()); - if (compareS == 1) { - valS = succS1.getValue(); - } else if (compareS == 2) { - valS = succS2.getValue(); - } else { - continue; - } - - storm::RationalFunction diff = valF-valS; - auto vars = diff.gatherVariables(); - if (vars.size() == 1) { - for (auto varsItr = vars.begin(); varsItr != vars.end(); ++varsItr) { - ValueType derivative = diff.derivative(*varsItr); - if (derivative.isConstant()) { - std::map sub0; - sub0.emplace(*varsItr, - storm::utility::convertNumber( - std::string("0"))); - std::map sub1; - sub1.emplace(*varsItr, - storm::utility::convertNumber( - std::string("1"))); - if (diff.evaluate(sub0) >= 0 && diff.evaluate(sub1) >= 0) { - lattice->addRelation(lattice->getNode(first.getColumn()), - lattice->getNode(i), - lattice->getNode(second.getColumn())); - } else if (diff.evaluate(sub0) <= 0 && diff.evaluate(sub1) <= 0) { - lattice->addRelation(lattice->getNode(second.getColumn()), - lattice->getNode(i), - lattice->getNode(first.getColumn())); - } - } - } - } - } - } - - } - } - - criticalStatesWatch.stop(); - STORM_PRINT(std::endl << "Time for critical states checking: " << criticalStatesWatch << "." << std::endl << std::endl); myfile.open ("lattice.dot"); lattice->toDotFile(myfile); myfile.close(); - // Monotonicity? storm::utility::Stopwatch monotonicityWatch(true); std::map> varsMonotone = analyseMonotonicity(lattice, matrix); @@ -746,14 +626,14 @@ namespace storm { for (auto itr = varsMonotone.begin(); itr != varsMonotone.end(); ++itr) { if (itr->second.first) { - std::cout << "Monotone increasing in: " << itr->first << std::endl; + STORM_PRINT("Monotone increasing in: " << itr->first << std::endl); } else { - std::cout << "Do not know if monotone increasing in: " << itr->first << std::endl; + STORM_PRINT("Do not know if monotone increasing in: " << itr->first << std::endl); } if (itr->second.second) { - std::cout << "Monotone decreasing in: " << itr->first << std::endl; + STORM_PRINT("Monotone decreasing in: " << itr->first << std::endl); } else { - std::cout << "Do not know if monotone decreasing in: " << itr->first << std::endl; + STORM_PRINT("Do not know if monotone decreasing in: " << itr->first << std::endl); } } From b0b0623fcfe7caf740006b6e85fb14bd8d59556a Mon Sep 17 00:00:00 2001 From: Jip Spel Date: Tue, 28 Aug 2018 12:52:30 +0200 Subject: [PATCH 036/178] Add matrix declaration --- src/storm-pars-cli/storm-pars.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/storm-pars-cli/storm-pars.cpp b/src/storm-pars-cli/storm-pars.cpp index fd7fd0988..96b13e6e0 100644 --- a/src/storm-pars-cli/storm-pars.cpp +++ b/src/storm-pars-cli/storm-pars.cpp @@ -619,6 +619,7 @@ namespace storm { myfile.close(); // Monotonicity? + auto matrix = sparseModel.get()->getTransitionMatrix(); storm::utility::Stopwatch monotonicityWatch(true); std::map> varsMonotone = analyseMonotonicity(lattice, matrix); monotonicityWatch.stop(); From 9e8d910a49a2d40106166306cb0d4084770c72c9 Mon Sep 17 00:00:00 2001 From: Jip Spel Date: Tue, 28 Aug 2018 16:25:03 +0200 Subject: [PATCH 037/178] WIP Add LatticeExtender --- src/storm-pars/analysis/Lattice.cpp | 8 +- src/storm-pars/analysis/Lattice.h | 120 ++---------------- src/storm-pars/analysis/LatticeExtender.cpp | 129 ++++++++++++++++++++ src/storm-pars/analysis/LatticeExtender.h | 42 +++++++ 4 files changed, 185 insertions(+), 114 deletions(-) create mode 100644 src/storm-pars/analysis/LatticeExtender.cpp create mode 100644 src/storm-pars/analysis/LatticeExtender.h diff --git a/src/storm-pars/analysis/Lattice.cpp b/src/storm-pars/analysis/Lattice.cpp index b2fa043e7..5adc1cbc3 100644 --- a/src/storm-pars/analysis/Lattice.cpp +++ b/src/storm-pars/analysis/Lattice.cpp @@ -24,7 +24,7 @@ namespace storm { nodes.at(i) = bottom; } this->numberOfStates = numberOfStates; - + this->addedStates = storm::storage::BitVector(numberOfStates); } void Lattice::addBetween(uint_fast64_t state, Node *above, Node *below) { @@ -38,11 +38,13 @@ namespace storm { (below->above).insert(newNode); above->below.insert(newNode); nodes.at(state) = newNode; + addedStates.set(state); } void Lattice::addToNode(uint_fast64_t state, Node *node) { node->states.set(state); nodes.at(state) = node; + addedStates.set(state); } void Lattice::add(uint_fast64_t state) { @@ -83,6 +85,10 @@ namespace storm { return nodes.at(stateNumber); } + storm::storage::BitVector Lattice::getAddedStates() { + return addedStates; + } + void Lattice::toString(std::ostream &out) { std::vector printedNodes = std::vector({}); for (auto itr = nodes.begin(); itr != nodes.end(); ++itr) { diff --git a/src/storm-pars/analysis/Lattice.h b/src/storm-pars/analysis/Lattice.h index 03147431e..a5644db48 100644 --- a/src/storm-pars/analysis/Lattice.h +++ b/src/storm-pars/analysis/Lattice.h @@ -6,17 +6,12 @@ #define LATTICE_LATTICE_H #include +#include #include -#include -#include -#include "storm/models/sparse/Model.h" #include "storm/storage/BitVector.h" -#include "storm/storage/SparseMatrix.h" -#include "storm/utility/macros.h" -#include "storm/utility/graph.h" -#include "storm/exceptions/NotImplementedException.h" -#include "storm/exceptions/NotSupportedException.h" + + namespace storm { @@ -90,6 +85,8 @@ namespace storm { */ Node *getNode(uint_fast64_t state); + storm::storage::BitVector getAddedStates(); + /*! * Prints a string representation of the lattice to the output stream. * @@ -104,115 +101,12 @@ namespace storm { */ void toDotFile(std::ostream &out); - /*! - * Creates a Lattice based on the transition matrix, topStates of the Lattice and bottomStates of the Lattice - * @tparam ValueType Type of the probabilities - * @param model The pointer to the model - * @param formulas Vector with pointer to formula - * @return pointer to the created Lattice. - */ - template - static Lattice* toLattice(std::shared_ptr> sparseModel, std::vector> formulas) { - STORM_LOG_THROW((++formulas.begin()) == formulas.end(), storm::exceptions::NotSupportedException, "Only one formula allowed for monotonicity analysis"); - STORM_LOG_THROW((*(formulas[0])).isProbabilityOperatorFormula() - && ((*(formulas[0])).asProbabilityOperatorFormula().getSubformula().isUntilFormula() - || (*(formulas[0])).asProbabilityOperatorFormula().getSubformula().isEventuallyFormula()), storm::exceptions::NotSupportedException, "Expecting until formula"); - - uint_fast64_t numberOfStates = sparseModel.get()->getNumberOfStates(); - - storm::modelchecker::SparsePropositionalModelChecker> propositionalChecker(*sparseModel); - storm::storage::BitVector phiStates; - storm::storage::BitVector psiStates; - if ((*(formulas[0])).asProbabilityOperatorFormula().getSubformula().isUntilFormula()) { - phiStates = propositionalChecker.check((*(formulas[0])).asProbabilityOperatorFormula().getSubformula().asUntilFormula().getLeftSubformula())->asExplicitQualitativeCheckResult().getTruthValuesVector(); - psiStates = propositionalChecker.check((*(formulas[0])).asProbabilityOperatorFormula().getSubformula().asUntilFormula().getRightSubformula())->asExplicitQualitativeCheckResult().getTruthValuesVector(); - } else { - phiStates = storm::storage::BitVector(numberOfStates, true); - psiStates = propositionalChecker.check((*(formulas[0])).asProbabilityOperatorFormula().getSubformula().asEventuallyFormula().getSubformula())->asExplicitQualitativeCheckResult().getTruthValuesVector(); - } - - // Get the maybeStates - std::pair statesWithProbability01 = storm::utility::graph::performProb01(sparseModel.get()->getBackwardTransitions(), phiStates, psiStates); - storm::storage::BitVector topStates = statesWithProbability01.second; - storm::storage::BitVector bottomStates = statesWithProbability01.first; - - STORM_LOG_THROW(topStates.begin() != topStates.end(), storm::exceptions::NotImplementedException, "Formula yields to no 1 states"); - STORM_LOG_THROW(bottomStates.begin() != bottomStates.end(), storm::exceptions::NotImplementedException, "Formula yields to no zero states"); - - // Transform to Lattice - auto matrix = sparseModel.get()->getTransitionMatrix(); - - std::map stateMap; - for (uint_fast64_t i = 0; i < numberOfStates; ++i) { - stateMap[i] = storm::storage::BitVector(numberOfStates, false); - - auto row = matrix.getRow(i); - for (auto rowItr = row.begin(); rowItr != row.end(); ++rowItr) { - stateMap[i].set(rowItr->getColumn(), true); - } - // TODO: allow more than 2 transitions? or fix this in preprocessing? - STORM_LOG_THROW(stateMap[i].getNumberOfSetBits() <= 2, storm::exceptions::NotSupportedException, "Only two outgoing transitions per state allowed"); - } - - // Start creating the Lattice - storm::analysis::Lattice *lattice = new storm::analysis::Lattice(topStates, bottomStates, numberOfStates); - storm::storage::BitVector oldStates(numberOfStates); - - // Create a copy of the states already present in the lattice. - storm::storage::BitVector seenStates = topStates|= bottomStates; - - while (oldStates != seenStates) { - // As long as new states are added to the lattice, continue. - oldStates = storm::storage::BitVector(seenStates); - - for (auto stateItr = stateMap.begin(); stateItr != stateMap.end(); ++stateItr) { - // Iterate over all states - auto stateNumber = stateItr->first; - storm::storage::BitVector successors = stateItr->second; - - // Check if current state has not been added yet, and all successors have - bool check = !seenStates[stateNumber]; - for (auto succIndex = successors.getNextSetIndex(0); check && succIndex != numberOfStates; succIndex = successors.getNextSetIndex(++succIndex)) { - check &= seenStates[succIndex]; - } - - if (check && successors.getNumberOfSetBits() == 1) { - // As there is only one successor the current state and its successor must be at the same nodes. - lattice->addToNode(stateNumber, lattice->getNode(successors.getNextSetIndex(0))); - seenStates.set(stateNumber); - } else if (check && successors.getNumberOfSetBits() > 1) { - // TODO: allow more than 2 transitions? - - // Otherwise, check how the two states compare, and add if the comparison is possible. - uint_fast64_t successor1 = successors.getNextSetIndex(0); - uint_fast64_t successor2 = successors.getNextSetIndex(successor1 + 1); - int compareResult = lattice->compare(successor1, successor2); - if (compareResult == 1) { - // successor 1 is closer to top than successor 2 - lattice->addBetween(stateNumber, lattice->getNode(successor1), - lattice->getNode(successor2)); - } else if (compareResult == 2) { - // successor 2 is closer to top than successor 1 - lattice->addBetween(stateNumber, lattice->getNode(successor2), - lattice->getNode(successor1)); - } else if (compareResult == 0) { - // the successors are at the same level - lattice->addToNode(stateNumber, lattice->getNode(successor1)); - } else { - // TODO: is this what we want? - lattice->add(stateNumber); - } - seenStates.set(stateNumber); - } - } - } - - return lattice; - } private: std::vector nodes; + storm::storage::BitVector addedStates; + Node* top; Node* bottom; diff --git a/src/storm-pars/analysis/LatticeExtender.cpp b/src/storm-pars/analysis/LatticeExtender.cpp new file mode 100644 index 000000000..2b1cc1a48 --- /dev/null +++ b/src/storm-pars/analysis/LatticeExtender.cpp @@ -0,0 +1,129 @@ +// +// Created by Jip Spel on 28.08.18. +// + +#include "LatticeExtender.h" +#include "storm/utility/macros.h" +#include "storm/storage/SparseMatrix.h" +#include "storm/utility/graph.h" +#include +#include +#include "storm/models/sparse/Model.h" + +#include "storm/exceptions/NotImplementedException.h" +#include "storm/exceptions/NotSupportedException.h" + +#include + +namespace storm { + namespace analysis { + + template + LatticeExtender::LatticeExtender(){//std::shared_ptr> model) { + //TODO + } + +// template +// storm::analysis::Lattice* LatticeExtender::toLattice(std::vector> formulas) { +// STORM_LOG_THROW((++formulas.begin()) == formulas.end(), storm::exceptions::NotSupportedException, "Only one formula allowed for monotonicity analysis"); +// STORM_LOG_THROW((*(formulas[0])).isProbabilityOperatorFormula() +// && ((*(formulas[0])).asProbabilityOperatorFormula().getSubformula().isUntilFormula() +// || (*(formulas[0])).asProbabilityOperatorFormula().getSubformula().isEventuallyFormula()), storm::exceptions::NotSupportedException, "Expecting until formula"); +// +// uint_fast64_t numberOfStates = this->model.getNumberOfStates(); +// +// storm::modelchecker::SparsePropositionalModelChecker> propositionalChecker(this->model); +// storm::storage::BitVector phiStates; +// storm::storage::BitVector psiStates; +// if ((*(formulas[0])).asProbabilityOperatorFormula().getSubformula().isUntilFormula()) { +// phiStates = propositionalChecker.check((*(formulas[0])).asProbabilityOperatorFormula().getSubformula().asUntilFormula().getLeftSubformula())->asExplicitQualitativeCheckResult().getTruthValuesVector(); +// psiStates = propositionalChecker.check((*(formulas[0])).asProbabilityOperatorFormula().getSubformula().asUntilFormula().getRightSubformula())->asExplicitQualitativeCheckResult().getTruthValuesVector(); +// } else { +// phiStates = storm::storage::BitVector(numberOfStates, true); +// psiStates = propositionalChecker.check((*(formulas[0])).asProbabilityOperatorFormula().getSubformula().asEventuallyFormula().getSubformula())->asExplicitQualitativeCheckResult().getTruthValuesVector(); +// } +// +// // Get the maybeStates +// std::pair statesWithProbability01 = storm::utility::graph::performProb01(this->model.getBackwardTransitions(), phiStates, psiStates); +// storm::storage::BitVector topStates = statesWithProbability01.second; +// storm::storage::BitVector bottomStates = statesWithProbability01.first; +// +// STORM_LOG_THROW(topStates.begin() != topStates.end(), storm::exceptions::NotImplementedException, "Formula yields to no 1 states"); +// STORM_LOG_THROW(bottomStates.begin() != bottomStates.end(), storm::exceptions::NotImplementedException, "Formula yields to no zero states"); +// +// // Transform to Lattice +// auto matrix = this->model.getTransitionMatrix(); +// +// for (uint_fast64_t i = 0; i < numberOfStates; ++i) { +// stateMap[i] = storm::storage::BitVector(numberOfStates, false); +// +// auto row = matrix.getRow(i); +// for (auto rowItr = row.begin(); rowItr != row.end(); ++rowItr) { +// stateMap[i].set(rowItr->getColumn(), true); +// } +// // TODO: allow more than 2 transitions? or fix this in preprocessing? +// STORM_LOG_THROW(stateMap[i].getNumberOfSetBits() <= 2, storm::exceptions::NotSupportedException, "Only two outgoing transitions per state allowed"); +// } +// +// // Create the Lattice +// storm::analysis::Lattice *lattice = new storm::analysis::Lattice(topStates, bottomStates, numberOfStates); +// return this->extendLattice(lattice, std::set({})); +// } +// +// template +// storm::analysis::Lattice* LatticeExtender::extendLattice(storm::analysis::Lattice* lattice, std::set assumptions) { +// uint_fast64_t numberOfStates = this->model.getNumberOfStates(); +// +// storm::storage::BitVector oldStates(numberOfStates); +// +// // Create a copy of the states already present in the lattice. +// storm::storage::BitVector seenStates = lattice->getAddedStates(); +// +// while (oldStates != seenStates) { +// // As long as new states are added to the lattice, continue. +// oldStates = storm::storage::BitVector(seenStates); +// +// for (auto stateItr = stateMap.begin(); stateItr != stateMap.end(); ++stateItr) { +// // Iterate over all states +// auto stateNumber = stateItr->first; +// storm::storage::BitVector successors = stateItr->second; +// +// // Check if current state has not been added yet, and all successors have +// bool check = !seenStates[stateNumber]; +// for (auto succIndex = successors.getNextSetIndex(0); check && succIndex != numberOfStates; succIndex = successors.getNextSetIndex(++succIndex)) { +// check &= seenStates[succIndex]; +// } +// +// if (check && successors.getNumberOfSetBits() == 1) { +// // As there is only one successor the current state and its successor must be at the same nodes. +// lattice->addToNode(stateNumber, lattice->getNode(successors.getNextSetIndex(0))); +// seenStates.set(stateNumber); +// } else if (check && successors.getNumberOfSetBits() > 1) { +// // TODO: allow more than 2 transitions? +// +// // Otherwise, check how the two states compare, and add if the comparison is possible. +// uint_fast64_t successor1 = successors.getNextSetIndex(0); +// uint_fast64_t successor2 = successors.getNextSetIndex(successor1 + 1); +// int compareResult = lattice->compare(successor1, successor2); +// if (compareResult == 1) { +// // successor 1 is closer to top than successor 2 +// lattice->addBetween(stateNumber, lattice->getNode(successor1), +// lattice->getNode(successor2)); +// } else if (compareResult == 2) { +// // successor 2 is closer to top than successor 1 +// lattice->addBetween(stateNumber, lattice->getNode(successor2), +// lattice->getNode(successor1)); +// } else if (compareResult == 0) { +// // the successors are at the same level +// lattice->addToNode(stateNumber, lattice->getNode(successor1)); +// } else { +// // TODO: create critical pair +// } +// seenStates.set(stateNumber); +// } +// } +// } +// return lattice; +// } + } +} \ No newline at end of file diff --git a/src/storm-pars/analysis/LatticeExtender.h b/src/storm-pars/analysis/LatticeExtender.h new file mode 100644 index 000000000..41b5da465 --- /dev/null +++ b/src/storm-pars/analysis/LatticeExtender.h @@ -0,0 +1,42 @@ +// +// Created by Jip Spel on 28.08.18. +// + +#ifndef STORM_LATTICEEXTENDER_H +#define STORM_LATTICEEXTENDER_H + +#include +#include "storm/models/sparse/Dtmc.h" +#include "storm-pars/analysis/Lattice.h" + + + +namespace storm { + namespace analysis { + + template + class LatticeExtender { + + public: + LatticeExtender(); + +// /*! +// * Creates a Lattice based on the transition matrix, topStates of the Lattice and bottomStates of the Lattice +// * @tparam ValueType Type of the probabilities +// * @param model The pointer to the model +// * @param formulas Vector with pointer to formula +// * @return pointer to the created Lattice. +// */ +// storm::analysis::Lattice* toLattice(std::vector> formulas); +// +// storm::analysis::Lattice* extendLattice(storm::analysis::Lattice* lattice, std::set assumptions); + + private: + std::shared_ptr> model; + + std::map stateMap; + }; + } +} + +#endif //STORM_LATTICEEXTENDER_H From b6e48b35cc18ab9040e04843dd58c54ffd0d3c8c Mon Sep 17 00:00:00 2001 From: Jip Spel Date: Wed, 29 Aug 2018 12:35:19 +0200 Subject: [PATCH 038/178] Implement first version of LatticeExtender --- src/storm-pars-cli/storm-pars.cpp | 5 +- src/storm-pars/analysis/Lattice.cpp | 2 + src/storm-pars/analysis/LatticeExtender.cpp | 218 ++++++++++---------- src/storm-pars/analysis/LatticeExtender.h | 24 +-- 4 files changed, 129 insertions(+), 120 deletions(-) diff --git a/src/storm-pars-cli/storm-pars.cpp b/src/storm-pars-cli/storm-pars.cpp index 96b13e6e0..5700e52e0 100644 --- a/src/storm-pars-cli/storm-pars.cpp +++ b/src/storm-pars-cli/storm-pars.cpp @@ -1,5 +1,6 @@ +#include "storm-pars/analysis/LatticeExtender.h" #include "storm-cli-utilities/cli.h" #include "storm-cli-utilities/model-handling.h" @@ -609,7 +610,9 @@ namespace storm { // Transform to Lattice storm::utility::Stopwatch latticeWatch(true); - storm::analysis::Lattice* lattice = storm::analysis::Lattice::toLattice(sparseModel, formulas); + + storm::analysis::LatticeExtender> extender = storm::analysis::LatticeExtender>(sparseModel); + storm::analysis::Lattice* lattice = extender.toLattice(formulas); latticeWatch.stop(); STORM_PRINT(std::endl << "Time for lattice creation: " << latticeWatch << "." << std::endl << std::endl); ofstream myfile; diff --git a/src/storm-pars/analysis/Lattice.cpp b/src/storm-pars/analysis/Lattice.cpp index 5adc1cbc3..6e04d82c2 100644 --- a/src/storm-pars/analysis/Lattice.cpp +++ b/src/storm-pars/analysis/Lattice.cpp @@ -25,6 +25,8 @@ namespace storm { } this->numberOfStates = numberOfStates; this->addedStates = storm::storage::BitVector(numberOfStates); + this->addedStates.operator|=(topStates); + this->addedStates.operator|=(bottomStates); } void Lattice::addBetween(uint_fast64_t state, Node *above, Node *below) { diff --git a/src/storm-pars/analysis/LatticeExtender.cpp b/src/storm-pars/analysis/LatticeExtender.cpp index 2b1cc1a48..d252149e3 100644 --- a/src/storm-pars/analysis/LatticeExtender.cpp +++ b/src/storm-pars/analysis/LatticeExtender.cpp @@ -9,121 +9,129 @@ #include #include #include "storm/models/sparse/Model.h" +#include "storm/modelchecker/results/CheckResult.h" +#include "storm/modelchecker/results/ExplicitQualitativeCheckResult.h" + #include "storm/exceptions/NotImplementedException.h" #include "storm/exceptions/NotSupportedException.h" #include +#include "storm/storage/BitVector.h" +#include "storm/utility/macros.h" + namespace storm { namespace analysis { - template - LatticeExtender::LatticeExtender(){//std::shared_ptr> model) { - //TODO + template + LatticeExtender::LatticeExtender(std::shared_ptr model) : model(model) { + // intentionally left empty } -// template -// storm::analysis::Lattice* LatticeExtender::toLattice(std::vector> formulas) { -// STORM_LOG_THROW((++formulas.begin()) == formulas.end(), storm::exceptions::NotSupportedException, "Only one formula allowed for monotonicity analysis"); -// STORM_LOG_THROW((*(formulas[0])).isProbabilityOperatorFormula() -// && ((*(formulas[0])).asProbabilityOperatorFormula().getSubformula().isUntilFormula() -// || (*(formulas[0])).asProbabilityOperatorFormula().getSubformula().isEventuallyFormula()), storm::exceptions::NotSupportedException, "Expecting until formula"); -// -// uint_fast64_t numberOfStates = this->model.getNumberOfStates(); -// -// storm::modelchecker::SparsePropositionalModelChecker> propositionalChecker(this->model); -// storm::storage::BitVector phiStates; -// storm::storage::BitVector psiStates; -// if ((*(formulas[0])).asProbabilityOperatorFormula().getSubformula().isUntilFormula()) { -// phiStates = propositionalChecker.check((*(formulas[0])).asProbabilityOperatorFormula().getSubformula().asUntilFormula().getLeftSubformula())->asExplicitQualitativeCheckResult().getTruthValuesVector(); -// psiStates = propositionalChecker.check((*(formulas[0])).asProbabilityOperatorFormula().getSubformula().asUntilFormula().getRightSubformula())->asExplicitQualitativeCheckResult().getTruthValuesVector(); -// } else { -// phiStates = storm::storage::BitVector(numberOfStates, true); -// psiStates = propositionalChecker.check((*(formulas[0])).asProbabilityOperatorFormula().getSubformula().asEventuallyFormula().getSubformula())->asExplicitQualitativeCheckResult().getTruthValuesVector(); -// } -// -// // Get the maybeStates -// std::pair statesWithProbability01 = storm::utility::graph::performProb01(this->model.getBackwardTransitions(), phiStates, psiStates); -// storm::storage::BitVector topStates = statesWithProbability01.second; -// storm::storage::BitVector bottomStates = statesWithProbability01.first; -// -// STORM_LOG_THROW(topStates.begin() != topStates.end(), storm::exceptions::NotImplementedException, "Formula yields to no 1 states"); -// STORM_LOG_THROW(bottomStates.begin() != bottomStates.end(), storm::exceptions::NotImplementedException, "Formula yields to no zero states"); -// -// // Transform to Lattice -// auto matrix = this->model.getTransitionMatrix(); -// -// for (uint_fast64_t i = 0; i < numberOfStates; ++i) { -// stateMap[i] = storm::storage::BitVector(numberOfStates, false); -// -// auto row = matrix.getRow(i); -// for (auto rowItr = row.begin(); rowItr != row.end(); ++rowItr) { -// stateMap[i].set(rowItr->getColumn(), true); -// } -// // TODO: allow more than 2 transitions? or fix this in preprocessing? -// STORM_LOG_THROW(stateMap[i].getNumberOfSetBits() <= 2, storm::exceptions::NotSupportedException, "Only two outgoing transitions per state allowed"); -// } -// -// // Create the Lattice -// storm::analysis::Lattice *lattice = new storm::analysis::Lattice(topStates, bottomStates, numberOfStates); -// return this->extendLattice(lattice, std::set({})); -// } -// -// template -// storm::analysis::Lattice* LatticeExtender::extendLattice(storm::analysis::Lattice* lattice, std::set assumptions) { -// uint_fast64_t numberOfStates = this->model.getNumberOfStates(); -// -// storm::storage::BitVector oldStates(numberOfStates); -// -// // Create a copy of the states already present in the lattice. -// storm::storage::BitVector seenStates = lattice->getAddedStates(); -// -// while (oldStates != seenStates) { -// // As long as new states are added to the lattice, continue. -// oldStates = storm::storage::BitVector(seenStates); -// -// for (auto stateItr = stateMap.begin(); stateItr != stateMap.end(); ++stateItr) { -// // Iterate over all states -// auto stateNumber = stateItr->first; -// storm::storage::BitVector successors = stateItr->second; -// -// // Check if current state has not been added yet, and all successors have -// bool check = !seenStates[stateNumber]; -// for (auto succIndex = successors.getNextSetIndex(0); check && succIndex != numberOfStates; succIndex = successors.getNextSetIndex(++succIndex)) { -// check &= seenStates[succIndex]; -// } -// -// if (check && successors.getNumberOfSetBits() == 1) { -// // As there is only one successor the current state and its successor must be at the same nodes. -// lattice->addToNode(stateNumber, lattice->getNode(successors.getNextSetIndex(0))); -// seenStates.set(stateNumber); -// } else if (check && successors.getNumberOfSetBits() > 1) { -// // TODO: allow more than 2 transitions? -// -// // Otherwise, check how the two states compare, and add if the comparison is possible. -// uint_fast64_t successor1 = successors.getNextSetIndex(0); -// uint_fast64_t successor2 = successors.getNextSetIndex(successor1 + 1); -// int compareResult = lattice->compare(successor1, successor2); -// if (compareResult == 1) { -// // successor 1 is closer to top than successor 2 -// lattice->addBetween(stateNumber, lattice->getNode(successor1), -// lattice->getNode(successor2)); -// } else if (compareResult == 2) { -// // successor 2 is closer to top than successor 1 -// lattice->addBetween(stateNumber, lattice->getNode(successor2), -// lattice->getNode(successor1)); -// } else if (compareResult == 0) { -// // the successors are at the same level -// lattice->addToNode(stateNumber, lattice->getNode(successor1)); -// } else { -// // TODO: create critical pair -// } -// seenStates.set(stateNumber); -// } -// } -// } -// return lattice; -// } + template + storm::analysis::Lattice* LatticeExtender::toLattice(std::vector> formulas) { + STORM_LOG_THROW((++formulas.begin()) == formulas.end(), storm::exceptions::NotSupportedException, "Only one formula allowed for monotonicity analysis"); + STORM_LOG_THROW((*(formulas[0])).isProbabilityOperatorFormula() + && ((*(formulas[0])).asProbabilityOperatorFormula().getSubformula().isUntilFormula() + || (*(formulas[0])).asProbabilityOperatorFormula().getSubformula().isEventuallyFormula()), storm::exceptions::NotSupportedException, "Expecting until formula"); + + uint_fast64_t numberOfStates = this->model.get()->getNumberOfStates(); + + storm::modelchecker::SparsePropositionalModelChecker propositionalChecker(*model); + storm::storage::BitVector phiStates; + storm::storage::BitVector psiStates; + if ((*(formulas[0])).asProbabilityOperatorFormula().getSubformula().isUntilFormula()) { + phiStates = propositionalChecker.check((*(formulas[0])).asProbabilityOperatorFormula().getSubformula().asUntilFormula().getLeftSubformula())->asExplicitQualitativeCheckResult().getTruthValuesVector(); + psiStates = propositionalChecker.check((*(formulas[0])).asProbabilityOperatorFormula().getSubformula().asUntilFormula().getRightSubformula())->asExplicitQualitativeCheckResult().getTruthValuesVector(); + } else { + phiStates = storm::storage::BitVector(numberOfStates, true); + psiStates = propositionalChecker.check((*(formulas[0])).asProbabilityOperatorFormula().getSubformula().asEventuallyFormula().getSubformula())->asExplicitQualitativeCheckResult().getTruthValuesVector(); + } + + // Get the maybeStates + std::pair statesWithProbability01 = storm::utility::graph::performProb01(this->model.get()->getBackwardTransitions(), phiStates, psiStates); + storm::storage::BitVector topStates = statesWithProbability01.second; + storm::storage::BitVector bottomStates = statesWithProbability01.first; + + STORM_LOG_THROW(topStates.begin() != topStates.end(), storm::exceptions::NotImplementedException, "Formula yields to no 1 states"); + STORM_LOG_THROW(bottomStates.begin() != bottomStates.end(), storm::exceptions::NotImplementedException, "Formula yields to no zero states"); + + // Transform to Lattice + auto matrix = this->model.get()->getTransitionMatrix(); + + for (uint_fast64_t i = 0; i < numberOfStates; ++i) { + stateMap[i] = storm::storage::BitVector(numberOfStates, false); + + auto row = matrix.getRow(i); + for (auto rowItr = row.begin(); rowItr != row.end(); ++rowItr) { + stateMap[i].set(rowItr->getColumn(), true); + } + // TODO: allow more than 2 transitions? or fix this in preprocessing? + STORM_LOG_THROW(stateMap[i].getNumberOfSetBits() <= 2, storm::exceptions::NotSupportedException, "Only two outgoing transitions per state allowed"); + } + + // Create the Lattice + storm::analysis::Lattice *lattice = new storm::analysis::Lattice(topStates, bottomStates, numberOfStates); + return this->extendLattice(lattice, std::set({})); + } + + template + storm::analysis::Lattice* LatticeExtender::extendLattice(storm::analysis::Lattice* lattice, std::set assumptions) { + uint_fast64_t numberOfStates = this->model.get()->getNumberOfStates(); + + storm::storage::BitVector oldStates(numberOfStates); + + // Create a copy of the states already present in the lattice. + storm::storage::BitVector seenStates = (lattice->getAddedStates()); + + while (oldStates != seenStates) { + // As long as new states are added to the lattice, continue. + oldStates = storm::storage::BitVector(seenStates); + + for (auto stateItr = stateMap.begin(); stateItr != stateMap.end(); ++stateItr) { + // Iterate over all states + auto stateNumber = stateItr->first; + storm::storage::BitVector successors = stateItr->second; + + // Check if current state has not been added yet, and all successors have + bool check = !seenStates[stateNumber]; + for (auto succIndex = successors.getNextSetIndex(0); check && succIndex != numberOfStates; succIndex = successors.getNextSetIndex(++succIndex)) { + check &= seenStates[succIndex]; + } + + if (check && successors.getNumberOfSetBits() == 1) { + // As there is only one successor the current state and its successor must be at the same nodes. + lattice->addToNode(stateNumber, lattice->getNode(successors.getNextSetIndex(0))); + seenStates.set(stateNumber); + } else if (check && successors.getNumberOfSetBits() > 1) { + // TODO: allow more than 2 transitions? + // Otherwise, check how the two states compare, and add if the comparison is possible. + uint_fast64_t successor1 = successors.getNextSetIndex(0); + uint_fast64_t successor2 = successors.getNextSetIndex(successor1 + 1); + int compareResult = lattice->compare(successor1, successor2); + if (compareResult == 1) { + // successor 1 is closer to top than successor 2 + lattice->addBetween(stateNumber, lattice->getNode(successor1), + lattice->getNode(successor2)); + } else if (compareResult == 2) { + // successor 2 is closer to top than successor 1 + lattice->addBetween(stateNumber, lattice->getNode(successor2), + lattice->getNode(successor1)); + } else if (compareResult == 0) { + // the successors are at the same level + lattice->addToNode(stateNumber, lattice->getNode(successor1)); + } else { + // TODO: create critical pair + } + seenStates.set(stateNumber); + } + } + } + return lattice; + } + + template class LatticeExtender>; +// template class LatticeExtender>; } } \ No newline at end of file diff --git a/src/storm-pars/analysis/LatticeExtender.h b/src/storm-pars/analysis/LatticeExtender.h index 41b5da465..e52a3417d 100644 --- a/src/storm-pars/analysis/LatticeExtender.h +++ b/src/storm-pars/analysis/LatticeExtender.h @@ -8,31 +8,27 @@ #include #include "storm/models/sparse/Dtmc.h" #include "storm-pars/analysis/Lattice.h" +#include "storm/api/storm.h" + namespace storm { namespace analysis { - template + + template class LatticeExtender { public: - LatticeExtender(); - -// /*! -// * Creates a Lattice based on the transition matrix, topStates of the Lattice and bottomStates of the Lattice -// * @tparam ValueType Type of the probabilities -// * @param model The pointer to the model -// * @param formulas Vector with pointer to formula -// * @return pointer to the created Lattice. -// */ -// storm::analysis::Lattice* toLattice(std::vector> formulas); -// -// storm::analysis::Lattice* extendLattice(storm::analysis::Lattice* lattice, std::set assumptions); + LatticeExtender(std::shared_ptr model); + + storm::analysis::Lattice* toLattice(std::vector> formulas); + + storm::analysis::Lattice* extendLattice(storm::analysis::Lattice* lattice, std::set assumptions); private: - std::shared_ptr> model; + std::shared_ptr model; std::map stateMap; }; From 34c87453fb9b63c317bfd11ff5550f55df0c9801 Mon Sep 17 00:00:00 2001 From: Jip Spel Date: Fri, 31 Aug 2018 11:24:45 +0200 Subject: [PATCH 039/178] Implement extension of lattice with assumptions --- src/storm-pars-cli/storm-pars.cpp | 13 ++++- src/storm-pars/analysis/Lattice.cpp | 21 ++++++-- src/storm-pars/analysis/Lattice.h | 10 ++++ src/storm-pars/analysis/LatticeExtender.cpp | 54 +++++++++++++++++---- src/storm-pars/analysis/LatticeExtender.h | 5 +- 5 files changed, 86 insertions(+), 17 deletions(-) diff --git a/src/storm-pars-cli/storm-pars.cpp b/src/storm-pars-cli/storm-pars.cpp index 5700e52e0..b14285761 100644 --- a/src/storm-pars-cli/storm-pars.cpp +++ b/src/storm-pars-cli/storm-pars.cpp @@ -513,6 +513,7 @@ namespace storm { color = "color = blue, "; } } + myfile << "\t" << i << " -> " << first.getColumn() << "[" << color << "label=\"" << first.getValue() << "\"];" << std::endl; myfile << "\t" << i << " -> " << second.getColumn() << "[" << color << "label=\"" << second.getValue() << "\"];" @@ -610,13 +611,21 @@ namespace storm { // Transform to Lattice storm::utility::Stopwatch latticeWatch(true); - storm::analysis::LatticeExtender> extender = storm::analysis::LatticeExtender>(sparseModel); storm::analysis::Lattice* lattice = extender.toLattice(formulas); + + // Declare variables for all states + std::shared_ptr expressionManager(new storm::expressions::ExpressionManager()); + for (uint_fast64_t i = 0; i < sparseModel.get()->getNumberOfStates(); ++i) { + expressionManager->declareFreshIntegerVariable(); + } +// std::set assumptions; +// extender.extendLattice(lattice, expressionManager, assumptions); latticeWatch.stop(); STORM_PRINT(std::endl << "Time for lattice creation: " << latticeWatch << "." << std::endl << std::endl); - ofstream myfile; + // Write lattice to file + ofstream myfile; myfile.open ("lattice.dot"); lattice->toDotFile(myfile); myfile.close(); diff --git a/src/storm-pars/analysis/Lattice.cpp b/src/storm-pars/analysis/Lattice.cpp index 6e04d82c2..67205c4fe 100644 --- a/src/storm-pars/analysis/Lattice.cpp +++ b/src/storm-pars/analysis/Lattice.cpp @@ -61,6 +61,11 @@ namespace storm { below->above.insert(between); } + void Lattice::addRelationNodes(storm::analysis::Lattice::Node *above, storm::analysis::Lattice::Node * below) { + above->below.insert(below); + below->above.insert(above); + } + int Lattice::compare(uint_fast64_t state1, uint_fast64_t state2) { Node *node1 = getNode(state1); Node *node2 = getNode(state2); @@ -68,25 +73,33 @@ namespace storm { // TODO: Wat als above(node1, node2) en above(node2, node1), dan moeten ze samengevoegd? if (node1 != nullptr && node2 != nullptr) { if (node1 == node2) { - return 0; + return SAME; } if (above(node1, node2)) { - return 1; + return ABOVE; } if (above(node2, node1)) { - return 2; + return BELOW; } } - return -1; + return UNKNOWN; } Lattice::Node *Lattice::getNode(uint_fast64_t stateNumber) { return nodes.at(stateNumber); } + Lattice::Node *Lattice::getTop() { + return top; + } + + Lattice::Node *Lattice::getBottom() { + return bottom; + } + storm::storage::BitVector Lattice::getAddedStates() { return addedStates; } diff --git a/src/storm-pars/analysis/Lattice.h b/src/storm-pars/analysis/Lattice.h index a5644db48..57fc43e13 100644 --- a/src/storm-pars/analysis/Lattice.h +++ b/src/storm-pars/analysis/Lattice.h @@ -63,6 +63,8 @@ namespace storm { */ void addRelation(Node* above, Node* between, Node* below); + void addRelationNodes(storm::analysis::Lattice::Node *above, storm::analysis::Lattice::Node * below); + /*! * Compares the level of the nodes of the states. * Behaviour unknown when one or more of the states doesnot occur at any Node in the Lattice. @@ -85,6 +87,10 @@ namespace storm { */ Node *getNode(uint_fast64_t state); + Node* getTop(); + + Node* getBottom(); + storm::storage::BitVector getAddedStates(); /*! @@ -101,6 +107,10 @@ namespace storm { */ void toDotFile(std::ostream &out); + static const int UNKNOWN = -1; + static const int BELOW = 2; + static const int ABOVE = 1; + static const int SAME = 0; private: std::vector nodes; diff --git a/src/storm-pars/analysis/LatticeExtender.cpp b/src/storm-pars/analysis/LatticeExtender.cpp index d252149e3..921e66d42 100644 --- a/src/storm-pars/analysis/LatticeExtender.cpp +++ b/src/storm-pars/analysis/LatticeExtender.cpp @@ -36,7 +36,7 @@ namespace storm { && ((*(formulas[0])).asProbabilityOperatorFormula().getSubformula().isUntilFormula() || (*(formulas[0])).asProbabilityOperatorFormula().getSubformula().isEventuallyFormula()), storm::exceptions::NotSupportedException, "Expecting until formula"); - uint_fast64_t numberOfStates = this->model.get()->getNumberOfStates(); + uint_fast64_t numberOfStates = this->model->getNumberOfStates(); storm::modelchecker::SparsePropositionalModelChecker propositionalChecker(*model); storm::storage::BitVector phiStates; @@ -50,7 +50,7 @@ namespace storm { } // Get the maybeStates - std::pair statesWithProbability01 = storm::utility::graph::performProb01(this->model.get()->getBackwardTransitions(), phiStates, psiStates); + std::pair statesWithProbability01 = storm::utility::graph::performProb01(this->model->getBackwardTransitions(), phiStates, psiStates); storm::storage::BitVector topStates = statesWithProbability01.second; storm::storage::BitVector bottomStates = statesWithProbability01.first; @@ -58,7 +58,7 @@ namespace storm { STORM_LOG_THROW(bottomStates.begin() != bottomStates.end(), storm::exceptions::NotImplementedException, "Formula yields to no zero states"); // Transform to Lattice - auto matrix = this->model.get()->getTransitionMatrix(); + auto matrix = this->model->getTransitionMatrix(); for (uint_fast64_t i = 0; i < numberOfStates; ++i) { stateMap[i] = storm::storage::BitVector(numberOfStates, false); @@ -73,18 +73,51 @@ namespace storm { // Create the Lattice storm::analysis::Lattice *lattice = new storm::analysis::Lattice(topStates, bottomStates, numberOfStates); - return this->extendLattice(lattice, std::set({})); + return this->extendLattice(lattice); } template - storm::analysis::Lattice* LatticeExtender::extendLattice(storm::analysis::Lattice* lattice, std::set assumptions) { - uint_fast64_t numberOfStates = this->model.get()->getNumberOfStates(); + storm::analysis::Lattice* LatticeExtender::extendLattice(storm::analysis::Lattice* lattice) { + std::shared_ptr expressionManager(new storm::expressions::ExpressionManager()); + std::set assumptions; + return this->extendLattice(lattice, expressionManager, assumptions); + } - storm::storage::BitVector oldStates(numberOfStates); + template + storm::analysis::Lattice* LatticeExtender::extendLattice(storm::analysis::Lattice* lattice, std::shared_ptr expressionManager, std::set assumptions) { + // First handle assumptions + for (auto itr = assumptions.begin(); itr != assumptions.end(); ++itr) { + storm::expressions::BinaryRelationExpression expr = *(*itr); + STORM_LOG_THROW(expr.getRelationType() == storm::expressions::BinaryRelationExpression::RelationType::Greater, storm::exceptions::NotImplementedException, "Only greater assumptions allowed"); + if (expr.getFirstOperand()->isVariable() && expr.getSecondOperand()->isVariable()) { + storm::expressions::Variable largest = expr.getFirstOperand()->asVariableExpression().getVariable(); + storm::expressions::Variable smallest = expr.getSecondOperand()->asVariableExpression().getVariable(); + + if (lattice->compare(largest.getOffset(), smallest.getOffset()) != storm::analysis::Lattice::ABOVE) { + storm::analysis::Lattice::Node* n1 = lattice->getNode(largest.getOffset()); + storm::analysis::Lattice::Node* n2 = lattice->getNode(smallest.getOffset()); + + if (n1 != nullptr && n2 != nullptr) { + lattice->addRelationNodes(n1, n2); + } else if (n1 != nullptr) { + lattice->addBetween(smallest.getOffset(), n1, lattice->getBottom()); + } else if (n2 != nullptr) { + lattice->addBetween(largest.getOffset(), lattice->getTop(), n2); + } else { + lattice->add(largest.getOffset()); + lattice->addBetween(smallest.getOffset(), lattice->getNode(largest.getOffset()), + lattice->getBottom()); + } + } + } + } // Create a copy of the states already present in the lattice. storm::storage::BitVector seenStates = (lattice->getAddedStates()); + auto numberOfStates = this->model->getNumberOfStates(); + storm::storage::BitVector oldStates(numberOfStates); + while (oldStates != seenStates) { // As long as new states are added to the lattice, continue. oldStates = storm::storage::BitVector(seenStates); @@ -110,15 +143,15 @@ namespace storm { uint_fast64_t successor1 = successors.getNextSetIndex(0); uint_fast64_t successor2 = successors.getNextSetIndex(successor1 + 1); int compareResult = lattice->compare(successor1, successor2); - if (compareResult == 1) { + if (compareResult == storm::analysis::Lattice::ABOVE) { // successor 1 is closer to top than successor 2 lattice->addBetween(stateNumber, lattice->getNode(successor1), lattice->getNode(successor2)); - } else if (compareResult == 2) { + } else if (compareResult == storm::analysis::Lattice::BELOW) { // successor 2 is closer to top than successor 1 lattice->addBetween(stateNumber, lattice->getNode(successor2), lattice->getNode(successor1)); - } else if (compareResult == 0) { + } else if (compareResult == storm::analysis::Lattice::SAME) { // the successors are at the same level lattice->addToNode(stateNumber, lattice->getNode(successor1)); } else { @@ -128,6 +161,7 @@ namespace storm { } } } + // TODO allow returning critical pair return lattice; } diff --git a/src/storm-pars/analysis/LatticeExtender.h b/src/storm-pars/analysis/LatticeExtender.h index e52a3417d..37c39dc2a 100644 --- a/src/storm-pars/analysis/LatticeExtender.h +++ b/src/storm-pars/analysis/LatticeExtender.h @@ -25,12 +25,15 @@ namespace storm { storm::analysis::Lattice* toLattice(std::vector> formulas); - storm::analysis::Lattice* extendLattice(storm::analysis::Lattice* lattice, std::set assumptions); + storm::analysis::Lattice* extendLattice(storm::analysis::Lattice* lattice, std::shared_ptr expressionManager, std::set assumptions); private: std::shared_ptr model; std::map stateMap; + + storm::analysis::Lattice* extendLattice(storm::analysis::Lattice* lattice); + }; } } From 43eebf8e056c3d4eb1e53ef29a8ac235fc37d761 Mon Sep 17 00:00:00 2001 From: Jip Spel Date: Fri, 31 Aug 2018 12:35:14 +0200 Subject: [PATCH 040/178] Return tuple and add assumptions --- src/storm-pars-cli/storm-pars.cpp | 22 ++++++++++++++++----- src/storm-pars/analysis/Lattice.h | 3 --- src/storm-pars/analysis/LatticeExtender.cpp | 17 +++++++--------- src/storm-pars/analysis/LatticeExtender.h | 6 +++--- 4 files changed, 27 insertions(+), 21 deletions(-) diff --git a/src/storm-pars-cli/storm-pars.cpp b/src/storm-pars-cli/storm-pars.cpp index b14285761..06f5a18c9 100644 --- a/src/storm-pars-cli/storm-pars.cpp +++ b/src/storm-pars-cli/storm-pars.cpp @@ -612,15 +612,27 @@ namespace storm { // Transform to Lattice storm::utility::Stopwatch latticeWatch(true); storm::analysis::LatticeExtender> extender = storm::analysis::LatticeExtender>(sparseModel); - storm::analysis::Lattice* lattice = extender.toLattice(formulas); + std::tuple criticalPair = extender.toLattice(formulas); // Declare variables for all states std::shared_ptr expressionManager(new storm::expressions::ExpressionManager()); - for (uint_fast64_t i = 0; i < sparseModel.get()->getNumberOfStates(); ++i) { + for (uint_fast64_t i = 0; i < sparseModel->getNumberOfStates(); ++i) { expressionManager->declareFreshIntegerVariable(); } -// std::set assumptions; -// extender.extendLattice(lattice, expressionManager, assumptions); + + // Make assumptions + std::set assumptions; + while (std::get<1>(criticalPair) != sparseModel->getNumberOfStates()) { + storm::expressions::Variable var1 = expressionManager->getVariable("_x" + std::to_string(std::get<1>(criticalPair))); + storm::expressions::Variable var2 = expressionManager->getVariable("_x" + std::to_string(std::get<2>(criticalPair))); + auto assumption = new storm::expressions::BinaryRelationExpression(*expressionManager, var1.getType(), + var1.getExpression().getBaseExpressionPointer(), var2.getExpression().getBaseExpressionPointer(), + storm::expressions::BinaryRelationExpression::RelationType::Greater); + assumptions.insert(assumption); + criticalPair = extender.extendLattice(std::get<0>(criticalPair), expressionManager, assumptions); + } + auto lattice = std::get<0>(criticalPair); + latticeWatch.stop(); STORM_PRINT(std::endl << "Time for lattice creation: " << latticeWatch << "." << std::endl << std::endl); @@ -631,7 +643,7 @@ namespace storm { myfile.close(); // Monotonicity? - auto matrix = sparseModel.get()->getTransitionMatrix(); + auto matrix = sparseModel->getTransitionMatrix(); storm::utility::Stopwatch monotonicityWatch(true); std::map> varsMonotone = analyseMonotonicity(lattice, matrix); monotonicityWatch.stop(); diff --git a/src/storm-pars/analysis/Lattice.h b/src/storm-pars/analysis/Lattice.h index 57fc43e13..dcfa8c552 100644 --- a/src/storm-pars/analysis/Lattice.h +++ b/src/storm-pars/analysis/Lattice.h @@ -11,9 +11,6 @@ #include "storm/storage/BitVector.h" - - - namespace storm { namespace analysis { class Lattice { diff --git a/src/storm-pars/analysis/LatticeExtender.cpp b/src/storm-pars/analysis/LatticeExtender.cpp index 921e66d42..fdb4471a8 100644 --- a/src/storm-pars/analysis/LatticeExtender.cpp +++ b/src/storm-pars/analysis/LatticeExtender.cpp @@ -30,7 +30,7 @@ namespace storm { } template - storm::analysis::Lattice* LatticeExtender::toLattice(std::vector> formulas) { + std::tuple LatticeExtender::toLattice(std::vector> formulas) { STORM_LOG_THROW((++formulas.begin()) == formulas.end(), storm::exceptions::NotSupportedException, "Only one formula allowed for monotonicity analysis"); STORM_LOG_THROW((*(formulas[0])).isProbabilityOperatorFormula() && ((*(formulas[0])).asProbabilityOperatorFormula().getSubformula().isUntilFormula() @@ -77,14 +77,15 @@ namespace storm { } template - storm::analysis::Lattice* LatticeExtender::extendLattice(storm::analysis::Lattice* lattice) { + std::tuple LatticeExtender::extendLattice(storm::analysis::Lattice* lattice) { std::shared_ptr expressionManager(new storm::expressions::ExpressionManager()); std::set assumptions; return this->extendLattice(lattice, expressionManager, assumptions); } template - storm::analysis::Lattice* LatticeExtender::extendLattice(storm::analysis::Lattice* lattice, std::shared_ptr expressionManager, std::set assumptions) { + std::tuple LatticeExtender::extendLattice(storm::analysis::Lattice* lattice, std::shared_ptr expressionManager, std::set assumptions) { + auto numberOfStates = this->model->getNumberOfStates(); // First handle assumptions for (auto itr = assumptions.begin(); itr != assumptions.end(); ++itr) { storm::expressions::BinaryRelationExpression expr = *(*itr); @@ -114,8 +115,6 @@ namespace storm { // Create a copy of the states already present in the lattice. storm::storage::BitVector seenStates = (lattice->getAddedStates()); - - auto numberOfStates = this->model->getNumberOfStates(); storm::storage::BitVector oldStates(numberOfStates); while (oldStates != seenStates) { @@ -155,17 +154,15 @@ namespace storm { // the successors are at the same level lattice->addToNode(stateNumber, lattice->getNode(successor1)); } else { - // TODO: create critical pair + return std::make_tuple(lattice, successor1, successor2); } seenStates.set(stateNumber); } } } - // TODO allow returning critical pair - return lattice; + return std::make_tuple(lattice, numberOfStates, numberOfStates); } template class LatticeExtender>; -// template class LatticeExtender>; } -} \ No newline at end of file +} diff --git a/src/storm-pars/analysis/LatticeExtender.h b/src/storm-pars/analysis/LatticeExtender.h index 37c39dc2a..9c854b4f5 100644 --- a/src/storm-pars/analysis/LatticeExtender.h +++ b/src/storm-pars/analysis/LatticeExtender.h @@ -23,16 +23,16 @@ namespace storm { public: LatticeExtender(std::shared_ptr model); - storm::analysis::Lattice* toLattice(std::vector> formulas); + std::tuple toLattice(std::vector> formulas); - storm::analysis::Lattice* extendLattice(storm::analysis::Lattice* lattice, std::shared_ptr expressionManager, std::set assumptions); + std::tuple extendLattice(storm::analysis::Lattice* lattice, std::shared_ptr expressionManager, std::set assumptions); private: std::shared_ptr model; std::map stateMap; - storm::analysis::Lattice* extendLattice(storm::analysis::Lattice* lattice); + std::tuple extendLattice(storm::analysis::Lattice* lattice); }; } From 2a93b89c220c2d88b5254f6f16e21dfeee5802e3 Mon Sep 17 00:00:00 2001 From: Jip Spel Date: Wed, 5 Sep 2018 15:53:21 +0200 Subject: [PATCH 041/178] Create AssumptionMaker --- src/storm-pars-cli/storm-pars.cpp | 28 ++--- src/storm-pars/analysis/AssumptionMaker.cpp | 97 +++++++++++++++++ src/storm-pars/analysis/AssumptionMaker.h | 34 ++++++ src/storm-pars/analysis/Lattice.cpp | 111 ++++++++++---------- src/storm-pars/analysis/Lattice.h | 9 +- src/storm-pars/analysis/LatticeExtender.cpp | 41 ++++---- src/storm-pars/analysis/LatticeExtender.h | 8 +- 7 files changed, 228 insertions(+), 100 deletions(-) create mode 100644 src/storm-pars/analysis/AssumptionMaker.cpp create mode 100644 src/storm-pars/analysis/AssumptionMaker.h diff --git a/src/storm-pars-cli/storm-pars.cpp b/src/storm-pars-cli/storm-pars.cpp index 06f5a18c9..c44e8a8f8 100644 --- a/src/storm-pars-cli/storm-pars.cpp +++ b/src/storm-pars-cli/storm-pars.cpp @@ -1,6 +1,7 @@ #include "storm-pars/analysis/LatticeExtender.h" +#include "storm-pars/analysis/AssumptionMaker.h" #include "storm-cli-utilities/cli.h" #include "storm-cli-utilities/model-handling.h" @@ -611,27 +612,16 @@ namespace storm { // Transform to Lattice storm::utility::Stopwatch latticeWatch(true); - storm::analysis::LatticeExtender> extender = storm::analysis::LatticeExtender>(sparseModel); - std::tuple criticalPair = extender.toLattice(formulas); + storm::analysis::LatticeExtender *extender = new storm::analysis::LatticeExtender(sparseModel); + std::tuple criticalPair = extender->toLattice(formulas); - // Declare variables for all states - std::shared_ptr expressionManager(new storm::expressions::ExpressionManager()); - for (uint_fast64_t i = 0; i < sparseModel->getNumberOfStates(); ++i) { - expressionManager->declareFreshIntegerVariable(); - } + // TODO met assumptionmaker dingen doen - // Make assumptions - std::set assumptions; - while (std::get<1>(criticalPair) != sparseModel->getNumberOfStates()) { - storm::expressions::Variable var1 = expressionManager->getVariable("_x" + std::to_string(std::get<1>(criticalPair))); - storm::expressions::Variable var2 = expressionManager->getVariable("_x" + std::to_string(std::get<2>(criticalPair))); - auto assumption = new storm::expressions::BinaryRelationExpression(*expressionManager, var1.getType(), - var1.getExpression().getBaseExpressionPointer(), var2.getExpression().getBaseExpressionPointer(), - storm::expressions::BinaryRelationExpression::RelationType::Greater); - assumptions.insert(assumption); - criticalPair = extender.extendLattice(std::get<0>(criticalPair), expressionManager, assumptions); - } - auto lattice = std::get<0>(criticalPair); + + auto assumptionMaker = storm::analysis::AssumptionMaker(extender, sparseModel->getNumberOfStates()); + std::map>> result = assumptionMaker.startMakingAssumptions(std::get<0>(criticalPair), std::get<1>(criticalPair), std::get<2>(criticalPair)); + + auto lattice = result.begin()->first; latticeWatch.stop(); STORM_PRINT(std::endl << "Time for lattice creation: " << latticeWatch << "." << std::endl << std::endl); diff --git a/src/storm-pars/analysis/AssumptionMaker.cpp b/src/storm-pars/analysis/AssumptionMaker.cpp new file mode 100644 index 000000000..7124748b2 --- /dev/null +++ b/src/storm-pars/analysis/AssumptionMaker.cpp @@ -0,0 +1,97 @@ +// +// Created by Jip Spel on 03.09.18. +// + +#include "AssumptionMaker.h" + +namespace storm { + namespace analysis { + template + AssumptionMaker::AssumptionMaker(storm::analysis::LatticeExtender* latticeExtender, uint_fast64_t numberOfStates) { + this->latticeExtender = latticeExtender; + this->numberOfStates = numberOfStates; + this->expressionManager = std::make_shared(storm::expressions::ExpressionManager()); + for (uint_fast64_t i = 0; i < this->numberOfStates; ++i) { + expressionManager->declareIntegerVariable(std::to_string(i)); + expressionManager->declareFreshIntegerVariable(); + } + } + + + template + std::map>> + AssumptionMaker::startMakingAssumptions(storm::analysis::Lattice* lattice, uint_fast64_t critical1, uint_fast64_t critical2) { + + std::map>> result; + + std::set> emptySet; + if (critical1 == numberOfStates || critical2 == numberOfStates) { + result.insert(std::pair>>(lattice, emptySet)); + } else { + storm::expressions::Variable var1 = expressionManager->getVariable(std::to_string(critical1)); + storm::expressions::Variable var2 = expressionManager->getVariable(std::to_string(critical2)); + std::set> assumptions1; + std::shared_ptr assumption1 + = std::make_shared(storm::expressions::BinaryRelationExpression(*expressionManager, var1.getType(), + var1.getExpression().getBaseExpressionPointer(), var2.getExpression().getBaseExpressionPointer(), + storm::expressions::BinaryRelationExpression::RelationType::Greater)); + assumptions1.insert(assumption1); + auto lattice1 = new storm::analysis::Lattice(*lattice); + auto myMap = (runRecursive(lattice1, assumptions1)); + result.insert(myMap.begin(), myMap.end()); + + std::set> assumptions2; + std::shared_ptr assumption2 + = std::make_shared(storm::expressions::BinaryRelationExpression(*expressionManager, var1.getType(), + var2.getExpression().getBaseExpressionPointer(), var1.getExpression().getBaseExpressionPointer(), + storm::expressions::BinaryRelationExpression::RelationType::Greater)); + assumptions2.insert(assumption2); + + auto lattice2 = new storm::analysis::Lattice(*lattice); + auto myMap2 = (runRecursive(lattice2, assumptions2)); + result.insert(myMap2.begin(), myMap2.end()); + } + return result; + } + + template + std::map>> AssumptionMaker::runRecursive(storm::analysis::Lattice* lattice, std::set> assumptions) { + std::map>> result; + std::tuple criticalPair = this->latticeExtender->extendLattice(lattice, assumptions); + + if (std::get<1>(criticalPair) == numberOfStates) { + result.insert(std::pair>>(lattice, assumptions)); + } else { + storm::expressions::Variable var1 = expressionManager->getVariable(std::to_string(std::get<1>(criticalPair))); + storm::expressions::Variable var2 = expressionManager->getVariable(std::to_string(std::get<2>(criticalPair))); + + std::set> assumptions1 = std::set>(assumptions); + std::shared_ptr assumption1 = std::make_shared(storm::expressions::BinaryRelationExpression(*expressionManager, var1.getType(), + var1.getExpression().getBaseExpressionPointer(), var2.getExpression().getBaseExpressionPointer(), + storm::expressions::BinaryRelationExpression::RelationType::Greater)); + assumptions1.insert(assumption1); + auto lattice1 = new storm::analysis::Lattice(*lattice); + auto myMap = (runRecursive(lattice1, assumptions1)); + result.insert(myMap.begin(), myMap.end()); + + + std::set> assumptions2 = assumptions; + std::shared_ptr assumption2 = std::make_shared(storm::expressions::BinaryRelationExpression(*expressionManager, var1.getType(), + var2.getExpression().getBaseExpressionPointer(), var1.getExpression().getBaseExpressionPointer(), + storm::expressions::BinaryRelationExpression::RelationType::Greater)) ; + assumptions2.insert(assumption2); + auto lattice2 = new storm::analysis::Lattice(*lattice); + myMap = (runRecursive(lattice2, assumptions2)); + result.insert(myMap.begin(), myMap.end()); + } + + return result; + } + + + template class AssumptionMaker; + } +} + + +// Een map met daarin een pointer naar de lattic en een set met de geldende assumptions voor die lattice \ No newline at end of file diff --git a/src/storm-pars/analysis/AssumptionMaker.h b/src/storm-pars/analysis/AssumptionMaker.h new file mode 100644 index 000000000..0472d2fbc --- /dev/null +++ b/src/storm-pars/analysis/AssumptionMaker.h @@ -0,0 +1,34 @@ +// +// Created by Jip Spel on 03.09.18. +// + +#ifndef STORM_ASSUMPTIONMAKER_H +#define STORM_ASSUMPTIONMAKER_H + +#include "Lattice.h" +#include "storm/storage/expressions/BinaryRelationExpression.h" +#include "LatticeExtender.h" + +namespace storm { + namespace analysis { + + template + class AssumptionMaker { + public: + AssumptionMaker(storm::analysis::LatticeExtender* latticeExtender, uint_fast64_t numberOfStates); + + std::map>> startMakingAssumptions(storm::analysis::Lattice* lattice, uint_fast64_t critical1, uint_fast64_t critical2); + + + private: + std::map>> runRecursive(storm::analysis::Lattice* lattice, std::set> assumptions); + + storm::analysis::LatticeExtender* latticeExtender; + + std::shared_ptr expressionManager; + + uint_fast64_t numberOfStates; + }; + } +} +#endif //STORM_ASSUMPTIONMAKER_H diff --git a/src/storm-pars/analysis/Lattice.cpp b/src/storm-pars/analysis/Lattice.cpp index 67205c4fe..189cff147 100644 --- a/src/storm-pars/analysis/Lattice.cpp +++ b/src/storm-pars/analysis/Lattice.cpp @@ -76,11 +76,13 @@ namespace storm { return SAME; } - if (above(node1, node2)) { + std::set* seen1 = new std::set({}); + if (above(node1, node2, seen1)) { return ABOVE; } - if (above(node2, node1)) { + std::set* seen2 = new std::set({}); + if (above(node2, node1, seen2)) { return BELOW; } } @@ -108,7 +110,7 @@ namespace storm { std::vector printedNodes = std::vector({}); for (auto itr = nodes.begin(); itr != nodes.end(); ++itr) { - if (std::find(printedNodes.begin(), printedNodes.end(), (*itr)) == printedNodes.end()) { + if ((*itr) != nullptr && std::find(printedNodes.begin(), printedNodes.end(), (*itr)) == printedNodes.end()) { Node *node = *itr; printedNodes.push_back(*itr); out << "Node: {"; @@ -123,24 +125,23 @@ namespace storm { out << "}" << "\n"; out << " Address: " << node << "\n"; out << " Above: {"; - for (auto itr2 = node->above.begin(); itr2 != node->above.end(); ++itr2) { - Node *above = *itr2; - out << "{"; - index = above->states.getNextSetIndex(0); - while (index < numberOfStates) { - out << index; - index = above->states.getNextSetIndex(index + 1); - if (index < numberOfStates) { - out << ", "; + + for (auto itr2 = node->above.begin(); itr2 != node->above.end(); ++itr2) { + Node *above = *itr2; + index = above->states.getNextSetIndex(0); + out << "{"; + while (index < numberOfStates) { + out << index; + index = above->states.getNextSetIndex(index + 1); + if (index < numberOfStates) { + out << ", "; + } } - } - out << "}"; - if ((++itr2) != node->above.end()) { - out << ", "; + out << "}"; } - } - out << "}" << "\n"; + out << "}" << "\n"; + out << " Below: {"; for (auto itr2 = node->below.begin(); itr2 != node->below.end(); ++itr2) { @@ -156,9 +157,6 @@ namespace storm { } out << "}"; - if ((++itr2) != node->below.end()) { - out << ", "; - } } out << "}" << "\n"; } @@ -166,50 +164,53 @@ namespace storm { } void Lattice::toDotFile(std::ostream &out) { - out << "digraph \"Lattice\" {" << std::endl; - - // print all nodes - std::vector printed; - out << "\t" << "node [shape=ellipse]" << std::endl; - for (auto itr = nodes.begin(); itr != nodes.end(); ++itr) { - if (find(printed.begin(), printed.end(), (*itr)) == printed.end()) { - out << "\t\"" << (*itr) << "\" [label = \""; - uint_fast64_t index = (*itr)->states.getNextSetIndex(0); - while (index < numberOfStates) { - out << index; - index = (*itr)->states.getNextSetIndex(index + 1); - if (index < numberOfStates) { - out << ", "; - } + out << "digraph \"Lattice\" {" << std::endl; + + // print all nodes + std::vector printed; + out << "\t" << "node [shape=ellipse]" << std::endl; + for (auto itr = nodes.begin(); itr != nodes.end(); ++itr) { + + if ((*itr) != nullptr && find(printed.begin(), printed.end(), (*itr)) == printed.end()) { + out << "\t\"" << (*itr) << "\" [label = \""; + uint_fast64_t index = (*itr)->states.getNextSetIndex(0); + while (index < numberOfStates) { + out << index; + index = (*itr)->states.getNextSetIndex(index + 1); + if (index < numberOfStates) { + out << ", "; } - - out << "\"]" << std::endl; - printed.push_back(*itr); } + + out << "\"]" << std::endl; + printed.push_back(*itr); } + } - // print arcs - printed.clear(); - for (auto itr = nodes.begin(); itr != nodes.end(); ++itr) { - if (find(printed.begin(), printed.end(), (*itr)) == printed.end()) { - auto below = (*itr)->below; - for (auto itr2 = below.begin(); itr2 != below.end(); ++itr2) { - out << "\t\"" << (*itr) << "\" -> \"" << (*itr2) << "\";" << std::endl; - } - printed.push_back(*itr); + // print arcs + printed.clear(); + for (auto itr = nodes.begin(); itr != nodes.end(); ++itr) { + if ((*itr) != nullptr && find(printed.begin(), printed.end(), (*itr)) == printed.end()) { + auto below = (*itr)->below; + for (auto itr2 = below.begin(); itr2 != below.end(); ++itr2) { + out << "\t\"" << (*itr) << "\" -> \"" << (*itr2) << "\";" << std::endl; } + printed.push_back(*itr); } - - out << "}" << std::endl; } - bool Lattice::above(Node *node1, Node *node2) { - bool result = !node1->below.empty() && std::find(node1->below.begin(), node1->below.end(), node2) != node1->below.end(); + out << "}" << std::endl; + } - for (auto itr = node1->below.begin(); !result && node1->below.end() != itr; ++itr) { - result |= above(*itr, node2); + bool Lattice::above(Node *node1, Node *node2, std::set* seenNodes) { + bool result = !node1->below.empty() && std::find(node1->below.begin(), node1->below.end(), node2) != node1->below.end(); + for (auto itr = node1->below.begin(); !result && node1->below.end() != itr; ++itr) { + if (std::find(seenNodes->begin(), seenNodes->end(), (*itr)) == seenNodes->end()) { + seenNodes->insert(*itr); + result |= above(*itr, node2, seenNodes); } - return result; } + return result; } } +} diff --git a/src/storm-pars/analysis/Lattice.h b/src/storm-pars/analysis/Lattice.h index dcfa8c552..3d36b9120 100644 --- a/src/storm-pars/analysis/Lattice.h +++ b/src/storm-pars/analysis/Lattice.h @@ -120,7 +120,14 @@ namespace storm { uint_fast64_t numberOfStates; - bool above(Node *, Node *); + /** + * Check if node1 lies above node2 + * @param node1 + * @param node2 + * @param seenNodes + * @return + */ + bool above(Node * node1, Node * node2, std::set* seenNodes); }; } } diff --git a/src/storm-pars/analysis/LatticeExtender.cpp b/src/storm-pars/analysis/LatticeExtender.cpp index fdb4471a8..f3e7f2476 100644 --- a/src/storm-pars/analysis/LatticeExtender.cpp +++ b/src/storm-pars/analysis/LatticeExtender.cpp @@ -24,13 +24,13 @@ namespace storm { namespace analysis { - template - LatticeExtender::LatticeExtender(std::shared_ptr model) : model(model) { + template + LatticeExtender::LatticeExtender(std::shared_ptr> model) : model(model) { // intentionally left empty } - template - std::tuple LatticeExtender::toLattice(std::vector> formulas) { + template + std::tuple LatticeExtender::toLattice(std::vector> formulas) { STORM_LOG_THROW((++formulas.begin()) == formulas.end(), storm::exceptions::NotSupportedException, "Only one formula allowed for monotonicity analysis"); STORM_LOG_THROW((*(formulas[0])).isProbabilityOperatorFormula() && ((*(formulas[0])).asProbabilityOperatorFormula().getSubformula().isUntilFormula() @@ -38,7 +38,7 @@ namespace storm { uint_fast64_t numberOfStates = this->model->getNumberOfStates(); - storm::modelchecker::SparsePropositionalModelChecker propositionalChecker(*model); + storm::modelchecker::SparsePropositionalModelChecker> propositionalChecker(*model); storm::storage::BitVector phiStates; storm::storage::BitVector psiStates; if ((*(formulas[0])).asProbabilityOperatorFormula().getSubformula().isUntilFormula()) { @@ -76,15 +76,14 @@ namespace storm { return this->extendLattice(lattice); } - template - std::tuple LatticeExtender::extendLattice(storm::analysis::Lattice* lattice) { - std::shared_ptr expressionManager(new storm::expressions::ExpressionManager()); - std::set assumptions; - return this->extendLattice(lattice, expressionManager, assumptions); + template + std::tuple LatticeExtender::extendLattice(storm::analysis::Lattice* lattice) { + std::set> assumptions; + return this->extendLattice(lattice, assumptions); } - template - std::tuple LatticeExtender::extendLattice(storm::analysis::Lattice* lattice, std::shared_ptr expressionManager, std::set assumptions) { + template + std::tuple LatticeExtender::extendLattice(storm::analysis::Lattice* lattice, std::set> assumptions) { auto numberOfStates = this->model->getNumberOfStates(); // First handle assumptions for (auto itr = assumptions.begin(); itr != assumptions.end(); ++itr) { @@ -93,20 +92,19 @@ namespace storm { if (expr.getFirstOperand()->isVariable() && expr.getSecondOperand()->isVariable()) { storm::expressions::Variable largest = expr.getFirstOperand()->asVariableExpression().getVariable(); storm::expressions::Variable smallest = expr.getSecondOperand()->asVariableExpression().getVariable(); - - if (lattice->compare(largest.getOffset(), smallest.getOffset()) != storm::analysis::Lattice::ABOVE) { - storm::analysis::Lattice::Node* n1 = lattice->getNode(largest.getOffset()); - storm::analysis::Lattice::Node* n2 = lattice->getNode(smallest.getOffset()); + if (lattice->compare(std::stoul(largest.getName(), nullptr, 0), std::stoul(smallest.getName(), nullptr, 0)) != storm::analysis::Lattice::ABOVE) { + storm::analysis::Lattice::Node* n1 = lattice->getNode(std::stoul(largest.getName(), nullptr, 0)); + storm::analysis::Lattice::Node* n2 = lattice->getNode(std::stoul(smallest.getName(), nullptr, 0)); if (n1 != nullptr && n2 != nullptr) { lattice->addRelationNodes(n1, n2); } else if (n1 != nullptr) { - lattice->addBetween(smallest.getOffset(), n1, lattice->getBottom()); + lattice->addBetween(std::stoul(smallest.getName(), nullptr, 0), n1, lattice->getBottom()); } else if (n2 != nullptr) { - lattice->addBetween(largest.getOffset(), lattice->getTop(), n2); + lattice->addBetween(std::stoul(largest.getName(), nullptr, 0), lattice->getTop(), n2); } else { - lattice->add(largest.getOffset()); - lattice->addBetween(smallest.getOffset(), lattice->getNode(largest.getOffset()), + lattice->add(std::stoul(largest.getName(), nullptr, 0)); + lattice->addBetween(std::stoul(smallest.getName(), nullptr, 0), lattice->getNode(std::stoul(largest.getName(), nullptr, 0)), lattice->getBottom()); } } @@ -141,6 +139,7 @@ namespace storm { // Otherwise, check how the two states compare, and add if the comparison is possible. uint_fast64_t successor1 = successors.getNextSetIndex(0); uint_fast64_t successor2 = successors.getNextSetIndex(successor1 + 1); + int compareResult = lattice->compare(successor1, successor2); if (compareResult == storm::analysis::Lattice::ABOVE) { // successor 1 is closer to top than successor 2 @@ -163,6 +162,6 @@ namespace storm { return std::make_tuple(lattice, numberOfStates, numberOfStates); } - template class LatticeExtender>; + template class LatticeExtender; } } diff --git a/src/storm-pars/analysis/LatticeExtender.h b/src/storm-pars/analysis/LatticeExtender.h index 9c854b4f5..72d91a8c1 100644 --- a/src/storm-pars/analysis/LatticeExtender.h +++ b/src/storm-pars/analysis/LatticeExtender.h @@ -17,18 +17,18 @@ namespace storm { namespace analysis { - template + template class LatticeExtender { public: - LatticeExtender(std::shared_ptr model); + LatticeExtender(std::shared_ptr> model); std::tuple toLattice(std::vector> formulas); - std::tuple extendLattice(storm::analysis::Lattice* lattice, std::shared_ptr expressionManager, std::set assumptions); + std::tuple extendLattice(storm::analysis::Lattice* lattice, std::set> assumptions); private: - std::shared_ptr model; + std::shared_ptr> model; std::map stateMap; From 28b77e6a7d8e7872e451741e1e050a47225377f8 Mon Sep 17 00:00:00 2001 From: Jip Spel Date: Thu, 6 Sep 2018 13:08:01 +0200 Subject: [PATCH 042/178] Create MonotonicityChecker and fix some bugs in AssumptionMaker --- src/storm-pars-cli/storm-pars.cpp | 119 ++------------- src/storm-pars/analysis/AssumptionMaker.cpp | 12 +- src/storm-pars/analysis/Lattice.cpp | 50 +++++- src/storm-pars/analysis/Lattice.h | 8 + .../analysis/MonotonicityChecker.cpp | 144 ++++++++++++++++++ src/storm-pars/analysis/MonotonicityChecker.h | 29 ++++ 6 files changed, 246 insertions(+), 116 deletions(-) create mode 100644 src/storm-pars/analysis/MonotonicityChecker.cpp create mode 100644 src/storm-pars/analysis/MonotonicityChecker.h diff --git a/src/storm-pars-cli/storm-pars.cpp b/src/storm-pars-cli/storm-pars.cpp index c44e8a8f8..3a67b13a9 100644 --- a/src/storm-pars-cli/storm-pars.cpp +++ b/src/storm-pars-cli/storm-pars.cpp @@ -1,12 +1,14 @@ -#include "storm-pars/analysis/LatticeExtender.h" + #include "storm-pars/analysis/AssumptionMaker.h" +#include "storm-pars/analysis/Lattice.h" +#include "storm-pars/analysis/LatticeExtender.h" +#include "storm-pars/analysis/MonotonicityChecker.h" + #include "storm-cli-utilities/cli.h" #include "storm-cli-utilities/model-handling.h" -#include "storm-pars/analysis/Lattice.h" - #include "storm-pars/api/storm-pars.h" #include "storm-pars/api/region.h" @@ -456,88 +458,6 @@ namespace storm { storm::pars::verifyWithSparseEngine(model->as>(), input, regions, samples); } - template - std::map> analyseMonotonicity(storm::analysis::Lattice* lattice, storm::storage::SparseMatrix matrix) { - //TODO: Seperate cpp file with this and criticalstatefinding/handling - std::map> varsMonotone; - ofstream myfile; - myfile.open ("mc.dot"); - myfile << "digraph \"MC\" {" << std::endl; - myfile << "\t" << "node [shape=ellipse]" << std::endl; - // print all nodes - for (uint_fast64_t i = 0; i < matrix.getColumnCount(); ++i) { - myfile << "\t\"" << i << "\" [label = \"" << i << "\"]" << std::endl; - } - - - for (uint_fast64_t i = 0; i < matrix.getColumnCount(); ++i) { - // go over all rows - auto row = matrix.getRow(i); - - auto first = (*row.begin()); - if (first.getValue() != ValueType(1)) { - auto second = (*(++row.begin())); - string color = ""; - auto val = first.getValue(); - auto vars = val.gatherVariables(); - for (auto itr = vars.begin(); itr != vars.end(); ++itr) { - auto derivative = val.derivative(*itr); - STORM_LOG_THROW(derivative.isConstant(), storm::exceptions::NotSupportedException, "Expecting derivative to be constant"); - - if (varsMonotone.find(*itr) == varsMonotone.end()) { - varsMonotone[*itr].first = true; - varsMonotone[*itr].second = true; - } - - auto compare = lattice->compare(first.getColumn(), second.getColumn()); - std::pair* value = &varsMonotone.find(*itr)->second; - std::pair old = *value; - if (compare == 1) { - value->first &=derivative.constantPart() >= 0; - value->second &=derivative.constantPart() <= 0; - } else if (compare == 2) { - value->first &=derivative.constantPart() <= 0; - value->second &=derivative.constantPart() >= 0; - } else if (compare == 0) { - STORM_LOG_THROW(false, storm::exceptions::UnexpectedException, "Don't know what is happening, something in monotonicity checking went wrong"); - } else { - value->first = false; - value->second = false; - } - if ((value->first != old.first) && (value->second != old.second)) { - color = "color = red, "; - } else if ((value->first != old.first)) { - myfile << "\t edge[style=dashed];" << std::endl; - color = "color = blue, "; - } else if ((value->second != old.second)) { - myfile << "\t edge[style=dotted];" << std::endl; - color = "color = blue, "; - } - } - - myfile << "\t" << i << " -> " << first.getColumn() << "[" << color << "label=\"" << first.getValue() << "\"];" - << std::endl; - myfile << "\t" << i << " -> " << second.getColumn() << "[" << color << "label=\"" << second.getValue() << "\"];" - << std::endl; - myfile << "\t edge[style=\"\"];" << std::endl; - } else { - myfile << "\t" << i << " -> " << first.getColumn() << "[label=\"" << first.getValue() << "\"];" - << std::endl; - } - } - - myfile << "\tsubgraph legend {" << std::endl; - myfile << "\t\tnode [color=white];" << std::endl; - myfile << "\t\tedge [style=invis];" << std::endl; - myfile << "\t\tt0 [label=\"incr? and decr?\", fontcolor=red];" << std::endl; - myfile << "\t\tt1 [label=\"incr? (dashed)\", fontcolor=blue];" << std::endl; - myfile << "\t\tt2 [label=\"decr? (dotted)\", fontcolor=blue];" << std::endl; - - myfile << "\t}" << std::endl; - myfile << "}" << std::endl; - myfile.close(); - return varsMonotone; - }; template void processInputWithValueTypeAndDdlib(SymbolicInput& input) { @@ -610,47 +530,26 @@ namespace storm { std::vector> formulas = storm::api::extractFormulasFromProperties(input.properties); std::shared_ptr> sparseModel = model->as>(); - // Transform to Lattice + // Transform to Lattices storm::utility::Stopwatch latticeWatch(true); storm::analysis::LatticeExtender *extender = new storm::analysis::LatticeExtender(sparseModel); std::tuple criticalPair = extender->toLattice(formulas); - // TODO met assumptionmaker dingen doen - - auto assumptionMaker = storm::analysis::AssumptionMaker(extender, sparseModel->getNumberOfStates()); std::map>> result = assumptionMaker.startMakingAssumptions(std::get<0>(criticalPair), std::get<1>(criticalPair), std::get<2>(criticalPair)); - auto lattice = result.begin()->first; - latticeWatch.stop(); STORM_PRINT(std::endl << "Time for lattice creation: " << latticeWatch << "." << std::endl << std::endl); - // Write lattice to file - ofstream myfile; - myfile.open ("lattice.dot"); - lattice->toDotFile(myfile); - myfile.close(); // Monotonicity? - auto matrix = sparseModel->getTransitionMatrix(); + storm::utility::Stopwatch monotonicityWatch(true); - std::map> varsMonotone = analyseMonotonicity(lattice, matrix); + auto monotonicityChecker = storm::analysis::MonotonicityChecker(); + monotonicityChecker.checkMonotonicity(result, sparseModel->getTransitionMatrix()); monotonicityWatch.stop(); STORM_PRINT(std::endl << "Time for monotonicity: " << monotonicityWatch << "." << std::endl << std::endl); - for (auto itr = varsMonotone.begin(); itr != varsMonotone.end(); ++itr) { - if (itr->second.first) { - STORM_PRINT("Monotone increasing in: " << itr->first << std::endl); - } else { - STORM_PRINT("Do not know if monotone increasing in: " << itr->first << std::endl); - } - if (itr->second.second) { - STORM_PRINT("Monotone decreasing in: " << itr->first << std::endl); - } else { - STORM_PRINT("Do not know if monotone decreasing in: " << itr->first << std::endl); - } - } std::cout << "Bye, Jip2" << std::endl; return; diff --git a/src/storm-pars/analysis/AssumptionMaker.cpp b/src/storm-pars/analysis/AssumptionMaker.cpp index 7124748b2..eec265d23 100644 --- a/src/storm-pars/analysis/AssumptionMaker.cpp +++ b/src/storm-pars/analysis/AssumptionMaker.cpp @@ -28,6 +28,8 @@ namespace storm { if (critical1 == numberOfStates || critical2 == numberOfStates) { result.insert(std::pair>>(lattice, emptySet)); } else { + + //TODO: opruimen storm::expressions::Variable var1 = expressionManager->getVariable(std::to_string(critical1)); storm::expressions::Variable var2 = expressionManager->getVariable(std::to_string(critical2)); std::set> assumptions1; @@ -36,18 +38,18 @@ namespace storm { var1.getExpression().getBaseExpressionPointer(), var2.getExpression().getBaseExpressionPointer(), storm::expressions::BinaryRelationExpression::RelationType::Greater)); assumptions1.insert(assumption1); - auto lattice1 = new storm::analysis::Lattice(*lattice); + auto lattice1 = lattice->deepCopy(); auto myMap = (runRecursive(lattice1, assumptions1)); result.insert(myMap.begin(), myMap.end()); std::set> assumptions2; std::shared_ptr assumption2 - = std::make_shared(storm::expressions::BinaryRelationExpression(*expressionManager, var1.getType(), + = std::make_shared(storm::expressions::BinaryRelationExpression(*expressionManager, var2.getType(), var2.getExpression().getBaseExpressionPointer(), var1.getExpression().getBaseExpressionPointer(), storm::expressions::BinaryRelationExpression::RelationType::Greater)); assumptions2.insert(assumption2); - auto lattice2 = new storm::analysis::Lattice(*lattice); + auto lattice2 = lattice->deepCopy(); auto myMap2 = (runRecursive(lattice2, assumptions2)); result.insert(myMap2.begin(), myMap2.end()); } @@ -70,7 +72,7 @@ namespace storm { var1.getExpression().getBaseExpressionPointer(), var2.getExpression().getBaseExpressionPointer(), storm::expressions::BinaryRelationExpression::RelationType::Greater)); assumptions1.insert(assumption1); - auto lattice1 = new storm::analysis::Lattice(*lattice); + auto lattice1 = lattice->deepCopy(); auto myMap = (runRecursive(lattice1, assumptions1)); result.insert(myMap.begin(), myMap.end()); @@ -80,7 +82,7 @@ namespace storm { var2.getExpression().getBaseExpressionPointer(), var1.getExpression().getBaseExpressionPointer(), storm::expressions::BinaryRelationExpression::RelationType::Greater)) ; assumptions2.insert(assumption2); - auto lattice2 = new storm::analysis::Lattice(*lattice); + auto lattice2 = lattice->deepCopy(); myMap = (runRecursive(lattice2, assumptions2)); result.insert(myMap.begin(), myMap.end()); } diff --git a/src/storm-pars/analysis/Lattice.cpp b/src/storm-pars/analysis/Lattice.cpp index 189cff147..e65363cd0 100644 --- a/src/storm-pars/analysis/Lattice.cpp +++ b/src/storm-pars/analysis/Lattice.cpp @@ -164,6 +164,7 @@ namespace storm { } void Lattice::toDotFile(std::ostream &out) { + // TODO: op de een of andere manier ontstaan er nodes die nergens eindigen/beginnen out << "digraph \"Lattice\" {" << std::endl; // print all nodes @@ -202,7 +203,54 @@ namespace storm { out << "}" << std::endl; } - bool Lattice::above(Node *node1, Node *node2, std::set* seenNodes) { + Lattice* Lattice::deepCopy() { + // TODO zonder bottom is eigenlijk beter + Lattice* result = new Lattice(top->states, bottom->states, numberOfStates); + + for (auto itr = top->below.begin(); itr != top->below.end(); ++itr) { + result->nogBedenken(*itr, result->getTop(), storm::storage::BitVector(numberOfStates)); + } + + + return result; + } + + void Lattice::nogBedenken(Lattice::Node* nodeFromOld, Lattice::Node* higherNode, storm::storage::BitVector seenStates) { + auto index = numberOfStates; + std::set seenNodes = std::set({}); + for (auto i = nodeFromOld->states.getNextSetIndex(0); i < numberOfStates; i =nodeFromOld->states.getNextSetIndex(i+1)) { + Node * nodeI = getNode(i); + if (nodeI == nullptr && index == numberOfStates) { + nodeI = new Node(); + nodeI->states = storm::storage::BitVector(numberOfStates); + nodeI->states.set(i); + higherNode->above.insert(nodeI); + nodeI->below.insert(higherNode); + addedStates.set(i); + nodes.at(i) = nodeI; + } else if (nodeI == nullptr) { + addToNode(i, getNode(index)); + } else { + nodeI->above.insert(higherNode); + higherNode->below.insert(nodeI); + addedStates.set(i); + } + seenStates.set(i); + index = i; + seenNodes.insert(nodeI); + } + + for (auto itr = nodeFromOld->below.begin(); itr != nodeFromOld->below.end(); itr++) { +// if (!seenStates.get((*itr)->states.getNextSetIndex(0))) { + for (auto itr2 = seenNodes.begin(); itr2 != seenNodes.end(); ++itr2) { + nogBedenken(*itr, *itr2, seenStates); + } +// } + } + + } + + bool Lattice::above(Node *node1, Node *node2, std::set* seenNodes) { bool result = !node1->below.empty() && std::find(node1->below.begin(), node1->below.end(), node2) != node1->below.end(); for (auto itr = node1->below.begin(); !result && node1->below.end() != itr; ++itr) { if (std::find(seenNodes->begin(), seenNodes->end(), (*itr)) == seenNodes->end()) { diff --git a/src/storm-pars/analysis/Lattice.h b/src/storm-pars/analysis/Lattice.h index 3d36b9120..02cbdf30a 100644 --- a/src/storm-pars/analysis/Lattice.h +++ b/src/storm-pars/analysis/Lattice.h @@ -104,11 +104,18 @@ namespace storm { */ void toDotFile(std::ostream &out); + Lattice* deepCopy(); + static const int UNKNOWN = -1; static const int BELOW = 2; static const int ABOVE = 1; static const int SAME = 0; + protected: + void addBelow(uint_fast64_t state, Node* node); + + void addAbove(uint_fast64_t state, Node* node); + private: std::vector nodes; @@ -120,6 +127,7 @@ namespace storm { uint_fast64_t numberOfStates; + void nogBedenken(Node* nodeFromOld, Node* higherNode, storm::storage::BitVector seenStates); /** * Check if node1 lies above node2 * @param node1 diff --git a/src/storm-pars/analysis/MonotonicityChecker.cpp b/src/storm-pars/analysis/MonotonicityChecker.cpp new file mode 100644 index 000000000..4d490ae9b --- /dev/null +++ b/src/storm-pars/analysis/MonotonicityChecker.cpp @@ -0,0 +1,144 @@ +// +// Created by Jip Spel on 05.09.18. +// + +#include "MonotonicityChecker.h" +#include "storm/exceptions/UnexpectedException.h" +#include "storm/exceptions/NotSupportedException.h" + +namespace storm { + namespace analysis { + template + void MonotonicityChecker::checkMonotonicity(std::map>> map, storm::storage::SparseMatrix matrix) { + + auto i = 0; + for (auto itr = map.begin(); itr != map.end(); ++itr) { + auto lattice = itr->first; + auto assumptions = itr->second; + std::ofstream myfile; + std::string filename = "lattice" + std::to_string(i) + ".dot"; + myfile.open (filename); + lattice->toDotFile(myfile); + myfile.close(); + + STORM_PRINT("Given assumptions: " << std::endl); + bool first = true; + for (auto itr = assumptions.begin(); itr != assumptions.end(); ++itr) { + if (!first) { + STORM_PRINT(" ^ "); + } else { + STORM_PRINT(" "); + } + first = false; + std::shared_ptr expression = *itr; + auto var1 = expression->getFirstOperand(); + auto var2 = expression->getSecondOperand(); + STORM_PRINT("(" << var1->getIdentifier() << " > " << var2->getIdentifier() << ")"); + } + STORM_PRINT(std::endl); + + std::map> varsMonotone = analyseMonotonicity(i, lattice, matrix); + for (auto itr2 = varsMonotone.begin(); itr2 != varsMonotone.end(); ++itr2) { + if (itr2->second.first) { + STORM_PRINT(" - Monotone increasing in: " << itr2->first << std::endl); + } else { + STORM_PRINT(" - Do not know if monotone increasing in: " << itr2->first << std::endl); + } + if (itr2->second.second) { + STORM_PRINT(" - Monotone decreasing in: " << itr2->first << std::endl); + } else { + STORM_PRINT(" - Do not know if monotone decreasing in: " << itr2->first << std::endl); + } + } + + ++i; + } + } + + template + std::map> MonotonicityChecker::analyseMonotonicity(uint_fast64_t i, storm::analysis::Lattice* lattice, storm::storage::SparseMatrix matrix) { + std::map> varsMonotone; + std::ofstream myfile; + std::string filename = "mc" + std::to_string(i) + ".dot"; + myfile.open (filename); + myfile << "digraph \"MC\" {" << std::endl; + myfile << "\t" << "node [shape=ellipse]" << std::endl; + // print all nodes + for (uint_fast64_t i = 0; i < matrix.getColumnCount(); ++i) { + myfile << "\t\"" << i << "\" [label = \"" << i << "\"]" << std::endl; + } + + + for (uint_fast64_t i = 0; i < matrix.getColumnCount(); ++i) { + // go over all rows + auto row = matrix.getRow(i); + + auto first = (*row.begin()); + if (first.getValue() != ValueType(1)) { + auto second = (*(++row.begin())); + std::string color = ""; + auto val = first.getValue(); + auto vars = val.gatherVariables(); + for (auto itr = vars.begin(); itr != vars.end(); ++itr) { + auto derivative = val.derivative(*itr); + STORM_LOG_THROW(derivative.isConstant(), storm::exceptions::NotSupportedException, "Expecting derivative to be constant"); + + if (varsMonotone.find(*itr) == varsMonotone.end()) { + varsMonotone[*itr].first = true; + varsMonotone[*itr].second = true; + } + + auto compare = lattice->compare(first.getColumn(), second.getColumn()); + std::pair* value = &varsMonotone.find(*itr)->second; + std::pair old = *value; + if (compare == 1) { + value->first &=derivative.constantPart() >= 0; + value->second &=derivative.constantPart() <= 0; + } else if (compare == 2) { + value->first &=derivative.constantPart() <= 0; + value->second &=derivative.constantPart() >= 0; + } else if (compare == 0) { + STORM_LOG_THROW(false, storm::exceptions::UnexpectedException, "Don't know what is happening, something in monotonicity checking went wrong"); + } else { + value->first = false; + value->second = false; + } + if ((value->first != old.first) && (value->second != old.second)) { + color = "color = red, "; + } else if ((value->first != old.first)) { + myfile << "\t edge[style=dashed];" << std::endl; + color = "color = blue, "; + } else if ((value->second != old.second)) { + myfile << "\t edge[style=dotted];" << std::endl; + color = "color = blue, "; + } + } + + myfile << "\t" << i << " -> " << first.getColumn() << "[" << color << "label=\"" << first.getValue() << "\"];" + << std::endl; + myfile << "\t" << i << " -> " << second.getColumn() << "[" << color << "label=\"" << second.getValue() << "\"];" + << std::endl; + myfile << "\t edge[style=\"\"];" << std::endl; + } else { + myfile << "\t" << i << " -> " << first.getColumn() << "[label=\"" << first.getValue() << "\"];" + << std::endl; + } + } + + myfile << "\tsubgraph legend {" << std::endl; + myfile << "\t\tnode [color=white];" << std::endl; + myfile << "\t\tedge [style=invis];" << std::endl; + myfile << "\t\tt0 [label=\"incr? and decr?\", fontcolor=red];" << std::endl; + myfile << "\t\tt1 [label=\"incr? (dashed)\", fontcolor=blue];" << std::endl; + myfile << "\t\tt2 [label=\"decr? (dotted)\", fontcolor=blue];" << std::endl; + + myfile << "\t}" << std::endl; + myfile << "}" << std::endl; + myfile.close(); + return varsMonotone; + }; + template class MonotonicityChecker; + } + +} + diff --git a/src/storm-pars/analysis/MonotonicityChecker.h b/src/storm-pars/analysis/MonotonicityChecker.h new file mode 100644 index 000000000..7b1dcb1f1 --- /dev/null +++ b/src/storm-pars/analysis/MonotonicityChecker.h @@ -0,0 +1,29 @@ +// +// Created by Jip Spel on 03.09.18. +// + +#ifndef STORM_MONOTONICITYCHECKER_H +#define STORM_MONOTONICITYCHECKER_H + +#include +#include "Lattice.h" +#include "storm/storage/expressions/BinaryRelationExpression.h" +#include "storm/storage/SparseMatrix.h" +#include "carl/core/Variable.h" + +namespace storm { + namespace analysis { + + template + class MonotonicityChecker { + + public: + void checkMonotonicity(std::map>> map, storm::storage::SparseMatrix matrix); + + private: + std::map> analyseMonotonicity(uint_fast64_t i, storm::analysis::Lattice* lattice, storm::storage::SparseMatrix matrix) ; + + }; + } +} +#endif //STORM_MONOTONICITYCHECKER_H From 2e4991a75e69004c649edcd93f9feae4655594f5 Mon Sep 17 00:00:00 2001 From: Jip Spel Date: Thu, 6 Sep 2018 13:46:57 +0200 Subject: [PATCH 043/178] TODO added create deep copy not yet working correctly --- src/storm-pars-cli/storm-pars.cpp | 3 --- src/storm-pars/analysis/Lattice.cpp | 8 ++++---- src/storm-pars/analysis/Lattice.h | 2 +- 3 files changed, 5 insertions(+), 8 deletions(-) diff --git a/src/storm-pars-cli/storm-pars.cpp b/src/storm-pars-cli/storm-pars.cpp index 3a67b13a9..d57c4932f 100644 --- a/src/storm-pars-cli/storm-pars.cpp +++ b/src/storm-pars-cli/storm-pars.cpp @@ -541,16 +541,13 @@ namespace storm { latticeWatch.stop(); STORM_PRINT(std::endl << "Time for lattice creation: " << latticeWatch << "." << std::endl << std::endl); - // Monotonicity? - storm::utility::Stopwatch monotonicityWatch(true); auto monotonicityChecker = storm::analysis::MonotonicityChecker(); monotonicityChecker.checkMonotonicity(result, sparseModel->getTransitionMatrix()); monotonicityWatch.stop(); STORM_PRINT(std::endl << "Time for monotonicity: " << monotonicityWatch << "." << std::endl << std::endl); - std::cout << "Bye, Jip2" << std::endl; return; } diff --git a/src/storm-pars/analysis/Lattice.cpp b/src/storm-pars/analysis/Lattice.cpp index e65363cd0..ddb0003a6 100644 --- a/src/storm-pars/analysis/Lattice.cpp +++ b/src/storm-pars/analysis/Lattice.cpp @@ -208,14 +208,14 @@ namespace storm { Lattice* result = new Lattice(top->states, bottom->states, numberOfStates); for (auto itr = top->below.begin(); itr != top->below.end(); ++itr) { - result->nogBedenken(*itr, result->getTop(), storm::storage::BitVector(numberOfStates)); + result->createLattice(*itr, result->getTop(), storm::storage::BitVector(numberOfStates)); } - return result; } - void Lattice::nogBedenken(Lattice::Node* nodeFromOld, Lattice::Node* higherNode, storm::storage::BitVector seenStates) { + void Lattice::createLattice(Lattice::Node* nodeFromOld, Lattice::Node* higherNode, storm::storage::BitVector seenStates) { + //TODO: nog niet helemaal goed auto index = numberOfStates; std::set seenNodes = std::set({}); for (auto i = nodeFromOld->states.getNextSetIndex(0); i < numberOfStates; i =nodeFromOld->states.getNextSetIndex(i+1)) { @@ -243,7 +243,7 @@ namespace storm { for (auto itr = nodeFromOld->below.begin(); itr != nodeFromOld->below.end(); itr++) { // if (!seenStates.get((*itr)->states.getNextSetIndex(0))) { for (auto itr2 = seenNodes.begin(); itr2 != seenNodes.end(); ++itr2) { - nogBedenken(*itr, *itr2, seenStates); + createLattice(*itr, *itr2, seenStates); } // } } diff --git a/src/storm-pars/analysis/Lattice.h b/src/storm-pars/analysis/Lattice.h index 02cbdf30a..5aeaf14cc 100644 --- a/src/storm-pars/analysis/Lattice.h +++ b/src/storm-pars/analysis/Lattice.h @@ -127,7 +127,7 @@ namespace storm { uint_fast64_t numberOfStates; - void nogBedenken(Node* nodeFromOld, Node* higherNode, storm::storage::BitVector seenStates); + void createLattice(Node* nodeFromOld, Node* higherNode, storm::storage::BitVector seenStates); /** * Check if node1 lies above node2 * @param node1 From 19475b30b977cdbfdb4e952b71cf545ef2e9cf19 Mon Sep 17 00:00:00 2001 From: Jip Spel Date: Thu, 6 Sep 2018 14:11:52 +0200 Subject: [PATCH 044/178] Fix issue with deepCopy not containing all transitions --- src/storm-pars/analysis/Lattice.cpp | 58 ++++++++++------------------- src/storm-pars/analysis/Lattice.h | 1 - 2 files changed, 20 insertions(+), 39 deletions(-) diff --git a/src/storm-pars/analysis/Lattice.cpp b/src/storm-pars/analysis/Lattice.cpp index ddb0003a6..2728d5cfd 100644 --- a/src/storm-pars/analysis/Lattice.cpp +++ b/src/storm-pars/analysis/Lattice.cpp @@ -204,50 +204,32 @@ namespace storm { } Lattice* Lattice::deepCopy() { - // TODO zonder bottom is eigenlijk beter Lattice* result = new Lattice(top->states, bottom->states, numberOfStates); - - for (auto itr = top->below.begin(); itr != top->below.end(); ++itr) { - result->createLattice(*itr, result->getTop(), storm::storage::BitVector(numberOfStates)); - } - - return result; - } - - void Lattice::createLattice(Lattice::Node* nodeFromOld, Lattice::Node* higherNode, storm::storage::BitVector seenStates) { - //TODO: nog niet helemaal goed - auto index = numberOfStates; - std::set seenNodes = std::set({}); - for (auto i = nodeFromOld->states.getNextSetIndex(0); i < numberOfStates; i =nodeFromOld->states.getNextSetIndex(i+1)) { - Node * nodeI = getNode(i); - if (nodeI == nullptr && index == numberOfStates) { - nodeI = new Node(); - nodeI->states = storm::storage::BitVector(numberOfStates); - nodeI->states.set(i); - higherNode->above.insert(nodeI); - nodeI->below.insert(higherNode); - addedStates.set(i); - nodes.at(i) = nodeI; - } else if (nodeI == nullptr) { - addToNode(i, getNode(index)); - } else { - nodeI->above.insert(higherNode); - higherNode->below.insert(nodeI); - addedStates.set(i); + // Create all nodes + for (auto itr = nodes.begin(); itr != nodes.end(); ++itr) { + Node* oldNode = (*itr); + if (oldNode != nullptr) { + Node *newNode = new Node(); + newNode->states = storm::storage::BitVector(oldNode->states); + for (auto i = newNode->states.getNextSetIndex(0); + i < numberOfStates; i = newNode->states.getNextSetIndex(i + 1)) { + result->addedStates.set(i); + result->nodes.at(i) = newNode; + } } - seenStates.set(i); - index = i; - seenNodes.insert(nodeI); } - for (auto itr = nodeFromOld->below.begin(); itr != nodeFromOld->below.end(); itr++) { -// if (!seenStates.get((*itr)->states.getNextSetIndex(0))) { - for (auto itr2 = seenNodes.begin(); itr2 != seenNodes.end(); ++itr2) { - createLattice(*itr, *itr2, seenStates); + // Create transitions + for (auto itr = nodes.begin(); itr != nodes.end(); ++itr) { + if (*itr != nullptr) { + auto state = (*itr)->states.getNextSetIndex(0); + for (auto itr2 = (*itr)->below.begin(); itr2 != (*itr)->below.end(); ++itr2) { + auto stateBelow = (*itr2)->states.getNextSetIndex(0); + result->addRelationNodes(result->getNode((state)), result->getNode((stateBelow))); } -// } + } } - + return result; } bool Lattice::above(Node *node1, Node *node2, std::set* seenNodes) { diff --git a/src/storm-pars/analysis/Lattice.h b/src/storm-pars/analysis/Lattice.h index 5aeaf14cc..12e05512a 100644 --- a/src/storm-pars/analysis/Lattice.h +++ b/src/storm-pars/analysis/Lattice.h @@ -127,7 +127,6 @@ namespace storm { uint_fast64_t numberOfStates; - void createLattice(Node* nodeFromOld, Node* higherNode, storm::storage::BitVector seenStates); /** * Check if node1 lies above node2 * @param node1 From bb1f1a370179670b8047a67bbf8a299a00a2814d Mon Sep 17 00:00:00 2001 From: Jip Spel Date: Thu, 6 Sep 2018 14:34:48 +0200 Subject: [PATCH 045/178] Change deepCopy into constructor --- src/storm-pars/analysis/AssumptionMaker.cpp | 8 +- src/storm-pars/analysis/Lattice.cpp | 92 +++++++++++++-------- src/storm-pars/analysis/Lattice.h | 6 +- 3 files changed, 66 insertions(+), 40 deletions(-) diff --git a/src/storm-pars/analysis/AssumptionMaker.cpp b/src/storm-pars/analysis/AssumptionMaker.cpp index eec265d23..0117a655f 100644 --- a/src/storm-pars/analysis/AssumptionMaker.cpp +++ b/src/storm-pars/analysis/AssumptionMaker.cpp @@ -38,7 +38,7 @@ namespace storm { var1.getExpression().getBaseExpressionPointer(), var2.getExpression().getBaseExpressionPointer(), storm::expressions::BinaryRelationExpression::RelationType::Greater)); assumptions1.insert(assumption1); - auto lattice1 = lattice->deepCopy(); + auto lattice1 = new Lattice(lattice); auto myMap = (runRecursive(lattice1, assumptions1)); result.insert(myMap.begin(), myMap.end()); @@ -49,7 +49,7 @@ namespace storm { storm::expressions::BinaryRelationExpression::RelationType::Greater)); assumptions2.insert(assumption2); - auto lattice2 = lattice->deepCopy(); + auto lattice2 = new Lattice(lattice); auto myMap2 = (runRecursive(lattice2, assumptions2)); result.insert(myMap2.begin(), myMap2.end()); } @@ -72,7 +72,7 @@ namespace storm { var1.getExpression().getBaseExpressionPointer(), var2.getExpression().getBaseExpressionPointer(), storm::expressions::BinaryRelationExpression::RelationType::Greater)); assumptions1.insert(assumption1); - auto lattice1 = lattice->deepCopy(); + auto lattice1 = new Lattice(lattice); auto myMap = (runRecursive(lattice1, assumptions1)); result.insert(myMap.begin(), myMap.end()); @@ -82,7 +82,7 @@ namespace storm { var2.getExpression().getBaseExpressionPointer(), var1.getExpression().getBaseExpressionPointer(), storm::expressions::BinaryRelationExpression::RelationType::Greater)) ; assumptions2.insert(assumption2); - auto lattice2 = lattice->deepCopy(); + auto lattice2 = new Lattice(lattice); myMap = (runRecursive(lattice2, assumptions2)); result.insert(myMap.begin(), myMap.end()); } diff --git a/src/storm-pars/analysis/Lattice.cpp b/src/storm-pars/analysis/Lattice.cpp index 2728d5cfd..c9b05dc0a 100644 --- a/src/storm-pars/analysis/Lattice.cpp +++ b/src/storm-pars/analysis/Lattice.cpp @@ -29,6 +29,53 @@ namespace storm { this->addedStates.operator|=(bottomStates); } + Lattice::Lattice(Lattice* lattice) { + top = new Node(); + top->states = storm::storage::BitVector(lattice->getTop()->states); + bottom = new Node(); + bottom->states = storm::storage::BitVector(lattice->getBottom()->states); + numberOfStates = top->states.size(); + nodes = std::vector(numberOfStates); + addedStates = storm::storage::BitVector(numberOfStates); + addedStates.operator|=(top->states); + addedStates.operator|=(bottom->states); + + for (auto i = top->states.getNextSetIndex(0); i < numberOfStates; i = top->states.getNextSetIndex(i+1)) { + nodes.at(i) = top; + + } + + for (auto i = bottom->states.getNextSetIndex(0); i < numberOfStates; i = bottom->states.getNextSetIndex(i+1)) { + nodes.at(i) = bottom; + } + + // Create all nodes + for (auto itr = lattice->getNodes().begin(); itr != lattice->getNodes().end(); ++itr) { + Node* oldNode = (*itr); + if (oldNode != nullptr) { + Node *newNode = new Node(); + newNode->states = storm::storage::BitVector(oldNode->states); + for (auto i = newNode->states.getNextSetIndex(0); + i < numberOfStates; i = newNode->states.getNextSetIndex(i + 1)) { + addedStates.set(i); + nodes.at(i) = newNode; + } + } + } + + // Create transitions + for (auto itr = lattice->getNodes().begin(); itr != lattice->getNodes().end(); ++itr) { + Node* oldNode = (*itr); + if (oldNode != nullptr) { + auto state = (*itr)->states.getNextSetIndex(0); + for (auto itr2 = (*itr)->below.begin(); itr2 != (*itr)->below.end(); ++itr2) { + auto stateBelow = (*itr2)->states.getNextSetIndex(0); + addRelationNodes(getNode((state)), getNode((stateBelow))); + } + } + } + } + void Lattice::addBetween(uint_fast64_t state, Node *above, Node *below) { Node *newNode = new Node(); newNode->states = storm::storage::BitVector(numberOfStates); @@ -102,6 +149,11 @@ namespace storm { return bottom; } + std::vector Lattice::getNodes() { + return nodes; + } + + storm::storage::BitVector Lattice::getAddedStates() { return addedStates; } @@ -203,44 +255,16 @@ namespace storm { out << "}" << std::endl; } - Lattice* Lattice::deepCopy() { - Lattice* result = new Lattice(top->states, bottom->states, numberOfStates); - // Create all nodes - for (auto itr = nodes.begin(); itr != nodes.end(); ++itr) { - Node* oldNode = (*itr); - if (oldNode != nullptr) { - Node *newNode = new Node(); - newNode->states = storm::storage::BitVector(oldNode->states); - for (auto i = newNode->states.getNextSetIndex(0); - i < numberOfStates; i = newNode->states.getNextSetIndex(i + 1)) { - result->addedStates.set(i); - result->nodes.at(i) = newNode; - } - } - } - // Create transitions - for (auto itr = nodes.begin(); itr != nodes.end(); ++itr) { - if (*itr != nullptr) { - auto state = (*itr)->states.getNextSetIndex(0); - for (auto itr2 = (*itr)->below.begin(); itr2 != (*itr)->below.end(); ++itr2) { - auto stateBelow = (*itr2)->states.getNextSetIndex(0); - result->addRelationNodes(result->getNode((state)), result->getNode((stateBelow))); - } + bool Lattice::above(Node *node1, Node *node2, std::set* seenNodes) { + bool result = !node1->below.empty() && std::find(node1->below.begin(), node1->below.end(), node2) != node1->below.end(); + for (auto itr = node1->below.begin(); !result && node1->below.end() != itr; ++itr) { + if (std::find(seenNodes->begin(), seenNodes->end(), (*itr)) == seenNodes->end()) { + seenNodes->insert(*itr); + result |= above(*itr, node2, seenNodes); } } return result; } - - bool Lattice::above(Node *node1, Node *node2, std::set* seenNodes) { - bool result = !node1->below.empty() && std::find(node1->below.begin(), node1->below.end(), node2) != node1->below.end(); - for (auto itr = node1->below.begin(); !result && node1->below.end() != itr; ++itr) { - if (std::find(seenNodes->begin(), seenNodes->end(), (*itr)) == seenNodes->end()) { - seenNodes->insert(*itr); - result |= above(*itr, node2, seenNodes); - } - } - return result; } } -} diff --git a/src/storm-pars/analysis/Lattice.h b/src/storm-pars/analysis/Lattice.h index 12e05512a..806c1b6e7 100644 --- a/src/storm-pars/analysis/Lattice.h +++ b/src/storm-pars/analysis/Lattice.h @@ -31,6 +31,8 @@ namespace storm { Lattice(storm::storage::BitVector topStates, storm::storage::BitVector bottomStates, uint_fast64_t numberOfStates); + Lattice(Lattice* lattice); + /*! * Adds a node with the given state below node1 and above node2. * @param state The given state. @@ -88,6 +90,8 @@ namespace storm { Node* getBottom(); + std::vector getNodes(); + storm::storage::BitVector getAddedStates(); /*! @@ -104,8 +108,6 @@ namespace storm { */ void toDotFile(std::ostream &out); - Lattice* deepCopy(); - static const int UNKNOWN = -1; static const int BELOW = 2; static const int ABOVE = 1; From 83797afc5b26352eb02ca93f6da19823333cd2ae Mon Sep 17 00:00:00 2001 From: Jip Spel Date: Thu, 6 Sep 2018 15:06:07 +0200 Subject: [PATCH 046/178] Remove TODO AssumptionMaker (clean up) --- src/storm-pars/analysis/AssumptionMaker.cpp | 54 +++++++-------------- src/storm-pars/analysis/AssumptionMaker.h | 2 + 2 files changed, 20 insertions(+), 36 deletions(-) diff --git a/src/storm-pars/analysis/AssumptionMaker.cpp b/src/storm-pars/analysis/AssumptionMaker.cpp index 0117a655f..0fadf2bfc 100644 --- a/src/storm-pars/analysis/AssumptionMaker.cpp +++ b/src/storm-pars/analysis/AssumptionMaker.cpp @@ -28,30 +28,15 @@ namespace storm { if (critical1 == numberOfStates || critical2 == numberOfStates) { result.insert(std::pair>>(lattice, emptySet)); } else { - - //TODO: opruimen storm::expressions::Variable var1 = expressionManager->getVariable(std::to_string(critical1)); storm::expressions::Variable var2 = expressionManager->getVariable(std::to_string(critical2)); - std::set> assumptions1; - std::shared_ptr assumption1 - = std::make_shared(storm::expressions::BinaryRelationExpression(*expressionManager, var1.getType(), - var1.getExpression().getBaseExpressionPointer(), var2.getExpression().getBaseExpressionPointer(), - storm::expressions::BinaryRelationExpression::RelationType::Greater)); - assumptions1.insert(assumption1); - auto lattice1 = new Lattice(lattice); - auto myMap = (runRecursive(lattice1, assumptions1)); - result.insert(myMap.begin(), myMap.end()); + std::set> assumptions; - std::set> assumptions2; - std::shared_ptr assumption2 - = std::make_shared(storm::expressions::BinaryRelationExpression(*expressionManager, var2.getType(), - var2.getExpression().getBaseExpressionPointer(), var1.getExpression().getBaseExpressionPointer(), - storm::expressions::BinaryRelationExpression::RelationType::Greater)); - assumptions2.insert(assumption2); + auto myMap = createAssumptions(var1, var2, lattice, assumptions); + result.insert(myMap.begin(), myMap.end()); - auto lattice2 = new Lattice(lattice); - auto myMap2 = (runRecursive(lattice2, assumptions2)); - result.insert(myMap2.begin(), myMap2.end()); + myMap = createAssumptions(var2, var1, lattice, assumptions); + result.insert(myMap.begin(), myMap.end()); } return result; } @@ -67,29 +52,26 @@ namespace storm { storm::expressions::Variable var1 = expressionManager->getVariable(std::to_string(std::get<1>(criticalPair))); storm::expressions::Variable var2 = expressionManager->getVariable(std::to_string(std::get<2>(criticalPair))); - std::set> assumptions1 = std::set>(assumptions); - std::shared_ptr assumption1 = std::make_shared(storm::expressions::BinaryRelationExpression(*expressionManager, var1.getType(), - var1.getExpression().getBaseExpressionPointer(), var2.getExpression().getBaseExpressionPointer(), - storm::expressions::BinaryRelationExpression::RelationType::Greater)); - assumptions1.insert(assumption1); - auto lattice1 = new Lattice(lattice); - auto myMap = (runRecursive(lattice1, assumptions1)); + auto myMap = createAssumptions(var1, var2, lattice, assumptions); result.insert(myMap.begin(), myMap.end()); - - - std::set> assumptions2 = assumptions; - std::shared_ptr assumption2 = std::make_shared(storm::expressions::BinaryRelationExpression(*expressionManager, var1.getType(), - var2.getExpression().getBaseExpressionPointer(), var1.getExpression().getBaseExpressionPointer(), - storm::expressions::BinaryRelationExpression::RelationType::Greater)) ; - assumptions2.insert(assumption2); - auto lattice2 = new Lattice(lattice); - myMap = (runRecursive(lattice2, assumptions2)); + myMap = createAssumptions(var2, var1, lattice, assumptions); result.insert(myMap.begin(), myMap.end()); } return result; } + template + std::map>> AssumptionMaker::createAssumptions(storm::expressions::Variable var1, storm::expressions::Variable var2, storm::analysis::Lattice* lattice, std::set> assumptions) { + std::set> assumptions1 = std::set>(assumptions); + std::shared_ptr assumption1 + = std::make_shared(storm::expressions::BinaryRelationExpression(*expressionManager, var1.getType(), + var1.getExpression().getBaseExpressionPointer(), var2.getExpression().getBaseExpressionPointer(), + storm::expressions::BinaryRelationExpression::RelationType::Greater)); + assumptions1.insert(assumption1); + auto lattice1 = new Lattice(lattice); + return (runRecursive(lattice1, assumptions1)); + } template class AssumptionMaker; } diff --git a/src/storm-pars/analysis/AssumptionMaker.h b/src/storm-pars/analysis/AssumptionMaker.h index 0472d2fbc..7061a43fb 100644 --- a/src/storm-pars/analysis/AssumptionMaker.h +++ b/src/storm-pars/analysis/AssumptionMaker.h @@ -23,6 +23,8 @@ namespace storm { private: std::map>> runRecursive(storm::analysis::Lattice* lattice, std::set> assumptions); + std::map>> createAssumptions(storm::expressions::Variable var1, storm::expressions::Variable var2, storm::analysis::Lattice* lattice,std::set> assumptions); + storm::analysis::LatticeExtender* latticeExtender; std::shared_ptr expressionManager; From 2c9cefe7cceb55d8ffc79cf00002625cbf9ffccb Mon Sep 17 00:00:00 2001 From: Jip Spel Date: Fri, 7 Sep 2018 09:23:33 +0200 Subject: [PATCH 047/178] Use predefined constants --- src/storm-pars/analysis/MonotonicityChecker.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/storm-pars/analysis/MonotonicityChecker.cpp b/src/storm-pars/analysis/MonotonicityChecker.cpp index 4d490ae9b..a925bc555 100644 --- a/src/storm-pars/analysis/MonotonicityChecker.cpp +++ b/src/storm-pars/analysis/MonotonicityChecker.cpp @@ -91,14 +91,14 @@ namespace storm { auto compare = lattice->compare(first.getColumn(), second.getColumn()); std::pair* value = &varsMonotone.find(*itr)->second; std::pair old = *value; - if (compare == 1) { + if (compare == storm::analysis::Lattice::ABOVE) { value->first &=derivative.constantPart() >= 0; value->second &=derivative.constantPart() <= 0; - } else if (compare == 2) { + } else if (compare == storm::analysis::Lattice::BELOW) { value->first &=derivative.constantPart() <= 0; value->second &=derivative.constantPart() >= 0; - } else if (compare == 0) { - STORM_LOG_THROW(false, storm::exceptions::UnexpectedException, "Don't know what is happening, something in monotonicity checking went wrong"); + } else if (compare == storm::analysis::Lattice::SAME) { + // Behaviour doesn't matter, as they are at the same level } else { value->first = false; value->second = false; From 728dc9e8a43bc41ac2a05f31b1b7790e6b956291 Mon Sep 17 00:00:00 2001 From: Jip Spel Date: Fri, 7 Sep 2018 09:29:47 +0200 Subject: [PATCH 048/178] Fix TODO --- src/storm-pars/analysis/Lattice.cpp | 122 ++++++++++++++-------------- src/storm-pars/analysis/Lattice.h | 7 +- 2 files changed, 64 insertions(+), 65 deletions(-) diff --git a/src/storm-pars/analysis/Lattice.cpp b/src/storm-pars/analysis/Lattice.cpp index c9b05dc0a..1846b816e 100644 --- a/src/storm-pars/analysis/Lattice.cpp +++ b/src/storm-pars/analysis/Lattice.cpp @@ -3,6 +3,7 @@ // #include +#include #include "Lattice.h" namespace storm { namespace analysis { @@ -100,36 +101,37 @@ namespace storm { addBetween(state, top, bottom); } - void Lattice::addRelation(storm::analysis::Lattice::Node *above, storm::analysis::Lattice::Node *between, - storm::analysis::Lattice::Node *below) { - above->below.insert(between); - between->above.insert(above); - between->below.insert(below); - below->above.insert(between); - } - void Lattice::addRelationNodes(storm::analysis::Lattice::Node *above, storm::analysis::Lattice::Node * below) { - above->below.insert(below); - below->above.insert(above); + if (above != below) { + above->below.insert(below); + below->above.insert(above); + } } int Lattice::compare(uint_fast64_t state1, uint_fast64_t state2) { Node *node1 = getNode(state1); Node *node2 = getNode(state2); - // TODO: Wat als above(node1, node2) en above(node2, node1), dan moeten ze samengevoegd? + return compare(node1, node2); + } + + int Lattice::compare(Node* node1, Node* node2) { if (node1 != nullptr && node2 != nullptr) { if (node1 == node2) { return SAME; } - std::set* seen1 = new std::set({}); - if (above(node1, node2, seen1)) { + bool isAbove = above(node1, node2, new std::set({})); + bool isBelow = above(node2, node1, new std::set({})); + if (isAbove && isBelow) { + return SAME; + } + + if (isAbove) { return ABOVE; } - std::set* seen2 = new std::set({}); - if (above(node2, node1, seen2)) { + if (isBelow) { return BELOW; } } @@ -137,6 +139,7 @@ namespace storm { return UNKNOWN; } + Lattice::Node *Lattice::getNode(uint_fast64_t stateNumber) { return nodes.at(stateNumber); } @@ -153,7 +156,6 @@ namespace storm { return nodes; } - storm::storage::BitVector Lattice::getAddedStates() { return addedStates; } @@ -178,21 +180,21 @@ namespace storm { out << " Address: " << node << "\n"; out << " Above: {"; - for (auto itr2 = node->above.begin(); itr2 != node->above.end(); ++itr2) { - Node *above = *itr2; - index = above->states.getNextSetIndex(0); - out << "{"; - while (index < numberOfStates) { - out << index; - index = above->states.getNextSetIndex(index + 1); - if (index < numberOfStates) { - out << ", "; - } + for (auto itr2 = node->above.begin(); itr2 != node->above.end(); ++itr2) { + Node *above = *itr2; + index = above->states.getNextSetIndex(0); + out << "{"; + while (index < numberOfStates) { + out << index; + index = above->states.getNextSetIndex(index + 1); + if (index < numberOfStates) { + out << ", "; } - - out << "}"; } - out << "}" << "\n"; + + out << "}"; + } + out << "}" << "\n"; out << " Below: {"; @@ -216,45 +218,43 @@ namespace storm { } void Lattice::toDotFile(std::ostream &out) { - // TODO: op de een of andere manier ontstaan er nodes die nergens eindigen/beginnen - out << "digraph \"Lattice\" {" << std::endl; - - // print all nodes - std::vector printed; - out << "\t" << "node [shape=ellipse]" << std::endl; - for (auto itr = nodes.begin(); itr != nodes.end(); ++itr) { - - if ((*itr) != nullptr && find(printed.begin(), printed.end(), (*itr)) == printed.end()) { - out << "\t\"" << (*itr) << "\" [label = \""; - uint_fast64_t index = (*itr)->states.getNextSetIndex(0); - while (index < numberOfStates) { - out << index; - index = (*itr)->states.getNextSetIndex(index + 1); - if (index < numberOfStates) { - out << ", "; + out << "digraph \"Lattice\" {" << std::endl; + + // print all nodes + std::vector printed; + out << "\t" << "node [shape=ellipse]" << std::endl; + for (auto itr = nodes.begin(); itr != nodes.end(); ++itr) { + + if ((*itr) != nullptr && find(printed.begin(), printed.end(), (*itr)) == printed.end()) { + out << "\t\"" << (*itr) << "\" [label = \""; + uint_fast64_t index = (*itr)->states.getNextSetIndex(0); + while (index < numberOfStates) { + out << index; + index = (*itr)->states.getNextSetIndex(index + 1); + if (index < numberOfStates) { + out << ", "; + } } - } - out << "\"]" << std::endl; - printed.push_back(*itr); + out << "\"]" << std::endl; + printed.push_back(*itr); + } } - } - // print arcs - printed.clear(); - for (auto itr = nodes.begin(); itr != nodes.end(); ++itr) { - if ((*itr) != nullptr && find(printed.begin(), printed.end(), (*itr)) == printed.end()) { - auto below = (*itr)->below; - for (auto itr2 = below.begin(); itr2 != below.end(); ++itr2) { - out << "\t\"" << (*itr) << "\" -> \"" << (*itr2) << "\";" << std::endl; + // print arcs + printed.clear(); + for (auto itr = nodes.begin(); itr != nodes.end(); ++itr) { + if ((*itr) != nullptr && find(printed.begin(), printed.end(), (*itr)) == printed.end()) { + auto below = (*itr)->below; + for (auto itr2 = below.begin(); itr2 != below.end(); ++itr2) { + out << "\t\"" << (*itr) << "\" -> \"" << (*itr2) << "\";" << std::endl; + } + printed.push_back(*itr); } - printed.push_back(*itr); } - } - - out << "}" << std::endl; - } + out << "}" << std::endl; + } bool Lattice::above(Node *node1, Node *node2, std::set* seenNodes) { bool result = !node1->below.empty() && std::find(node1->below.begin(), node1->below.end(), node2) != node1->below.end(); diff --git a/src/storm-pars/analysis/Lattice.h b/src/storm-pars/analysis/Lattice.h index 806c1b6e7..a62d2763f 100644 --- a/src/storm-pars/analysis/Lattice.h +++ b/src/storm-pars/analysis/Lattice.h @@ -55,13 +55,10 @@ namespace storm { void add(uint_fast64_t state); /*! - * Adds a new relation to the lattice + * Adds a new relation between two nodes to the lattice * @param above The node closest to the top Node of the Lattice. - * @param between The node between above and below. * @param below The node closest to the bottom Node of the Lattice. */ - void addRelation(Node* above, Node* between, Node* below); - void addRelationNodes(storm::analysis::Lattice::Node *above, storm::analysis::Lattice::Node * below); /*! @@ -137,6 +134,8 @@ namespace storm { * @return */ bool above(Node * node1, Node * node2, std::set* seenNodes); + + int compare(Node* node1, Node* node2); }; } } From dc52e9b056eac7656468ab620091963f78023118 Mon Sep 17 00:00:00 2001 From: Jip Spel Date: Fri, 7 Sep 2018 12:57:56 +0200 Subject: [PATCH 049/178] Create copy of lattice and assumptionslist at earlier point --- src/storm-pars/analysis/AssumptionMaker.cpp | 20 ++++++++------------ src/storm-pars/analysis/AssumptionMaker.h | 1 - src/storm-pars/analysis/Lattice.cpp | 1 - 3 files changed, 8 insertions(+), 14 deletions(-) diff --git a/src/storm-pars/analysis/AssumptionMaker.cpp b/src/storm-pars/analysis/AssumptionMaker.cpp index 0fadf2bfc..134e52097 100644 --- a/src/storm-pars/analysis/AssumptionMaker.cpp +++ b/src/storm-pars/analysis/AssumptionMaker.cpp @@ -13,15 +13,12 @@ namespace storm { this->expressionManager = std::make_shared(storm::expressions::ExpressionManager()); for (uint_fast64_t i = 0; i < this->numberOfStates; ++i) { expressionManager->declareIntegerVariable(std::to_string(i)); - expressionManager->declareFreshIntegerVariable(); } } - template std::map>> AssumptionMaker::startMakingAssumptions(storm::analysis::Lattice* lattice, uint_fast64_t critical1, uint_fast64_t critical2) { - std::map>> result; std::set> emptySet; @@ -32,7 +29,9 @@ namespace storm { storm::expressions::Variable var2 = expressionManager->getVariable(std::to_string(critical2)); std::set> assumptions; - auto myMap = createAssumptions(var1, var2, lattice, assumptions); + auto latticeCopy = new Lattice(lattice); + std::set> assumptionsCopy = std::set>(assumptions); + auto myMap = createAssumptions(var1, var2, latticeCopy, assumptionsCopy); result.insert(myMap.begin(), myMap.end()); myMap = createAssumptions(var2, var1, lattice, assumptions); @@ -52,7 +51,9 @@ namespace storm { storm::expressions::Variable var1 = expressionManager->getVariable(std::to_string(std::get<1>(criticalPair))); storm::expressions::Variable var2 = expressionManager->getVariable(std::to_string(std::get<2>(criticalPair))); - auto myMap = createAssumptions(var1, var2, lattice, assumptions); + auto latticeCopy = new Lattice(lattice); + std::set> assumptionsCopy = std::set>(assumptions); + auto myMap = createAssumptions(var1, var2, latticeCopy, assumptionsCopy); result.insert(myMap.begin(), myMap.end()); myMap = createAssumptions(var2, var1, lattice, assumptions); result.insert(myMap.begin(), myMap.end()); @@ -63,19 +64,14 @@ namespace storm { template std::map>> AssumptionMaker::createAssumptions(storm::expressions::Variable var1, storm::expressions::Variable var2, storm::analysis::Lattice* lattice, std::set> assumptions) { - std::set> assumptions1 = std::set>(assumptions); std::shared_ptr assumption1 = std::make_shared(storm::expressions::BinaryRelationExpression(*expressionManager, var1.getType(), var1.getExpression().getBaseExpressionPointer(), var2.getExpression().getBaseExpressionPointer(), storm::expressions::BinaryRelationExpression::RelationType::Greater)); - assumptions1.insert(assumption1); - auto lattice1 = new Lattice(lattice); - return (runRecursive(lattice1, assumptions1)); + assumptions.insert(assumption1); + return (runRecursive(lattice, assumptions)); } template class AssumptionMaker; } } - - -// Een map met daarin een pointer naar de lattic en een set met de geldende assumptions voor die lattice \ No newline at end of file diff --git a/src/storm-pars/analysis/AssumptionMaker.h b/src/storm-pars/analysis/AssumptionMaker.h index 7061a43fb..2fa0a890c 100644 --- a/src/storm-pars/analysis/AssumptionMaker.h +++ b/src/storm-pars/analysis/AssumptionMaker.h @@ -19,7 +19,6 @@ namespace storm { std::map>> startMakingAssumptions(storm::analysis::Lattice* lattice, uint_fast64_t critical1, uint_fast64_t critical2); - private: std::map>> runRecursive(storm::analysis::Lattice* lattice, std::set> assumptions); diff --git a/src/storm-pars/analysis/Lattice.cpp b/src/storm-pars/analysis/Lattice.cpp index 1846b816e..a7e5acfe5 100644 --- a/src/storm-pars/analysis/Lattice.cpp +++ b/src/storm-pars/analysis/Lattice.cpp @@ -139,7 +139,6 @@ namespace storm { return UNKNOWN; } - Lattice::Node *Lattice::getNode(uint_fast64_t stateNumber) { return nodes.at(stateNumber); } From 90c325a38f200cab64acce2f998982cbac73cc2e Mon Sep 17 00:00:00 2001 From: Jip Spel Date: Mon, 10 Sep 2018 10:10:33 +0200 Subject: [PATCH 050/178] Make nodes variable before using it --- src/storm-pars/analysis/Lattice.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/storm-pars/analysis/Lattice.cpp b/src/storm-pars/analysis/Lattice.cpp index a7e5acfe5..001873698 100644 --- a/src/storm-pars/analysis/Lattice.cpp +++ b/src/storm-pars/analysis/Lattice.cpp @@ -50,8 +50,9 @@ namespace storm { nodes.at(i) = bottom; } + auto oldNodes = lattice->getNodes(); // Create all nodes - for (auto itr = lattice->getNodes().begin(); itr != lattice->getNodes().end(); ++itr) { + for (auto itr = oldNodes.begin(); itr != oldNodes.end(); ++itr) { Node* oldNode = (*itr); if (oldNode != nullptr) { Node *newNode = new Node(); @@ -65,7 +66,7 @@ namespace storm { } // Create transitions - for (auto itr = lattice->getNodes().begin(); itr != lattice->getNodes().end(); ++itr) { + for (auto itr = oldNodes.begin(); itr != oldNodes.end(); ++itr) { Node* oldNode = (*itr); if (oldNode != nullptr) { auto state = (*itr)->states.getNextSetIndex(0); From 7c1929948859bd5ade8ad5137ca3de39fce808cf Mon Sep 17 00:00:00 2001 From: Jip Spel Date: Mon, 10 Sep 2018 11:20:20 +0200 Subject: [PATCH 051/178] Handle cycles in pMCs --- src/storm-pars/analysis/LatticeExtender.cpp | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/src/storm-pars/analysis/LatticeExtender.cpp b/src/storm-pars/analysis/LatticeExtender.cpp index f3e7f2476..f24360852 100644 --- a/src/storm-pars/analysis/LatticeExtender.cpp +++ b/src/storm-pars/analysis/LatticeExtender.cpp @@ -111,15 +111,10 @@ namespace storm { } } - // Create a copy of the states already present in the lattice. - storm::storage::BitVector seenStates = (lattice->getAddedStates()); - storm::storage::BitVector oldStates(numberOfStates); - - while (oldStates != seenStates) { - // As long as new states are added to the lattice, continue. - oldStates = storm::storage::BitVector(seenStates); - + auto oldNumberSet = lattice->getAddedStates().getNumberOfSetBits(); + while (lattice->getAddedStates().getNumberOfSetBits() != numberOfStates) { for (auto stateItr = stateMap.begin(); stateItr != stateMap.end(); ++stateItr) { + storm::storage::BitVector seenStates = (lattice->getAddedStates()); // Iterate over all states auto stateNumber = stateItr->first; storm::storage::BitVector successors = stateItr->second; @@ -133,7 +128,6 @@ namespace storm { if (check && successors.getNumberOfSetBits() == 1) { // As there is only one successor the current state and its successor must be at the same nodes. lattice->addToNode(stateNumber, lattice->getNode(successors.getNextSetIndex(0))); - seenStates.set(stateNumber); } else if (check && successors.getNumberOfSetBits() > 1) { // TODO: allow more than 2 transitions? // Otherwise, check how the two states compare, and add if the comparison is possible. @@ -155,9 +149,14 @@ namespace storm { } else { return std::make_tuple(lattice, successor1, successor2); } - seenStates.set(stateNumber); } } + // Nothing changed and not done yet + if (oldNumberSet == lattice->getAddedStates().getNumberOfSetBits()) { + // add the first unset state to the lattice between top and bottom + lattice->add(lattice->getAddedStates().getNextUnsetIndex(0)); + } + oldNumberSet = lattice->getAddedStates().getNumberOfSetBits(); } return std::make_tuple(lattice, numberOfStates, numberOfStates); } From 9d02519b01adbd75d43eee3210e6f7bda911dcf4 Mon Sep 17 00:00:00 2001 From: Jip Spel Date: Mon, 10 Sep 2018 13:41:49 +0200 Subject: [PATCH 052/178] Allow more than 2 outgoing transitions --- src/storm-pars/analysis/LatticeExtender.cpp | 7 +- .../analysis/MonotonicityChecker.cpp | 87 +++++++++++-------- 2 files changed, 56 insertions(+), 38 deletions(-) diff --git a/src/storm-pars/analysis/LatticeExtender.cpp b/src/storm-pars/analysis/LatticeExtender.cpp index f24360852..24d5c4039 100644 --- a/src/storm-pars/analysis/LatticeExtender.cpp +++ b/src/storm-pars/analysis/LatticeExtender.cpp @@ -67,8 +67,6 @@ namespace storm { for (auto rowItr = row.begin(); rowItr != row.end(); ++rowItr) { stateMap[i].set(rowItr->getColumn(), true); } - // TODO: allow more than 2 transitions? or fix this in preprocessing? - STORM_LOG_THROW(stateMap[i].getNumberOfSetBits() <= 2, storm::exceptions::NotSupportedException, "Only two outgoing transitions per state allowed"); } // Create the Lattice @@ -128,8 +126,7 @@ namespace storm { if (check && successors.getNumberOfSetBits() == 1) { // As there is only one successor the current state and its successor must be at the same nodes. lattice->addToNode(stateNumber, lattice->getNode(successors.getNextSetIndex(0))); - } else if (check && successors.getNumberOfSetBits() > 1) { - // TODO: allow more than 2 transitions? + } else if (check && successors.getNumberOfSetBits() == 2) { // Otherwise, check how the two states compare, and add if the comparison is possible. uint_fast64_t successor1 = successors.getNextSetIndex(0); uint_fast64_t successor2 = successors.getNextSetIndex(successor1 + 1); @@ -149,6 +146,8 @@ namespace storm { } else { return std::make_tuple(lattice, successor1, successor2); } + } else if (check && successors.getNumberOfSetBits() > 2) { + // TODO } } // Nothing changed and not done yet diff --git a/src/storm-pars/analysis/MonotonicityChecker.cpp b/src/storm-pars/analysis/MonotonicityChecker.cpp index a925bc555..d211c8fb8 100644 --- a/src/storm-pars/analysis/MonotonicityChecker.cpp +++ b/src/storm-pars/analysis/MonotonicityChecker.cpp @@ -21,21 +21,23 @@ namespace storm { lattice->toDotFile(myfile); myfile.close(); - STORM_PRINT("Given assumptions: " << std::endl); - bool first = true; - for (auto itr = assumptions.begin(); itr != assumptions.end(); ++itr) { - if (!first) { - STORM_PRINT(" ^ "); - } else { - STORM_PRINT(" "); + if (assumptions.size() > 0) { + STORM_PRINT("Given assumptions: " << std::endl); + bool first = true; + for (auto itr = assumptions.begin(); itr != assumptions.end(); ++itr) { + if (!first) { + STORM_PRINT(" ^ "); + } else { + STORM_PRINT(" "); + } + first = false; + std::shared_ptr expression = *itr; + auto var1 = expression->getFirstOperand(); + auto var2 = expression->getSecondOperand(); + STORM_PRINT("(" << var1->getIdentifier() << " > " << var2->getIdentifier() << ")"); } - first = false; - std::shared_ptr expression = *itr; - auto var1 = expression->getFirstOperand(); - auto var2 = expression->getSecondOperand(); - STORM_PRINT("(" << var1->getIdentifier() << " > " << var2->getIdentifier() << ")"); + STORM_PRINT(std::endl); } - STORM_PRINT(std::endl); std::map> varsMonotone = analyseMonotonicity(i, lattice, matrix); for (auto itr2 = varsMonotone.begin(); itr2 != varsMonotone.end(); ++itr2) { @@ -75,34 +77,49 @@ namespace storm { auto first = (*row.begin()); if (first.getValue() != ValueType(1)) { - auto second = (*(++row.begin())); + std::map transitions; + + for (auto itr = row.begin(); itr != row.end(); ++itr) { + transitions.insert(std::pair((*itr).getColumn(), (*itr).getValue())); + } + std::string color = ""; auto val = first.getValue(); auto vars = val.gatherVariables(); for (auto itr = vars.begin(); itr != vars.end(); ++itr) { - auto derivative = val.derivative(*itr); - STORM_LOG_THROW(derivative.isConstant(), storm::exceptions::NotSupportedException, "Expecting derivative to be constant"); - if (varsMonotone.find(*itr) == varsMonotone.end()) { varsMonotone[*itr].first = true; varsMonotone[*itr].second = true; } - - auto compare = lattice->compare(first.getColumn(), second.getColumn()); std::pair* value = &varsMonotone.find(*itr)->second; std::pair old = *value; - if (compare == storm::analysis::Lattice::ABOVE) { - value->first &=derivative.constantPart() >= 0; - value->second &=derivative.constantPart() <= 0; - } else if (compare == storm::analysis::Lattice::BELOW) { - value->first &=derivative.constantPart() <= 0; - value->second &=derivative.constantPart() >= 0; - } else if (compare == storm::analysis::Lattice::SAME) { - // Behaviour doesn't matter, as they are at the same level - } else { - value->first = false; - value->second = false; + + for (auto itr2 = transitions.begin(); itr2 != transitions.end(); ++itr2) { + for (auto itr3 = transitions.begin(); itr3 != transitions.end(); ++itr3) { + // TODO improve + + auto derivative2 = (*itr2).second.derivative(*itr); + auto derivative3 = (*itr3).second.derivative(*itr); + STORM_LOG_THROW(derivative2.isConstant() && derivative3.isConstant(), storm::exceptions::NotSupportedException, "Expecting derivative to be constant"); + + auto compare = lattice->compare((*itr2).first, (*itr3).first); + + if (compare == storm::analysis::Lattice::ABOVE) { + value->first &=derivative2.constantPart() >= 0; + value->second &=derivative2.constantPart() <= 0; + } else if (compare == storm::analysis::Lattice::BELOW) { + value->first &=derivative3.constantPart() <= 0; + value->second &=derivative3.constantPart() >= 0; + } else if (compare == storm::analysis::Lattice::SAME) { + // Behaviour doesn't matter, as they are at the same level + } else { + value->first = false; + value->second = false; + } + } } + + if ((value->first != old.first) && (value->second != old.second)) { color = "color = red, "; } else if ((value->first != old.first)) { @@ -114,10 +131,12 @@ namespace storm { } } - myfile << "\t" << i << " -> " << first.getColumn() << "[" << color << "label=\"" << first.getValue() << "\"];" - << std::endl; - myfile << "\t" << i << " -> " << second.getColumn() << "[" << color << "label=\"" << second.getValue() << "\"];" - << std::endl; + for (auto itr = transitions.begin(); itr != transitions.end(); ++itr) { + myfile << "\t" << i << " -> " << itr->first << "[" << color << "label=\"" << itr->second << "\"];" + << std::endl; + } + + myfile << "\t edge[style=\"\"];" << std::endl; } else { myfile << "\t" << i << " -> " << first.getColumn() << "[label=\"" << first.getValue() << "\"];" From c256bd167769af16a4cef3d822e2c51f07823d01 Mon Sep 17 00:00:00 2001 From: Jip Spel Date: Mon, 10 Sep 2018 14:04:13 +0200 Subject: [PATCH 053/178] Fix derivative comparison MonotonicityChecker --- src/storm-pars/analysis/MonotonicityChecker.cpp | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/storm-pars/analysis/MonotonicityChecker.cpp b/src/storm-pars/analysis/MonotonicityChecker.cpp index d211c8fb8..8d2537598 100644 --- a/src/storm-pars/analysis/MonotonicityChecker.cpp +++ b/src/storm-pars/analysis/MonotonicityChecker.cpp @@ -86,8 +86,7 @@ namespace storm { std::string color = ""; auto val = first.getValue(); auto vars = val.gatherVariables(); - for (auto itr = vars.begin(); itr != vars.end(); ++itr) { - if (varsMonotone.find(*itr) == varsMonotone.end()) { + for (auto itr = vars.begin(); itr != vars.end(); ++itr) { if (varsMonotone.find(*itr) == varsMonotone.end()) { varsMonotone[*itr].first = true; varsMonotone[*itr].second = true; } @@ -97,7 +96,6 @@ namespace storm { for (auto itr2 = transitions.begin(); itr2 != transitions.end(); ++itr2) { for (auto itr3 = transitions.begin(); itr3 != transitions.end(); ++itr3) { // TODO improve - auto derivative2 = (*itr2).second.derivative(*itr); auto derivative3 = (*itr3).second.derivative(*itr); STORM_LOG_THROW(derivative2.isConstant() && derivative3.isConstant(), storm::exceptions::NotSupportedException, "Expecting derivative to be constant"); @@ -108,8 +106,8 @@ namespace storm { value->first &=derivative2.constantPart() >= 0; value->second &=derivative2.constantPart() <= 0; } else if (compare == storm::analysis::Lattice::BELOW) { - value->first &=derivative3.constantPart() <= 0; - value->second &=derivative3.constantPart() >= 0; + value->first &=derivative3.constantPart() >= 0; + value->second &=derivative3.constantPart() <= 0; } else if (compare == storm::analysis::Lattice::SAME) { // Behaviour doesn't matter, as they are at the same level } else { From 581410c54b31de8b94ef1c7f0c3c90b7b7dad847 Mon Sep 17 00:00:00 2001 From: Jip Spel Date: Tue, 11 Sep 2018 11:16:15 +0200 Subject: [PATCH 054/178] Add check acyclic --- src/storm-pars-cli/storm-pars.cpp | 172 ++++++++++++++++-------------- 1 file changed, 90 insertions(+), 82 deletions(-) diff --git a/src/storm-pars-cli/storm-pars.cpp b/src/storm-pars-cli/storm-pars.cpp index d57c4932f..befc25505 100644 --- a/src/storm-pars-cli/storm-pars.cpp +++ b/src/storm-pars-cli/storm-pars.cpp @@ -52,7 +52,7 @@ namespace storm { namespace pars { - + typedef typename storm::cli::SymbolicInput SymbolicInput; template @@ -60,11 +60,11 @@ namespace storm { SampleInformation(bool graphPreserving = false, bool exact = false) : graphPreserving(graphPreserving), exact(exact) { // Intentionally left empty. } - + bool empty() const { return cartesianProducts.empty(); } - + std::vector::type, std::vector::type>>> cartesianProducts; bool graphPreserving; bool exact; @@ -79,7 +79,7 @@ namespace storm { } return result; } - + template SampleInformation parseSamples(std::shared_ptr const& model, std::string const& sampleString, bool graphPreserving) { STORM_LOG_THROW(!model || model->isSparseModel(), storm::exceptions::NotSupportedException, "Sampling is only supported for sparse models."); @@ -88,7 +88,7 @@ namespace storm { if (sampleString.empty()) { return sampleInfo; } - + // Get all parameters from the model. std::set::type> modelParameters; auto const& sparseModel = *model->as>(); @@ -100,14 +100,14 @@ namespace storm { boost::split(cartesianProducts, sampleString, boost::is_any_of(";")); for (auto& product : cartesianProducts) { boost::trim(product); - + // Get the values string for each variable. std::vector valuesForVariables; boost::split(valuesForVariables, product, boost::is_any_of(",")); for (auto& values : valuesForVariables) { boost::trim(values); } - + std::set::type> encounteredParameters; sampleInfo.cartesianProducts.emplace_back(); auto& newCartesianProduct = sampleInfo.cartesianProducts.back(); @@ -118,7 +118,7 @@ namespace storm { boost::trim(variableName); std::string values = varValues.substr(equalsPosition + 1); boost::trim(values); - + bool foundParameter = false; typename utility::parametric::VariableType::type theParameter; for (auto const& parameter : modelParameters) { @@ -131,56 +131,56 @@ namespace storm { } } STORM_LOG_THROW(foundParameter, storm::exceptions::WrongFormatException, "Unknown parameter '" << variableName << "'."); - + std::vector splitValues; boost::split(splitValues, values, boost::is_any_of(":")); STORM_LOG_THROW(!splitValues.empty(), storm::exceptions::WrongFormatException, "Expecting at least one value per parameter."); - + auto& list = newCartesianProduct[theParameter]; - + for (auto& value : splitValues) { boost::trim(value); list.push_back(storm::utility::convertNumber::type>(value)); } } - + STORM_LOG_THROW(encounteredParameters == modelParameters, storm::exceptions::WrongFormatException, "Variables for all parameters are required when providing samples."); } - + return sampleInfo; } - + template std::pair, bool> preprocessSparseModel(std::shared_ptr> const& model, SymbolicInput const& input) { auto generalSettings = storm::settings::getModule(); auto bisimulationSettings = storm::settings::getModule(); auto parametricSettings = storm::settings::getModule(); - + std::pair, bool> result = std::make_pair(model, false); - + if (result.first->isOfType(storm::models::ModelType::MarkovAutomaton)) { result.first = storm::cli::preprocessSparseMarkovAutomaton(result.first->template as>()); result.second = true; } - + if (generalSettings.isBisimulationSet()) { result.first = storm::cli::preprocessSparseModelBisimulation(result.first->template as>(), input, bisimulationSettings); result.second = true; } - + if (parametricSettings.transformContinuousModel() && (result.first->isOfType(storm::models::ModelType::Ctmc) || result.first->isOfType(storm::models::ModelType::MarkovAutomaton))) { result.first = storm::api::transformContinuousToDiscreteTimeSparseModel(std::move(*result.first->template as>()), storm::api::extractFormulasFromProperties(input.properties)); result.second = true; } - + return result; } - + template std::pair, bool> preprocessDdModel(std::shared_ptr> const& model, SymbolicInput const& input) { - + std::pair, bool> result = std::make_pair(model, false); - + auto coreSettings = storm::settings::getModule(); if (coreSettings.getEngine() == storm::settings::modules::CoreSettings::Engine::Hybrid) { // Currently, hybrid engine for parametric models just referrs to building the model symbolically. @@ -195,11 +195,11 @@ namespace storm { } return result; } - + template std::pair, bool> preprocessModel(std::shared_ptr const& model, SymbolicInput const& input) { storm::utility::Stopwatch preprocessingWatch(true); - + std::pair, bool> result = std::make_pair(model, false); if (model->isSparseModel()) { result = storm::pars::preprocessSparseModel(result.first->as>(), input); @@ -207,13 +207,13 @@ namespace storm { STORM_LOG_ASSERT(model->isSymbolicModel(), "Unexpected model type."); result = storm::pars::preprocessDdModel(result.first->as>(), input); } - + if (result.second) { STORM_PRINT_AND_LOG(std::endl << "Time for model preprocessing: " << preprocessingWatch << "." << std::endl << std::endl); } return result; } - + template void printInitialStatesResult(std::unique_ptr const& result, storm::jani::Property const& property, storm::utility::Stopwatch* watch = nullptr, storm::utility::parametric::Valuation const* valuation = nullptr) { if (result) { @@ -229,11 +229,11 @@ namespace storm { } ss << entry.first << "=" << entry.second; } - + STORM_PRINT_AND_LOG(" for instance [" << ss.str() << "]"); } STORM_PRINT_AND_LOG(": ") - + auto const* regionCheckResult = dynamic_cast const*>(result.get()); if (regionCheckResult != nullptr) { auto regionSettings = storm::settings::getModule(); @@ -262,7 +262,7 @@ namespace storm { STORM_PRINT_AND_LOG(" failed, property is unsupported by selected engine/settings." << std::endl); } } - + template void verifyProperties(std::vector const& properties, std::function(std::shared_ptr const& formula)> const& verificationCallback, std::function const&)> const& postprocessingCallback) { for (auto const& property : properties) { @@ -274,59 +274,59 @@ namespace storm { postprocessingCallback(result); } } - + template class ModelCheckerType, typename ModelType, typename ValueType, typename SolveValueType = double> void verifyPropertiesAtSamplePoints(ModelType const& model, SymbolicInput const& input, SampleInformation const& samples) { - + // When samples are provided, we create an instantiation model checker. ModelCheckerType modelchecker(model); - + for (auto const& property : input.properties) { storm::cli::printModelCheckingProperty(property); - + modelchecker.specifyFormula(storm::api::createTask(property.getRawFormula(), true)); modelchecker.setInstantiationsAreGraphPreserving(samples.graphPreserving); - + storm::utility::parametric::Valuation valuation; - + std::vector::type> parameters; std::vector::type>::const_iterator> iterators; std::vector::type>::const_iterator> iteratorEnds; - + storm::utility::Stopwatch watch(true); for (auto const& product : samples.cartesianProducts) { parameters.clear(); iterators.clear(); iteratorEnds.clear(); - + for (auto const& entry : product) { parameters.push_back(entry.first); iterators.push_back(entry.second.cbegin()); iteratorEnds.push_back(entry.second.cend()); } - + bool done = false; while (!done) { // Read off valuation. for (uint64_t i = 0; i < parameters.size(); ++i) { valuation[parameters[i]] = *iterators[i]; } - + storm::utility::Stopwatch valuationWatch(true); std::unique_ptr result = modelchecker.check(Environment(), valuation); valuationWatch.stop(); - + if (result) { result->filter(storm::modelchecker::ExplicitQualitativeCheckResult(model.getInitialStates())); } printInitialStatesResult(result, property, &valuationWatch, &valuation); - + for (uint64_t i = 0; i < parameters.size(); ++i) { ++iterators[i]; if (iterators[i] == iteratorEnds[i]) { // Reset iterator and proceed to move next iterator. iterators[i] = product.at(parameters[i]).cbegin(); - + // If the last iterator was removed, we are done. if (i == parameters.size() - 1) { done = true; @@ -336,15 +336,15 @@ namespace storm { break; } } - + } } - + watch.stop(); STORM_PRINT_AND_LOG("Overall time for sampling all instances: " << watch << std::endl << std::endl); } } - + template void verifyPropertiesAtSamplePoints(std::shared_ptr> const& model, SymbolicInput const& input, SampleInformation const& samples) { if (model->isOfType(storm::models::ModelType::Dtmc)) { @@ -357,10 +357,10 @@ namespace storm { STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Sampling is currently only supported for DTMCs, CTMCs and MDPs."); } } - + template void verifyPropertiesWithSparseEngine(std::shared_ptr> const& model, SymbolicInput const& input, SampleInformation const& samples) { - + if (samples.empty()) { verifyProperties(input.properties, [&model] (std::shared_ptr const& formula) { @@ -380,7 +380,7 @@ namespace storm { }); } else { STORM_LOG_TRACE("Sampling the model at given points."); - + if (samples.exact) { verifyPropertiesAtSamplePoints(model, input, samples); } else { @@ -388,17 +388,17 @@ namespace storm { } } } - + template void verifyRegionsWithSparseEngine(std::shared_ptr> const& model, SymbolicInput const& input, std::vector> const& regions) { STORM_LOG_ASSERT(!regions.empty(), "Can not analyze an empty set of regions."); - + auto parametricSettings = storm::settings::getModule(); auto regionSettings = storm::settings::getModule(); - + std::function(std::shared_ptr const& formula)> verificationCallback; std::function const&)> postprocessingCallback; - + STORM_PRINT_AND_LOG(std::endl); if (regionSettings.isHypothesisSet()) { STORM_PRINT_AND_LOG("Checking hypothesis " << regionSettings.getHypothesis() << " on "); @@ -412,37 +412,37 @@ namespace storm { } auto engine = regionSettings.getRegionCheckEngine(); STORM_PRINT_AND_LOG(" using " << engine); - + // Check the given set of regions with or without refinement if (regionSettings.isRefineSet()) { STORM_LOG_THROW(regions.size() == 1, storm::exceptions::NotSupportedException, "Region refinement is not supported for multiple initial regions."); STORM_PRINT_AND_LOG(" with iterative refinement until " << (1.0 - regionSettings.getCoverageThreshold()) * 100.0 << "% is covered." << (regionSettings.isDepthLimitSet() ? " Depth limit is " + std::to_string(regionSettings.getDepthLimit()) + "." : "") << std::endl); verificationCallback = [&] (std::shared_ptr const& formula) { - ValueType refinementThreshold = storm::utility::convertNumber(regionSettings.getCoverageThreshold()); - boost::optional optionalDepthLimit; - if (regionSettings.isDepthLimitSet()) { - optionalDepthLimit = regionSettings.getDepthLimit(); - } - std::unique_ptr> result = storm::api::checkAndRefineRegionWithSparseEngine(model, storm::api::createTask(formula, true), regions.front(), engine, refinementThreshold, optionalDepthLimit, regionSettings.getHypothesis()); - return result; - }; + ValueType refinementThreshold = storm::utility::convertNumber(regionSettings.getCoverageThreshold()); + boost::optional optionalDepthLimit; + if (regionSettings.isDepthLimitSet()) { + optionalDepthLimit = regionSettings.getDepthLimit(); + } + std::unique_ptr> result = storm::api::checkAndRefineRegionWithSparseEngine(model, storm::api::createTask(formula, true), regions.front(), engine, refinementThreshold, optionalDepthLimit, regionSettings.getHypothesis()); + return result; + }; } else { STORM_PRINT_AND_LOG("." << std::endl); verificationCallback = [&] (std::shared_ptr const& formula) { - std::unique_ptr result = storm::api::checkRegionsWithSparseEngine(model, storm::api::createTask(formula, true), regions, engine, regionSettings.getHypothesis()); - return result; - }; + std::unique_ptr result = storm::api::checkRegionsWithSparseEngine(model, storm::api::createTask(formula, true), regions, engine, regionSettings.getHypothesis()); + return result; + }; } - + postprocessingCallback = [&] (std::unique_ptr const& result) { - if (parametricSettings.exportResultToFile()) { - storm::api::exportRegionCheckResultToFile(result, parametricSettings.exportResultPath()); - } - }; - + if (parametricSettings.exportResultToFile()) { + storm::api::exportRegionCheckResultToFile(result, parametricSettings.exportResultPath()); + } + }; + verifyProperties(input.properties, verificationCallback, postprocessingCallback); } - + template void verifyWithSparseEngine(std::shared_ptr> const& model, SymbolicInput const& input, std::vector> const& regions, SampleInformation const& samples) { if (regions.empty()) { @@ -466,19 +466,19 @@ namespace storm { auto buildSettings = storm::settings::getModule(); auto parSettings = storm::settings::getModule(); - + auto engine = coreSettings.getEngine(); STORM_LOG_THROW(engine == storm::settings::modules::CoreSettings::Engine::Sparse || engine == storm::settings::modules::CoreSettings::Engine::Hybrid || engine == storm::settings::modules::CoreSettings::Engine::Dd, storm::exceptions::InvalidSettingsException, "The selected engine is not supported for parametric models."); - + std::shared_ptr model; if (!buildSettings.isNoBuildModelSet()) { model = storm::cli::buildModel(engine, input, ioSettings); } - + if (model) { model->printModelInformationToStream(std::cout); } - + STORM_LOG_THROW(model || input.properties.empty(), storm::exceptions::InvalidSettingsException, "No input model."); if (parSettings.isMonotonicityAnalysisSet()) { @@ -527,17 +527,25 @@ namespace storm { if (parSettings.isMonotonicityAnalysisSet()) { std::cout << "Hello, Jip2" << std::endl; + std::vector> formulas = storm::api::extractFormulasFromProperties(input.properties); std::shared_ptr> sparseModel = model->as>(); + // Check if MC is acyclic + auto decomposition = storm::storage::StronglyConnectedComponentDecomposition(sparseModel->getTransitionMatrix(), false, false); + for (auto i = 0; i < decomposition.size(); ++i) { + auto scc = decomposition.getBlock(i); + STORM_LOG_THROW(scc.size() <= 1, storm::exceptions::NotSupportedException, "Cycle found, not supporting cyclic MCs"); + } + + // Transform to Lattices storm::utility::Stopwatch latticeWatch(true); storm::analysis::LatticeExtender *extender = new storm::analysis::LatticeExtender(sparseModel); std::tuple criticalPair = extender->toLattice(formulas); - - auto assumptionMaker = storm::analysis::AssumptionMaker(extender, sparseModel->getNumberOfStates()); std::map>> result = assumptionMaker.startMakingAssumptions(std::get<0>(criticalPair), std::get<1>(criticalPair), std::get<2>(criticalPair)); + latticeWatch.stop(); STORM_PRINT(std::endl << "Time for lattice creation: " << latticeWatch << "." << std::endl << std::endl); @@ -559,7 +567,7 @@ namespace storm { samples = parseSamples(model, samplesAsString, parSettings.isSamplesAreGraphPreservingSet()); samples.exact = parSettings.isSampleExactSet(); } - + if (model) { storm::cli::exportModel(model, input); } @@ -574,18 +582,18 @@ namespace storm { verifyParametricModel(model, input, regions, samples); } } - + void processOptions() { // Start by setting some urgent options (log levels, resources, etc.) storm::cli::setUrgentOptions(); - + // Parse and preprocess symbolic input (PRISM, JANI, properties, etc.) SymbolicInput symbolicInput = storm::cli::parseAndPreprocessSymbolicInput(); - + auto coreSettings = storm::settings::getModule(); auto engine = coreSettings.getEngine(); STORM_LOG_WARN_COND(engine != storm::settings::modules::CoreSettings::Engine::Dd || engine != storm::settings::modules::CoreSettings::Engine::Hybrid || coreSettings.getDdLibraryType() == storm::dd::DdType::Sylvan, "The selected DD library does not support parametric models. Switching to Sylvan..."); - + processInputWithValueTypeAndDdlib(symbolicInput); } From 92193cfb0819fee979c1d53980463e548d9ba08a Mon Sep 17 00:00:00 2001 From: Jip Spel Date: Thu, 13 Sep 2018 14:54:06 +0200 Subject: [PATCH 055/178] WIP: Check assumptions on samples --- src/storm-pars-cli/storm-pars.cpp | 6 ++ src/storm-pars/analysis/AssumptionChecker.cpp | 72 +++++++++++++++++++ src/storm-pars/analysis/AssumptionChecker.h | 35 +++++++++ src/storm-pars/analysis/AssumptionMaker.cpp | 58 +++++++++------ src/storm-pars/analysis/AssumptionMaker.h | 7 +- src/storm-pars/analysis/LatticeExtender.cpp | 4 +- .../analysis/MonotonicityChecker.cpp | 2 - 7 files changed, 158 insertions(+), 26 deletions(-) create mode 100644 src/storm-pars/analysis/AssumptionChecker.cpp create mode 100644 src/storm-pars/analysis/AssumptionChecker.h diff --git a/src/storm-pars-cli/storm-pars.cpp b/src/storm-pars-cli/storm-pars.cpp index befc25505..ed8cc4a57 100644 --- a/src/storm-pars-cli/storm-pars.cpp +++ b/src/storm-pars-cli/storm-pars.cpp @@ -543,6 +543,12 @@ namespace storm { storm::utility::Stopwatch latticeWatch(true); storm::analysis::LatticeExtender *extender = new storm::analysis::LatticeExtender(sparseModel); std::tuple criticalPair = extender->toLattice(formulas); + // TODO check not mdp + auto dtmcModel = model->as>(); + // TODO check formula type + auto assumptionChecker = storm::analysis::AssumptionChecker(formulas[0], dtmcModel, 3); + auto assumptionMaker = storm::analysis::AssumptionMaker(extender, &assumptionChecker, sparseModel->getNumberOfStates()); + std::map>> result = assumptionMaker.startMakingAssumptions(std::get<0>(criticalPair), std::get<1>(criticalPair), std::get<2>(criticalPair)); diff --git a/src/storm-pars/analysis/AssumptionChecker.cpp b/src/storm-pars/analysis/AssumptionChecker.cpp new file mode 100644 index 000000000..6727793c0 --- /dev/null +++ b/src/storm-pars/analysis/AssumptionChecker.cpp @@ -0,0 +1,72 @@ +// +// Created by Jip Spel on 12.09.18. +// + +#include +#include +#include +#include "AssumptionChecker.h" +#include "storm/modelchecker/CheckTask.h" +#include "storm/environment/Environment.h" +#include "storm/modelchecker/results/CheckResult.h" +#include "storm/modelchecker/results/ExplicitQuantitativeCheckResult.h" + + + + +namespace storm { + namespace analysis { + template + AssumptionChecker::AssumptionChecker(std::shared_ptr formula, std::shared_ptr> model, uint_fast64_t numberOfSamples) { + this->formula = formula; + + auto instantiator = storm::utility::ModelInstantiator, storm::models::sparse::Dtmc>(*model.get()); + auto matrix = model->getTransitionMatrix(); + std::set variables = storm::models::sparse::getProbabilityParameters(*model); + + + for (auto i = 0; i < numberOfSamples; ++i) { + auto valuation = storm::utility::parametric::Valuation(); + for (auto itr = variables.begin(); itr != variables.end(); ++itr) { + auto val = std::pair((*itr), storm::utility::convertNumber(boost::lexical_cast((i+1)/(double (numberOfSamples + 1))))); + valuation.insert(val); + } + storm::models::sparse::Dtmc sampleModel = instantiator.instantiate(valuation); + auto checker = storm::modelchecker::SparseDtmcPrctlModelChecker>(sampleModel); + std::unique_ptr checkResult; + if (formula->isProbabilityOperatorFormula() && + formula->asProbabilityOperatorFormula().getSubformula().isUntilFormula()) { + const storm::modelchecker::CheckTask checkTask = storm::modelchecker::CheckTask( + (*formula).asProbabilityOperatorFormula().getSubformula().asUntilFormula()); + checkResult = checker.computeUntilProbabilities(Environment(), checkTask); + } else if (formula->isProbabilityOperatorFormula() && + formula->asProbabilityOperatorFormula().getSubformula().isEventuallyFormula()) { + const storm::modelchecker::CheckTask checkTask = storm::modelchecker::CheckTask( + (*formula).asProbabilityOperatorFormula().getSubformula().asEventuallyFormula()); + checkResult = checker.computeReachabilityProbabilities(Environment(), checkTask); + } else { + STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, + "Expecting until or eventually formula"); + } + auto quantitativeResult = checkResult->asExplicitQuantitativeCheckResult(); + std::vector values = quantitativeResult.getValueVector(); + results.push_back(values); + } + this->numberOfStates = model->getNumberOfStates(); + this->initialStates = model->getInitialStates(); + } + + template + bool AssumptionChecker::checkOnSamples(uint_fast64_t val1, uint_fast64_t val2) { + bool result = true; + for (auto itr = results.begin(); result && itr != results.end(); ++itr) { + // TODO: als expressie + auto values = (*itr); + result &= (values[val1] >= values[val2]); + } + return result; + } + + template class AssumptionChecker; + } +} \ No newline at end of file diff --git a/src/storm-pars/analysis/AssumptionChecker.h b/src/storm-pars/analysis/AssumptionChecker.h new file mode 100644 index 000000000..7bd8cc916 --- /dev/null +++ b/src/storm-pars/analysis/AssumptionChecker.h @@ -0,0 +1,35 @@ +// +// Created by Jip Spel on 12.09.18. +// + +#ifndef STORM_ASSUMPTIONCHECKER_H +#define STORM_ASSUMPTIONCHECKER_H + +#include +#include +#include "storm/environment/Environment.h" + +namespace storm { + namespace analysis { + template + class AssumptionChecker { + public: + AssumptionChecker(std::shared_ptr formula, std::shared_ptr> model, uint_fast64_t numberOfSamples); + + bool checkOnSamples(uint_fast64_t val1, uint_fast64_t val2); + private: + std::shared_ptr formula; + + std::vector> sampleModels; + + std::vector> results; + + uint_fast64_t numberOfStates; + + storm::storage::BitVector initialStates; + }; + } +} + + +#endif //STORM_ASSUMPTIONCHECKER_H diff --git a/src/storm-pars/analysis/AssumptionMaker.cpp b/src/storm-pars/analysis/AssumptionMaker.cpp index 134e52097..d61b5ef28 100644 --- a/src/storm-pars/analysis/AssumptionMaker.cpp +++ b/src/storm-pars/analysis/AssumptionMaker.cpp @@ -7,9 +7,10 @@ namespace storm { namespace analysis { template - AssumptionMaker::AssumptionMaker(storm::analysis::LatticeExtender* latticeExtender, uint_fast64_t numberOfStates) { + AssumptionMaker::AssumptionMaker(storm::analysis::LatticeExtender* latticeExtender, storm::analysis::AssumptionChecker* assumptionChecker, uint_fast64_t numberOfStates) { this->latticeExtender = latticeExtender; this->numberOfStates = numberOfStates; + this->assumptionChecker = assumptionChecker; this->expressionManager = std::make_shared(storm::expressions::ExpressionManager()); for (uint_fast64_t i = 0; i < this->numberOfStates; ++i) { expressionManager->declareIntegerVariable(std::to_string(i)); @@ -27,15 +28,20 @@ namespace storm { } else { storm::expressions::Variable var1 = expressionManager->getVariable(std::to_string(critical1)); storm::expressions::Variable var2 = expressionManager->getVariable(std::to_string(critical2)); - std::set> assumptions; - auto latticeCopy = new Lattice(lattice); - std::set> assumptionsCopy = std::set>(assumptions); - auto myMap = createAssumptions(var1, var2, latticeCopy, assumptionsCopy); - result.insert(myMap.begin(), myMap.end()); - - myMap = createAssumptions(var2, var1, lattice, assumptions); - result.insert(myMap.begin(), myMap.end()); + if (assumptionChecker->checkOnSamples(critical1, critical2)) { + auto latticeCopy = new Lattice(lattice); + std::set> assumptions; + auto myMap = createAssumptions(var1, var2, latticeCopy, assumptions); + result.insert(myMap.begin(), myMap.end()); + } + if (assumptionChecker->checkOnSamples(critical2, critical1)) { + std::set> assumptions; + auto myMap = createAssumptions(var2, var1, lattice, assumptions); + result.insert(myMap.begin(), myMap.end()); + } else { + delete lattice; + } } return result; } @@ -43,22 +49,30 @@ namespace storm { template std::map>> AssumptionMaker::runRecursive(storm::analysis::Lattice* lattice, std::set> assumptions) { std::map>> result; - std::tuple criticalPair = this->latticeExtender->extendLattice(lattice, assumptions); + std::tuple criticalTriple = this->latticeExtender->extendLattice(lattice, assumptions); - if (std::get<1>(criticalPair) == numberOfStates) { + if (std::get<1>(criticalTriple) == numberOfStates) { result.insert(std::pair>>(lattice, assumptions)); } else { - storm::expressions::Variable var1 = expressionManager->getVariable(std::to_string(std::get<1>(criticalPair))); - storm::expressions::Variable var2 = expressionManager->getVariable(std::to_string(std::get<2>(criticalPair))); + auto val1 = std::get<1>(criticalTriple); + auto val2 = std::get<2>(criticalTriple); + storm::expressions::Variable var1 = expressionManager->getVariable(std::to_string(val1)); + storm::expressions::Variable var2 = expressionManager->getVariable(std::to_string(val2)); - auto latticeCopy = new Lattice(lattice); - std::set> assumptionsCopy = std::set>(assumptions); - auto myMap = createAssumptions(var1, var2, latticeCopy, assumptionsCopy); - result.insert(myMap.begin(), myMap.end()); - myMap = createAssumptions(var2, var1, lattice, assumptions); - result.insert(myMap.begin(), myMap.end()); - } + if (assumptionChecker->checkOnSamples(val1, val2)) { + auto latticeCopy = new Lattice(lattice); + std::set> assumptionsCopy = std::set>(assumptions); + auto myMap = createAssumptions(var1, var2, latticeCopy, assumptionsCopy); + result.insert(myMap.begin(), myMap.end()); + } + if (assumptionChecker->checkOnSamples(val2, val1)) { + auto myMap = createAssumptions(var2, var1, lattice, assumptions); + result.insert(myMap.begin(), myMap.end()); + } else { + delete lattice; + } + } return result; } @@ -67,11 +81,13 @@ namespace storm { std::shared_ptr assumption1 = std::make_shared(storm::expressions::BinaryRelationExpression(*expressionManager, var1.getType(), var1.getExpression().getBaseExpressionPointer(), var2.getExpression().getBaseExpressionPointer(), - storm::expressions::BinaryRelationExpression::RelationType::Greater)); + storm::expressions::BinaryRelationExpression::RelationType::GreaterOrEqual)); assumptions.insert(assumption1); return (runRecursive(lattice, assumptions)); } + + template class AssumptionMaker; } } diff --git a/src/storm-pars/analysis/AssumptionMaker.h b/src/storm-pars/analysis/AssumptionMaker.h index 2fa0a890c..49b50d3ea 100644 --- a/src/storm-pars/analysis/AssumptionMaker.h +++ b/src/storm-pars/analysis/AssumptionMaker.h @@ -6,8 +6,11 @@ #define STORM_ASSUMPTIONMAKER_H #include "Lattice.h" +#include "AssumptionChecker.h" #include "storm/storage/expressions/BinaryRelationExpression.h" #include "LatticeExtender.h" +#include "storm-pars/utility/ModelInstantiator.h" + namespace storm { namespace analysis { @@ -15,7 +18,7 @@ namespace storm { template class AssumptionMaker { public: - AssumptionMaker(storm::analysis::LatticeExtender* latticeExtender, uint_fast64_t numberOfStates); + AssumptionMaker(storm::analysis::LatticeExtender* latticeExtender, storm::analysis::AssumptionChecker* checker, uint_fast64_t numberOfStates); std::map>> startMakingAssumptions(storm::analysis::Lattice* lattice, uint_fast64_t critical1, uint_fast64_t critical2); @@ -29,6 +32,8 @@ namespace storm { std::shared_ptr expressionManager; uint_fast64_t numberOfStates; + + storm::analysis::AssumptionChecker* assumptionChecker; }; } } diff --git a/src/storm-pars/analysis/LatticeExtender.cpp b/src/storm-pars/analysis/LatticeExtender.cpp index 24d5c4039..d62a0a696 100644 --- a/src/storm-pars/analysis/LatticeExtender.cpp +++ b/src/storm-pars/analysis/LatticeExtender.cpp @@ -34,7 +34,7 @@ namespace storm { STORM_LOG_THROW((++formulas.begin()) == formulas.end(), storm::exceptions::NotSupportedException, "Only one formula allowed for monotonicity analysis"); STORM_LOG_THROW((*(formulas[0])).isProbabilityOperatorFormula() && ((*(formulas[0])).asProbabilityOperatorFormula().getSubformula().isUntilFormula() - || (*(formulas[0])).asProbabilityOperatorFormula().getSubformula().isEventuallyFormula()), storm::exceptions::NotSupportedException, "Expecting until formula"); + || (*(formulas[0])).asProbabilityOperatorFormula().getSubformula().isEventuallyFormula()), storm::exceptions::NotSupportedException, "Expecting until or eventually formula"); uint_fast64_t numberOfStates = this->model->getNumberOfStates(); @@ -86,7 +86,7 @@ namespace storm { // First handle assumptions for (auto itr = assumptions.begin(); itr != assumptions.end(); ++itr) { storm::expressions::BinaryRelationExpression expr = *(*itr); - STORM_LOG_THROW(expr.getRelationType() == storm::expressions::BinaryRelationExpression::RelationType::Greater, storm::exceptions::NotImplementedException, "Only greater assumptions allowed"); + STORM_LOG_THROW(expr.getRelationType() == storm::expressions::BinaryRelationExpression::RelationType::GreaterOrEqual, storm::exceptions::NotImplementedException, "Only greater assumptions allowed"); if (expr.getFirstOperand()->isVariable() && expr.getSecondOperand()->isVariable()) { storm::expressions::Variable largest = expr.getFirstOperand()->asVariableExpression().getVariable(); storm::expressions::Variable smallest = expr.getSecondOperand()->asVariableExpression().getVariable(); diff --git a/src/storm-pars/analysis/MonotonicityChecker.cpp b/src/storm-pars/analysis/MonotonicityChecker.cpp index 8d2537598..62be096db 100644 --- a/src/storm-pars/analysis/MonotonicityChecker.cpp +++ b/src/storm-pars/analysis/MonotonicityChecker.cpp @@ -156,6 +156,4 @@ namespace storm { }; template class MonotonicityChecker; } - } - From 06255ef08ee2a350fb0835060e43804e875cad27 Mon Sep 17 00:00:00 2001 From: Jip Spel Date: Fri, 14 Sep 2018 11:06:28 +0200 Subject: [PATCH 056/178] Use BinaryRelationExpression to check on samples --- src/storm-pars/analysis/AssumptionChecker.cpp | 34 ++++++++--- src/storm-pars/analysis/AssumptionChecker.h | 15 +++-- src/storm-pars/analysis/AssumptionMaker.cpp | 60 +++++++++---------- 3 files changed, 64 insertions(+), 45 deletions(-) diff --git a/src/storm-pars/analysis/AssumptionChecker.cpp b/src/storm-pars/analysis/AssumptionChecker.cpp index 6727793c0..bba77fb37 100644 --- a/src/storm-pars/analysis/AssumptionChecker.cpp +++ b/src/storm-pars/analysis/AssumptionChecker.cpp @@ -2,15 +2,16 @@ // Created by Jip Spel on 12.09.18. // -#include -#include -#include +#include "storm-pars/utility/ModelInstantiator.h" +#include "storm/modelchecker/prctl/SparseDtmcPrctlModelChecker.h" +#include "storm/exceptions/NotSupportedException.h" #include "AssumptionChecker.h" #include "storm/modelchecker/CheckTask.h" #include "storm/environment/Environment.h" #include "storm/modelchecker/results/CheckResult.h" #include "storm/modelchecker/results/ExplicitQuantitativeCheckResult.h" - +#include "storm/storage/expressions/SimpleValuation.h" +#include "storm/storage/expressions/ExpressionManager.h" @@ -23,8 +24,6 @@ namespace storm { auto instantiator = storm::utility::ModelInstantiator, storm::models::sparse::Dtmc>(*model.get()); auto matrix = model->getTransitionMatrix(); std::set variables = storm::models::sparse::getProbabilityParameters(*model); - - for (auto i = 0; i < numberOfSamples; ++i) { auto valuation = storm::utility::parametric::Valuation(); for (auto itr = variables.begin(); itr != variables.end(); ++itr) { @@ -52,8 +51,8 @@ namespace storm { std::vector values = quantitativeResult.getValueVector(); results.push_back(values); } - this->numberOfStates = model->getNumberOfStates(); - this->initialStates = model->getInitialStates(); +// this->numberOfStates = model->getNumberOfStates(); +// this->initialStates = model->getInitialStates(); } template @@ -67,6 +66,25 @@ namespace storm { return result; } + template + bool AssumptionChecker::checkOnSamples(std::shared_ptr assumption) { + bool result = true; + std::set vars = std::set({}); + assumption->gatherVariables(vars); + for (auto itr = results.begin(); result && itr != results.end(); ++itr) { + std::shared_ptr manager = assumption->getManager().getSharedPointer(); + auto valuation = storm::expressions::SimpleValuation(manager); + auto values = (*itr); + for (auto var = vars.begin(); result && var != vars.end(); ++var) { + storm::expressions::Variable par = *var; + auto index = std::stoi(par.getName()); + valuation.setRationalValue(par, values[index]); + } + result &= assumption->evaluateAsBool(&valuation); + } + return result; + } + template class AssumptionChecker; } } \ No newline at end of file diff --git a/src/storm-pars/analysis/AssumptionChecker.h b/src/storm-pars/analysis/AssumptionChecker.h index 7bd8cc916..78e209ab2 100644 --- a/src/storm-pars/analysis/AssumptionChecker.h +++ b/src/storm-pars/analysis/AssumptionChecker.h @@ -5,9 +5,11 @@ #ifndef STORM_ASSUMPTIONCHECKER_H #define STORM_ASSUMPTIONCHECKER_H -#include -#include +#include "storm/logic/Formula.h" +#include "storm/models/sparse/Dtmc.h" #include "storm/environment/Environment.h" +#include "storm/storage/expressions/BinaryRelationExpression.h" + namespace storm { namespace analysis { @@ -17,16 +19,17 @@ namespace storm { AssumptionChecker(std::shared_ptr formula, std::shared_ptr> model, uint_fast64_t numberOfSamples); bool checkOnSamples(uint_fast64_t val1, uint_fast64_t val2); + bool checkOnSamples(std::shared_ptr assumption); private: std::shared_ptr formula; - std::vector> sampleModels; +// std::vector> sampleModels; std::vector> results; - uint_fast64_t numberOfStates; - - storm::storage::BitVector initialStates; +// uint_fast64_t numberOfStates; +// +// storm::storage::BitVector initialStates; }; } } diff --git a/src/storm-pars/analysis/AssumptionMaker.cpp b/src/storm-pars/analysis/AssumptionMaker.cpp index d61b5ef28..db98a3498 100644 --- a/src/storm-pars/analysis/AssumptionMaker.cpp +++ b/src/storm-pars/analysis/AssumptionMaker.cpp @@ -13,7 +13,7 @@ namespace storm { this->assumptionChecker = assumptionChecker; this->expressionManager = std::make_shared(storm::expressions::ExpressionManager()); for (uint_fast64_t i = 0; i < this->numberOfStates; ++i) { - expressionManager->declareIntegerVariable(std::to_string(i)); + expressionManager->declareRationalVariable(std::to_string(i)); } } @@ -29,19 +29,14 @@ namespace storm { storm::expressions::Variable var1 = expressionManager->getVariable(std::to_string(critical1)); storm::expressions::Variable var2 = expressionManager->getVariable(std::to_string(critical2)); - if (assumptionChecker->checkOnSamples(critical1, critical2)) { - auto latticeCopy = new Lattice(lattice); - std::set> assumptions; - auto myMap = createAssumptions(var1, var2, latticeCopy, assumptions); - result.insert(myMap.begin(), myMap.end()); - } - if (assumptionChecker->checkOnSamples(critical2, critical1)) { - std::set> assumptions; - auto myMap = createAssumptions(var2, var1, lattice, assumptions); - result.insert(myMap.begin(), myMap.end()); - } else { - delete lattice; - } + auto latticeCopy = new Lattice(lattice); + std::set> assumptions; + auto myMap = createAssumptions(var1, var2, latticeCopy, assumptions); + result.insert(myMap.begin(), myMap.end()); + + std::set> assumptions2; + myMap = createAssumptions(var2, var1, lattice, assumptions2); + result.insert(myMap.begin(), myMap.end()); } return result; } @@ -59,31 +54,34 @@ namespace storm { storm::expressions::Variable var1 = expressionManager->getVariable(std::to_string(val1)); storm::expressions::Variable var2 = expressionManager->getVariable(std::to_string(val2)); - if (assumptionChecker->checkOnSamples(val1, val2)) { - auto latticeCopy = new Lattice(lattice); - std::set> assumptionsCopy = std::set>(assumptions); - auto myMap = createAssumptions(var1, var2, latticeCopy, assumptionsCopy); - result.insert(myMap.begin(), myMap.end()); - } - - if (assumptionChecker->checkOnSamples(val2, val1)) { - auto myMap = createAssumptions(var2, var1, lattice, assumptions); - result.insert(myMap.begin(), myMap.end()); - } else { - delete lattice; - } + auto latticeCopy = new Lattice(lattice); + std::set> assumptionsCopy = std::set>( + assumptions); + auto myMap = createAssumptions(var1, var2, latticeCopy, assumptionsCopy); + result.insert(myMap.begin(), myMap.end()); + + myMap = createAssumptions(var2, var1, lattice, assumptions); + result.insert(myMap.begin(), myMap.end()); } return result; } template std::map>> AssumptionMaker::createAssumptions(storm::expressions::Variable var1, storm::expressions::Variable var2, storm::analysis::Lattice* lattice, std::set> assumptions) { - std::shared_ptr assumption1 - = std::make_shared(storm::expressions::BinaryRelationExpression(*expressionManager, var1.getType(), + std::map>> result; + + std::shared_ptr assumption + = std::make_shared(storm::expressions::BinaryRelationExpression(*expressionManager, expressionManager->getBooleanType(), var1.getExpression().getBaseExpressionPointer(), var2.getExpression().getBaseExpressionPointer(), storm::expressions::BinaryRelationExpression::RelationType::GreaterOrEqual)); - assumptions.insert(assumption1); - return (runRecursive(lattice, assumptions)); + if (assumptionChecker->checkOnSamples(assumption)) { + assumptions.insert(assumption); + result = (runRecursive(lattice, assumptions)); + } else { + delete lattice; + } + + return result; } From fba6fe76b5c334b5a879a8ee454ff92a06ffc415 Mon Sep 17 00:00:00 2001 From: Jip Spel Date: Fri, 14 Sep 2018 11:30:59 +0200 Subject: [PATCH 057/178] Clean up AssumptionChecker --- src/storm-pars/analysis/AssumptionChecker.cpp | 26 +++++-------------- src/storm-pars/analysis/AssumptionChecker.h | 22 ++++++++++------ 2 files changed, 21 insertions(+), 27 deletions(-) diff --git a/src/storm-pars/analysis/AssumptionChecker.cpp b/src/storm-pars/analysis/AssumptionChecker.cpp index bba77fb37..5cc5e6ea9 100644 --- a/src/storm-pars/analysis/AssumptionChecker.cpp +++ b/src/storm-pars/analysis/AssumptionChecker.cpp @@ -1,26 +1,26 @@ // // Created by Jip Spel on 12.09.18. // +#include "AssumptionChecker.h" #include "storm-pars/utility/ModelInstantiator.h" -#include "storm/modelchecker/prctl/SparseDtmcPrctlModelChecker.h" + +#include "storm/environment/Environment.h" #include "storm/exceptions/NotSupportedException.h" -#include "AssumptionChecker.h" #include "storm/modelchecker/CheckTask.h" -#include "storm/environment/Environment.h" +#include "storm/modelchecker/prctl/SparseDtmcPrctlModelChecker.h" #include "storm/modelchecker/results/CheckResult.h" #include "storm/modelchecker/results/ExplicitQuantitativeCheckResult.h" #include "storm/storage/expressions/SimpleValuation.h" #include "storm/storage/expressions/ExpressionManager.h" - - namespace storm { namespace analysis { template AssumptionChecker::AssumptionChecker(std::shared_ptr formula, std::shared_ptr> model, uint_fast64_t numberOfSamples) { this->formula = formula; + // Create sample points auto instantiator = storm::utility::ModelInstantiator, storm::models::sparse::Dtmc>(*model.get()); auto matrix = model->getTransitionMatrix(); std::set variables = storm::models::sparse::getProbabilityParameters(*model); @@ -51,19 +51,6 @@ namespace storm { std::vector values = quantitativeResult.getValueVector(); results.push_back(values); } -// this->numberOfStates = model->getNumberOfStates(); -// this->initialStates = model->getInitialStates(); - } - - template - bool AssumptionChecker::checkOnSamples(uint_fast64_t val1, uint_fast64_t val2) { - bool result = true; - for (auto itr = results.begin(); result && itr != results.end(); ++itr) { - // TODO: als expressie - auto values = (*itr); - result &= (values[val1] >= values[val2]); - } - return result; } template @@ -80,6 +67,7 @@ namespace storm { auto index = std::stoi(par.getName()); valuation.setRationalValue(par, values[index]); } + assert(assumption->hasBooleanType()); result &= assumption->evaluateAsBool(&valuation); } return result; @@ -87,4 +75,4 @@ namespace storm { template class AssumptionChecker; } -} \ No newline at end of file +} diff --git a/src/storm-pars/analysis/AssumptionChecker.h b/src/storm-pars/analysis/AssumptionChecker.h index 78e209ab2..2f0f8313a 100644 --- a/src/storm-pars/analysis/AssumptionChecker.h +++ b/src/storm-pars/analysis/AssumptionChecker.h @@ -10,29 +10,35 @@ #include "storm/environment/Environment.h" #include "storm/storage/expressions/BinaryRelationExpression.h" - namespace storm { namespace analysis { template class AssumptionChecker { public: + /*! + * Constructs an AssumptionChecker based on the number of samples, for the given formula and model. + * + * @param formula The formula to check. + * @param model The model to check the formula on. + * @param numberOfSamples Number of sample points. + */ AssumptionChecker(std::shared_ptr formula, std::shared_ptr> model, uint_fast64_t numberOfSamples); - bool checkOnSamples(uint_fast64_t val1, uint_fast64_t val2); + /*! + * Checks if the assumption holds at the sample points of the AssumptionChecker. + * + * @param assumption The assumption to check. + * @return true if the assumption holds at the sample points + */ bool checkOnSamples(std::shared_ptr assumption); + private: std::shared_ptr formula; -// std::vector> sampleModels; - std::vector> results; -// uint_fast64_t numberOfStates; -// -// storm::storage::BitVector initialStates; }; } } - #endif //STORM_ASSUMPTIONCHECKER_H From 3fcf4f83c056b3d7ddd764181804961c1d200198 Mon Sep 17 00:00:00 2001 From: Jip Spel Date: Fri, 14 Sep 2018 11:31:21 +0200 Subject: [PATCH 058/178] Clean up AssumptionMaker --- src/storm-pars-cli/storm-pars.cpp | 3 ++- src/storm-pars/analysis/AssumptionMaker.cpp | 3 ++- src/storm-pars/analysis/AssumptionMaker.h | 22 ++++++++++++++++++--- 3 files changed, 23 insertions(+), 5 deletions(-) diff --git a/src/storm-pars-cli/storm-pars.cpp b/src/storm-pars-cli/storm-pars.cpp index ed8cc4a57..e2fec0e19 100644 --- a/src/storm-pars-cli/storm-pars.cpp +++ b/src/storm-pars-cli/storm-pars.cpp @@ -549,7 +549,8 @@ namespace storm { auto assumptionChecker = storm::analysis::AssumptionChecker(formulas[0], dtmcModel, 3); auto assumptionMaker = storm::analysis::AssumptionMaker(extender, &assumptionChecker, sparseModel->getNumberOfStates()); - std::map>> result = assumptionMaker.startMakingAssumptions(std::get<0>(criticalPair), std::get<1>(criticalPair), std::get<2>(criticalPair)); + std::map>> result = assumptionMaker.makeAssumptions( + std::get<0>(criticalPair), std::get<1>(criticalPair), std::get<2>(criticalPair)); latticeWatch.stop(); diff --git a/src/storm-pars/analysis/AssumptionMaker.cpp b/src/storm-pars/analysis/AssumptionMaker.cpp index db98a3498..711a069cd 100644 --- a/src/storm-pars/analysis/AssumptionMaker.cpp +++ b/src/storm-pars/analysis/AssumptionMaker.cpp @@ -19,7 +19,8 @@ namespace storm { template std::map>> - AssumptionMaker::startMakingAssumptions(storm::analysis::Lattice* lattice, uint_fast64_t critical1, uint_fast64_t critical2) { + AssumptionMaker::makeAssumptions(storm::analysis::Lattice *lattice, uint_fast64_t critical1, + uint_fast64_t critical2) { std::map>> result; std::set> emptySet; diff --git a/src/storm-pars/analysis/AssumptionMaker.h b/src/storm-pars/analysis/AssumptionMaker.h index 49b50d3ea..a4d1a3478 100644 --- a/src/storm-pars/analysis/AssumptionMaker.h +++ b/src/storm-pars/analysis/AssumptionMaker.h @@ -5,10 +5,10 @@ #ifndef STORM_ASSUMPTIONMAKER_H #define STORM_ASSUMPTIONMAKER_H -#include "Lattice.h" #include "AssumptionChecker.h" -#include "storm/storage/expressions/BinaryRelationExpression.h" +#include "Lattice.h" #include "LatticeExtender.h" +#include "storm/storage/expressions/BinaryRelationExpression.h" #include "storm-pars/utility/ModelInstantiator.h" @@ -18,9 +18,25 @@ namespace storm { template class AssumptionMaker { public: + /*! + * Constructs AssumptionMaker based on the lattice extender, the assumption checker and number of states of the model. + * + * @param latticeExtender The LatticeExtender which needs the assumptions made by the AssumptionMaker. + * @param checker The AssumptionChecker which checks the assumptions at sample points. + * @param numberOfStates The number of states of the model. + */ AssumptionMaker(storm::analysis::LatticeExtender* latticeExtender, storm::analysis::AssumptionChecker* checker, uint_fast64_t numberOfStates); - std::map>> startMakingAssumptions(storm::analysis::Lattice* lattice, uint_fast64_t critical1, uint_fast64_t critical2); + /*! + * Make the assumptions given a lattice and two states which could not be added to the lattice. Returns when no more assumptions can be made. + * + * @param lattice The lattice on which assumptions are needed to allow further extension. + * @param critical1 State number + * @param critical2 State number + * @return A mapping from pointers to different lattices and assumptions made to create the specific lattice. + */ + std::map>> makeAssumptions( + storm::analysis::Lattice *lattice, uint_fast64_t critical1, uint_fast64_t critical2); private: std::map>> runRecursive(storm::analysis::Lattice* lattice, std::set> assumptions); From 240f81dfcbd2054eefff3178f3dded509c19846e Mon Sep 17 00:00:00 2001 From: Jip Spel Date: Fri, 14 Sep 2018 11:34:24 +0200 Subject: [PATCH 059/178] Clean up MonotonicityChecker --- src/storm-pars/analysis/MonotonicityChecker.cpp | 10 ++++------ src/storm-pars/analysis/MonotonicityChecker.h | 6 ++++++ 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/storm-pars/analysis/MonotonicityChecker.cpp b/src/storm-pars/analysis/MonotonicityChecker.cpp index 62be096db..0d98cd3f9 100644 --- a/src/storm-pars/analysis/MonotonicityChecker.cpp +++ b/src/storm-pars/analysis/MonotonicityChecker.cpp @@ -3,14 +3,13 @@ // #include "MonotonicityChecker.h" -#include "storm/exceptions/UnexpectedException.h" #include "storm/exceptions/NotSupportedException.h" +#include "storm/exceptions/UnexpectedException.h" namespace storm { namespace analysis { template void MonotonicityChecker::checkMonotonicity(std::map>> map, storm::storage::SparseMatrix matrix) { - auto i = 0; for (auto itr = map.begin(); itr != map.end(); ++itr) { auto lattice = itr->first; @@ -52,7 +51,6 @@ namespace storm { STORM_PRINT(" - Do not know if monotone decreasing in: " << itr2->first << std::endl); } } - ++i; } } @@ -65,12 +63,12 @@ namespace storm { myfile.open (filename); myfile << "digraph \"MC\" {" << std::endl; myfile << "\t" << "node [shape=ellipse]" << std::endl; + // print all nodes for (uint_fast64_t i = 0; i < matrix.getColumnCount(); ++i) { myfile << "\t\"" << i << "\" [label = \"" << i << "\"]" << std::endl; } - for (uint_fast64_t i = 0; i < matrix.getColumnCount(); ++i) { // go over all rows auto row = matrix.getRow(i); @@ -134,7 +132,6 @@ namespace storm { << std::endl; } - myfile << "\t edge[style=\"\"];" << std::endl; } else { myfile << "\t" << i << " -> " << first.getColumn() << "[label=\"" << first.getValue() << "\"];" @@ -153,7 +150,8 @@ namespace storm { myfile << "}" << std::endl; myfile.close(); return varsMonotone; - }; + } + template class MonotonicityChecker; } } diff --git a/src/storm-pars/analysis/MonotonicityChecker.h b/src/storm-pars/analysis/MonotonicityChecker.h index 7b1dcb1f1..9d90e8b5d 100644 --- a/src/storm-pars/analysis/MonotonicityChecker.h +++ b/src/storm-pars/analysis/MonotonicityChecker.h @@ -18,6 +18,12 @@ namespace storm { class MonotonicityChecker { public: + /*! + * Checks for all lattices in the map if they are monotone increasing or monotone decreasing. + * + * @param map The map with lattices and the assumptions made to create the lattices. + * @param matrix The transition matrix. + */ void checkMonotonicity(std::map>> map, storm::storage::SparseMatrix matrix); private: From edc21be6ec421e5523fc27455477e21636603f27 Mon Sep 17 00:00:00 2001 From: Jip Spel Date: Fri, 14 Sep 2018 11:53:41 +0200 Subject: [PATCH 060/178] Add comments --- src/storm-pars/analysis/MonotonicityChecker.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/storm-pars/analysis/MonotonicityChecker.cpp b/src/storm-pars/analysis/MonotonicityChecker.cpp index 0d98cd3f9..36d185acb 100644 --- a/src/storm-pars/analysis/MonotonicityChecker.cpp +++ b/src/storm-pars/analysis/MonotonicityChecker.cpp @@ -93,7 +93,6 @@ namespace storm { for (auto itr2 = transitions.begin(); itr2 != transitions.end(); ++itr2) { for (auto itr3 = transitions.begin(); itr3 != transitions.end(); ++itr3) { - // TODO improve auto derivative2 = (*itr2).second.derivative(*itr); auto derivative3 = (*itr3).second.derivative(*itr); STORM_LOG_THROW(derivative2.isConstant() && derivative3.isConstant(), storm::exceptions::NotSupportedException, "Expecting derivative to be constant"); @@ -101,14 +100,17 @@ namespace storm { auto compare = lattice->compare((*itr2).first, (*itr3).first); if (compare == storm::analysis::Lattice::ABOVE) { + // As the first state (itr2) is above the second state (itr3) it is sufficient to look at the derivative of itr2. value->first &=derivative2.constantPart() >= 0; value->second &=derivative2.constantPart() <= 0; } else if (compare == storm::analysis::Lattice::BELOW) { + // As the second state (itr3) is above the first state (itr2) it is sufficient to look at the derivative of itr3. value->first &=derivative3.constantPart() >= 0; value->second &=derivative3.constantPart() <= 0; } else if (compare == storm::analysis::Lattice::SAME) { - // Behaviour doesn't matter, as they are at the same level + // Behaviour doesn't matter, as the states are at the same level. } else { + // As the relation between the states is unknown, we can't claim anything about the monotonicity. value->first = false; value->second = false; } From 8bded41867ae39c57902f052c4fca59702b9571e Mon Sep 17 00:00:00 2001 From: Jip Spel Date: Fri, 14 Sep 2018 13:00:12 +0200 Subject: [PATCH 061/178] Add state to lattice when there are more than 2 outgoing transitions --- src/storm-pars/analysis/LatticeExtender.cpp | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/src/storm-pars/analysis/LatticeExtender.cpp b/src/storm-pars/analysis/LatticeExtender.cpp index d62a0a696..a0448ce42 100644 --- a/src/storm-pars/analysis/LatticeExtender.cpp +++ b/src/storm-pars/analysis/LatticeExtender.cpp @@ -147,7 +147,25 @@ namespace storm { return std::make_tuple(lattice, successor1, successor2); } } else if (check && successors.getNumberOfSetBits() > 2) { - // TODO + for (auto i = successors.getNextSetIndex(0); i < successors.size(); i = successors.getNextSetIndex(i+1)) { + for (auto j = successors.getNextSetIndex(i+1); j < successors.size(); j = successors.getNextSetIndex(j+1)) { + if (lattice->compare(i,j) == storm::analysis::Lattice::UNKNOWN) { + return std::make_tuple(lattice, i, j); + } + } + } + + auto highest = successors.getNextSetIndex(0); + auto lowest = highest; + for (auto i = successors.getNextSetIndex(highest+1); i < successors.size(); i = successors.getNextSetIndex(i+1)) { + if (lattice->compare(i, highest) == storm::analysis::Lattice::ABOVE) { + highest = i; + } + if (lattice->compare(lowest, i) == storm::analysis::Lattice::ABOVE) { + lowest = i; + } + } + lattice->addBetween(stateNumber, lattice->getNode(highest), lattice->getNode(lowest)); } } // Nothing changed and not done yet From e4a2e9ffadbd7a07fde7b71f64bb3237001daabe Mon Sep 17 00:00:00 2001 From: Jip Spel Date: Fri, 14 Sep 2018 13:06:48 +0200 Subject: [PATCH 062/178] Update documentation Lattice.h --- src/storm-pars/analysis/Lattice.h | 35 +++++++++++++++++++++++-------- 1 file changed, 26 insertions(+), 9 deletions(-) diff --git a/src/storm-pars/analysis/Lattice.h b/src/storm-pars/analysis/Lattice.h index a62d2763f..42a4802cb 100644 --- a/src/storm-pars/analysis/Lattice.h +++ b/src/storm-pars/analysis/Lattice.h @@ -75,20 +75,41 @@ namespace storm { /*! * Retrieves the pointer to a Node at which the state occurs. - * Behaviour unknown when state does not exists at any Node in the Lattice. * * @param state The number of the state. * - * @return The pointer to the node of the state, nullptr if the node does not exist + * @return The pointer to the node of the state, nullptr if the node does not exist. */ Node *getNode(uint_fast64_t state); + /*! + * Retrieves the top node of the lattice. + * + * @return The top node. + */ Node* getTop(); + /*! + * Retrieves the bottom node of the lattice. + * + * @return The bottom node. + */ Node* getBottom(); + /*! + * Returns the vector with the nodes of the lattice. + * Each index in the vector refers to a state. + * When the state is not yet added at a node, it will contain the nullptr. + * + * @return The vector with nodes of the lattice. + */ std::vector getNodes(); + /*! + * Returns a BitVector in which all added states are set. + * + * @return The BitVector with all added states. + */ storm::storage::BitVector getAddedStates(); /*! @@ -105,6 +126,9 @@ namespace storm { */ void toDotFile(std::ostream &out); + /*! + * Constants for comparison of nodes/states + */ static const int UNKNOWN = -1; static const int BELOW = 2; static const int ABOVE = 1; @@ -126,13 +150,6 @@ namespace storm { uint_fast64_t numberOfStates; - /** - * Check if node1 lies above node2 - * @param node1 - * @param node2 - * @param seenNodes - * @return - */ bool above(Node * node1, Node * node2, std::set* seenNodes); int compare(Node* node1, Node* node2); From f2c2da64fa37be4b9b246c173578f4ca2afd5038 Mon Sep 17 00:00:00 2001 From: Jip Spel Date: Fri, 14 Sep 2018 13:16:37 +0200 Subject: [PATCH 063/178] Add documentation LatticeExtender.h --- src/storm-pars/analysis/LatticeExtender.h | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/storm-pars/analysis/LatticeExtender.h b/src/storm-pars/analysis/LatticeExtender.h index 72d91a8c1..38cc5429b 100644 --- a/src/storm-pars/analysis/LatticeExtender.h +++ b/src/storm-pars/analysis/LatticeExtender.h @@ -21,10 +21,32 @@ namespace storm { class LatticeExtender { public: + /*! + * Constructs LatticeExtender which can extend a lattice + * + * @param model The model for which the lattice should be extended. + */ LatticeExtender(std::shared_ptr> model); + /*! + * Creates a lattice based on the given formula. + * + * @param formulas The formulas based on which the lattice is created, only the first is used. + * @return A triple with a pointer to the lattice and two states of which the current place in the lattice + * is unknown but needed. When the states have as number the number of states, no states are + * unplaced but needed. + */ std::tuple toLattice(std::vector> formulas); + /*! + * Extends the lattice based on the given assumptions. + * + * @param lattice The lattice. + * @param assumptions The assumptions on states. + * @return A triple with a pointer to the lattice and two states of which the current place in the lattice + * is unknown but needed. When the states have as number the number of states, no states are + * unplaced but needed. + */ std::tuple extendLattice(storm::analysis::Lattice* lattice, std::set> assumptions); private: From e23a2226056d97f295adce42daf2790aacf20cd2 Mon Sep 17 00:00:00 2001 From: Jip Spel Date: Tue, 18 Sep 2018 10:30:59 +0200 Subject: [PATCH 064/178] Add simple validation for assumptions --- src/storm-pars-cli/storm-pars.cpp | 3 +- src/storm-pars/analysis/AssumptionChecker.cpp | 60 ++++++++++++++++++- src/storm-pars/analysis/AssumptionChecker.h | 12 ++++ src/storm-pars/analysis/AssumptionMaker.cpp | 33 +++++----- src/storm-pars/analysis/AssumptionMaker.h | 6 +- src/storm-pars/analysis/Lattice.cpp | 2 +- src/storm-pars/analysis/LatticeExtender.cpp | 31 +++++----- src/storm-pars/analysis/LatticeExtender.h | 9 +-- .../analysis/MonotonicityChecker.cpp | 11 ++-- src/storm-pars/analysis/MonotonicityChecker.h | 2 +- 10 files changed, 121 insertions(+), 48 deletions(-) diff --git a/src/storm-pars-cli/storm-pars.cpp b/src/storm-pars-cli/storm-pars.cpp index e2fec0e19..a5a06cc34 100644 --- a/src/storm-pars-cli/storm-pars.cpp +++ b/src/storm-pars-cli/storm-pars.cpp @@ -549,10 +549,9 @@ namespace storm { auto assumptionChecker = storm::analysis::AssumptionChecker(formulas[0], dtmcModel, 3); auto assumptionMaker = storm::analysis::AssumptionMaker(extender, &assumptionChecker, sparseModel->getNumberOfStates()); - std::map>> result = assumptionMaker.makeAssumptions( + std::map, bool>>> result = assumptionMaker.makeAssumptions( std::get<0>(criticalPair), std::get<1>(criticalPair), std::get<2>(criticalPair)); - latticeWatch.stop(); STORM_PRINT(std::endl << "Time for lattice creation: " << latticeWatch << "." << std::endl << std::endl); diff --git a/src/storm-pars/analysis/AssumptionChecker.cpp b/src/storm-pars/analysis/AssumptionChecker.cpp index 5cc5e6ea9..1d175a01c 100644 --- a/src/storm-pars/analysis/AssumptionChecker.cpp +++ b/src/storm-pars/analysis/AssumptionChecker.cpp @@ -13,20 +13,23 @@ #include "storm/modelchecker/results/ExplicitQuantitativeCheckResult.h" #include "storm/storage/expressions/SimpleValuation.h" #include "storm/storage/expressions/ExpressionManager.h" +#include "storm/storage/expressions/VariableExpression.h" namespace storm { namespace analysis { template AssumptionChecker::AssumptionChecker(std::shared_ptr formula, std::shared_ptr> model, uint_fast64_t numberOfSamples) { this->formula = formula; + this->matrix = model->getTransitionMatrix(); // Create sample points - auto instantiator = storm::utility::ModelInstantiator, storm::models::sparse::Dtmc>(*model.get()); + auto instantiator = storm::utility::ModelInstantiator, storm::models::sparse::Dtmc>(*model); auto matrix = model->getTransitionMatrix(); std::set variables = storm::models::sparse::getProbabilityParameters(*model); for (auto i = 0; i < numberOfSamples; ++i) { auto valuation = storm::utility::parametric::Valuation(); for (auto itr = variables.begin(); itr != variables.end(); ++itr) { + // TODO: Type auto val = std::pair((*itr), storm::utility::convertNumber(boost::lexical_cast((i+1)/(double (numberOfSamples + 1))))); valuation.insert(val); } @@ -73,6 +76,61 @@ namespace storm { return result; } + template + bool AssumptionChecker::validateAssumption(std::shared_ptr assumption, storm::analysis::Lattice* lattice) { + bool result = false; + std::set vars = std::set({}); + assumption->gatherVariables(vars); + + STORM_LOG_THROW(assumption->getRelationType() == storm::expressions::BinaryRelationExpression::RelationType::GreaterOrEqual, storm::exceptions::NotSupportedException, "Only Greater Or Equal assumptions supported"); + + auto val1 = std::stoi(assumption->getFirstOperand()->asVariableExpression().getVariableName()); + auto val2 = std::stoi(assumption->getSecondOperand()->asVariableExpression().getVariableName()); + auto row1 = matrix.getRow(val1); + auto row2 = matrix.getRow(val2); + if (row1.getNumberOfEntries() != 2 && row2.getNumberOfEntries() != 2) { + assert (false); + } + + auto succ11 = row1.begin(); + auto succ12 = (++row1.begin()); + auto succ21 = row2.begin(); + auto succ22 = (++row2.begin()); + + if (succ12->getColumn() == succ21->getColumn() && succ11->getColumn() == succ22->getColumn()) { + auto temp = succ12; + succ12 = succ11; + succ11 = temp; + } + + if (succ11->getColumn() == succ21->getColumn() && succ12->getColumn() == succ22->getColumn()) { + ValueType prob; + auto comp = lattice->compare(succ11->getColumn(), succ12->getColumn()); + if (comp == storm::analysis::Lattice::ABOVE) { + prob = succ11->getValue() - succ21->getValue(); + } else if (comp == storm::analysis::Lattice::BELOW) { + prob = succ12->getValue() - succ22->getValue(); + } + auto vars = prob.gatherVariables(); + // TODO: Type + std::map substitutions; + for (auto var:vars) { + auto derivative = prob.derivative(var); + assert(derivative.isConstant()); + if (derivative.constantPart() >=0) { + substitutions[var] = 0; + } else if(derivative.constantPart() <= 0) { + substitutions[var] = 1; + } + } + result = prob.evaluate(substitutions) >= 0; + } + if (!result) { + STORM_PRINT("Could not validate: " << *assumption << std::endl); + } + return result; + } + template class AssumptionChecker; } } diff --git a/src/storm-pars/analysis/AssumptionChecker.h b/src/storm-pars/analysis/AssumptionChecker.h index 2f0f8313a..45b2b237e 100644 --- a/src/storm-pars/analysis/AssumptionChecker.h +++ b/src/storm-pars/analysis/AssumptionChecker.h @@ -9,6 +9,7 @@ #include "storm/models/sparse/Dtmc.h" #include "storm/environment/Environment.h" #include "storm/storage/expressions/BinaryRelationExpression.h" +#include "Lattice.h" namespace storm { namespace analysis { @@ -32,9 +33,20 @@ namespace storm { */ bool checkOnSamples(std::shared_ptr assumption); + /*! + * Checks if an assumption can be validated based on the lattice and underlying transition matrix. + * + * @param assumption The assumption to validate. + * @param lattice The lattice. + * @return true if the assumption is validated and holds, false otherwise + */ + bool validateAssumption(std::shared_ptr assumption, storm::analysis::Lattice* lattice); + private: std::shared_ptr formula; + storm::storage::SparseMatrix matrix; + std::vector> results; }; diff --git a/src/storm-pars/analysis/AssumptionMaker.cpp b/src/storm-pars/analysis/AssumptionMaker.cpp index 711a069cd..3382e3b2e 100644 --- a/src/storm-pars/analysis/AssumptionMaker.cpp +++ b/src/storm-pars/analysis/AssumptionMaker.cpp @@ -18,24 +18,24 @@ namespace storm { } template - std::map>> + std::map, bool>>> AssumptionMaker::makeAssumptions(storm::analysis::Lattice *lattice, uint_fast64_t critical1, uint_fast64_t critical2) { - std::map>> result; + std::map, bool>>> result; - std::set> emptySet; + std::vector, bool>> emptySet; if (critical1 == numberOfStates || critical2 == numberOfStates) { - result.insert(std::pair>>(lattice, emptySet)); + result.insert(std::pair, bool>>>(lattice, emptySet)); } else { storm::expressions::Variable var1 = expressionManager->getVariable(std::to_string(critical1)); storm::expressions::Variable var2 = expressionManager->getVariable(std::to_string(critical2)); auto latticeCopy = new Lattice(lattice); - std::set> assumptions; + std::vector, bool>> assumptions; auto myMap = createAssumptions(var1, var2, latticeCopy, assumptions); result.insert(myMap.begin(), myMap.end()); - std::set> assumptions2; + std::vector, bool>> assumptions2; myMap = createAssumptions(var2, var1, lattice, assumptions2); result.insert(myMap.begin(), myMap.end()); } @@ -43,12 +43,17 @@ namespace storm { } template - std::map>> AssumptionMaker::runRecursive(storm::analysis::Lattice* lattice, std::set> assumptions) { - std::map>> result; - std::tuple criticalTriple = this->latticeExtender->extendLattice(lattice, assumptions); + std::map, bool>>> AssumptionMaker::runRecursive(storm::analysis::Lattice* lattice, std::vector,bool>> assumptions) { + std::map,bool>>> result; + // only the last assumption is new + std::tuple criticalTriple = this->latticeExtender->extendLattice(lattice, assumptions.back().first); + + if (assumptions.back().second) { + assumptions.pop_back(); + } if (std::get<1>(criticalTriple) == numberOfStates) { - result.insert(std::pair>>(lattice, assumptions)); + result.insert(std::pair,bool>>>(lattice, assumptions)); } else { auto val1 = std::get<1>(criticalTriple); auto val2 = std::get<2>(criticalTriple); @@ -56,7 +61,7 @@ namespace storm { storm::expressions::Variable var2 = expressionManager->getVariable(std::to_string(val2)); auto latticeCopy = new Lattice(lattice); - std::set> assumptionsCopy = std::set>( + std::vector, bool>> assumptionsCopy = std::vector, bool>>( assumptions); auto myMap = createAssumptions(var1, var2, latticeCopy, assumptionsCopy); result.insert(myMap.begin(), myMap.end()); @@ -68,15 +73,15 @@ namespace storm { } template - std::map>> AssumptionMaker::createAssumptions(storm::expressions::Variable var1, storm::expressions::Variable var2, storm::analysis::Lattice* lattice, std::set> assumptions) { - std::map>> result; + std::map, bool>>> AssumptionMaker::createAssumptions(storm::expressions::Variable var1, storm::expressions::Variable var2, storm::analysis::Lattice* lattice, std::vector, bool>> assumptions) { + std::map, bool>>> result; std::shared_ptr assumption = std::make_shared(storm::expressions::BinaryRelationExpression(*expressionManager, expressionManager->getBooleanType(), var1.getExpression().getBaseExpressionPointer(), var2.getExpression().getBaseExpressionPointer(), storm::expressions::BinaryRelationExpression::RelationType::GreaterOrEqual)); if (assumptionChecker->checkOnSamples(assumption)) { - assumptions.insert(assumption); + assumptions.push_back(std::pair, bool>(assumption, assumptionChecker->validateAssumption(assumption, lattice))); result = (runRecursive(lattice, assumptions)); } else { delete lattice; diff --git a/src/storm-pars/analysis/AssumptionMaker.h b/src/storm-pars/analysis/AssumptionMaker.h index a4d1a3478..55adbe0f5 100644 --- a/src/storm-pars/analysis/AssumptionMaker.h +++ b/src/storm-pars/analysis/AssumptionMaker.h @@ -35,13 +35,13 @@ namespace storm { * @param critical2 State number * @return A mapping from pointers to different lattices and assumptions made to create the specific lattice. */ - std::map>> makeAssumptions( + std::map, bool>>> makeAssumptions( storm::analysis::Lattice *lattice, uint_fast64_t critical1, uint_fast64_t critical2); private: - std::map>> runRecursive(storm::analysis::Lattice* lattice, std::set> assumptions); + std::map, bool>>> runRecursive(storm::analysis::Lattice* lattice, std::vector, bool>> assumptions); - std::map>> createAssumptions(storm::expressions::Variable var1, storm::expressions::Variable var2, storm::analysis::Lattice* lattice,std::set> assumptions); + std::map, bool>>> createAssumptions(storm::expressions::Variable var1, storm::expressions::Variable var2, storm::analysis::Lattice* lattice,std::vector, bool>> assumptions); storm::analysis::LatticeExtender* latticeExtender; diff --git a/src/storm-pars/analysis/Lattice.cpp b/src/storm-pars/analysis/Lattice.cpp index 001873698..bea6439d2 100644 --- a/src/storm-pars/analysis/Lattice.cpp +++ b/src/storm-pars/analysis/Lattice.cpp @@ -121,7 +121,7 @@ namespace storm { if (node1 == node2) { return SAME; } - + // TODO: Uberhaupt niet mogelijk? bool isAbove = above(node1, node2, new std::set({})); bool isBelow = above(node2, node1, new std::set({})); if (isAbove && isBelow) { diff --git a/src/storm-pars/analysis/LatticeExtender.cpp b/src/storm-pars/analysis/LatticeExtender.cpp index a0448ce42..b4be618ed 100644 --- a/src/storm-pars/analysis/LatticeExtender.cpp +++ b/src/storm-pars/analysis/LatticeExtender.cpp @@ -75,24 +75,24 @@ namespace storm { } template - std::tuple LatticeExtender::extendLattice(storm::analysis::Lattice* lattice) { - std::set> assumptions; - return this->extendLattice(lattice, assumptions); - } - - template - std::tuple LatticeExtender::extendLattice(storm::analysis::Lattice* lattice, std::set> assumptions) { + std::tuple LatticeExtender::extendLattice(storm::analysis::Lattice* lattice, std::shared_ptr assumption) { auto numberOfStates = this->model->getNumberOfStates(); - // First handle assumptions - for (auto itr = assumptions.begin(); itr != assumptions.end(); ++itr) { - storm::expressions::BinaryRelationExpression expr = *(*itr); - STORM_LOG_THROW(expr.getRelationType() == storm::expressions::BinaryRelationExpression::RelationType::GreaterOrEqual, storm::exceptions::NotImplementedException, "Only greater assumptions allowed"); + // First handle assumption + if (assumption != nullptr) { + storm::expressions::BinaryRelationExpression expr = *assumption; + STORM_LOG_THROW(expr.getRelationType() == + storm::expressions::BinaryRelationExpression::RelationType::GreaterOrEqual, + storm::exceptions::NotImplementedException, "Only GreaterOrEqual assumptions allowed"); if (expr.getFirstOperand()->isVariable() && expr.getSecondOperand()->isVariable()) { storm::expressions::Variable largest = expr.getFirstOperand()->asVariableExpression().getVariable(); storm::expressions::Variable smallest = expr.getSecondOperand()->asVariableExpression().getVariable(); - if (lattice->compare(std::stoul(largest.getName(), nullptr, 0), std::stoul(smallest.getName(), nullptr, 0)) != storm::analysis::Lattice::ABOVE) { - storm::analysis::Lattice::Node* n1 = lattice->getNode(std::stoul(largest.getName(), nullptr, 0)); - storm::analysis::Lattice::Node* n2 = lattice->getNode(std::stoul(smallest.getName(), nullptr, 0)); + if (lattice->compare(std::stoul(largest.getName(), nullptr, 0), + std::stoul(smallest.getName(), nullptr, 0)) != + storm::analysis::Lattice::ABOVE) { + storm::analysis::Lattice::Node *n1 = lattice->getNode( + std::stoul(largest.getName(), nullptr, 0)); + storm::analysis::Lattice::Node *n2 = lattice->getNode( + std::stoul(smallest.getName(), nullptr, 0)); if (n1 != nullptr && n2 != nullptr) { lattice->addRelationNodes(n1, n2); @@ -102,7 +102,8 @@ namespace storm { lattice->addBetween(std::stoul(largest.getName(), nullptr, 0), lattice->getTop(), n2); } else { lattice->add(std::stoul(largest.getName(), nullptr, 0)); - lattice->addBetween(std::stoul(smallest.getName(), nullptr, 0), lattice->getNode(std::stoul(largest.getName(), nullptr, 0)), + lattice->addBetween(std::stoul(smallest.getName(), nullptr, 0), + lattice->getNode(std::stoul(largest.getName(), nullptr, 0)), lattice->getBottom()); } } diff --git a/src/storm-pars/analysis/LatticeExtender.h b/src/storm-pars/analysis/LatticeExtender.h index 38cc5429b..48bb7123a 100644 --- a/src/storm-pars/analysis/LatticeExtender.h +++ b/src/storm-pars/analysis/LatticeExtender.h @@ -39,23 +39,20 @@ namespace storm { std::tuple toLattice(std::vector> formulas); /*! - * Extends the lattice based on the given assumptions. + * Extends the lattice based on the given assumption. * * @param lattice The lattice. - * @param assumptions The assumptions on states. + * @param assumption The assumption on states. * @return A triple with a pointer to the lattice and two states of which the current place in the lattice * is unknown but needed. When the states have as number the number of states, no states are * unplaced but needed. */ - std::tuple extendLattice(storm::analysis::Lattice* lattice, std::set> assumptions); + std::tuple extendLattice(storm::analysis::Lattice* lattice, std::shared_ptr assumption = nullptr); private: std::shared_ptr> model; std::map stateMap; - - std::tuple extendLattice(storm::analysis::Lattice* lattice); - }; } } diff --git a/src/storm-pars/analysis/MonotonicityChecker.cpp b/src/storm-pars/analysis/MonotonicityChecker.cpp index 36d185acb..4750d21ff 100644 --- a/src/storm-pars/analysis/MonotonicityChecker.cpp +++ b/src/storm-pars/analysis/MonotonicityChecker.cpp @@ -9,7 +9,7 @@ namespace storm { namespace analysis { template - void MonotonicityChecker::checkMonotonicity(std::map>> map, storm::storage::SparseMatrix matrix) { + void MonotonicityChecker::checkMonotonicity(std::map, bool>>> map, storm::storage::SparseMatrix matrix) { auto i = 0; for (auto itr = map.begin(); itr != map.end(); ++itr) { auto lattice = itr->first; @@ -23,17 +23,18 @@ namespace storm { if (assumptions.size() > 0) { STORM_PRINT("Given assumptions: " << std::endl); bool first = true; - for (auto itr = assumptions.begin(); itr != assumptions.end(); ++itr) { + for (auto itr2 = assumptions.begin(); itr2 != assumptions.end(); ++itr2) { if (!first) { STORM_PRINT(" ^ "); } else { STORM_PRINT(" "); + first = false; } - first = false; - std::shared_ptr expression = *itr; + + std::shared_ptr expression = itr2->first; auto var1 = expression->getFirstOperand(); auto var2 = expression->getSecondOperand(); - STORM_PRINT("(" << var1->getIdentifier() << " > " << var2->getIdentifier() << ")"); + STORM_PRINT(*expression); } STORM_PRINT(std::endl); } diff --git a/src/storm-pars/analysis/MonotonicityChecker.h b/src/storm-pars/analysis/MonotonicityChecker.h index 9d90e8b5d..6147b765b 100644 --- a/src/storm-pars/analysis/MonotonicityChecker.h +++ b/src/storm-pars/analysis/MonotonicityChecker.h @@ -24,7 +24,7 @@ namespace storm { * @param map The map with lattices and the assumptions made to create the lattices. * @param matrix The transition matrix. */ - void checkMonotonicity(std::map>> map, storm::storage::SparseMatrix matrix); + void checkMonotonicity(std::map, bool>>> map, storm::storage::SparseMatrix matrix); private: std::map> analyseMonotonicity(uint_fast64_t i, storm::analysis::Lattice* lattice, storm::storage::SparseMatrix matrix) ; From 24a40bba80605f9afa5d0ce3d3dd3d3d15290295 Mon Sep 17 00:00:00 2001 From: Jip Spel Date: Tue, 18 Sep 2018 12:08:53 +0200 Subject: [PATCH 065/178] Add validated assumptions to set --- src/storm-pars-cli/storm-pars.cpp | 2 +- src/storm-pars/analysis/AssumptionChecker.cpp | 97 +++++++++++-------- src/storm-pars/analysis/AssumptionChecker.h | 3 + src/storm-pars/analysis/AssumptionMaker.cpp | 32 +++--- src/storm-pars/analysis/AssumptionMaker.h | 6 +- .../analysis/MonotonicityChecker.cpp | 4 +- src/storm-pars/analysis/MonotonicityChecker.h | 2 +- 7 files changed, 82 insertions(+), 64 deletions(-) diff --git a/src/storm-pars-cli/storm-pars.cpp b/src/storm-pars-cli/storm-pars.cpp index a5a06cc34..e7aedd2f7 100644 --- a/src/storm-pars-cli/storm-pars.cpp +++ b/src/storm-pars-cli/storm-pars.cpp @@ -549,7 +549,7 @@ namespace storm { auto assumptionChecker = storm::analysis::AssumptionChecker(formulas[0], dtmcModel, 3); auto assumptionMaker = storm::analysis::AssumptionMaker(extender, &assumptionChecker, sparseModel->getNumberOfStates()); - std::map, bool>>> result = assumptionMaker.makeAssumptions( + std::map>> result = assumptionMaker.makeAssumptions( std::get<0>(criticalPair), std::get<1>(criticalPair), std::get<2>(criticalPair)); latticeWatch.stop(); diff --git a/src/storm-pars/analysis/AssumptionChecker.cpp b/src/storm-pars/analysis/AssumptionChecker.cpp index 1d175a01c..c3014d3a9 100644 --- a/src/storm-pars/analysis/AssumptionChecker.cpp +++ b/src/storm-pars/analysis/AssumptionChecker.cpp @@ -78,59 +78,72 @@ namespace storm { template bool AssumptionChecker::validateAssumption(std::shared_ptr assumption, storm::analysis::Lattice* lattice) { - bool result = false; - std::set vars = std::set({}); - assumption->gatherVariables(vars); - - STORM_LOG_THROW(assumption->getRelationType() == storm::expressions::BinaryRelationExpression::RelationType::GreaterOrEqual, storm::exceptions::NotSupportedException, "Only Greater Or Equal assumptions supported"); + bool result = validated(assumption); + if (!result) { + std::set vars = std::set({}); + assumption->gatherVariables(vars); - auto val1 = std::stoi(assumption->getFirstOperand()->asVariableExpression().getVariableName()); - auto val2 = std::stoi(assumption->getSecondOperand()->asVariableExpression().getVariableName()); - auto row1 = matrix.getRow(val1); - auto row2 = matrix.getRow(val2); - if (row1.getNumberOfEntries() != 2 && row2.getNumberOfEntries() != 2) { - assert (false); - } + STORM_LOG_THROW(assumption->getRelationType() == + storm::expressions::BinaryRelationExpression::RelationType::GreaterOrEqual, + storm::exceptions::NotSupportedException, + "Only Greater Or Equal assumptions supported"); - auto succ11 = row1.begin(); - auto succ12 = (++row1.begin()); - auto succ21 = row2.begin(); - auto succ22 = (++row2.begin()); + auto val1 = std::stoi(assumption->getFirstOperand()->asVariableExpression().getVariableName()); + auto val2 = std::stoi(assumption->getSecondOperand()->asVariableExpression().getVariableName()); + auto row1 = matrix.getRow(val1); + auto row2 = matrix.getRow(val2); + if (row1.getNumberOfEntries() != 2 && row2.getNumberOfEntries() != 2) { + assert (false); + } - if (succ12->getColumn() == succ21->getColumn() && succ11->getColumn() == succ22->getColumn()) { - auto temp = succ12; - succ12 = succ11; - succ11 = temp; - } + auto succ11 = row1.begin(); + auto succ12 = (++row1.begin()); + auto succ21 = row2.begin(); + auto succ22 = (++row2.begin()); - if (succ11->getColumn() == succ21->getColumn() && succ12->getColumn() == succ22->getColumn()) { - ValueType prob; - auto comp = lattice->compare(succ11->getColumn(), succ12->getColumn()); - if (comp == storm::analysis::Lattice::ABOVE) { - prob = succ11->getValue() - succ21->getValue(); - } else if (comp == storm::analysis::Lattice::BELOW) { - prob = succ12->getValue() - succ22->getValue(); + if (succ12->getColumn() == succ21->getColumn() && succ11->getColumn() == succ22->getColumn()) { + auto temp = succ12; + succ12 = succ11; + succ11 = temp; } - auto vars = prob.gatherVariables(); - // TODO: Type - std::map substitutions; - for (auto var:vars) { - auto derivative = prob.derivative(var); - assert(derivative.isConstant()); - if (derivative.constantPart() >=0) { - substitutions[var] = 0; - } else if(derivative.constantPart() <= 0) { - substitutions[var] = 1; + + if (succ11->getColumn() == succ21->getColumn() && succ12->getColumn() == succ22->getColumn()) { + ValueType prob; + auto comp = lattice->compare(succ11->getColumn(), succ12->getColumn()); + if (comp == storm::analysis::Lattice::ABOVE) { + prob = succ11->getValue() - succ21->getValue(); + } else if (comp == storm::analysis::Lattice::BELOW) { + prob = succ12->getValue() - succ22->getValue(); + } + auto vars = prob.gatherVariables(); + // TODO: Type + std::map substitutions; + for (auto var:vars) { + auto derivative = prob.derivative(var); + assert(derivative.isConstant()); + if (derivative.constantPart() >= 0) { + substitutions[var] = 0; + } else if (derivative.constantPart() <= 0) { + substitutions[var] = 1; + } } + result = prob.evaluate(substitutions) >= 0; + } + if (result) { + validatedAssumptions.insert(assumption); + } else { + STORM_PRINT("Could not validate: " << *assumption << std::endl); } - result = prob.evaluate(substitutions) >= 0; - } - if (!result) { - STORM_PRINT("Could not validate: " << *assumption << std::endl); } + return result; } + template + bool AssumptionChecker::validated(std::shared_ptr assumption) { + return find(validatedAssumptions.begin(), validatedAssumptions.end(), assumption) != validatedAssumptions.end(); + } + template class AssumptionChecker; } } diff --git a/src/storm-pars/analysis/AssumptionChecker.h b/src/storm-pars/analysis/AssumptionChecker.h index 45b2b237e..e336f97f3 100644 --- a/src/storm-pars/analysis/AssumptionChecker.h +++ b/src/storm-pars/analysis/AssumptionChecker.h @@ -42,6 +42,7 @@ namespace storm { */ bool validateAssumption(std::shared_ptr assumption, storm::analysis::Lattice* lattice); + bool validated(std::shared_ptr assumption); private: std::shared_ptr formula; @@ -49,6 +50,8 @@ namespace storm { std::vector> results; + std::set> validatedAssumptions; + }; } } diff --git a/src/storm-pars/analysis/AssumptionMaker.cpp b/src/storm-pars/analysis/AssumptionMaker.cpp index 3382e3b2e..c6804ef59 100644 --- a/src/storm-pars/analysis/AssumptionMaker.cpp +++ b/src/storm-pars/analysis/AssumptionMaker.cpp @@ -18,24 +18,24 @@ namespace storm { } template - std::map, bool>>> + std::map>> AssumptionMaker::makeAssumptions(storm::analysis::Lattice *lattice, uint_fast64_t critical1, uint_fast64_t critical2) { - std::map, bool>>> result; + std::map>> result; - std::vector, bool>> emptySet; + std::vector> emptySet; if (critical1 == numberOfStates || critical2 == numberOfStates) { - result.insert(std::pair, bool>>>(lattice, emptySet)); + result.insert(std::pair>>(lattice, emptySet)); } else { storm::expressions::Variable var1 = expressionManager->getVariable(std::to_string(critical1)); storm::expressions::Variable var2 = expressionManager->getVariable(std::to_string(critical2)); auto latticeCopy = new Lattice(lattice); - std::vector, bool>> assumptions; + std::vector> assumptions; auto myMap = createAssumptions(var1, var2, latticeCopy, assumptions); result.insert(myMap.begin(), myMap.end()); - std::vector, bool>> assumptions2; + std::vector> assumptions2; myMap = createAssumptions(var2, var1, lattice, assumptions2); result.insert(myMap.begin(), myMap.end()); } @@ -43,17 +43,17 @@ namespace storm { } template - std::map, bool>>> AssumptionMaker::runRecursive(storm::analysis::Lattice* lattice, std::vector,bool>> assumptions) { - std::map,bool>>> result; + std::map>> AssumptionMaker::runRecursive(storm::analysis::Lattice* lattice, std::vector> assumptions) { + std::map>> result; // only the last assumption is new - std::tuple criticalTriple = this->latticeExtender->extendLattice(lattice, assumptions.back().first); + std::tuple criticalTriple = this->latticeExtender->extendLattice(lattice, assumptions.back()); - if (assumptions.back().second) { + if (assumptionChecker->validated(assumptions.back())) { assumptions.pop_back(); } if (std::get<1>(criticalTriple) == numberOfStates) { - result.insert(std::pair,bool>>>(lattice, assumptions)); + result.insert(std::pair>>(lattice, assumptions)); } else { auto val1 = std::get<1>(criticalTriple); auto val2 = std::get<2>(criticalTriple); @@ -61,7 +61,7 @@ namespace storm { storm::expressions::Variable var2 = expressionManager->getVariable(std::to_string(val2)); auto latticeCopy = new Lattice(lattice); - std::vector, bool>> assumptionsCopy = std::vector, bool>>( + std::vector> assumptionsCopy = std::vector>( assumptions); auto myMap = createAssumptions(var1, var2, latticeCopy, assumptionsCopy); result.insert(myMap.begin(), myMap.end()); @@ -73,15 +73,17 @@ namespace storm { } template - std::map, bool>>> AssumptionMaker::createAssumptions(storm::expressions::Variable var1, storm::expressions::Variable var2, storm::analysis::Lattice* lattice, std::vector, bool>> assumptions) { - std::map, bool>>> result; + std::map>> AssumptionMaker::createAssumptions(storm::expressions::Variable var1, storm::expressions::Variable var2, storm::analysis::Lattice* lattice, std::vector> assumptions) { + std::map>> result; std::shared_ptr assumption = std::make_shared(storm::expressions::BinaryRelationExpression(*expressionManager, expressionManager->getBooleanType(), var1.getExpression().getBaseExpressionPointer(), var2.getExpression().getBaseExpressionPointer(), storm::expressions::BinaryRelationExpression::RelationType::GreaterOrEqual)); if (assumptionChecker->checkOnSamples(assumption)) { - assumptions.push_back(std::pair, bool>(assumption, assumptionChecker->validateAssumption(assumption, lattice))); + // TODO: only if validation on + assumptionChecker->validateAssumption(assumption, lattice); + assumptions.push_back(std::shared_ptr(assumption)); result = (runRecursive(lattice, assumptions)); } else { delete lattice; diff --git a/src/storm-pars/analysis/AssumptionMaker.h b/src/storm-pars/analysis/AssumptionMaker.h index 55adbe0f5..73e6c5bdd 100644 --- a/src/storm-pars/analysis/AssumptionMaker.h +++ b/src/storm-pars/analysis/AssumptionMaker.h @@ -35,13 +35,13 @@ namespace storm { * @param critical2 State number * @return A mapping from pointers to different lattices and assumptions made to create the specific lattice. */ - std::map, bool>>> makeAssumptions( + std::map>> makeAssumptions( storm::analysis::Lattice *lattice, uint_fast64_t critical1, uint_fast64_t critical2); private: - std::map, bool>>> runRecursive(storm::analysis::Lattice* lattice, std::vector, bool>> assumptions); + std::map>> runRecursive(storm::analysis::Lattice* lattice, std::vector> assumptions); - std::map, bool>>> createAssumptions(storm::expressions::Variable var1, storm::expressions::Variable var2, storm::analysis::Lattice* lattice,std::vector, bool>> assumptions); + std::map>> createAssumptions(storm::expressions::Variable var1, storm::expressions::Variable var2, storm::analysis::Lattice* lattice,std::vector> assumptions); storm::analysis::LatticeExtender* latticeExtender; diff --git a/src/storm-pars/analysis/MonotonicityChecker.cpp b/src/storm-pars/analysis/MonotonicityChecker.cpp index 4750d21ff..0ee7c6ad2 100644 --- a/src/storm-pars/analysis/MonotonicityChecker.cpp +++ b/src/storm-pars/analysis/MonotonicityChecker.cpp @@ -9,7 +9,7 @@ namespace storm { namespace analysis { template - void MonotonicityChecker::checkMonotonicity(std::map, bool>>> map, storm::storage::SparseMatrix matrix) { + void MonotonicityChecker::checkMonotonicity(std::map>> map, storm::storage::SparseMatrix matrix) { auto i = 0; for (auto itr = map.begin(); itr != map.end(); ++itr) { auto lattice = itr->first; @@ -31,7 +31,7 @@ namespace storm { first = false; } - std::shared_ptr expression = itr2->first; + std::shared_ptr expression = *itr2; auto var1 = expression->getFirstOperand(); auto var2 = expression->getSecondOperand(); STORM_PRINT(*expression); diff --git a/src/storm-pars/analysis/MonotonicityChecker.h b/src/storm-pars/analysis/MonotonicityChecker.h index 6147b765b..222c0129a 100644 --- a/src/storm-pars/analysis/MonotonicityChecker.h +++ b/src/storm-pars/analysis/MonotonicityChecker.h @@ -24,7 +24,7 @@ namespace storm { * @param map The map with lattices and the assumptions made to create the lattices. * @param matrix The transition matrix. */ - void checkMonotonicity(std::map, bool>>> map, storm::storage::SparseMatrix matrix); + void checkMonotonicity(std::map>> map, storm::storage::SparseMatrix matrix); private: std::map> analyseMonotonicity(uint_fast64_t i, storm::analysis::Lattice* lattice, storm::storage::SparseMatrix matrix) ; From 11776a822a96caba94ba3161bd4e3cffacbad659 Mon Sep 17 00:00:00 2001 From: Jip Spel Date: Tue, 18 Sep 2018 12:51:39 +0200 Subject: [PATCH 066/178] Add documentation --- src/storm-pars/analysis/AssumptionChecker.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/storm-pars/analysis/AssumptionChecker.h b/src/storm-pars/analysis/AssumptionChecker.h index e336f97f3..8d434e561 100644 --- a/src/storm-pars/analysis/AssumptionChecker.h +++ b/src/storm-pars/analysis/AssumptionChecker.h @@ -42,7 +42,14 @@ namespace storm { */ bool validateAssumption(std::shared_ptr assumption, storm::analysis::Lattice* lattice); + /*! + * Looks up if assumption has been validated and holds. + * + * @param assumption The assumption. + * @return true if the assumption has been validated and holds, false otherwise + */ bool validated(std::shared_ptr assumption); + private: std::shared_ptr formula; From 4afa6d8a0fe2323e5c998a31331e2bab31277655 Mon Sep 17 00:00:00 2001 From: Jip Spel Date: Tue, 18 Sep 2018 13:19:44 +0200 Subject: [PATCH 067/178] Make validation of assumptions optional --- src/storm-pars-cli/storm-pars.cpp | 2 +- src/storm-pars/analysis/AssumptionMaker.cpp | 10 ++++++---- src/storm-pars/analysis/AssumptionMaker.h | 8 ++++++-- src/storm-pars/settings/modules/ParametricSettings.cpp | 5 +++++ src/storm-pars/settings/modules/ParametricSettings.h | 4 +++- 5 files changed, 21 insertions(+), 8 deletions(-) diff --git a/src/storm-pars-cli/storm-pars.cpp b/src/storm-pars-cli/storm-pars.cpp index e7aedd2f7..f40d27f2f 100644 --- a/src/storm-pars-cli/storm-pars.cpp +++ b/src/storm-pars-cli/storm-pars.cpp @@ -547,7 +547,7 @@ namespace storm { auto dtmcModel = model->as>(); // TODO check formula type auto assumptionChecker = storm::analysis::AssumptionChecker(formulas[0], dtmcModel, 3); - auto assumptionMaker = storm::analysis::AssumptionMaker(extender, &assumptionChecker, sparseModel->getNumberOfStates()); + auto assumptionMaker = storm::analysis::AssumptionMaker(extender, &assumptionChecker, sparseModel->getNumberOfStates(), parSettings.isValidateAssumptionsSet()); std::map>> result = assumptionMaker.makeAssumptions( std::get<0>(criticalPair), std::get<1>(criticalPair), std::get<2>(criticalPair)); diff --git a/src/storm-pars/analysis/AssumptionMaker.cpp b/src/storm-pars/analysis/AssumptionMaker.cpp index c6804ef59..bc918b48c 100644 --- a/src/storm-pars/analysis/AssumptionMaker.cpp +++ b/src/storm-pars/analysis/AssumptionMaker.cpp @@ -7,10 +7,11 @@ namespace storm { namespace analysis { template - AssumptionMaker::AssumptionMaker(storm::analysis::LatticeExtender* latticeExtender, storm::analysis::AssumptionChecker* assumptionChecker, uint_fast64_t numberOfStates) { + AssumptionMaker::AssumptionMaker(storm::analysis::LatticeExtender* latticeExtender, storm::analysis::AssumptionChecker* assumptionChecker, uint_fast64_t numberOfStates, bool validate) { this->latticeExtender = latticeExtender; this->numberOfStates = numberOfStates; this->assumptionChecker = assumptionChecker; + this->validate = validate; this->expressionManager = std::make_shared(storm::expressions::ExpressionManager()); for (uint_fast64_t i = 0; i < this->numberOfStates; ++i) { expressionManager->declareRationalVariable(std::to_string(i)); @@ -48,7 +49,7 @@ namespace storm { // only the last assumption is new std::tuple criticalTriple = this->latticeExtender->extendLattice(lattice, assumptions.back()); - if (assumptionChecker->validated(assumptions.back())) { + if (validate && assumptionChecker->validated(assumptions.back())) { assumptions.pop_back(); } @@ -81,8 +82,9 @@ namespace storm { var1.getExpression().getBaseExpressionPointer(), var2.getExpression().getBaseExpressionPointer(), storm::expressions::BinaryRelationExpression::RelationType::GreaterOrEqual)); if (assumptionChecker->checkOnSamples(assumption)) { - // TODO: only if validation on - assumptionChecker->validateAssumption(assumption, lattice); + if (validate) { + assumptionChecker->validateAssumption(assumption, lattice); + } assumptions.push_back(std::shared_ptr(assumption)); result = (runRecursive(lattice, assumptions)); } else { diff --git a/src/storm-pars/analysis/AssumptionMaker.h b/src/storm-pars/analysis/AssumptionMaker.h index 73e6c5bdd..1381d4ad0 100644 --- a/src/storm-pars/analysis/AssumptionMaker.h +++ b/src/storm-pars/analysis/AssumptionMaker.h @@ -25,7 +25,7 @@ namespace storm { * @param checker The AssumptionChecker which checks the assumptions at sample points. * @param numberOfStates The number of states of the model. */ - AssumptionMaker(storm::analysis::LatticeExtender* latticeExtender, storm::analysis::AssumptionChecker* checker, uint_fast64_t numberOfStates); + AssumptionMaker(storm::analysis::LatticeExtender* latticeExtender, storm::analysis::AssumptionChecker* checker, uint_fast64_t numberOfStates, bool validate); /*! * Make the assumptions given a lattice and two states which could not be added to the lattice. Returns when no more assumptions can be made. @@ -45,11 +45,15 @@ namespace storm { storm::analysis::LatticeExtender* latticeExtender; + storm::analysis::AssumptionChecker* assumptionChecker; + std::shared_ptr expressionManager; uint_fast64_t numberOfStates; - storm::analysis::AssumptionChecker* assumptionChecker; + bool validate; + + }; } } diff --git a/src/storm-pars/settings/modules/ParametricSettings.cpp b/src/storm-pars/settings/modules/ParametricSettings.cpp index ef64acb94..97c8bb16b 100644 --- a/src/storm-pars/settings/modules/ParametricSettings.cpp +++ b/src/storm-pars/settings/modules/ParametricSettings.cpp @@ -70,6 +70,11 @@ namespace storm { // TODO: Make this dependent on the input. return true; } + + bool ParametricSettings::isValidateAssumptionsSet() const { + // TODO: Make this dependent on the input. + return true; + } } // namespace modules } // namespace settings } // namespace storm diff --git a/src/storm-pars/settings/modules/ParametricSettings.h b/src/storm-pars/settings/modules/ParametricSettings.h index 0fa167409..dd84e9975 100644 --- a/src/storm-pars/settings/modules/ParametricSettings.h +++ b/src/storm-pars/settings/modules/ParametricSettings.h @@ -65,7 +65,9 @@ namespace storm { bool isSampleExactSet() const; bool isMonotonicityAnalysisSet() const; - + + bool isValidateAssumptionsSet() const; + const static std::string moduleName; private: From b20a7efe12996578d6716fc6d0245ebd0d5704ad Mon Sep 17 00:00:00 2001 From: Jip Spel Date: Tue, 18 Sep 2018 13:47:06 +0200 Subject: [PATCH 068/178] Replace dummy code --- src/storm-pars/settings/modules/ParametricSettings.cpp | 10 ++++++---- src/storm-pars/settings/modules/ParametricSettings.h | 2 ++ 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/storm-pars/settings/modules/ParametricSettings.cpp b/src/storm-pars/settings/modules/ParametricSettings.cpp index 97c8bb16b..8c1be78d4 100644 --- a/src/storm-pars/settings/modules/ParametricSettings.cpp +++ b/src/storm-pars/settings/modules/ParametricSettings.cpp @@ -21,6 +21,8 @@ namespace storm { const std::string ParametricSettings::samplesOptionName = "samples"; const std::string ParametricSettings::samplesGraphPreservingOptionName = "samples-graph-preserving"; const std::string ParametricSettings::sampleExactOptionName = "sample-exact"; + const std::string ParametricSettings::monotonicityAnalysis = "monotonicity-analysis"; + const std::string ParametricSettings::validateAssumptions = "validate-assumptions"; ParametricSettings::ParametricSettings() : ModuleSettings(moduleName) { this->addOption(storm::settings::OptionBuilder(moduleName, exportResultOptionName, false, "A path to a file where the parametric result should be saved.") @@ -32,6 +34,8 @@ namespace storm { .addArgument(storm::settings::ArgumentBuilder::createStringArgument("samples", "The samples are semicolon-separated entries of the form 'Var1=Val1:Val2:...:Valk,Var2=... that span the sample spaces.").setDefaultValueString("").build()).build()); this->addOption(storm::settings::OptionBuilder(moduleName, samplesGraphPreservingOptionName, false, "Sets whether it can be assumed that the samples are graph-preserving.").build()); this->addOption(storm::settings::OptionBuilder(moduleName, sampleExactOptionName, false, "Sets whether to sample using exact arithmetic.").build()); + this->addOption(storm::settings::OptionBuilder(moduleName, monotonicityAnalysis, false, "Sets whether monotonicity analysis is done").build()); + this->addOption(storm::settings::OptionBuilder(moduleName, validateAssumptions, false, "Sets whether assumptions made in monotonicity analysis are validated").build()); } bool ParametricSettings::exportResultToFile() const { @@ -67,13 +71,11 @@ namespace storm { } bool ParametricSettings::isMonotonicityAnalysisSet() const { - // TODO: Make this dependent on the input. - return true; + return this->getOption(monotonicityAnalysis).getHasOptionBeenSet(); } bool ParametricSettings::isValidateAssumptionsSet() const { - // TODO: Make this dependent on the input. - return true; + return this->getOption(validateAssumptions).getHasOptionBeenSet(); } } // namespace modules } // namespace settings diff --git a/src/storm-pars/settings/modules/ParametricSettings.h b/src/storm-pars/settings/modules/ParametricSettings.h index dd84e9975..2fc386471 100644 --- a/src/storm-pars/settings/modules/ParametricSettings.h +++ b/src/storm-pars/settings/modules/ParametricSettings.h @@ -79,6 +79,8 @@ namespace storm { const static std::string samplesOptionName; const static std::string samplesGraphPreservingOptionName; const static std::string sampleExactOptionName; + const static std::string monotonicityAnalysis; + const static std::string validateAssumptions; }; } // namespace modules From 285cde32aeabef3e8a90711b07409f9c4687dfe7 Mon Sep 17 00:00:00 2001 From: Jip Spel Date: Tue, 18 Sep 2018 14:40:18 +0200 Subject: [PATCH 069/178] Also give result when lattice does not contain all states --- src/storm-pars/analysis/AssumptionMaker.cpp | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/storm-pars/analysis/AssumptionMaker.cpp b/src/storm-pars/analysis/AssumptionMaker.cpp index bc918b48c..9cef9ab3c 100644 --- a/src/storm-pars/analysis/AssumptionMaker.cpp +++ b/src/storm-pars/analysis/AssumptionMaker.cpp @@ -31,14 +31,19 @@ namespace storm { storm::expressions::Variable var1 = expressionManager->getVariable(std::to_string(critical1)); storm::expressions::Variable var2 = expressionManager->getVariable(std::to_string(critical2)); - auto latticeCopy = new Lattice(lattice); std::vector> assumptions; - auto myMap = createAssumptions(var1, var2, latticeCopy, assumptions); + auto myMap = createAssumptions(var1, var2, new Lattice(lattice), assumptions); result.insert(myMap.begin(), myMap.end()); std::vector> assumptions2; - myMap = createAssumptions(var2, var1, lattice, assumptions2); + myMap = createAssumptions(var2, var1, new Lattice(lattice), assumptions2); result.insert(myMap.begin(), myMap.end()); + if (result.size() == 0) { + // No assumptions could be made, all not valid based on sampling, therefore returning original lattice + result.insert(std::pair>>(lattice, emptySet)); + } else { + delete lattice; + } } return result; } From 23edcc1a75dda2d7057178870c219401e40a3cb4 Mon Sep 17 00:00:00 2001 From: Jip Spel Date: Tue, 18 Sep 2018 17:38:20 +0200 Subject: [PATCH 070/178] Refactor AssumptionChecker --- src/storm-pars/analysis/AssumptionChecker.cpp | 82 +++++++++---------- 1 file changed, 41 insertions(+), 41 deletions(-) diff --git a/src/storm-pars/analysis/AssumptionChecker.cpp b/src/storm-pars/analysis/AssumptionChecker.cpp index c3014d3a9..1ed16f149 100644 --- a/src/storm-pars/analysis/AssumptionChecker.cpp +++ b/src/storm-pars/analysis/AssumptionChecker.cpp @@ -88,54 +88,54 @@ namespace storm { storm::exceptions::NotSupportedException, "Only Greater Or Equal assumptions supported"); - auto val1 = std::stoi(assumption->getFirstOperand()->asVariableExpression().getVariableName()); - auto val2 = std::stoi(assumption->getSecondOperand()->asVariableExpression().getVariableName()); - auto row1 = matrix.getRow(val1); - auto row2 = matrix.getRow(val2); - if (row1.getNumberOfEntries() != 2 && row2.getNumberOfEntries() != 2) { - assert (false); - } - - auto succ11 = row1.begin(); - auto succ12 = (++row1.begin()); - auto succ21 = row2.begin(); - auto succ22 = (++row2.begin()); + auto row1 = matrix.getRow(std::stoi(assumption->getFirstOperand()->asVariableExpression().getVariableName())); + auto row2 = matrix.getRow(std::stoi(assumption->getSecondOperand()->asVariableExpression().getVariableName())); - if (succ12->getColumn() == succ21->getColumn() && succ11->getColumn() == succ22->getColumn()) { - auto temp = succ12; - succ12 = succ11; - succ11 = temp; - } + // Only implemented for two successors + if (row1.getNumberOfEntries() == 2 && row2.getNumberOfEntries() == 2) { + auto succ1State1 = row1.begin(); + auto succ2State1 = (++row1.begin()); + auto succ1State2 = row2.begin(); + auto succ2State2 = (++row2.begin()); - if (succ11->getColumn() == succ21->getColumn() && succ12->getColumn() == succ22->getColumn()) { - ValueType prob; - auto comp = lattice->compare(succ11->getColumn(), succ12->getColumn()); - if (comp == storm::analysis::Lattice::ABOVE) { - prob = succ11->getValue() - succ21->getValue(); - } else if (comp == storm::analysis::Lattice::BELOW) { - prob = succ12->getValue() - succ22->getValue(); + if (succ1State1->getColumn() == succ2State2->getColumn() + && succ1State2->getColumn() == succ2State1->getColumn()) { + // swap them + auto temp = succ2State1; + succ2State1 = succ1State1; + succ1State1 = temp; } - auto vars = prob.gatherVariables(); - // TODO: Type - std::map substitutions; - for (auto var:vars) { - auto derivative = prob.derivative(var); - assert(derivative.isConstant()); - if (derivative.constantPart() >= 0) { - substitutions[var] = 0; - } else if (derivative.constantPart() <= 0) { - substitutions[var] = 1; + + if (succ1State1->getColumn() == succ1State2->getColumn() && succ2State1->getColumn() == succ2State2->getColumn()) { + ValueType prob; + auto comp = lattice->compare(succ1State1->getColumn(), succ2State1->getColumn()); + if (comp == storm::analysis::Lattice::ABOVE) { + prob = succ1State1->getValue() - succ1State2->getValue(); + } else if (comp == storm::analysis::Lattice::BELOW) { + prob = succ2State1->getValue() - succ2State2->getValue(); + } + auto vars = prob.gatherVariables(); + // TODO: Type + std::map substitutions; + for (auto var:vars) { + auto derivative = prob.derivative(var); + assert(derivative.isConstant()); + if (derivative.constantPart() >= 0) { + substitutions[var] = 0; + } else if (derivative.constantPart() <= 0) { + substitutions[var] = 1; + } } + result = prob.evaluate(substitutions) >= 0; + } + + if (result) { + validatedAssumptions.insert(assumption); + } else { + STORM_LOG_DEBUG("Could not validate: " << *assumption << std::endl); } - result = prob.evaluate(substitutions) >= 0; - } - if (result) { - validatedAssumptions.insert(assumption); - } else { - STORM_PRINT("Could not validate: " << *assumption << std::endl); } } - return result; } From 82931f339085a4d7c652821681552a582f9207ac Mon Sep 17 00:00:00 2001 From: Jip Spel Date: Wed, 19 Sep 2018 08:35:48 +0200 Subject: [PATCH 071/178] Add asserts to Lattice --- src/storm-pars/analysis/Lattice.cpp | 37 +++++++++++++---------------- 1 file changed, 16 insertions(+), 21 deletions(-) diff --git a/src/storm-pars/analysis/Lattice.cpp b/src/storm-pars/analysis/Lattice.cpp index bea6439d2..10a1f5082 100644 --- a/src/storm-pars/analysis/Lattice.cpp +++ b/src/storm-pars/analysis/Lattice.cpp @@ -5,6 +5,7 @@ #include #include #include "Lattice.h" + namespace storm { namespace analysis { Lattice::Lattice(storm::storage::BitVector topStates, @@ -21,13 +22,15 @@ namespace storm { nodes.at(i) = top; } + for (auto i = bottomStates.getNextSetIndex(0); i < numberOfStates; i = bottomStates.getNextSetIndex(i+1)) { nodes.at(i) = bottom; } + this->numberOfStates = numberOfStates; this->addedStates = storm::storage::BitVector(numberOfStates); - this->addedStates.operator|=(topStates); - this->addedStates.operator|=(bottomStates); + this->addedStates |= (topStates); + this->addedStates |= (bottomStates); } Lattice::Lattice(Lattice* lattice) { @@ -43,7 +46,6 @@ namespace storm { for (auto i = top->states.getNextSetIndex(0); i < numberOfStates; i = top->states.getNextSetIndex(i+1)) { nodes.at(i) = top; - } for (auto i = bottom->states.getNextSetIndex(0); i < numberOfStates; i = bottom->states.getNextSetIndex(i+1)) { @@ -51,7 +53,7 @@ namespace storm { } auto oldNodes = lattice->getNodes(); - // Create all nodes + // Create nodes for (auto itr = oldNodes.begin(); itr != oldNodes.end(); ++itr) { Node* oldNode = (*itr); if (oldNode != nullptr) { @@ -79,6 +81,8 @@ namespace storm { } void Lattice::addBetween(uint_fast64_t state, Node *above, Node *below) { + assert(!addedStates[state]); + assert(compare(above, below) == ABOVE); Node *newNode = new Node(); newNode->states = storm::storage::BitVector(numberOfStates); newNode->states.set(state); @@ -93,6 +97,7 @@ namespace storm { } void Lattice::addToNode(uint_fast64_t state, Node *node) { + assert(!addedStates[state]); node->states.set(state); nodes.at(state) = node; addedStates.set(state); @@ -103,17 +108,13 @@ namespace storm { } void Lattice::addRelationNodes(storm::analysis::Lattice::Node *above, storm::analysis::Lattice::Node * below) { - if (above != below) { - above->below.insert(below); - below->above.insert(above); - } + assert(compare(above, below) == UNKNOWN); + above->below.insert(below); + below->above.insert(above); } int Lattice::compare(uint_fast64_t state1, uint_fast64_t state2) { - Node *node1 = getNode(state1); - Node *node2 = getNode(state2); - - return compare(node1, node2); + return compare(getNode(state1), getNode(state2)); } int Lattice::compare(Node* node1, Node* node2) { @@ -121,22 +122,16 @@ namespace storm { if (node1 == node2) { return SAME; } - // TODO: Uberhaupt niet mogelijk? - bool isAbove = above(node1, node2, new std::set({})); - bool isBelow = above(node2, node1, new std::set({})); - if (isAbove && isBelow) { - return SAME; - } - if (isAbove) { + if (above(node1, node2, new std::set({}))) { + assert(!above(node2, node1, new std::set({}))); return ABOVE; } - if (isBelow) { + if (above(node2, node1, new std::set({}))) { return BELOW; } } - return UNKNOWN; } From 24abcfb61cad917aad3546fe1f96bbc75e6160e1 Mon Sep 17 00:00:00 2001 From: Jip Spel Date: Wed, 19 Sep 2018 09:14:10 +0200 Subject: [PATCH 072/178] AssumptionChecker for mdp --- src/storm-pars-cli/storm-pars.cpp | 23 +++++++---- src/storm-pars/analysis/AssumptionChecker.cpp | 40 +++++++++++++++++++ src/storm-pars/analysis/AssumptionChecker.h | 12 +++++- 3 files changed, 66 insertions(+), 9 deletions(-) diff --git a/src/storm-pars-cli/storm-pars.cpp b/src/storm-pars-cli/storm-pars.cpp index f40d27f2f..b124538b7 100644 --- a/src/storm-pars-cli/storm-pars.cpp +++ b/src/storm-pars-cli/storm-pars.cpp @@ -543,14 +543,21 @@ namespace storm { storm::utility::Stopwatch latticeWatch(true); storm::analysis::LatticeExtender *extender = new storm::analysis::LatticeExtender(sparseModel); std::tuple criticalPair = extender->toLattice(formulas); - // TODO check not mdp - auto dtmcModel = model->as>(); - // TODO check formula type - auto assumptionChecker = storm::analysis::AssumptionChecker(formulas[0], dtmcModel, 3); - auto assumptionMaker = storm::analysis::AssumptionMaker(extender, &assumptionChecker, sparseModel->getNumberOfStates(), parSettings.isValidateAssumptionsSet()); - - std::map>> result = assumptionMaker.makeAssumptions( - std::get<0>(criticalPair), std::get<1>(criticalPair), std::get<2>(criticalPair)); + std::map>> result; + if (model->isOfType(storm::models::ModelType::Dtmc)) { + auto dtmcModel = model->as>(); + auto assumptionChecker = storm::analysis::AssumptionChecker(formulas[0], dtmcModel, 3); + auto assumptionMaker = storm::analysis::AssumptionMaker(extender, &assumptionChecker, sparseModel->getNumberOfStates(), parSettings.isValidateAssumptionsSet()); + result = assumptionMaker.makeAssumptions(std::get<0>(criticalPair), std::get<1>(criticalPair), std::get<2>(criticalPair)); + } else if (model->isOfType(storm::models::ModelType::Dtmc)) { + auto mdpModel = model->as>(); + auto assumptionChecker = storm::analysis::AssumptionChecker(formulas[0], mdpModel, 3); + auto assumptionMaker = storm::analysis::AssumptionMaker(extender, &assumptionChecker, sparseModel->getNumberOfStates(), parSettings.isValidateAssumptionsSet()); + result = assumptionMaker.makeAssumptions(std::get<0>(criticalPair), std::get<1>(criticalPair), std::get<2>(criticalPair)); + } else { + STORM_LOG_THROW(false, storm::exceptions::InvalidOperationException, "Unable to perform monotonicity analysis on the provided model type."); + } + latticeWatch.stop(); STORM_PRINT(std::endl << "Time for lattice creation: " << latticeWatch << "." << std::endl << std::endl); diff --git a/src/storm-pars/analysis/AssumptionChecker.cpp b/src/storm-pars/analysis/AssumptionChecker.cpp index 1ed16f149..359dc1a86 100644 --- a/src/storm-pars/analysis/AssumptionChecker.cpp +++ b/src/storm-pars/analysis/AssumptionChecker.cpp @@ -9,6 +9,7 @@ #include "storm/exceptions/NotSupportedException.h" #include "storm/modelchecker/CheckTask.h" #include "storm/modelchecker/prctl/SparseDtmcPrctlModelChecker.h" +#include "storm/modelchecker/prctl/SparseMdpPrctlModelChecker.h" #include "storm/modelchecker/results/CheckResult.h" #include "storm/modelchecker/results/ExplicitQuantitativeCheckResult.h" #include "storm/storage/expressions/SimpleValuation.h" @@ -56,6 +57,45 @@ namespace storm { } } + template + AssumptionChecker::AssumptionChecker(std::shared_ptr formula, std::shared_ptr> model, uint_fast64_t numberOfSamples) { + this->formula = formula; + this->matrix = model->getTransitionMatrix(); + + // Create sample points + auto instantiator = storm::utility::ModelInstantiator, storm::models::sparse::Mdp>(*model); + auto matrix = model->getTransitionMatrix(); + std::set variables = storm::models::sparse::getProbabilityParameters(*model); + for (auto i = 0; i < numberOfSamples; ++i) { + auto valuation = storm::utility::parametric::Valuation(); + for (auto itr = variables.begin(); itr != variables.end(); ++itr) { + // TODO: Type + auto val = std::pair((*itr), storm::utility::convertNumber(boost::lexical_cast((i+1)/(double (numberOfSamples + 1))))); + valuation.insert(val); + } + storm::models::sparse::Mdp sampleModel = instantiator.instantiate(valuation); + auto checker = storm::modelchecker::SparseMdpPrctlModelChecker>(sampleModel); + std::unique_ptr checkResult; + if (formula->isProbabilityOperatorFormula() && + formula->asProbabilityOperatorFormula().getSubformula().isUntilFormula()) { + const storm::modelchecker::CheckTask checkTask = storm::modelchecker::CheckTask( + (*formula).asProbabilityOperatorFormula().getSubformula().asUntilFormula()); + checkResult = checker.computeUntilProbabilities(Environment(), checkTask); + } else if (formula->isProbabilityOperatorFormula() && + formula->asProbabilityOperatorFormula().getSubformula().isEventuallyFormula()) { + const storm::modelchecker::CheckTask checkTask = storm::modelchecker::CheckTask( + (*formula).asProbabilityOperatorFormula().getSubformula().asEventuallyFormula()); + checkResult = checker.computeReachabilityProbabilities(Environment(), checkTask); + } else { + STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, + "Expecting until or eventually formula"); + } + auto quantitativeResult = checkResult->asExplicitQuantitativeCheckResult(); + std::vector values = quantitativeResult.getValueVector(); + results.push_back(values); + } + } + template bool AssumptionChecker::checkOnSamples(std::shared_ptr assumption) { bool result = true; diff --git a/src/storm-pars/analysis/AssumptionChecker.h b/src/storm-pars/analysis/AssumptionChecker.h index 8d434e561..deb75cd87 100644 --- a/src/storm-pars/analysis/AssumptionChecker.h +++ b/src/storm-pars/analysis/AssumptionChecker.h @@ -7,6 +7,7 @@ #include "storm/logic/Formula.h" #include "storm/models/sparse/Dtmc.h" +#include "storm/models/sparse/Mdp.h" #include "storm/environment/Environment.h" #include "storm/storage/expressions/BinaryRelationExpression.h" #include "Lattice.h" @@ -20,11 +21,20 @@ namespace storm { * Constructs an AssumptionChecker based on the number of samples, for the given formula and model. * * @param formula The formula to check. - * @param model The model to check the formula on. + * @param model The dtmc model to check the formula on. * @param numberOfSamples Number of sample points. */ AssumptionChecker(std::shared_ptr formula, std::shared_ptr> model, uint_fast64_t numberOfSamples); + /*! + * Constructs an AssumptionChecker based on the number of samples, for the given formula and model. + * + * @param formula The formula to check. + * @param model The mdp model to check the formula on. + * @param numberOfSamples Number of sample points. + */ + AssumptionChecker(std::shared_ptr formula, std::shared_ptr> model, uint_fast64_t numberOfSamples); + /*! * Checks if the assumption holds at the sample points of the AssumptionChecker. * From ce231fd927ded865a1cc6e29614b26c01255a7b1 Mon Sep 17 00:00:00 2001 From: Jip Spel Date: Wed, 19 Sep 2018 16:09:20 +0200 Subject: [PATCH 073/178] Fix assert in Lattice --- src/storm-pars/analysis/Lattice.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/storm-pars/analysis/Lattice.cpp b/src/storm-pars/analysis/Lattice.cpp index 10a1f5082..87db8a666 100644 --- a/src/storm-pars/analysis/Lattice.cpp +++ b/src/storm-pars/analysis/Lattice.cpp @@ -108,7 +108,7 @@ namespace storm { } void Lattice::addRelationNodes(storm::analysis::Lattice::Node *above, storm::analysis::Lattice::Node * below) { - assert(compare(above, below) == UNKNOWN); + assert(compare(above, below) == UNKNOWN || compare(above, below) == ABOVE); above->below.insert(below); below->above.insert(above); } From 71408bc011e639229357b1cd95a5e26bcefaf374 Mon Sep 17 00:00:00 2001 From: Jip Spel Date: Wed, 19 Sep 2018 16:44:25 +0200 Subject: [PATCH 074/178] Setup test for AssumptionChecker --- src/test/storm-pars/CMakeLists.txt | 2 +- .../analysis/AssumptionCheckerTest.cpp | 71 +++++++++++++++++++ 2 files changed, 72 insertions(+), 1 deletion(-) create mode 100644 src/test/storm-pars/analysis/AssumptionCheckerTest.cpp diff --git a/src/test/storm-pars/CMakeLists.txt b/src/test/storm-pars/CMakeLists.txt index 28c5a391d..ba3994449 100644 --- a/src/test/storm-pars/CMakeLists.txt +++ b/src/test/storm-pars/CMakeLists.txt @@ -9,7 +9,7 @@ register_source_groups_from_filestructure("${ALL_FILES}" test) # Note that the tests also need the source files, except for the main file include_directories(${GTEST_INCLUDE_DIR}) -foreach (testsuite modelchecker utility) +foreach (testsuite analysis modelchecker utility) file(GLOB_RECURSE TEST_${testsuite}_FILES ${STORM_TESTS_BASE_PATH}/${testsuite}/*.h ${STORM_TESTS_BASE_PATH}/${testsuite}/*.cpp) add_executable (test-pars-${testsuite} ${TEST_${testsuite}_FILES} ${STORM_TESTS_BASE_PATH}/storm-test.cpp) diff --git a/src/test/storm-pars/analysis/AssumptionCheckerTest.cpp b/src/test/storm-pars/analysis/AssumptionCheckerTest.cpp new file mode 100644 index 000000000..2847c9a43 --- /dev/null +++ b/src/test/storm-pars/analysis/AssumptionCheckerTest.cpp @@ -0,0 +1,71 @@ +// +// Created by Jip Spel on 19.09.18. +// + +// TODO: cleanup includes +#include "gtest/gtest.h" +#include "storm-config.h" +#include "test/storm_gtest.h" + +#include "storm-parsers/parser/FormulaParser.h" +#include "storm/logic/Formulas.h" +#include "storm/models/sparse/StandardRewardModel.h" +#include "storm/modelchecker/prctl/SparseDtmcPrctlModelChecker.h" +#include "storm/modelchecker/results/ExplicitQuantitativeCheckResult.h" +#include "storm-parsers/parser/AutoParser.h" +#include "storm-parsers/parser/PrismParser.h" +#include "storm/storage/expressions/ExpressionManager.h" +#include "storm/api/builder.h" + +#include "storm-pars/analysis/AssumptionChecker.h" +#include "storm-pars/analysis/Lattice.h" +#include "storm/storage/expressions/BinaryRelationExpression.h" +#include "storm-pars/transformer/SparseParametricDtmcSimplifier.h" + +#include "storm-pars/api/storm-pars.h" +#include "storm/api/storm.h" + +#include "storm-parsers/api/storm-parsers.h" + +// TODO: extend +TEST(AssumptionCheckerTest, Brp) { + std::string programFile = STORM_TEST_RESOURCES_DIR "/pdtmc/brp16_2.pm"; + std::string formulaAsString = "P<=0.84 [F s=5 ]"; + std::string constantsAsString = ""; //e.g. pL=0.9,TOACK=0.5 + + // Program and formula + storm::prism::Program program = storm::api::parseProgram(programFile); + program = storm::utility::prism::preprocess(program, constantsAsString); + std::vector> formulas = storm::api::extractFormulasFromProperties(storm::api::parsePropertiesForPrismProgram(formulaAsString, program)); + std::shared_ptr> model = storm::api::buildSparseModel(program, formulas)->as>(); + std::shared_ptr> dtmc = model->as>(); + auto simplifier = storm::transformer::SparseParametricDtmcSimplifier>(*dtmc); + + ASSERT_TRUE(simplifier.simplify(*(formulas[0]))); // TODO: verwacht path formula? + model = simplifier.getSimplifiedModel(); + + dtmc = model->as>(); + + ASSERT_EQ(dtmc->getNumberOfStates(), 193ull); + ASSERT_EQ(dtmc->getNumberOfTransitions(), 383ull); + + auto checker = storm::analysis::AssumptionChecker(formulas[0], dtmc, 3); + + // Check on samples + auto expressionManager = std::make_shared(storm::expressions::ExpressionManager()); + expressionManager->declareRationalVariable("7"); + expressionManager->declareRationalVariable("5"); + + auto assumption = std::make_shared( + storm::expressions::BinaryRelationExpression(*expressionManager, expressionManager->getBooleanType(), + expressionManager->getVariable("7").getExpression().getBaseExpressionPointer(), + expressionManager->getVariable("5").getExpression().getBaseExpressionPointer(), + storm::expressions::BinaryRelationExpression::RelationType::GreaterOrEqual)); + EXPECT_FALSE(checker.checkOnSamples(assumption)); + + auto emptyLattice = new storm::analysis::Lattice(storm::storage::BitVector(8), storm::storage::BitVector(8), 8); + // Validate assumptions + EXPECT_FALSE(checker.validateAssumption(assumption, emptyLattice)); + EXPECT_FALSE(checker.validated(assumption)); +} + From aaae25ee76fee09a5cb04bf7b213594454db9ac0 Mon Sep 17 00:00:00 2001 From: Jip Spel Date: Thu, 20 Sep 2018 09:28:43 +0200 Subject: [PATCH 075/178] Update AssumptionCheckerTest --- src/test/storm-pars/analysis/AssumptionCheckerTest.cpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/test/storm-pars/analysis/AssumptionCheckerTest.cpp b/src/test/storm-pars/analysis/AssumptionCheckerTest.cpp index 2847c9a43..86a992c9e 100644 --- a/src/test/storm-pars/analysis/AssumptionCheckerTest.cpp +++ b/src/test/storm-pars/analysis/AssumptionCheckerTest.cpp @@ -27,10 +27,10 @@ #include "storm-parsers/api/storm-parsers.h" -// TODO: extend +// TODO: extend for cases in which checkOnSamples and validateAssumption return true TEST(AssumptionCheckerTest, Brp) { std::string programFile = STORM_TEST_RESOURCES_DIR "/pdtmc/brp16_2.pm"; - std::string formulaAsString = "P<=0.84 [F s=5 ]"; + std::string formulaAsString = "P=? [F s=4 & i=N ]"; std::string constantsAsString = ""; //e.g. pL=0.9,TOACK=0.5 // Program and formula @@ -40,8 +40,7 @@ TEST(AssumptionCheckerTest, Brp) { std::shared_ptr> model = storm::api::buildSparseModel(program, formulas)->as>(); std::shared_ptr> dtmc = model->as>(); auto simplifier = storm::transformer::SparseParametricDtmcSimplifier>(*dtmc); - - ASSERT_TRUE(simplifier.simplify(*(formulas[0]))); // TODO: verwacht path formula? + ASSERT_TRUE(simplifier.simplify(*(formulas[0]))); model = simplifier.getSimplifiedModel(); dtmc = model->as>(); @@ -61,7 +60,7 @@ TEST(AssumptionCheckerTest, Brp) { expressionManager->getVariable("7").getExpression().getBaseExpressionPointer(), expressionManager->getVariable("5").getExpression().getBaseExpressionPointer(), storm::expressions::BinaryRelationExpression::RelationType::GreaterOrEqual)); - EXPECT_FALSE(checker.checkOnSamples(assumption)); + EXPECT_TRUE(checker.checkOnSamples(assumption)); auto emptyLattice = new storm::analysis::Lattice(storm::storage::BitVector(8), storm::storage::BitVector(8), 8); // Validate assumptions From c81319135d46706dbe17c1ee5379dad26e62fdef Mon Sep 17 00:00:00 2001 From: Jip Spel Date: Thu, 20 Sep 2018 10:22:46 +0200 Subject: [PATCH 076/178] Make enum for constants --- src/storm-pars/analysis/Lattice.h | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/src/storm-pars/analysis/Lattice.h b/src/storm-pars/analysis/Lattice.h index 42a4802cb..37a86ea5e 100644 --- a/src/storm-pars/analysis/Lattice.h +++ b/src/storm-pars/analysis/Lattice.h @@ -129,15 +129,12 @@ namespace storm { /*! * Constants for comparison of nodes/states */ - static const int UNKNOWN = -1; - static const int BELOW = 2; - static const int ABOVE = 1; - static const int SAME = 0; - - protected: - void addBelow(uint_fast64_t state, Node* node); - - void addAbove(uint_fast64_t state, Node* node); + enum { + UNKNOWN = -1, + BELOW = 2, + ABOVE = 1, + SAME = 0, + }; private: std::vector nodes; From 705d8ecc1ae5dd11b974cd29b59daeae8f8f6432 Mon Sep 17 00:00:00 2001 From: Jip Spel Date: Thu, 20 Sep 2018 10:26:39 +0200 Subject: [PATCH 077/178] Create test for Lattice --- src/test/storm-pars/analysis/LatticeTest.cpp | 38 ++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 src/test/storm-pars/analysis/LatticeTest.cpp diff --git a/src/test/storm-pars/analysis/LatticeTest.cpp b/src/test/storm-pars/analysis/LatticeTest.cpp new file mode 100644 index 000000000..7df231912 --- /dev/null +++ b/src/test/storm-pars/analysis/LatticeTest.cpp @@ -0,0 +1,38 @@ +// +// Created by Jip Spel on 20.09.18. +// + +// TODO: cleanup includes +#include "gtest/gtest.h" +#include "storm-config.h" +#include "test/storm_gtest.h" +#include "storm-pars/analysis/Lattice.h" +#include "storm/storage/BitVector.h" + +TEST(LatticeTest, Simple) { + auto numberOfStates = 5; + auto above = storm::storage::BitVector(numberOfStates); + above.set(0); + auto below = storm::storage::BitVector(numberOfStates); + below.set(1); + + auto lattice = storm::analysis::Lattice(above, below, numberOfStates); + EXPECT_EQ(storm::analysis::Lattice::ABOVE, lattice.compare(0,1)); + EXPECT_EQ(storm::analysis::Lattice::BELOW, lattice.compare(1,0)); + EXPECT_EQ(nullptr, lattice.getNode(2)); + + lattice.add(2); + EXPECT_EQ(storm::analysis::Lattice::ABOVE, lattice.compare(0,2)); + EXPECT_EQ(storm::analysis::Lattice::ABOVE, lattice.compare(2,1)); + + lattice.add(3); + EXPECT_EQ(storm::analysis::Lattice::UNKNOWN, lattice.compare(2,3)); + EXPECT_EQ(storm::analysis::Lattice::UNKNOWN, lattice.compare(3,2)); + + lattice.addToNode(4, lattice.getNode(2)); + EXPECT_EQ(storm::analysis::Lattice::SAME, lattice.compare(2,4)); + EXPECT_EQ(storm::analysis::Lattice::ABOVE, lattice.compare(0,4)); + EXPECT_EQ(storm::analysis::Lattice::ABOVE, lattice.compare(4,1)); + EXPECT_EQ(storm::analysis::Lattice::UNKNOWN, lattice.compare(4,3)); + EXPECT_EQ(storm::analysis::Lattice::UNKNOWN, lattice.compare(3,4)); +} From 712faae653be929a282c7cd0ef363aee91f92ca7 Mon Sep 17 00:00:00 2001 From: Jip Spel Date: Thu, 20 Sep 2018 11:06:20 +0200 Subject: [PATCH 078/178] Create test for LatticeExtender --- .../analysis/LatticeExtenderTest.cpp | 98 +++++++++++++++++++ 1 file changed, 98 insertions(+) create mode 100644 src/test/storm-pars/analysis/LatticeExtenderTest.cpp diff --git a/src/test/storm-pars/analysis/LatticeExtenderTest.cpp b/src/test/storm-pars/analysis/LatticeExtenderTest.cpp new file mode 100644 index 000000000..59f739b84 --- /dev/null +++ b/src/test/storm-pars/analysis/LatticeExtenderTest.cpp @@ -0,0 +1,98 @@ +// +// Created by Jip Spel on 20.09.18. +// + +// TODO: cleanup includes +#include "gtest/gtest.h" +#include "storm-config.h" +#include "test/storm_gtest.h" + +#include "storm-parsers/parser/FormulaParser.h" +#include "storm/logic/Formulas.h" +#include "storm/models/sparse/StandardRewardModel.h" +#include "storm/modelchecker/prctl/SparseDtmcPrctlModelChecker.h" +#include "storm/modelchecker/results/ExplicitQuantitativeCheckResult.h" +#include "storm-parsers/parser/AutoParser.h" +#include "storm-parsers/parser/PrismParser.h" +#include "storm/storage/expressions/ExpressionManager.h" +#include "storm/api/builder.h" + +#include "storm-pars/analysis/Lattice.h" +#include "storm-pars/analysis/LatticeExtender.h" +#include "storm-pars/transformer/SparseParametricDtmcSimplifier.h" + +#include "storm-pars/api/storm-pars.h" +#include "storm/api/storm.h" + +#include "storm-parsers/api/storm-parsers.h" + +TEST(LatticeExtenderTest, Brp_with_bisimulation) { + std::string programFile = STORM_TEST_RESOURCES_DIR "/pdtmc/brp16_2.pm"; + std::string formulaAsString = "P=? [F s=4 & i=N ]"; + std::string constantsAsString = ""; //e.g. pL=0.9,TOACK=0.5 + + // Program and formula + storm::prism::Program program = storm::api::parseProgram(programFile); + program = storm::utility::prism::preprocess(program, constantsAsString); + std::vector> formulas = storm::api::extractFormulasFromProperties(storm::api::parsePropertiesForPrismProgram(formulaAsString, program)); + std::shared_ptr> model = storm::api::buildSparseModel(program, formulas)->as>(); + std::shared_ptr> dtmc = model->as>(); + auto simplifier = storm::transformer::SparseParametricDtmcSimplifier>(*dtmc); + ASSERT_TRUE(simplifier.simplify(*(formulas[0]))); + model = simplifier.getSimplifiedModel(); + + // Apply bisimulation + storm::storage::BisimulationType bisimType = storm::storage::BisimulationType::Strong; + if (storm::settings::getModule().isWeakBisimulationSet()) { + bisimType = storm::storage::BisimulationType::Weak; + } + + dtmc = storm::api::performBisimulationMinimization(model, formulas, bisimType)->as>(); + + ASSERT_EQ(dtmc->getNumberOfStates(), 99ull); + ASSERT_EQ(dtmc->getNumberOfTransitions(), 195ull); + + auto *extender = new storm::analysis::LatticeExtender(dtmc); + auto criticalTuple = extender->toLattice(formulas); + EXPECT_EQ(dtmc->getNumberOfStates(), std::get<1>(criticalTuple)); + EXPECT_EQ(dtmc->getNumberOfStates(), std::get<2>(criticalTuple)); + + auto lattice = std::get<0>(criticalTuple); + for (auto i = 0; i < dtmc->getNumberOfStates(); ++i) { + EXPECT_TRUE(lattice->getAddedStates()[i]); + } + + // Check on some nodes + EXPECT_EQ(storm::analysis::Lattice::ABOVE, lattice->compare(1,0)); + EXPECT_EQ(storm::analysis::Lattice::ABOVE, lattice->compare(1,5)); + EXPECT_EQ(storm::analysis::Lattice::ABOVE, lattice->compare(5,0)); + EXPECT_EQ(storm::analysis::Lattice::ABOVE, lattice->compare(94,5)); + EXPECT_EQ(storm::analysis::Lattice::UNKNOWN, lattice->compare(7,13)); +} + +TEST(LatticeExtenderTest, Brp_without_bisimulation) { + std::string programFile = STORM_TEST_RESOURCES_DIR "/pdtmc/brp16_2.pm"; + std::string formulaAsString = "P=? [F s=4 & i=N ]"; + std::string constantsAsString = ""; //e.g. pL=0.9,TOACK=0.5 + + // Program and formula + storm::prism::Program program = storm::api::parseProgram(programFile); + program = storm::utility::prism::preprocess(program, constantsAsString); + std::vector> formulas = storm::api::extractFormulasFromProperties(storm::api::parsePropertiesForPrismProgram(formulaAsString, program)); + std::shared_ptr> model = storm::api::buildSparseModel(program, formulas)->as>(); + std::shared_ptr> dtmc = model->as>(); + auto simplifier = storm::transformer::SparseParametricDtmcSimplifier>(*dtmc); + ASSERT_TRUE(simplifier.simplify(*(formulas[0]))); + model = simplifier.getSimplifiedModel(); + dtmc = model->as>(); + + ASSERT_EQ(dtmc->getNumberOfStates(), 193ull); + ASSERT_EQ(dtmc->getNumberOfTransitions(), 383ull); + + auto *extender = new storm::analysis::LatticeExtender(dtmc); + auto criticalTuple = extender->toLattice(formulas); + EXPECT_EQ(183, std::get<1>(criticalTuple)); + EXPECT_EQ(186, std::get<2>(criticalTuple)); +} + + From 58dc2512cf37be1bd454e28772b2913157b27728 Mon Sep 17 00:00:00 2001 From: Jip Spel Date: Thu, 20 Sep 2018 11:31:44 +0200 Subject: [PATCH 079/178] Create test for AssumptionMaker --- .../analysis/AssumptionMakerTest.cpp | 64 +++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100644 src/test/storm-pars/analysis/AssumptionMakerTest.cpp diff --git a/src/test/storm-pars/analysis/AssumptionMakerTest.cpp b/src/test/storm-pars/analysis/AssumptionMakerTest.cpp new file mode 100644 index 000000000..722ca69bf --- /dev/null +++ b/src/test/storm-pars/analysis/AssumptionMakerTest.cpp @@ -0,0 +1,64 @@ +// +// Created by Jip Spel on 20.09.18. +// + +// TODO: cleanup includes +#include "gtest/gtest.h" +#include "storm-config.h" +#include "test/storm_gtest.h" + +#include "storm-parsers/parser/FormulaParser.h" +#include "storm/logic/Formulas.h" +#include "storm/models/sparse/StandardRewardModel.h" +#include "storm/modelchecker/prctl/SparseDtmcPrctlModelChecker.h" +#include "storm/modelchecker/results/ExplicitQuantitativeCheckResult.h" +#include "storm-parsers/parser/AutoParser.h" +#include "storm-parsers/parser/PrismParser.h" +#include "storm/storage/expressions/ExpressionManager.h" +#include "storm/api/builder.h" + +#include "storm-pars/analysis/Lattice.h" +#include "storm-pars/analysis/AssumptionMaker.h" +#include "storm-pars/analysis/AssumptionChecker.h" +#include "storm-pars/analysis/LatticeExtender.h" +#include "storm-pars/transformer/SparseParametricDtmcSimplifier.h" + +#include "storm-pars/api/storm-pars.h" +#include "storm/api/storm.h" + +#include "storm-parsers/api/storm-parsers.h" + +TEST(AssumptionMakerTest, Brp_without_bisimulation) { + std::string programFile = STORM_TEST_RESOURCES_DIR "/pdtmc/brp16_2.pm"; + std::string formulaAsString = "P=? [F s=4 & i=N ]"; + std::string constantsAsString = ""; //e.g. pL=0.9,TOACK=0.5 + + // Program and formula + storm::prism::Program program = storm::api::parseProgram(programFile); + program = storm::utility::prism::preprocess(program, constantsAsString); + std::vector> formulas = storm::api::extractFormulasFromProperties(storm::api::parsePropertiesForPrismProgram(formulaAsString, program)); + std::shared_ptr> model = storm::api::buildSparseModel(program, formulas)->as>(); + std::shared_ptr> dtmc = model->as>(); + auto simplifier = storm::transformer::SparseParametricDtmcSimplifier>(*dtmc); + ASSERT_TRUE(simplifier.simplify(*(formulas[0]))); + model = simplifier.getSimplifiedModel(); + dtmc = model->as>(); + + ASSERT_EQ(dtmc->getNumberOfStates(), 193ull); + ASSERT_EQ(dtmc->getNumberOfTransitions(), 383ull); + + auto *extender = new storm::analysis::LatticeExtender(dtmc); + auto criticalTuple = extender->toLattice(formulas); + ASSERT_EQ(183, std::get<1>(criticalTuple)); + ASSERT_EQ(186, std::get<2>(criticalTuple)); + + auto assumptionChecker = storm::analysis::AssumptionChecker(formulas[0], dtmc, 3); + auto assumptionMaker = storm::analysis::AssumptionMaker(extender, &assumptionChecker, dtmc->getNumberOfStates(), true); + auto result = assumptionMaker.makeAssumptions(std::get<0>(criticalTuple), std::get<1>(criticalTuple), std::get<2>(criticalTuple)); + EXPECT_EQ(1, result.size()); + auto lattice = result.begin()->first; + EXPECT_EQ(storm::analysis::Lattice::ABOVE, lattice->compare(186, 183)); + for (auto i = 0; i < dtmc->getNumberOfStates(); ++i) { + EXPECT_TRUE(lattice->getAddedStates()[i]); + } +} From d99e728add90a65f22663c508494e0473af2788d Mon Sep 17 00:00:00 2001 From: Jip Spel Date: Thu, 20 Sep 2018 12:48:16 +0200 Subject: [PATCH 080/178] Add return to check monotonicity --- src/storm-pars/analysis/MonotonicityChecker.cpp | 5 ++++- src/storm-pars/analysis/MonotonicityChecker.h | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/storm-pars/analysis/MonotonicityChecker.cpp b/src/storm-pars/analysis/MonotonicityChecker.cpp index 0ee7c6ad2..fa97cefc4 100644 --- a/src/storm-pars/analysis/MonotonicityChecker.cpp +++ b/src/storm-pars/analysis/MonotonicityChecker.cpp @@ -9,8 +9,9 @@ namespace storm { namespace analysis { template - void MonotonicityChecker::checkMonotonicity(std::map>> map, storm::storage::SparseMatrix matrix) { + std::map>> MonotonicityChecker::checkMonotonicity(std::map>> map, storm::storage::SparseMatrix matrix) { auto i = 0; + std::map>> result; for (auto itr = map.begin(); itr != map.end(); ++itr) { auto lattice = itr->first; auto assumptions = itr->second; @@ -53,7 +54,9 @@ namespace storm { } } ++i; + result.insert(std::pair>>(lattice, varsMonotone)); } + return result; } template diff --git a/src/storm-pars/analysis/MonotonicityChecker.h b/src/storm-pars/analysis/MonotonicityChecker.h index 222c0129a..9fe48067e 100644 --- a/src/storm-pars/analysis/MonotonicityChecker.h +++ b/src/storm-pars/analysis/MonotonicityChecker.h @@ -24,7 +24,7 @@ namespace storm { * @param map The map with lattices and the assumptions made to create the lattices. * @param matrix The transition matrix. */ - void checkMonotonicity(std::map>> map, storm::storage::SparseMatrix matrix); + std::map>> checkMonotonicity(std::map>> map, storm::storage::SparseMatrix matrix); private: std::map> analyseMonotonicity(uint_fast64_t i, storm::analysis::Lattice* lattice, storm::storage::SparseMatrix matrix) ; From a243a69aa66ce853aa8438cf4fac9e259d2447eb Mon Sep 17 00:00:00 2001 From: Jip Spel Date: Thu, 20 Sep 2018 12:49:50 +0200 Subject: [PATCH 081/178] Create test for MonotonicityChecker --- .../analysis/MonotonicityCheckerTest.cpp | 92 +++++++++++++++++++ 1 file changed, 92 insertions(+) create mode 100644 src/test/storm-pars/analysis/MonotonicityCheckerTest.cpp diff --git a/src/test/storm-pars/analysis/MonotonicityCheckerTest.cpp b/src/test/storm-pars/analysis/MonotonicityCheckerTest.cpp new file mode 100644 index 000000000..b7d40675a --- /dev/null +++ b/src/test/storm-pars/analysis/MonotonicityCheckerTest.cpp @@ -0,0 +1,92 @@ +// +// Created by Jip Spel on 20.09.18. +// + +#include "gtest/gtest.h" +#include "storm-config.h" +#include "test/storm_gtest.h" +#include "storm-pars/analysis/MonotonicityChecker.h" +#include "storm/storage/expressions/BinaryRelationExpression.h" +#include "storm/storage/SparseMatrix.h" +#include "storm/adapters/RationalFunctionAdapter.h" + +TEST(MonotonicityCheckerTest, Monotone) { + auto checker = storm::analysis::MonotonicityChecker(); + // Build lattice + auto numberOfStates = 4; + auto above = storm::storage::BitVector(numberOfStates); + above.set(1); + auto below = storm::storage::BitVector(numberOfStates); + below.set(0); + auto lattice = storm::analysis::Lattice(above, below, numberOfStates); + lattice.add(2); + lattice.add(3); + // Build map + std::vector> assumptions; + std::map>> map; + map.insert(std::pair>>(&lattice, assumptions)); + + // Build matrix + auto builder = storm::storage::SparseMatrixBuilder(numberOfStates, numberOfStates, 4); + std::shared_ptr cache = std::make_shared(); + carl::StringParser parser; + parser.setVariables({"p", "q"}); + auto func = storm::RationalFunction(storm::Polynomial(parser.template parseMultivariatePolynomial("p"), cache)); + auto funcMin = storm::RationalFunction(storm::RationalFunction(1)-func); + builder.addNextValue(2, 1, func); + builder.addNextValue(2, 0, funcMin); + func = storm::RationalFunction(storm::Polynomial(parser.template parseMultivariatePolynomial("q"), cache)); + funcMin = storm::RationalFunction(storm::RationalFunction(1)-func); + builder.addNextValue(3, 1, funcMin); + builder.addNextValue(3, 0, func); + storm::storage::SparseMatrix matrix = builder.build(); + + std::map>> result = checker.checkMonotonicity(map, matrix); + ASSERT_EQ(1, result.size()); + ASSERT_EQ(2, result.begin()->second.size()); + auto entry1 = result.begin()->second.begin(); + auto entry2 = ++ (result.begin()->second.begin()); + ASSERT_EQ("p", entry1->first.name()); + EXPECT_TRUE(entry1->second.first); + EXPECT_FALSE(entry1->second.second); + EXPECT_FALSE(entry2->second.first); + EXPECT_TRUE(entry2->second.second); +} + +TEST(MonotonicityCheckerTest, NotMonotone) { + auto checker = storm::analysis::MonotonicityChecker(); + // Build lattice + auto numberOfStates = 4; + auto above = storm::storage::BitVector(numberOfStates); + above.set(1); + auto below = storm::storage::BitVector(numberOfStates); + below.set(0); + auto lattice = storm::analysis::Lattice(above, below, numberOfStates); + lattice.add(2); + lattice.add(3); + // Build map + std::vector> assumptions; + std::map>> map; + map.insert(std::pair>>(&lattice, assumptions)); + + // Build matrix + auto builder = storm::storage::SparseMatrixBuilder(numberOfStates, numberOfStates, 4); + std::shared_ptr cache = std::make_shared(); + carl::StringParser parser; + parser.setVariables({"p", "q"}); + auto func = storm::RationalFunction(storm::Polynomial(parser.template parseMultivariatePolynomial("p"), cache)); + auto funcMin = storm::RationalFunction(storm::RationalFunction(1)-func); + builder.addNextValue(2, 1, func); + builder.addNextValue(2, 0, funcMin); + builder.addNextValue(3, 1, funcMin); + builder.addNextValue(3, 0, func); + auto matrix = builder.build(); + + auto result = checker.checkMonotonicity(map, matrix); + ASSERT_EQ(1, result.size()); + ASSERT_EQ(1, result.begin()->second.size()); + auto entry1 = result.begin()->second.begin(); + ASSERT_EQ("p", entry1->first.name()); + EXPECT_FALSE(entry1->second.first); + EXPECT_FALSE(entry1->second.second); +} \ No newline at end of file From 937570938100579b6127c0ce1819f3bb6f562d9d Mon Sep 17 00:00:00 2001 From: Jip Spel Date: Thu, 20 Sep 2018 14:03:16 +0200 Subject: [PATCH 082/178] Split validate into two methods --- src/storm-pars/analysis/AssumptionChecker.cpp | 82 ++++++++++--------- src/storm-pars/analysis/AssumptionChecker.h | 1 + 2 files changed, 45 insertions(+), 38 deletions(-) diff --git a/src/storm-pars/analysis/AssumptionChecker.cpp b/src/storm-pars/analysis/AssumptionChecker.cpp index 359dc1a86..0e18d0a7e 100644 --- a/src/storm-pars/analysis/AssumptionChecker.cpp +++ b/src/storm-pars/analysis/AssumptionChecker.cpp @@ -133,48 +133,54 @@ namespace storm { // Only implemented for two successors if (row1.getNumberOfEntries() == 2 && row2.getNumberOfEntries() == 2) { - auto succ1State1 = row1.begin(); - auto succ2State1 = (++row1.begin()); - auto succ1State2 = row2.begin(); - auto succ2State2 = (++row2.begin()); - - if (succ1State1->getColumn() == succ2State2->getColumn() - && succ1State2->getColumn() == succ2State1->getColumn()) { - // swap them - auto temp = succ2State1; - succ2State1 = succ1State1; - succ1State1 = temp; - } + result = validateAssumptionOnFunction(lattice, row1, row2); + } + } + if (result) { + validatedAssumptions.insert(assumption); + } else { + STORM_LOG_DEBUG("Could not validate: " << *assumption << std::endl); + } + return result; + } - if (succ1State1->getColumn() == succ1State2->getColumn() && succ2State1->getColumn() == succ2State2->getColumn()) { - ValueType prob; - auto comp = lattice->compare(succ1State1->getColumn(), succ2State1->getColumn()); - if (comp == storm::analysis::Lattice::ABOVE) { - prob = succ1State1->getValue() - succ1State2->getValue(); - } else if (comp == storm::analysis::Lattice::BELOW) { - prob = succ2State1->getValue() - succ2State2->getValue(); - } - auto vars = prob.gatherVariables(); - // TODO: Type - std::map substitutions; - for (auto var:vars) { - auto derivative = prob.derivative(var); - assert(derivative.isConstant()); - if (derivative.constantPart() >= 0) { - substitutions[var] = 0; - } else if (derivative.constantPart() <= 0) { - substitutions[var] = 1; - } - } - result = prob.evaluate(substitutions) >= 0; - } + template + bool AssumptionChecker::validateAssumptionOnFunction(storm::analysis::Lattice* lattice, typename storm::storage::SparseMatrix::rows row1, typename storm::storage::SparseMatrix::rows row2) { + bool result = false; + auto succ1State1 = row1.begin(); + auto succ2State1 = (++row1.begin()); + auto succ1State2 = row2.begin(); + auto succ2State2 = (++row2.begin()); + + if (succ1State1->getColumn() == succ2State2->getColumn() + && succ1State2->getColumn() == succ2State1->getColumn()) { + // swap them + auto temp = succ2State1; + succ2State1 = succ1State1; + succ1State1 = temp; + } - if (result) { - validatedAssumptions.insert(assumption); - } else { - STORM_LOG_DEBUG("Could not validate: " << *assumption << std::endl); + if (succ1State1->getColumn() == succ1State2->getColumn() && succ2State1->getColumn() == succ2State2->getColumn()) { + ValueType prob; + auto comp = lattice->compare(succ1State1->getColumn(), succ2State1->getColumn()); + if (comp == storm::analysis::Lattice::ABOVE) { + prob = succ1State1->getValue() - succ1State2->getValue(); + } else if (comp == storm::analysis::Lattice::BELOW) { + prob = succ2State1->getValue() - succ2State2->getValue(); + } + auto vars = prob.gatherVariables(); + // TODO: Type + std::map substitutions; + for (auto var:vars) { + auto derivative = prob.derivative(var); + assert(derivative.isConstant()); + if (derivative.constantPart() >= 0) { + substitutions[var] = 0; + } else if (derivative.constantPart() <= 0) { + substitutions[var] = 1; } } + result = prob.evaluate(substitutions) >= 0; } return result; } diff --git a/src/storm-pars/analysis/AssumptionChecker.h b/src/storm-pars/analysis/AssumptionChecker.h index deb75cd87..bec43dd11 100644 --- a/src/storm-pars/analysis/AssumptionChecker.h +++ b/src/storm-pars/analysis/AssumptionChecker.h @@ -69,6 +69,7 @@ namespace storm { std::set> validatedAssumptions; + bool validateAssumptionOnFunction(storm::analysis::Lattice* lattice, typename storm::storage::SparseMatrix::rows row1, typename storm::storage::SparseMatrix::rows row2); }; } } From 83cb1031770b57c2c5f8aba39bf0c20fdf91f22c Mon Sep 17 00:00:00 2001 From: Jip Spel Date: Mon, 24 Sep 2018 13:36:56 +0200 Subject: [PATCH 083/178] Change variable naming --- src/storm-pars-cli/storm-pars.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/storm-pars-cli/storm-pars.cpp b/src/storm-pars-cli/storm-pars.cpp index b124538b7..c44989300 100644 --- a/src/storm-pars-cli/storm-pars.cpp +++ b/src/storm-pars-cli/storm-pars.cpp @@ -542,18 +542,18 @@ namespace storm { // Transform to Lattices storm::utility::Stopwatch latticeWatch(true); storm::analysis::LatticeExtender *extender = new storm::analysis::LatticeExtender(sparseModel); - std::tuple criticalPair = extender->toLattice(formulas); + std::tuple criticalTuple = extender->toLattice(formulas); std::map>> result; if (model->isOfType(storm::models::ModelType::Dtmc)) { auto dtmcModel = model->as>(); auto assumptionChecker = storm::analysis::AssumptionChecker(formulas[0], dtmcModel, 3); auto assumptionMaker = storm::analysis::AssumptionMaker(extender, &assumptionChecker, sparseModel->getNumberOfStates(), parSettings.isValidateAssumptionsSet()); - result = assumptionMaker.makeAssumptions(std::get<0>(criticalPair), std::get<1>(criticalPair), std::get<2>(criticalPair)); + result = assumptionMaker.makeAssumptions(std::get<0>(criticalTuple), std::get<1>(criticalTuple), std::get<2>(criticalTuple)); } else if (model->isOfType(storm::models::ModelType::Dtmc)) { auto mdpModel = model->as>(); auto assumptionChecker = storm::analysis::AssumptionChecker(formulas[0], mdpModel, 3); auto assumptionMaker = storm::analysis::AssumptionMaker(extender, &assumptionChecker, sparseModel->getNumberOfStates(), parSettings.isValidateAssumptionsSet()); - result = assumptionMaker.makeAssumptions(std::get<0>(criticalPair), std::get<1>(criticalPair), std::get<2>(criticalPair)); + result = assumptionMaker.makeAssumptions(std::get<0>(criticalTuple), std::get<1>(criticalTuple), std::get<2>(criticalTuple)); } else { STORM_LOG_THROW(false, storm::exceptions::InvalidOperationException, "Unable to perform monotonicity analysis on the provided model type."); } From b82ab5f9c29350794bf68ca3d832ddd96eb2e61b Mon Sep 17 00:00:00 2001 From: Jip Spel Date: Mon, 24 Sep 2018 13:39:51 +0200 Subject: [PATCH 084/178] Validate assumption with SMT solving --- src/storm-pars/analysis/AssumptionChecker.cpp | 90 +++++++++++++++---- src/storm-pars/analysis/AssumptionChecker.h | 4 +- .../expressions/ValueTypeToExpression.cpp | 74 +++++++++++++++ .../expressions/ValueTypeToExpression.h | 46 ++++++++++ 4 files changed, 198 insertions(+), 16 deletions(-) create mode 100644 src/storm/storage/expressions/ValueTypeToExpression.cpp create mode 100644 src/storm/storage/expressions/ValueTypeToExpression.h diff --git a/src/storm-pars/analysis/AssumptionChecker.cpp b/src/storm-pars/analysis/AssumptionChecker.cpp index 0e18d0a7e..fdac5ed62 100644 --- a/src/storm-pars/analysis/AssumptionChecker.cpp +++ b/src/storm-pars/analysis/AssumptionChecker.cpp @@ -1,6 +1,7 @@ // // Created by Jip Spel on 12.09.18. // +#include #include "AssumptionChecker.h" #include "storm-pars/utility/ModelInstantiator.h" @@ -15,6 +16,8 @@ #include "storm/storage/expressions/SimpleValuation.h" #include "storm/storage/expressions/ExpressionManager.h" #include "storm/storage/expressions/VariableExpression.h" +#include "storm/utility/constants.h" +#include "storm/storage/expressions/ValueTypeToExpression.h" namespace storm { namespace analysis { @@ -133,9 +136,13 @@ namespace storm { // Only implemented for two successors if (row1.getNumberOfEntries() == 2 && row2.getNumberOfEntries() == 2) { - result = validateAssumptionOnFunction(lattice, row1, row2); + result = validateAssumptionFunction(lattice, row1, row2); + if (!result) { + result = validateAssumptionSMTSolver(lattice, row1, row2); + } } } + if (result) { validatedAssumptions.insert(assumption); } else { @@ -145,28 +152,28 @@ namespace storm { } template - bool AssumptionChecker::validateAssumptionOnFunction(storm::analysis::Lattice* lattice, typename storm::storage::SparseMatrix::rows row1, typename storm::storage::SparseMatrix::rows row2) { + bool AssumptionChecker::validateAssumptionFunction(storm::analysis::Lattice* lattice, typename storm::storage::SparseMatrix::rows row1, typename storm::storage::SparseMatrix::rows row2) { bool result = false; - auto succ1State1 = row1.begin(); - auto succ2State1 = (++row1.begin()); - auto succ1State2 = row2.begin(); - auto succ2State2 = (++row2.begin()); + auto state1succ1 = row1.begin(); + auto state1succ2 = (++row1.begin()); + auto state2succ1 = row2.begin(); + auto state2succ2 = (++row2.begin()); - if (succ1State1->getColumn() == succ2State2->getColumn() - && succ1State2->getColumn() == succ2State1->getColumn()) { + if (state1succ1->getColumn() == state2succ2->getColumn() + && state2succ1->getColumn() == state1succ2->getColumn()) { // swap them - auto temp = succ2State1; - succ2State1 = succ1State1; - succ1State1 = temp; + auto temp = state1succ2; + state1succ2 = state1succ1; + state1succ1 = temp; } - if (succ1State1->getColumn() == succ1State2->getColumn() && succ2State1->getColumn() == succ2State2->getColumn()) { + if (state1succ1->getColumn() == state2succ1->getColumn() && state1succ2->getColumn() == state2succ2->getColumn()) { ValueType prob; - auto comp = lattice->compare(succ1State1->getColumn(), succ2State1->getColumn()); + auto comp = lattice->compare(state1succ1->getColumn(), state1succ2->getColumn()); if (comp == storm::analysis::Lattice::ABOVE) { - prob = succ1State1->getValue() - succ1State2->getValue(); + prob = state1succ1->getValue() - state2succ1->getValue(); } else if (comp == storm::analysis::Lattice::BELOW) { - prob = succ2State1->getValue() - succ2State2->getValue(); + prob = state1succ2->getValue() - state2succ2->getValue(); } auto vars = prob.gatherVariables(); // TODO: Type @@ -185,6 +192,59 @@ namespace storm { return result; } + template + bool AssumptionChecker::validateAssumptionSMTSolver(storm::analysis::Lattice* lattice, typename storm::storage::SparseMatrix::rows row1, typename storm::storage::SparseMatrix::rows row2) { + bool result = false; + auto state1succ1 = row1.begin(); + auto state1succ2 = (++row1.begin()); + auto state2succ1 = row2.begin(); + auto state2succ2 = (++row2.begin()); + + if (state1succ1->getColumn() == state2succ2->getColumn() + && state2succ1->getColumn() == state1succ2->getColumn()) { + std::swap(state1succ1, state1succ2); + } + + if (state1succ1->getColumn() == state2succ1->getColumn() && state1succ2->getColumn() == state2succ2->getColumn()) { + std::shared_ptr smtSolverFactory = std::make_shared(); + std::shared_ptr manager( + new storm::expressions::ExpressionManager()); + + storm::solver::Z3SmtSolver s(*manager); + storm::solver::SmtSolver::CheckResult smtResult = storm::solver::SmtSolver::CheckResult::Unknown; + storm::expressions::Variable succ1 = manager->declareRationalVariable(std::to_string(state1succ1->getColumn())); + storm::expressions::Variable succ2 = manager->declareRationalVariable(std::to_string(state1succ2->getColumn())); + auto comp = lattice->compare(state1succ1->getColumn(), state1succ2->getColumn()); + if (comp == storm::analysis::Lattice::ABOVE || comp == storm::analysis::Lattice::BELOW) { + if (comp == storm::analysis::Lattice::BELOW) { + std::swap(succ1, succ2); + } + storm::expressions::Expression exprGiven = succ1 >= succ2; + + auto valueTypeToExpression = storm::expressions::ValueTypeToExpression(manager); + storm::expressions::Expression exprToCheck = + (valueTypeToExpression.toExpression(state1succ1->getValue())*succ1 + + valueTypeToExpression.toExpression(state2succ1->getValue())*succ2 + >= valueTypeToExpression.toExpression(state1succ2->getValue())*succ1 + + valueTypeToExpression.toExpression(state1succ1->getValue())*succ2); + + storm::expressions::Expression exprBounds = manager->boolean(true); + auto variables = manager->getVariables(); + for (auto var : variables) { + exprBounds = exprBounds && var >= 0 && var <= 1; + } + + s.add(exprGiven); + s.add(exprToCheck); + s.add(exprBounds); + smtResult = s.check(); + } + + result = smtResult == storm::solver::SmtSolver::CheckResult::Sat; + } + return result; + } + template bool AssumptionChecker::validated(std::shared_ptr assumption) { return find(validatedAssumptions.begin(), validatedAssumptions.end(), assumption) != validatedAssumptions.end(); diff --git a/src/storm-pars/analysis/AssumptionChecker.h b/src/storm-pars/analysis/AssumptionChecker.h index bec43dd11..098e6433d 100644 --- a/src/storm-pars/analysis/AssumptionChecker.h +++ b/src/storm-pars/analysis/AssumptionChecker.h @@ -69,7 +69,9 @@ namespace storm { std::set> validatedAssumptions; - bool validateAssumptionOnFunction(storm::analysis::Lattice* lattice, typename storm::storage::SparseMatrix::rows row1, typename storm::storage::SparseMatrix::rows row2); + bool validateAssumptionFunction(storm::analysis::Lattice* lattice, typename storm::storage::SparseMatrix::rows row1, typename storm::storage::SparseMatrix::rows row2); + + bool validateAssumptionSMTSolver(storm::analysis::Lattice* lattice, typename storm::storage::SparseMatrix::rows row1, typename storm::storage::SparseMatrix::rows row2); }; } } diff --git a/src/storm/storage/expressions/ValueTypeToExpression.cpp b/src/storm/storage/expressions/ValueTypeToExpression.cpp new file mode 100644 index 000000000..e1fa5c871 --- /dev/null +++ b/src/storm/storage/expressions/ValueTypeToExpression.cpp @@ -0,0 +1,74 @@ +// +// Created by Jip Spel on 24.09.18. +// + +#include "ValueTypeToExpression.h" +#include "storm/utility/constants.h" + +namespace storm { + namespace expressions { + template + ValueTypeToExpression::ValueTypeToExpression(std::shared_ptr manager) : manager(manager) { + // Intentionally left empty. + } + + template + std::shared_ptr ValueTypeToExpression::getManager() { + return manager; + } + + template + Expression ValueTypeToExpression::toExpression(ValueType function) { + auto varsFunction = function.gatherVariables(); + for (auto var : varsFunction) { + auto varsManager = manager->getVariables(); + bool found = find_if(varsManager.begin(), varsManager.end(), + [&](auto val) -> bool { + return val.getName() == var.name(); + }) != varsManager.end(); +// bool found = false; + // TODO kan dit niet anders + for (auto itr = varsManager.begin(); !found && itr != varsManager.end(); ++itr) { + found = (*itr).getName().compare(var.name()) == 0; + } + + if (!found) { + manager->declareIntegerVariable(var.name()); + } + } + + auto denominator = function.denominator(); + if (!denominator.isConstant()) { + STORM_LOG_DEBUG("Expecting the denominator to be constant"); + } + + storm::expressions::Expression denominatorVal = manager->integer(std::stoi(storm::utility::to_string(denominator.constantPart()))); + storm::expressions::Expression result; + if (function.isConstant()) { + result = manager->integer(std::stoi(storm::utility::to_string(function.constantPart()))); + } else { + auto nominator = function.nominatorAsPolynomial().polynomialWithCoefficient(); + result = manager->integer(std::stoi(storm::utility::to_string(nominator.constantPart()))); + for (auto itr = nominator.begin(); itr != nominator.end(); ++itr) { + varsFunction.clear(); + (*itr).gatherVariables(varsFunction); + // TODO: beter maken + storm::expressions::Expression nominatorPartExpr = manager->integer( + std::stoi(storm::utility::to_string((*itr).coeff()))); + for (auto var : varsFunction) { + if (!(*itr).derivative(var).isConstant()) { + STORM_LOG_DEBUG("Expecting partial derivatives of nominator parts to be constant"); + } + nominatorPartExpr = nominatorPartExpr * manager->getVariable(var.name()); + } + if (varsFunction.size() >= 1) { + result = result + nominatorPartExpr; + } + } + result = result / denominatorVal; + } + return result; + } + template class ValueTypeToExpression; + } +} \ No newline at end of file diff --git a/src/storm/storage/expressions/ValueTypeToExpression.h b/src/storm/storage/expressions/ValueTypeToExpression.h new file mode 100644 index 000000000..d0748483d --- /dev/null +++ b/src/storm/storage/expressions/ValueTypeToExpression.h @@ -0,0 +1,46 @@ +// +// Created by Jip Spel on 24.09.18. +// + +#ifndef STORM_VALUETYPETOEXPRESSION_H +#define STORM_VALUETYPETOEXPRESSION_H + +#include "storm/storage/expressions/ExpressionManager.h" +#include "storm/storage/expressions/Expression.h" + +namespace storm { + namespace expressions { + template + class ValueTypeToExpression { + public: + /*! + * + * + * @param manager The manager of the variables. + */ + ValueTypeToExpression(std::shared_ptr manager); + + /*! + * Retrieves the manager responsible for the variables of this valuation. + * + * @return The pointer to the manager. + */ + std::shared_ptr getManager(); + + /*! + * + * @param function + * @param manager + * @return + */ + Expression toExpression(ValueType function); + + private: + // The manager responsible for the variables of this valuation. + std::shared_ptr manager; + }; + } +} + + +#endif //STORM_VALUETYPETOEXPRESSION_H From 29f927530286df78aa8a93fe021c2232077fbde8 Mon Sep 17 00:00:00 2001 From: Jip Spel Date: Mon, 24 Sep 2018 14:46:56 +0200 Subject: [PATCH 085/178] Refactor validation methods --- src/storm-pars/analysis/AssumptionChecker.cpp | 163 +++++++++--------- src/storm-pars/analysis/AssumptionChecker.h | 13 +- 2 files changed, 88 insertions(+), 88 deletions(-) diff --git a/src/storm-pars/analysis/AssumptionChecker.cpp b/src/storm-pars/analysis/AssumptionChecker.cpp index fdac5ed62..b3326d519 100644 --- a/src/storm-pars/analysis/AssumptionChecker.cpp +++ b/src/storm-pars/analysis/AssumptionChecker.cpp @@ -136,10 +136,24 @@ namespace storm { // Only implemented for two successors if (row1.getNumberOfEntries() == 2 && row2.getNumberOfEntries() == 2) { - result = validateAssumptionFunction(lattice, row1, row2); - if (!result) { - result = validateAssumptionSMTSolver(lattice, row1, row2); + auto state1succ1 = row1.begin(); + auto state1succ2 = (++row1.begin()); + auto state2succ1 = row2.begin(); + auto state2succ2 = (++row2.begin()); + + if (state1succ1->getColumn() == state2succ2->getColumn() + && state2succ1->getColumn() == state1succ2->getColumn()) { + std::swap(state1succ1, state1succ2); } + + if (state1succ1->getColumn() == state2succ1->getColumn() && state1succ2->getColumn() == state2succ2->getColumn()) { + result = validateAssumptionFunction(lattice, state1succ1, state1succ2, state2succ1, state2succ2); + if (!result) { + result = validateAssumptionSMTSolver(lattice, state1succ1, state1succ2, state2succ1, state2succ2); + } + } + } else { + STORM_LOG_DEBUG("Validation only implemented for two successor states"); } } @@ -152,97 +166,76 @@ namespace storm { } template - bool AssumptionChecker::validateAssumptionFunction(storm::analysis::Lattice* lattice, typename storm::storage::SparseMatrix::rows row1, typename storm::storage::SparseMatrix::rows row2) { - bool result = false; - auto state1succ1 = row1.begin(); - auto state1succ2 = (++row1.begin()); - auto state2succ1 = row2.begin(); - auto state2succ2 = (++row2.begin()); - - if (state1succ1->getColumn() == state2succ2->getColumn() - && state2succ1->getColumn() == state1succ2->getColumn()) { - // swap them - auto temp = state1succ2; - state1succ2 = state1succ1; - state1succ1 = temp; + bool AssumptionChecker::validateAssumptionFunction(storm::analysis::Lattice* lattice, + typename storm::storage::SparseMatrix::iterator state1succ1, + typename storm::storage::SparseMatrix::iterator state1succ2, + typename storm::storage::SparseMatrix::iterator state2succ1, + typename storm::storage::SparseMatrix::iterator state2succ2) { + + ValueType prob; + auto comp = lattice->compare(state1succ1->getColumn(), state1succ2->getColumn()); + if (comp == storm::analysis::Lattice::ABOVE) { + prob = state1succ1->getValue() - state2succ1->getValue(); + } else if (comp == storm::analysis::Lattice::BELOW) { + prob = state1succ2->getValue() - state2succ2->getValue(); } - - if (state1succ1->getColumn() == state2succ1->getColumn() && state1succ2->getColumn() == state2succ2->getColumn()) { - ValueType prob; - auto comp = lattice->compare(state1succ1->getColumn(), state1succ2->getColumn()); - if (comp == storm::analysis::Lattice::ABOVE) { - prob = state1succ1->getValue() - state2succ1->getValue(); - } else if (comp == storm::analysis::Lattice::BELOW) { - prob = state1succ2->getValue() - state2succ2->getValue(); + auto vars = prob.gatherVariables(); + + // TODO: Type + std::map substitutions; + for (auto var:vars) { + auto derivative = prob.derivative(var); + assert(derivative.isConstant()); + if (derivative.constantPart() >= 0) { + substitutions[var] = 0; + } else if (derivative.constantPart() <= 0) { + substitutions[var] = 1; } - auto vars = prob.gatherVariables(); - // TODO: Type - std::map substitutions; - for (auto var:vars) { - auto derivative = prob.derivative(var); - assert(derivative.isConstant()); - if (derivative.constantPart() >= 0) { - substitutions[var] = 0; - } else if (derivative.constantPart() <= 0) { - substitutions[var] = 1; - } - } - result = prob.evaluate(substitutions) >= 0; } - return result; + return prob.evaluate(substitutions) >= 0; } template - bool AssumptionChecker::validateAssumptionSMTSolver(storm::analysis::Lattice* lattice, typename storm::storage::SparseMatrix::rows row1, typename storm::storage::SparseMatrix::rows row2) { - bool result = false; - auto state1succ1 = row1.begin(); - auto state1succ2 = (++row1.begin()); - auto state2succ1 = row2.begin(); - auto state2succ2 = (++row2.begin()); - - if (state1succ1->getColumn() == state2succ2->getColumn() - && state2succ1->getColumn() == state1succ2->getColumn()) { - std::swap(state1succ1, state1succ2); - } - - if (state1succ1->getColumn() == state2succ1->getColumn() && state1succ2->getColumn() == state2succ2->getColumn()) { - std::shared_ptr smtSolverFactory = std::make_shared(); - std::shared_ptr manager( - new storm::expressions::ExpressionManager()); - - storm::solver::Z3SmtSolver s(*manager); - storm::solver::SmtSolver::CheckResult smtResult = storm::solver::SmtSolver::CheckResult::Unknown; - storm::expressions::Variable succ1 = manager->declareRationalVariable(std::to_string(state1succ1->getColumn())); - storm::expressions::Variable succ2 = manager->declareRationalVariable(std::to_string(state1succ2->getColumn())); - auto comp = lattice->compare(state1succ1->getColumn(), state1succ2->getColumn()); - if (comp == storm::analysis::Lattice::ABOVE || comp == storm::analysis::Lattice::BELOW) { - if (comp == storm::analysis::Lattice::BELOW) { - std::swap(succ1, succ2); - } - storm::expressions::Expression exprGiven = succ1 >= succ2; - - auto valueTypeToExpression = storm::expressions::ValueTypeToExpression(manager); - storm::expressions::Expression exprToCheck = - (valueTypeToExpression.toExpression(state1succ1->getValue())*succ1 - + valueTypeToExpression.toExpression(state2succ1->getValue())*succ2 - >= valueTypeToExpression.toExpression(state1succ2->getValue())*succ1 - + valueTypeToExpression.toExpression(state1succ1->getValue())*succ2); - - storm::expressions::Expression exprBounds = manager->boolean(true); - auto variables = manager->getVariables(); - for (auto var : variables) { - exprBounds = exprBounds && var >= 0 && var <= 1; - } - - s.add(exprGiven); - s.add(exprToCheck); - s.add(exprBounds); - smtResult = s.check(); + bool AssumptionChecker::validateAssumptionSMTSolver(storm::analysis::Lattice* lattice, + typename storm::storage::SparseMatrix::iterator state1succ1, + typename storm::storage::SparseMatrix::iterator state1succ2, + typename storm::storage::SparseMatrix::iterator state2succ1, + typename storm::storage::SparseMatrix::iterator state2succ2) { + + std::shared_ptr smtSolverFactory = std::make_shared(); + std::shared_ptr manager( + new storm::expressions::ExpressionManager()); + + storm::solver::Z3SmtSolver s(*manager); + storm::solver::SmtSolver::CheckResult smtResult = storm::solver::SmtSolver::CheckResult::Unknown; + storm::expressions::Variable succ1 = manager->declareRationalVariable(std::to_string(state1succ1->getColumn())); + storm::expressions::Variable succ2 = manager->declareRationalVariable(std::to_string(state1succ2->getColumn())); + auto comp = lattice->compare(state1succ1->getColumn(), state1succ2->getColumn()); + if (comp == storm::analysis::Lattice::ABOVE || comp == storm::analysis::Lattice::BELOW) { + if (comp == storm::analysis::Lattice::BELOW) { + std::swap(succ1, succ2); + } + storm::expressions::Expression exprGiven = succ1 >= succ2; + + auto valueTypeToExpression = storm::expressions::ValueTypeToExpression(manager); + storm::expressions::Expression exprToCheck = + (valueTypeToExpression.toExpression(state1succ1->getValue())*succ1 + + valueTypeToExpression.toExpression(state2succ1->getValue())*succ2 + >= valueTypeToExpression.toExpression(state1succ2->getValue())*succ1 + + valueTypeToExpression.toExpression(state1succ1->getValue())*succ2); + + storm::expressions::Expression exprBounds = manager->boolean(true); + auto variables = manager->getVariables(); + for (auto var : variables) { + exprBounds = exprBounds && var >= 0 && var <= 1; } - result = smtResult == storm::solver::SmtSolver::CheckResult::Sat; + s.add(exprGiven); + s.add(exprToCheck); + s.add(exprBounds); + smtResult = s.check(); } - return result; + return smtResult == storm::solver::SmtSolver::CheckResult::Sat; } template diff --git a/src/storm-pars/analysis/AssumptionChecker.h b/src/storm-pars/analysis/AssumptionChecker.h index 098e6433d..cdb6faf2d 100644 --- a/src/storm-pars/analysis/AssumptionChecker.h +++ b/src/storm-pars/analysis/AssumptionChecker.h @@ -69,11 +69,18 @@ namespace storm { std::set> validatedAssumptions; - bool validateAssumptionFunction(storm::analysis::Lattice* lattice, typename storm::storage::SparseMatrix::rows row1, typename storm::storage::SparseMatrix::rows row2); + bool validateAssumptionFunction(storm::analysis::Lattice* lattice, + typename storm::storage::SparseMatrix::iterator state1succ1, + typename storm::storage::SparseMatrix::iterator state1succ2, + typename storm::storage::SparseMatrix::iterator state2succ1, + typename storm::storage::SparseMatrix::iterator state2succ2); - bool validateAssumptionSMTSolver(storm::analysis::Lattice* lattice, typename storm::storage::SparseMatrix::rows row1, typename storm::storage::SparseMatrix::rows row2); + bool validateAssumptionSMTSolver(storm::analysis::Lattice* lattice, + typename storm::storage::SparseMatrix::iterator state1succ1, + typename storm::storage::SparseMatrix::iterator state1succ2, + typename storm::storage::SparseMatrix::iterator state2succ1, + typename storm::storage::SparseMatrix::iterator state2succ2); }; } } - #endif //STORM_ASSUMPTIONCHECKER_H From a2189044f347af7e88137980a52d397667f2a3c0 Mon Sep 17 00:00:00 2001 From: Jip Spel Date: Mon, 24 Sep 2018 16:45:31 +0200 Subject: [PATCH 086/178] Use degree of variable in expression --- .../expressions/ValueTypeToExpression.cpp | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/src/storm/storage/expressions/ValueTypeToExpression.cpp b/src/storm/storage/expressions/ValueTypeToExpression.cpp index e1fa5c871..3495d7f35 100644 --- a/src/storm/storage/expressions/ValueTypeToExpression.cpp +++ b/src/storm/storage/expressions/ValueTypeToExpression.cpp @@ -24,14 +24,8 @@ namespace storm { auto varsManager = manager->getVariables(); bool found = find_if(varsManager.begin(), varsManager.end(), [&](auto val) -> bool { - return val.getName() == var.name(); + return val.getName() == var.name(); }) != varsManager.end(); -// bool found = false; - // TODO kan dit niet anders - for (auto itr = varsManager.begin(); !found && itr != varsManager.end(); ++itr) { - found = (*itr).getName().compare(var.name()) == 0; - } - if (!found) { manager->declareIntegerVariable(var.name()); } @@ -52,14 +46,12 @@ namespace storm { for (auto itr = nominator.begin(); itr != nominator.end(); ++itr) { varsFunction.clear(); (*itr).gatherVariables(varsFunction); - // TODO: beter maken + // TODO: improve transformation from coefficient to expression storm::expressions::Expression nominatorPartExpr = manager->integer( std::stoi(storm::utility::to_string((*itr).coeff()))); for (auto var : varsFunction) { - if (!(*itr).derivative(var).isConstant()) { - STORM_LOG_DEBUG("Expecting partial derivatives of nominator parts to be constant"); - } - nominatorPartExpr = nominatorPartExpr * manager->getVariable(var.name()); + auto degree = nominator.degree(var); + nominatorPartExpr = nominatorPartExpr * (manager->getVariable(var.name())^manager->integer(degree)); } if (varsFunction.size() >= 1) { result = result + nominatorPartExpr; @@ -71,4 +63,4 @@ namespace storm { } template class ValueTypeToExpression; } -} \ No newline at end of file +} From 4d1dfdc75c75720f639166d90ce3df3744539d62 Mon Sep 17 00:00:00 2001 From: Jip Spel Date: Tue, 25 Sep 2018 11:10:05 +0200 Subject: [PATCH 087/178] Fix problem with exponent and denominator --- src/storm/storage/expressions/ValueTypeToExpression.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/storm/storage/expressions/ValueTypeToExpression.cpp b/src/storm/storage/expressions/ValueTypeToExpression.cpp index 3495d7f35..9a676cd41 100644 --- a/src/storm/storage/expressions/ValueTypeToExpression.cpp +++ b/src/storm/storage/expressions/ValueTypeToExpression.cpp @@ -19,6 +19,7 @@ namespace storm { template Expression ValueTypeToExpression::toExpression(ValueType function) { + function.simplify(); auto varsFunction = function.gatherVariables(); for (auto var : varsFunction) { auto varsManager = manager->getVariables(); @@ -36,7 +37,7 @@ namespace storm { STORM_LOG_DEBUG("Expecting the denominator to be constant"); } - storm::expressions::Expression denominatorVal = manager->integer(std::stoi(storm::utility::to_string(denominator.constantPart()))); + storm::expressions::Expression denominatorVal = manager->rational(std::stod(storm::utility::to_string(denominator.constantPart()))); storm::expressions::Expression result; if (function.isConstant()) { result = manager->integer(std::stoi(storm::utility::to_string(function.constantPart()))); @@ -46,12 +47,12 @@ namespace storm { for (auto itr = nominator.begin(); itr != nominator.end(); ++itr) { varsFunction.clear(); (*itr).gatherVariables(varsFunction); + // TODO: improve transformation from coefficient to expression storm::expressions::Expression nominatorPartExpr = manager->integer( std::stoi(storm::utility::to_string((*itr).coeff()))); for (auto var : varsFunction) { - auto degree = nominator.degree(var); - nominatorPartExpr = nominatorPartExpr * (manager->getVariable(var.name())^manager->integer(degree)); + nominatorPartExpr = nominatorPartExpr * (manager->getVariable(var.name())^manager->integer((*itr).monomial()->exponentOfVariable(var))); } if (varsFunction.size() >= 1) { result = result + nominatorPartExpr; From 440b12788093b47da42df049779b5fd56ed30c88 Mon Sep 17 00:00:00 2001 From: Jip Spel Date: Tue, 25 Sep 2018 11:11:14 +0200 Subject: [PATCH 088/178] Add test for ValueType to Expression --- src/test/storm/storage/ExpressionTest.cpp | 34 +++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/src/test/storm/storage/ExpressionTest.cpp b/src/test/storm/storage/ExpressionTest.cpp index 27e4e7d7a..ed6d33152 100644 --- a/src/test/storm/storage/ExpressionTest.cpp +++ b/src/test/storm/storage/ExpressionTest.cpp @@ -6,7 +6,13 @@ #include "storm/storage/expressions/ExpressionManager.h" #include "storm/storage/expressions/LinearityCheckVisitor.h" #include "storm/storage/expressions/SimpleValuation.h" +#include "storm/storage/expressions/ExpressionEvaluator.h" +#include "storm/storage/expressions/ValueTypeToExpression.h" #include "storm/exceptions/InvalidTypeException.h" +#include "storm/adapters/RationalFunctionAdapter.h" +#include "storm-parsers/parser/ValueParser.h" +#include "storm/storage/expressions/ToRationalFunctionVisitor.h" + TEST(Expression, FactoryMethodTest) { std::shared_ptr manager(new storm::expressions::ExpressionManager()); @@ -369,3 +375,31 @@ TEST(Expression, VisitorTest) { storm::expressions::LinearityCheckVisitor visitor; EXPECT_TRUE(visitor.check(tempExpression)); } + +TEST(Expression, ValueTypeToExpressionTest) { + storm::parser::ValueParser parser; + parser.addParameter("p"); + parser.addParameter("q"); + auto rationalFunction = parser.parseValue("((5*p^(3))+(q*p*7)+2)/2"); + + std::shared_ptr manager(new storm::expressions::ExpressionManager()); + auto transformer = storm::expressions::ValueTypeToExpression(manager); + + storm::expressions::Expression expr; + EXPECT_NO_THROW(expr = transformer.toExpression(rationalFunction)); + auto base = storm::expressions::ExpressionEvaluator(*manager); + storm::expressions::ToRationalFunctionVisitor visitor(base); + ASSERT_NO_THROW(rationalFunction.simplify()); + storm::RationalFunction result; + ASSERT_NO_THROW(result = visitor.toRationalFunction(expr)); + ASSERT_NO_THROW(result.simplify()); + EXPECT_EQ(rationalFunction.toString(), result.toString()); + + rationalFunction = parser.parseValue("(5*((p^(3))+(q*p)))/2"); + transformer = storm::expressions::ValueTypeToExpression(manager); + EXPECT_NO_THROW(expr = transformer.toExpression(rationalFunction)); + ASSERT_NO_THROW(rationalFunction.simplify()); + ASSERT_NO_THROW(result = visitor.toRationalFunction(expr)); + ASSERT_NO_THROW(result.simplify()); + EXPECT_EQ(rationalFunction.toString(), result.toString()); +} \ No newline at end of file From c9c2816e1807ec559dd44cad2924616488953af7 Mon Sep 17 00:00:00 2001 From: Jip Spel Date: Tue, 25 Sep 2018 11:29:27 +0200 Subject: [PATCH 089/178] Add documentation --- .../storage/expressions/ValueTypeToExpression.h | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/src/storm/storage/expressions/ValueTypeToExpression.h b/src/storm/storage/expressions/ValueTypeToExpression.h index d0748483d..cc8e594e6 100644 --- a/src/storm/storage/expressions/ValueTypeToExpression.h +++ b/src/storm/storage/expressions/ValueTypeToExpression.h @@ -13,11 +13,6 @@ namespace storm { template class ValueTypeToExpression { public: - /*! - * - * - * @param manager The manager of the variables. - */ ValueTypeToExpression(std::shared_ptr manager); /*! @@ -28,10 +23,10 @@ namespace storm { std::shared_ptr getManager(); /*! + * Transforms the function into an expression. * - * @param function - * @param manager - * @return + * @param function The function to transform + * @return The created expression. */ Expression toExpression(ValueType function); @@ -42,5 +37,4 @@ namespace storm { } } - #endif //STORM_VALUETYPETOEXPRESSION_H From 51aace84216f71ee0a9cb8bb3afadd19d32c5419 Mon Sep 17 00:00:00 2001 From: Jip Spel Date: Tue, 25 Sep 2018 13:15:35 +0200 Subject: [PATCH 090/178] Renamed ValueTypeToExpression to RationalFunctionToExpression --- src/storm-pars/analysis/AssumptionChecker.cpp | 4 +- ...n.cpp => RationalFunctionToExpression.cpp} | 10 ++-- ...ssion.h => RationalFunctionToExpression.h} | 10 ++-- src/test/storm/storage/ExpressionTest.cpp | 58 +++++++++---------- 4 files changed, 41 insertions(+), 41 deletions(-) rename src/storm/storage/expressions/{ValueTypeToExpression.cpp => RationalFunctionToExpression.cpp} (85%) rename src/storm/storage/expressions/{ValueTypeToExpression.h => RationalFunctionToExpression.h} (77%) diff --git a/src/storm-pars/analysis/AssumptionChecker.cpp b/src/storm-pars/analysis/AssumptionChecker.cpp index b3326d519..0498230bb 100644 --- a/src/storm-pars/analysis/AssumptionChecker.cpp +++ b/src/storm-pars/analysis/AssumptionChecker.cpp @@ -17,7 +17,7 @@ #include "storm/storage/expressions/ExpressionManager.h" #include "storm/storage/expressions/VariableExpression.h" #include "storm/utility/constants.h" -#include "storm/storage/expressions/ValueTypeToExpression.h" +#include "storm/storage/expressions/RationalFunctionToExpression.h" namespace storm { namespace analysis { @@ -217,7 +217,7 @@ namespace storm { } storm::expressions::Expression exprGiven = succ1 >= succ2; - auto valueTypeToExpression = storm::expressions::ValueTypeToExpression(manager); + auto valueTypeToExpression = storm::expressions::RationalFunctionToExpression(manager); storm::expressions::Expression exprToCheck = (valueTypeToExpression.toExpression(state1succ1->getValue())*succ1 + valueTypeToExpression.toExpression(state2succ1->getValue())*succ2 diff --git a/src/storm/storage/expressions/ValueTypeToExpression.cpp b/src/storm/storage/expressions/RationalFunctionToExpression.cpp similarity index 85% rename from src/storm/storage/expressions/ValueTypeToExpression.cpp rename to src/storm/storage/expressions/RationalFunctionToExpression.cpp index 9a676cd41..6307d0e4e 100644 --- a/src/storm/storage/expressions/ValueTypeToExpression.cpp +++ b/src/storm/storage/expressions/RationalFunctionToExpression.cpp @@ -2,23 +2,23 @@ // Created by Jip Spel on 24.09.18. // -#include "ValueTypeToExpression.h" +#include "RationalFunctionToExpression.h" #include "storm/utility/constants.h" namespace storm { namespace expressions { template - ValueTypeToExpression::ValueTypeToExpression(std::shared_ptr manager) : manager(manager) { + RationalFunctionToExpression::RationalFunctionToExpression(std::shared_ptr manager) : manager(manager) { // Intentionally left empty. } template - std::shared_ptr ValueTypeToExpression::getManager() { + std::shared_ptr RationalFunctionToExpression::getManager() { return manager; } template - Expression ValueTypeToExpression::toExpression(ValueType function) { + Expression RationalFunctionToExpression::toExpression(ValueType function) { function.simplify(); auto varsFunction = function.gatherVariables(); for (auto var : varsFunction) { @@ -62,6 +62,6 @@ namespace storm { } return result; } - template class ValueTypeToExpression; + template class RationalFunctionToExpression; } } diff --git a/src/storm/storage/expressions/ValueTypeToExpression.h b/src/storm/storage/expressions/RationalFunctionToExpression.h similarity index 77% rename from src/storm/storage/expressions/ValueTypeToExpression.h rename to src/storm/storage/expressions/RationalFunctionToExpression.h index cc8e594e6..9ba38ccc5 100644 --- a/src/storm/storage/expressions/ValueTypeToExpression.h +++ b/src/storm/storage/expressions/RationalFunctionToExpression.h @@ -2,8 +2,8 @@ // Created by Jip Spel on 24.09.18. // -#ifndef STORM_VALUETYPETOEXPRESSION_H -#define STORM_VALUETYPETOEXPRESSION_H +#ifndef STORM_RATIONALFUNCTIONTOEXPRESSION_H +#define STORM_RATIONALFUNCTIONTOEXPRESSION_H #include "storm/storage/expressions/ExpressionManager.h" #include "storm/storage/expressions/Expression.h" @@ -11,9 +11,9 @@ namespace storm { namespace expressions { template - class ValueTypeToExpression { + class RationalFunctionToExpression { public: - ValueTypeToExpression(std::shared_ptr manager); + RationalFunctionToExpression(std::shared_ptr manager); /*! * Retrieves the manager responsible for the variables of this valuation. @@ -37,4 +37,4 @@ namespace storm { } } -#endif //STORM_VALUETYPETOEXPRESSION_H +#endif //STORM_RATIONALFUNCTIONTOEXPRESSION_H diff --git a/src/test/storm/storage/ExpressionTest.cpp b/src/test/storm/storage/ExpressionTest.cpp index ed6d33152..8b7e72f3b 100644 --- a/src/test/storm/storage/ExpressionTest.cpp +++ b/src/test/storm/storage/ExpressionTest.cpp @@ -7,7 +7,7 @@ #include "storm/storage/expressions/LinearityCheckVisitor.h" #include "storm/storage/expressions/SimpleValuation.h" #include "storm/storage/expressions/ExpressionEvaluator.h" -#include "storm/storage/expressions/ValueTypeToExpression.h" +#include "storm/storage/expressions/RationalFunctionToExpression.h" #include "storm/exceptions/InvalidTypeException.h" #include "storm/adapters/RationalFunctionAdapter.h" #include "storm-parsers/parser/ValueParser.h" @@ -299,27 +299,27 @@ TEST(Expression, SimplificationTest) { storm::expressions::Expression falseExpression; storm::expressions::Expression threeExpression; storm::expressions::Expression intVarExpression; - - ASSERT_NO_THROW(trueExpression = manager->boolean(true)); - ASSERT_NO_THROW(falseExpression = manager->boolean(false)); - ASSERT_NO_THROW(threeExpression = manager->integer(3)); - ASSERT_NO_THROW(intVarExpression = manager->declareIntegerVariable("y")); - - storm::expressions::Expression tempExpression; - storm::expressions::Expression simplifiedExpression; - ASSERT_NO_THROW(tempExpression = trueExpression || intVarExpression > threeExpression); - ASSERT_NO_THROW(simplifiedExpression = tempExpression.simplify()); - EXPECT_TRUE(simplifiedExpression.isTrue()); +ASSERT_NO_THROW(trueExpression = manager->boolean(true)); +ASSERT_NO_THROW(falseExpression = manager->boolean(false)); +ASSERT_NO_THROW(threeExpression = manager->integer(3)); +ASSERT_NO_THROW(intVarExpression = manager->declareIntegerVariable("y")); + +storm::expressions::Expression tempExpression; +storm::expressions::Expression simplifiedExpression; - ASSERT_NO_THROW(tempExpression = falseExpression && intVarExpression > threeExpression); - ASSERT_NO_THROW(simplifiedExpression = tempExpression.simplify()); - EXPECT_TRUE(simplifiedExpression.isFalse()); +ASSERT_NO_THROW(tempExpression = trueExpression || intVarExpression > threeExpression); +ASSERT_NO_THROW(simplifiedExpression = tempExpression.simplify()); +EXPECT_TRUE(simplifiedExpression.isTrue()); + +ASSERT_NO_THROW(tempExpression = falseExpression && intVarExpression > threeExpression); +ASSERT_NO_THROW(simplifiedExpression = tempExpression.simplify()); +EXPECT_TRUE(simplifiedExpression.isFalse()); } TEST(Expression, SimpleEvaluationTest) { std::shared_ptr manager(new storm::expressions::ExpressionManager()); - + storm::expressions::Expression trueExpression; storm::expressions::Expression falseExpression; storm::expressions::Expression threeExpression; @@ -327,7 +327,7 @@ TEST(Expression, SimpleEvaluationTest) { storm::expressions::Expression boolVarExpression; storm::expressions::Expression intVarExpression; storm::expressions::Expression rationalVarExpression; - + ASSERT_NO_THROW(trueExpression = manager->boolean(true)); ASSERT_NO_THROW(falseExpression = manager->boolean(false)); ASSERT_NO_THROW(threeExpression = manager->integer(3)); @@ -335,23 +335,23 @@ TEST(Expression, SimpleEvaluationTest) { ASSERT_NO_THROW(boolVarExpression = manager->declareBooleanVariable("x")); ASSERT_NO_THROW(intVarExpression = manager->declareIntegerVariable("y")); ASSERT_NO_THROW(rationalVarExpression = manager->declareRationalVariable("z")); - + storm::expressions::Expression tempExpression; - + ASSERT_NO_THROW(tempExpression = (intVarExpression < threeExpression || boolVarExpression) && boolVarExpression); - + ASSERT_NO_THROW(storm::expressions::SimpleValuation valuation(manager)); storm::expressions::SimpleValuation valuation(manager); ASSERT_NO_THROW(valuation.setBooleanValue(manager->getVariable("x"), false)); ASSERT_NO_THROW(valuation.setIntegerValue(manager->getVariable("y"), 0)); ASSERT_NO_THROW(valuation.setRationalValue(manager->getVariable("z"), 0)); - + ASSERT_THROW(tempExpression.evaluateAsDouble(&valuation), storm::exceptions::InvalidTypeException); ASSERT_THROW(tempExpression.evaluateAsInt(&valuation), storm::exceptions::InvalidTypeException); EXPECT_FALSE(tempExpression.evaluateAsBool(&valuation)); ASSERT_NO_THROW(valuation.setIntegerValue(manager->getVariable("y"), 3)); EXPECT_FALSE(tempExpression.evaluateAsBool(&valuation)); - + ASSERT_NO_THROW(tempExpression = storm::expressions::ite(intVarExpression < threeExpression, trueExpression, falseExpression)); ASSERT_THROW(tempExpression.evaluateAsDouble(&valuation), storm::exceptions::InvalidTypeException); ASSERT_THROW(tempExpression.evaluateAsInt(&valuation), storm::exceptions::InvalidTypeException); @@ -360,30 +360,30 @@ TEST(Expression, SimpleEvaluationTest) { TEST(Expression, VisitorTest) { std::shared_ptr manager(new storm::expressions::ExpressionManager()); - + storm::expressions::Expression threeExpression; storm::expressions::Expression piExpression; storm::expressions::Expression intVarExpression; storm::expressions::Expression rationalVarExpression; - + ASSERT_NO_THROW(threeExpression = manager->integer(3)); ASSERT_NO_THROW(piExpression = manager->rational(3.14)); ASSERT_NO_THROW(intVarExpression = manager->declareIntegerVariable("y")); ASSERT_NO_THROW(rationalVarExpression = manager->declareRationalVariable("z")); - + storm::expressions::Expression tempExpression = intVarExpression + rationalVarExpression * threeExpression; storm::expressions::LinearityCheckVisitor visitor; EXPECT_TRUE(visitor.check(tempExpression)); } -TEST(Expression, ValueTypeToExpressionTest) { +TEST(Expression, RationalFunctionToExpressionTest) { storm::parser::ValueParser parser; parser.addParameter("p"); parser.addParameter("q"); auto rationalFunction = parser.parseValue("((5*p^(3))+(q*p*7)+2)/2"); std::shared_ptr manager(new storm::expressions::ExpressionManager()); - auto transformer = storm::expressions::ValueTypeToExpression(manager); + auto transformer = storm::expressions::RationalFunctionToExpression(manager); storm::expressions::Expression expr; EXPECT_NO_THROW(expr = transformer.toExpression(rationalFunction)); @@ -396,10 +396,10 @@ TEST(Expression, ValueTypeToExpressionTest) { EXPECT_EQ(rationalFunction.toString(), result.toString()); rationalFunction = parser.parseValue("(5*((p^(3))+(q*p)))/2"); - transformer = storm::expressions::ValueTypeToExpression(manager); + transformer = storm::expressions::RationalFunctionToExpression(manager); EXPECT_NO_THROW(expr = transformer.toExpression(rationalFunction)); ASSERT_NO_THROW(rationalFunction.simplify()); ASSERT_NO_THROW(result = visitor.toRationalFunction(expr)); ASSERT_NO_THROW(result.simplify()); EXPECT_EQ(rationalFunction.toString(), result.toString()); -} \ No newline at end of file +} From 4999ac54403c9c04bcbfd5e6e72c82303d3de0f7 Mon Sep 17 00:00:00 2001 From: Jip Spel Date: Tue, 25 Sep 2018 13:41:40 +0200 Subject: [PATCH 091/178] Check if derivative is constant in validation of assumption --- src/storm-pars/analysis/AssumptionChecker.cpp | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/src/storm-pars/analysis/AssumptionChecker.cpp b/src/storm-pars/analysis/AssumptionChecker.cpp index 0498230bb..400020aff 100644 --- a/src/storm-pars/analysis/AssumptionChecker.cpp +++ b/src/storm-pars/analysis/AssumptionChecker.cpp @@ -171,6 +171,7 @@ namespace storm { typename storm::storage::SparseMatrix::iterator state1succ2, typename storm::storage::SparseMatrix::iterator state2succ1, typename storm::storage::SparseMatrix::iterator state2succ2) { + bool result = true; ValueType prob; auto comp = lattice->compare(state1succ1->getColumn(), state1succ2->getColumn()); @@ -183,16 +184,19 @@ namespace storm { // TODO: Type std::map substitutions; - for (auto var:vars) { + for (auto var : vars) { auto derivative = prob.derivative(var); - assert(derivative.isConstant()); - if (derivative.constantPart() >= 0) { - substitutions[var] = 0; - } else if (derivative.constantPart() <= 0) { - substitutions[var] = 1; + if(derivative.isConstant()) { + if (derivative.constantPart() >= 0) { + substitutions[var] = 0; + } else if (derivative.constantPart() <= 0) { + substitutions[var] = 1; + } + } else { + result = false; } } - return prob.evaluate(substitutions) >= 0; + return result && prob.evaluate(substitutions) >= 0; } template From bdad60150167d9790b6be204ff901f91dd8757c5 Mon Sep 17 00:00:00 2001 From: Jip Spel Date: Wed, 26 Sep 2018 10:37:43 +0200 Subject: [PATCH 092/178] Validate assumption with SMT Solver - more than 2 successor states --- src/storm-pars/analysis/AssumptionChecker.cpp | 129 ++++++++++++++++-- src/storm-pars/analysis/AssumptionChecker.h | 3 + 2 files changed, 122 insertions(+), 10 deletions(-) diff --git a/src/storm-pars/analysis/AssumptionChecker.cpp b/src/storm-pars/analysis/AssumptionChecker.cpp index 400020aff..f63ac68ac 100644 --- a/src/storm-pars/analysis/AssumptionChecker.cpp +++ b/src/storm-pars/analysis/AssumptionChecker.cpp @@ -134,7 +134,6 @@ namespace storm { auto row1 = matrix.getRow(std::stoi(assumption->getFirstOperand()->asVariableExpression().getVariableName())); auto row2 = matrix.getRow(std::stoi(assumption->getSecondOperand()->asVariableExpression().getVariableName())); - // Only implemented for two successors if (row1.getNumberOfEntries() == 2 && row2.getNumberOfEntries() == 2) { auto state1succ1 = row1.begin(); auto state1succ2 = (++row1.begin()); @@ -153,7 +152,7 @@ namespace storm { } } } else { - STORM_LOG_DEBUG("Validation only implemented for two successor states"); + result = validateAssumptionSMTSolver(lattice, assumption); } } @@ -171,6 +170,10 @@ namespace storm { typename storm::storage::SparseMatrix::iterator state1succ2, typename storm::storage::SparseMatrix::iterator state2succ1, typename storm::storage::SparseMatrix::iterator state2succ2) { + assert((state1succ1->getColumn() == state2succ1->getColumn() + && state1succ2->getColumn() == state2succ2->getColumn()) + || (state1succ1->getColumn() == state2succ2->getColumn() + && state1succ2->getColumn() == state2succ1->getColumn())); bool result = true; ValueType prob; @@ -201,11 +204,14 @@ namespace storm { template bool AssumptionChecker::validateAssumptionSMTSolver(storm::analysis::Lattice* lattice, - typename storm::storage::SparseMatrix::iterator state1succ1, - typename storm::storage::SparseMatrix::iterator state1succ2, - typename storm::storage::SparseMatrix::iterator state2succ1, - typename storm::storage::SparseMatrix::iterator state2succ2) { - + typename storm::storage::SparseMatrix::iterator state1succ1, + typename storm::storage::SparseMatrix::iterator state1succ2, + typename storm::storage::SparseMatrix::iterator state2succ1, + typename storm::storage::SparseMatrix::iterator state2succ2) { + assert((state1succ1->getColumn() == state2succ1->getColumn() + && state1succ2->getColumn() == state2succ2->getColumn()) + || (state1succ1->getColumn() == state2succ2->getColumn() + && state1succ2->getColumn() == state2succ1->getColumn())); std::shared_ptr smtSolverFactory = std::make_shared(); std::shared_ptr manager( new storm::expressions::ExpressionManager()); @@ -224,9 +230,9 @@ namespace storm { auto valueTypeToExpression = storm::expressions::RationalFunctionToExpression(manager); storm::expressions::Expression exprToCheck = (valueTypeToExpression.toExpression(state1succ1->getValue())*succ1 - + valueTypeToExpression.toExpression(state2succ1->getValue())*succ2 - >= valueTypeToExpression.toExpression(state1succ2->getValue())*succ1 - + valueTypeToExpression.toExpression(state1succ1->getValue())*succ2); + + valueTypeToExpression.toExpression(state1succ2->getValue())*succ2 + >= valueTypeToExpression.toExpression(state2succ1->getValue())*succ1 + + valueTypeToExpression.toExpression(state2succ2->getValue())*succ2); storm::expressions::Expression exprBounds = manager->boolean(true); auto variables = manager->getVariables(); @@ -242,6 +248,109 @@ namespace storm { return smtResult == storm::solver::SmtSolver::CheckResult::Sat; } + template + bool AssumptionChecker::validateAssumptionSMTSolver(storm::analysis::Lattice* lattice, std::shared_ptr assumption) { + std::shared_ptr smtSolverFactory = std::make_shared(); + std::shared_ptr manager(new storm::expressions::ExpressionManager()); + bool result = true; + auto row1 = matrix.getRow(std::stoi(assumption->getFirstOperand()->asVariableExpression().getVariableName())); + auto row2 = matrix.getRow(std::stoi(assumption->getSecondOperand()->asVariableExpression().getVariableName())); + + if (row1.getNumberOfEntries() <= row2.getNumberOfEntries()) { + for (auto itr1 = row1.begin(); result && itr1 != row1.end(); ++itr1) { + bool found = false; + for (auto itr2 = row2.begin(); !found && itr2 != row2.end(); ++itr2) { + found = itr1->getColumn() == itr2->getColumn(); + } + + if (!found) { + result = false; + } + } + } else { + for (auto itr1 = row2.begin(); result && itr1 != row2.end(); ++itr1) { + bool found = false; + for (auto itr2 = row1.begin(); !found && itr2 != row1.end(); ++itr2) { + found = itr1->getColumn() == itr2->getColumn(); + } + + if (!found) { + result = false; + } + } + } + + if (result) { + storm::solver::Z3SmtSolver s(*manager); + if (row1.getNumberOfEntries() >= row2.getNumberOfEntries()) { + for (auto itr1 = row1.begin(); itr1 != row1.end(); ++itr1) { + manager->declareRationalVariable(std::to_string(itr1->getColumn())); + } + } else { + for (auto itr1 = row2.begin(); itr1 != row2.end(); ++itr1) { + manager->declareRationalVariable(std::to_string(itr1->getColumn())); + } + } + + storm::expressions::Expression exprGiven = manager->boolean(true); + + for (auto itr1 = row1.begin(); result && itr1 != row1.end(); ++itr1) { + for (auto itr2 = (itr1 + 1); result && itr2 != row1.end(); ++itr2) { + auto comp = lattice->compare(itr1->getColumn(), itr2->getColumn()); + if (comp == storm::analysis::Lattice::ABOVE) { + exprGiven = exprGiven && (manager->getVariable(std::to_string(itr1->getColumn())) >= manager->getVariable(std::to_string(itr2->getColumn()))); + } else if (comp == storm::analysis::Lattice::BELOW) { + exprGiven = exprGiven && (manager->getVariable(std::to_string(itr1->getColumn())) <= manager->getVariable(std::to_string(itr2->getColumn()))); + } else if (comp == storm::analysis::Lattice::SAME) { + exprGiven = exprGiven && (manager->getVariable(std::to_string(itr1->getColumn())) = manager->getVariable(std::to_string(itr2->getColumn()))); + } else { + result = false; + } + } + } + + auto valueTypeToExpression = storm::expressions::RationalFunctionToExpression(manager); + storm::expressions::Expression expr1 = manager->integer(0); + for (auto itr1 = row1.begin(); result && itr1 != row1.end(); ++itr1) { + expr1 = expr1 + (valueTypeToExpression.toExpression(itr1->getValue()) * manager->getVariable(std::to_string(itr1->getColumn()))); + } + + storm::expressions::Expression expr2 = manager->integer(0); + for (auto itr2 = row2.begin(); result && itr2 != row2.end(); ++itr2) { + expr2 = expr2 + (valueTypeToExpression.toExpression(itr2->getValue()) * manager->getVariable(std::to_string(itr2->getColumn()))); + } + storm::expressions::Expression exprToCheck = expr1 >= expr2; + + storm::expressions::Expression exprProb1 = manager->integer(0); + for (auto itr1 = row1.begin(); result && itr1 != row1.end(); ++itr1) { + exprProb1 = exprProb1 + (valueTypeToExpression.toExpression(itr1->getValue())); + } + + storm::expressions::Expression exprProb2 = manager->integer(0); + for (auto itr2 = row2.begin(); result && itr2 != row2.end(); ++itr2) { + exprProb2 = exprProb2 + (valueTypeToExpression.toExpression(itr2->getValue())); + } + + storm::expressions::Expression exprBounds = exprProb1 >= manager->rational(0) + && exprProb1 <= manager->rational(1) + && exprProb2 >= manager->rational(0) + && exprProb2 <= manager->rational(1); + + auto variables = manager->getVariables(); + for (auto var : variables) { + exprBounds = exprBounds && var >= 0 && var <= 1; + } + + s.add(exprGiven); + s.add(exprBounds); + assert(s.check() == storm::solver::SmtSolver::CheckResult::Sat); + s.add(exprToCheck); + auto smtRes = s.check(); + result = result && smtRes == storm::solver::SmtSolver::CheckResult::Sat; + } + return result; + } + template bool AssumptionChecker::validated(std::shared_ptr assumption) { return find(validatedAssumptions.begin(), validatedAssumptions.end(), assumption) != validatedAssumptions.end(); diff --git a/src/storm-pars/analysis/AssumptionChecker.h b/src/storm-pars/analysis/AssumptionChecker.h index cdb6faf2d..6a11f7e6f 100644 --- a/src/storm-pars/analysis/AssumptionChecker.h +++ b/src/storm-pars/analysis/AssumptionChecker.h @@ -80,6 +80,9 @@ namespace storm { typename storm::storage::SparseMatrix::iterator state1succ2, typename storm::storage::SparseMatrix::iterator state2succ1, typename storm::storage::SparseMatrix::iterator state2succ2); + + bool validateAssumptionSMTSolver(storm::analysis::Lattice* lattice, + std::shared_ptr assumption); }; } } From 6695f6446045000bd8f1e6bceca4e0683bfc1d96 Mon Sep 17 00:00:00 2001 From: Jip Spel Date: Wed, 26 Sep 2018 10:48:42 +0200 Subject: [PATCH 093/178] Add test and fix bug RationalFunction to Expression --- .../RationalFunctionToExpression.cpp | 2 +- src/test/storm/storage/ExpressionTest.cpp | 21 +++++++++++++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/src/storm/storage/expressions/RationalFunctionToExpression.cpp b/src/storm/storage/expressions/RationalFunctionToExpression.cpp index 6307d0e4e..7ea655db6 100644 --- a/src/storm/storage/expressions/RationalFunctionToExpression.cpp +++ b/src/storm/storage/expressions/RationalFunctionToExpression.cpp @@ -58,8 +58,8 @@ namespace storm { result = result + nominatorPartExpr; } } - result = result / denominatorVal; } + result = result / denominatorVal; return result; } template class RationalFunctionToExpression; diff --git a/src/test/storm/storage/ExpressionTest.cpp b/src/test/storm/storage/ExpressionTest.cpp index 8b7e72f3b..98215eba9 100644 --- a/src/test/storm/storage/ExpressionTest.cpp +++ b/src/test/storm/storage/ExpressionTest.cpp @@ -403,3 +403,24 @@ TEST(Expression, RationalFunctionToExpressionTest) { ASSERT_NO_THROW(result.simplify()); EXPECT_EQ(rationalFunction.toString(), result.toString()); } + +TEST(Expression, RationalFunctionToExpressionTest_no_params) { + storm::parser::ValueParser parser; + parser.addParameter("p"); + auto rationalFunction1 = parser.parseValue("(p + 380)/3125"); + auto rationalFunction2 = parser.parseValue("(p)/3125"); + auto rationalFunction = rationalFunction1 - rationalFunction2; + + std::shared_ptr manager(new storm::expressions::ExpressionManager()); + auto transformer = storm::expressions::RationalFunctionToExpression(manager); + + storm::expressions::Expression expr; + EXPECT_NO_THROW(expr = transformer.toExpression(rationalFunction)); + auto base = storm::expressions::ExpressionEvaluator(*manager); + storm::expressions::ToRationalFunctionVisitor visitor(base); + ASSERT_NO_THROW(rationalFunction.simplify()); + storm::RationalFunction result; + ASSERT_NO_THROW(result = visitor.toRationalFunction(expr)); + ASSERT_NO_THROW(result.simplify()); + EXPECT_EQ(rationalFunction.toString(), result.toString()); +} \ No newline at end of file From 7f6823c6bb520d21190aae8f80223f875f41f00e Mon Sep 17 00:00:00 2001 From: Jip Spel Date: Fri, 28 Sep 2018 13:22:05 +0200 Subject: [PATCH 094/178] Resolve TODO --- .../expressions/RationalFunctionToExpression.cpp | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/src/storm/storage/expressions/RationalFunctionToExpression.cpp b/src/storm/storage/expressions/RationalFunctionToExpression.cpp index 7ea655db6..8929a58db 100644 --- a/src/storm/storage/expressions/RationalFunctionToExpression.cpp +++ b/src/storm/storage/expressions/RationalFunctionToExpression.cpp @@ -37,22 +37,20 @@ namespace storm { STORM_LOG_DEBUG("Expecting the denominator to be constant"); } - storm::expressions::Expression denominatorVal = manager->rational(std::stod(storm::utility::to_string(denominator.constantPart()))); + storm::expressions::Expression denominatorVal = manager->rational(storm::utility::convertNumber(denominator.constantPart())); storm::expressions::Expression result; if (function.isConstant()) { - result = manager->integer(std::stoi(storm::utility::to_string(function.constantPart()))); + result = manager->rational(storm::utility::convertNumber(function.constantPart())); } else { auto nominator = function.nominatorAsPolynomial().polynomialWithCoefficient(); - result = manager->integer(std::stoi(storm::utility::to_string(nominator.constantPart()))); + result = manager->rational(storm::utility::convertNumber(nominator.constantPart())); for (auto itr = nominator.begin(); itr != nominator.end(); ++itr) { varsFunction.clear(); - (*itr).gatherVariables(varsFunction); + itr->gatherVariables(varsFunction); - // TODO: improve transformation from coefficient to expression - storm::expressions::Expression nominatorPartExpr = manager->integer( - std::stoi(storm::utility::to_string((*itr).coeff()))); + storm::expressions::Expression nominatorPartExpr = manager->rational(storm::utility::convertNumber(itr->coeff())); for (auto var : varsFunction) { - nominatorPartExpr = nominatorPartExpr * (manager->getVariable(var.name())^manager->integer((*itr).monomial()->exponentOfVariable(var))); + nominatorPartExpr = nominatorPartExpr * (manager->getVariable(var.name())^manager->rational(storm::utility::convertNumber(itr->monomial()->exponentOfVariable(var)))); } if (varsFunction.size() >= 1) { result = result + nominatorPartExpr; @@ -62,6 +60,7 @@ namespace storm { result = result / denominatorVal; return result; } + template class RationalFunctionToExpression; } } From a37c42d7dcf9c7f9a8b5216b091b7b92aabf3cb2 Mon Sep 17 00:00:00 2001 From: Jip Spel Date: Mon, 1 Oct 2018 13:43:57 +0200 Subject: [PATCH 095/178] Fix same name parameter --- src/storm-pars/analysis/MonotonicityChecker.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/storm-pars/analysis/MonotonicityChecker.cpp b/src/storm-pars/analysis/MonotonicityChecker.cpp index fa97cefc4..30ca4f110 100644 --- a/src/storm-pars/analysis/MonotonicityChecker.cpp +++ b/src/storm-pars/analysis/MonotonicityChecker.cpp @@ -12,7 +12,7 @@ namespace storm { std::map>> MonotonicityChecker::checkMonotonicity(std::map>> map, storm::storage::SparseMatrix matrix) { auto i = 0; std::map>> result; - for (auto itr = map.begin(); itr != map.end(); ++itr) { + for (auto itr = map.begin(); i < map.size() && itr != map.end(); ++itr) { auto lattice = itr->first; auto assumptions = itr->second; std::ofstream myfile; @@ -53,17 +53,18 @@ namespace storm { STORM_PRINT(" - Do not know if monotone decreasing in: " << itr2->first << std::endl); } } + result.insert(std::pair>>( + lattice, varsMonotone)); ++i; - result.insert(std::pair>>(lattice, varsMonotone)); } return result; } template - std::map> MonotonicityChecker::analyseMonotonicity(uint_fast64_t i, storm::analysis::Lattice* lattice, storm::storage::SparseMatrix matrix) { + std::map> MonotonicityChecker::analyseMonotonicity(uint_fast64_t j, storm::analysis::Lattice* lattice, storm::storage::SparseMatrix matrix) { std::map> varsMonotone; std::ofstream myfile; - std::string filename = "mc" + std::to_string(i) + ".dot"; + std::string filename = "mc" + std::to_string(j) + ".dot"; myfile.open (filename); myfile << "digraph \"MC\" {" << std::endl; myfile << "\t" << "node [shape=ellipse]" << std::endl; @@ -76,7 +77,6 @@ namespace storm { for (uint_fast64_t i = 0; i < matrix.getColumnCount(); ++i) { // go over all rows auto row = matrix.getRow(i); - auto first = (*row.begin()); if (first.getValue() != ValueType(1)) { std::map transitions; @@ -88,7 +88,8 @@ namespace storm { std::string color = ""; auto val = first.getValue(); auto vars = val.gatherVariables(); - for (auto itr = vars.begin(); itr != vars.end(); ++itr) { if (varsMonotone.find(*itr) == varsMonotone.end()) { + for (auto itr = vars.begin(); itr != vars.end(); ++itr) { + if (varsMonotone.find(*itr) == varsMonotone.end()) { varsMonotone[*itr].first = true; varsMonotone[*itr].second = true; } @@ -121,7 +122,6 @@ namespace storm { } } - if ((value->first != old.first) && (value->second != old.second)) { color = "color = red, "; } else if ((value->first != old.first)) { From eb8240bfff5ec77427fd14db93f826e2fa53c3eb Mon Sep 17 00:00:00 2001 From: Jip Spel Date: Mon, 1 Oct 2018 13:52:44 +0200 Subject: [PATCH 096/178] Add message when no parameters occur in final model --- .../analysis/MonotonicityChecker.cpp | 29 +++++++++++-------- 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/src/storm-pars/analysis/MonotonicityChecker.cpp b/src/storm-pars/analysis/MonotonicityChecker.cpp index 30ca4f110..3a97e200b 100644 --- a/src/storm-pars/analysis/MonotonicityChecker.cpp +++ b/src/storm-pars/analysis/MonotonicityChecker.cpp @@ -41,20 +41,25 @@ namespace storm { } std::map> varsMonotone = analyseMonotonicity(i, lattice, matrix); - for (auto itr2 = varsMonotone.begin(); itr2 != varsMonotone.end(); ++itr2) { - if (itr2->second.first) { - STORM_PRINT(" - Monotone increasing in: " << itr2->first << std::endl); - } else { - STORM_PRINT(" - Do not know if monotone increasing in: " << itr2->first << std::endl); - } - if (itr2->second.second) { - STORM_PRINT(" - Monotone decreasing in: " << itr2->first << std::endl); - } else { - STORM_PRINT(" - Do not know if monotone decreasing in: " << itr2->first << std::endl); + if (varsMonotone.size() == 0) { + STORM_PRINT("Result is constant" << std::endl); + } else { + for (auto itr2 = varsMonotone.begin(); itr2 != varsMonotone.end(); ++itr2) { + if (itr2->second.first) { + STORM_PRINT(" - Monotone increasing in: " << itr2->first << std::endl); + } else { + STORM_PRINT(" - Do not know if monotone increasing in: " << itr2->first << std::endl); + } + if (itr2->second.second) { + STORM_PRINT(" - Monotone decreasing in: " << itr2->first << std::endl); + } else { + STORM_PRINT(" - Do not know if monotone decreasing in: " << itr2->first << std::endl); + } } + result.insert( + std::pair>>( + lattice, varsMonotone)); } - result.insert(std::pair>>( - lattice, varsMonotone)); ++i; } return result; From 67862b0a8d6633837602d22276b437edb4562417 Mon Sep 17 00:00:00 2001 From: Jip Spel Date: Mon, 1 Oct 2018 14:05:56 +0200 Subject: [PATCH 097/178] First implementation for cyclic parts in model --- src/storm-pars-cli/storm-pars.cpp | 8 ---- src/storm-pars/analysis/AssumptionMaker.cpp | 2 + src/storm-pars/analysis/LatticeExtender.cpp | 47 ++++++++++++++++----- src/storm-pars/analysis/LatticeExtender.h | 2 + 4 files changed, 41 insertions(+), 18 deletions(-) diff --git a/src/storm-pars-cli/storm-pars.cpp b/src/storm-pars-cli/storm-pars.cpp index c44989300..ed4e645d3 100644 --- a/src/storm-pars-cli/storm-pars.cpp +++ b/src/storm-pars-cli/storm-pars.cpp @@ -531,14 +531,6 @@ namespace storm { std::vector> formulas = storm::api::extractFormulasFromProperties(input.properties); std::shared_ptr> sparseModel = model->as>(); - // Check if MC is acyclic - auto decomposition = storm::storage::StronglyConnectedComponentDecomposition(sparseModel->getTransitionMatrix(), false, false); - for (auto i = 0; i < decomposition.size(); ++i) { - auto scc = decomposition.getBlock(i); - STORM_LOG_THROW(scc.size() <= 1, storm::exceptions::NotSupportedException, "Cycle found, not supporting cyclic MCs"); - } - - // Transform to Lattices storm::utility::Stopwatch latticeWatch(true); storm::analysis::LatticeExtender *extender = new storm::analysis::LatticeExtender(sparseModel); diff --git a/src/storm-pars/analysis/AssumptionMaker.cpp b/src/storm-pars/analysis/AssumptionMaker.cpp index 9cef9ab3c..280183184 100644 --- a/src/storm-pars/analysis/AssumptionMaker.cpp +++ b/src/storm-pars/analysis/AssumptionMaker.cpp @@ -65,7 +65,9 @@ namespace storm { auto val2 = std::get<2>(criticalTriple); storm::expressions::Variable var1 = expressionManager->getVariable(std::to_string(val1)); storm::expressions::Variable var2 = expressionManager->getVariable(std::to_string(val2)); + // TODO: check of in lattice de relatie niet al andersom bestaat + assert(lattice->compare(val1, val2) == storm::analysis::Lattice::UNKNOWN); auto latticeCopy = new Lattice(lattice); std::vector> assumptionsCopy = std::vector>( assumptions); diff --git a/src/storm-pars/analysis/LatticeExtender.cpp b/src/storm-pars/analysis/LatticeExtender.cpp index b4be618ed..a26713fa7 100644 --- a/src/storm-pars/analysis/LatticeExtender.cpp +++ b/src/storm-pars/analysis/LatticeExtender.cpp @@ -17,6 +17,8 @@ #include "storm/exceptions/NotSupportedException.h" #include +#include +#include #include "storm/storage/BitVector.h" #include "storm/utility/macros.h" @@ -25,8 +27,35 @@ namespace storm { namespace analysis { template - LatticeExtender::LatticeExtender(std::shared_ptr> model) : model(model) { - // intentionally left empty + LatticeExtender::LatticeExtender(std::shared_ptr> model) { + this->model = model; + + initialMiddleStates = storm::storage::BitVector(model->getNumberOfStates()); + // Check if MC is acyclic + auto decomposition = storm::storage::StronglyConnectedComponentDecomposition(model->getTransitionMatrix(), false, false); + for (auto i = 0; i < decomposition.size(); ++i) { + auto scc = decomposition.getBlock(i); + if (scc.size() > 1) { + auto states = scc.getStates(); + bool added = false; + for (auto itr = states.begin(); !added && itr != states.end(); ++itr) { + auto state = *itr; + storm::storage::BitVector subSystem = storm::storage::BitVector(model->getNumberOfStates()); + subSystem.set(states.begin(), states.end(), true); + subSystem.set(state, false); + auto subDecomposition = storm::storage::StronglyConnectedComponentDecomposition(model->getTransitionMatrix(), subSystem, false, false); + bool acyclic = true; + for (auto i = 0; acyclic && i < subDecomposition.size(); ++i) { + auto subScc = subDecomposition.getBlock(i); + acyclic = subScc.size() <= 1; + } + if (acyclic) { + initialMiddleStates.set(state); + added = true; + } + } + } + } } template @@ -71,6 +100,9 @@ namespace storm { // Create the Lattice storm::analysis::Lattice *lattice = new storm::analysis::Lattice(topStates, bottomStates, numberOfStates); + for (auto state = initialMiddleStates.getNextSetIndex(0); state != numberOfStates; state = initialMiddleStates.getNextSetIndex(state + 1)) { + lattice->add(state); + } return this->extendLattice(lattice); } @@ -110,8 +142,9 @@ namespace storm { } } - auto oldNumberSet = lattice->getAddedStates().getNumberOfSetBits(); - while (lattice->getAddedStates().getNumberOfSetBits() != numberOfStates) { + auto oldNumberSet = numberOfStates; + while (oldNumberSet != lattice->getAddedStates().getNumberOfSetBits()) { + oldNumberSet = lattice->getAddedStates().getNumberOfSetBits(); for (auto stateItr = stateMap.begin(); stateItr != stateMap.end(); ++stateItr) { storm::storage::BitVector seenStates = (lattice->getAddedStates()); // Iterate over all states @@ -169,12 +202,6 @@ namespace storm { lattice->addBetween(stateNumber, lattice->getNode(highest), lattice->getNode(lowest)); } } - // Nothing changed and not done yet - if (oldNumberSet == lattice->getAddedStates().getNumberOfSetBits()) { - // add the first unset state to the lattice between top and bottom - lattice->add(lattice->getAddedStates().getNextUnsetIndex(0)); - } - oldNumberSet = lattice->getAddedStates().getNumberOfSetBits(); } return std::make_tuple(lattice, numberOfStates, numberOfStates); } diff --git a/src/storm-pars/analysis/LatticeExtender.h b/src/storm-pars/analysis/LatticeExtender.h index 48bb7123a..8737c8f9e 100644 --- a/src/storm-pars/analysis/LatticeExtender.h +++ b/src/storm-pars/analysis/LatticeExtender.h @@ -53,6 +53,8 @@ namespace storm { std::shared_ptr> model; std::map stateMap; + + storm::storage::BitVector initialMiddleStates; }; } } From c85da52e8b6475eaef70e5b252be7fb51f25fd69 Mon Sep 17 00:00:00 2001 From: Jip Spel Date: Mon, 1 Oct 2018 14:07:08 +0200 Subject: [PATCH 098/178] Give message when no lattices are created --- src/storm-pars-cli/storm-pars.cpp | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/storm-pars-cli/storm-pars.cpp b/src/storm-pars-cli/storm-pars.cpp index ed4e645d3..a32a92f3d 100644 --- a/src/storm-pars-cli/storm-pars.cpp +++ b/src/storm-pars-cli/storm-pars.cpp @@ -556,10 +556,15 @@ namespace storm { // Monotonicity? storm::utility::Stopwatch monotonicityWatch(true); - auto monotonicityChecker = storm::analysis::MonotonicityChecker(); - monotonicityChecker.checkMonotonicity(result, sparseModel->getTransitionMatrix()); - monotonicityWatch.stop(); - STORM_PRINT(std::endl << "Time for monotonicity: " << monotonicityWatch << "." << std::endl << std::endl); + if (result.size() > 0) { + auto monotonicityChecker = storm::analysis::MonotonicityChecker(); + monotonicityChecker.checkMonotonicity(result, sparseModel->getTransitionMatrix()); + monotonicityWatch.stop(); + } else { + STORM_PRINT(std::endl << "Could not find monotonicity, no lattices created" << std::endl); + } + STORM_PRINT(std::endl << "Time for monotonicity: " << monotonicityWatch << "." << std::endl + << std::endl); std::cout << "Bye, Jip2" << std::endl; return; From 88c6b4d66b45888fec7cb5186711dfd609b6bef5 Mon Sep 17 00:00:00 2001 From: Jip Spel Date: Mon, 1 Oct 2018 14:40:47 +0200 Subject: [PATCH 099/178] Ignore self loops in lattice creation when there are several outgoing transitions --- src/storm-pars/analysis/Lattice.cpp | 3 ++- src/storm-pars/analysis/LatticeExtender.cpp | 10 ++++++++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/storm-pars/analysis/Lattice.cpp b/src/storm-pars/analysis/Lattice.cpp index 87db8a666..dbf2c0964 100644 --- a/src/storm-pars/analysis/Lattice.cpp +++ b/src/storm-pars/analysis/Lattice.cpp @@ -82,7 +82,8 @@ namespace storm { void Lattice::addBetween(uint_fast64_t state, Node *above, Node *below) { assert(!addedStates[state]); - assert(compare(above, below) == ABOVE); + auto res = compare(above, below); + assert(res == ABOVE || res == UNKNOWN); Node *newNode = new Node(); newNode->states = storm::storage::BitVector(numberOfStates); newNode->states.set(state); diff --git a/src/storm-pars/analysis/LatticeExtender.cpp b/src/storm-pars/analysis/LatticeExtender.cpp index a26713fa7..7765dc8ed 100644 --- a/src/storm-pars/analysis/LatticeExtender.cpp +++ b/src/storm-pars/analysis/LatticeExtender.cpp @@ -94,7 +94,10 @@ namespace storm { auto row = matrix.getRow(i); for (auto rowItr = row.begin(); rowItr != row.end(); ++rowItr) { - stateMap[i].set(rowItr->getColumn(), true); + // ignore self-loops when there are more transitions + if (i != rowItr->getColumn() || row.getNumberOfEntries() == 1) { + stateMap[i].set(rowItr->getColumn(), true); + } } } @@ -154,7 +157,10 @@ namespace storm { // Check if current state has not been added yet, and all successors have bool check = !seenStates[stateNumber]; for (auto succIndex = successors.getNextSetIndex(0); check && succIndex != numberOfStates; succIndex = successors.getNextSetIndex(++succIndex)) { - check &= seenStates[succIndex]; + if (succIndex != stateNumber) { + check &= seenStates[succIndex]; + } + // if the stateNumber equals succIndex we have a self-loop } if (check && successors.getNumberOfSetBits() == 1) { From 28b06f5eda73f5ac68890d012c1bf1c095f58ec5 Mon Sep 17 00:00:00 2001 From: Jip Spel Date: Tue, 2 Oct 2018 16:47:53 +0200 Subject: [PATCH 100/178] Add another way to extend the lattice --- src/storm-pars/analysis/LatticeExtender.cpp | 36 +++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/src/storm-pars/analysis/LatticeExtender.cpp b/src/storm-pars/analysis/LatticeExtender.cpp index 7765dc8ed..24058fd8a 100644 --- a/src/storm-pars/analysis/LatticeExtender.cpp +++ b/src/storm-pars/analysis/LatticeExtender.cpp @@ -54,6 +54,10 @@ namespace storm { added = true; } } + if (!added) { + // Add one of the states of the scc + initialMiddleStates.set(*(states.begin())); + } } } } @@ -111,6 +115,7 @@ namespace storm { template std::tuple LatticeExtender::extendLattice(storm::analysis::Lattice* lattice, std::shared_ptr assumption) { + // TODO: split up auto numberOfStates = this->model->getNumberOfStates(); // First handle assumption if (assumption != nullptr) { @@ -207,6 +212,37 @@ namespace storm { } lattice->addBetween(stateNumber, lattice->getNode(highest), lattice->getNode(lowest)); } + + bool checkOneSuccLeft = seenStates[stateNumber] && successors.getNumberOfSetBits() <= 2; + bool helper = true; + for (auto succIndex = successors.getNextSetIndex(0); (check || checkOneSuccLeft) && succIndex != numberOfStates; succIndex = successors.getNextSetIndex(++succIndex)) { + checkOneSuccLeft &= !(!helper && !seenStates[succIndex]); + helper &= seenStates[succIndex]; + } + + checkOneSuccLeft &= !helper; + + + if (checkOneSuccLeft) { + // at most 2 successors + auto succ1 = successors.getNextSetIndex(0); + auto succ2 = successors.getNextSetIndex(succ1+1); + // Otherwise there is just one transition, this is already handled above + if (succ2 != numberOfStates) { + auto nodeCurr = lattice->getNode(stateNumber); + if (!seenStates[succ1]) { + std::swap(succ1, succ2); + } + assert (seenStates[succ1]); + auto nodeSucc = lattice->getNode(succ1); + auto compare = lattice->compare(stateNumber, succ1); + if (compare == storm::analysis::Lattice::ABOVE) { + lattice->addBetween(succ2, lattice->getTop(), lattice->getNode(stateNumber)); + } else if (compare == storm::analysis::Lattice::BELOW) { + lattice->addBetween(succ2, lattice->getNode(stateNumber), lattice->getBottom()); + } + } + } } } return std::make_tuple(lattice, numberOfStates, numberOfStates); From eab6a9e38adfcee432d65c1c04e412ba90e62722 Mon Sep 17 00:00:00 2001 From: Jip Spel Date: Fri, 5 Oct 2018 11:49:14 +0200 Subject: [PATCH 101/178] Distinguish between validated and valid in AssumptionChecker and AssumptionMaker --- src/storm-pars/analysis/AssumptionChecker.cpp | 65 ++++++++++--------- src/storm-pars/analysis/AssumptionChecker.h | 5 +- src/storm-pars/analysis/AssumptionMaker.cpp | 15 +++-- 3 files changed, 49 insertions(+), 36 deletions(-) diff --git a/src/storm-pars/analysis/AssumptionChecker.cpp b/src/storm-pars/analysis/AssumptionChecker.cpp index f63ac68ac..ac6b202ae 100644 --- a/src/storm-pars/analysis/AssumptionChecker.cpp +++ b/src/storm-pars/analysis/AssumptionChecker.cpp @@ -147,19 +147,40 @@ namespace storm { if (state1succ1->getColumn() == state2succ1->getColumn() && state1succ2->getColumn() == state2succ2->getColumn()) { result = validateAssumptionFunction(lattice, state1succ1, state1succ2, state2succ1, state2succ2); + if (!result) { result = validateAssumptionSMTSolver(lattice, state1succ1, state1succ2, state2succ1, state2succ2); } + + validatedAssumptions.insert(assumption); + if (result) { + validAssumptions.insert(assumption); + } } } else { - result = validateAssumptionSMTSolver(lattice, assumption); - } - } + bool subset = true; + auto row1 = matrix.getRow(std::stoi(assumption->getFirstOperand()->asVariableExpression().getVariableName())); + auto row2 = matrix.getRow(std::stoi(assumption->getSecondOperand()->asVariableExpression().getVariableName())); - if (result) { - validatedAssumptions.insert(assumption); - } else { - STORM_LOG_DEBUG("Could not validate: " << *assumption << std::endl); + if (row1.getNumberOfEntries() > row2.getNumberOfEntries()) { + std::swap(row1, row2); + } + for (auto itr1 = row1.begin(); subset && itr1 != row1.end(); ++itr1) { + bool found = false; + for (auto itr2 = row2.begin(); !found && itr2 != row2.end(); ++itr2) { + found = itr1->getColumn() == itr2->getColumn(); + } + subset &= found; + } + + if (subset) { + result = validateAssumptionSMTSolver(lattice, assumption); + validatedAssumptions.insert(assumption); + if (result) { + validAssumptions.insert(assumption); + } + } + } } return result; } @@ -256,30 +277,6 @@ namespace storm { auto row1 = matrix.getRow(std::stoi(assumption->getFirstOperand()->asVariableExpression().getVariableName())); auto row2 = matrix.getRow(std::stoi(assumption->getSecondOperand()->asVariableExpression().getVariableName())); - if (row1.getNumberOfEntries() <= row2.getNumberOfEntries()) { - for (auto itr1 = row1.begin(); result && itr1 != row1.end(); ++itr1) { - bool found = false; - for (auto itr2 = row2.begin(); !found && itr2 != row2.end(); ++itr2) { - found = itr1->getColumn() == itr2->getColumn(); - } - - if (!found) { - result = false; - } - } - } else { - for (auto itr1 = row2.begin(); result && itr1 != row2.end(); ++itr1) { - bool found = false; - for (auto itr2 = row1.begin(); !found && itr2 != row1.end(); ++itr2) { - found = itr1->getColumn() == itr2->getColumn(); - } - - if (!found) { - result = false; - } - } - } - if (result) { storm::solver::Z3SmtSolver s(*manager); if (row1.getNumberOfEntries() >= row2.getNumberOfEntries()) { @@ -356,6 +353,12 @@ namespace storm { return find(validatedAssumptions.begin(), validatedAssumptions.end(), assumption) != validatedAssumptions.end(); } + template + bool AssumptionChecker::valid(std::shared_ptr assumption) { + assert(find(validatedAssumptions.begin(), validatedAssumptions.end(), assumption) != validatedAssumptions.end()); + return find(validAssumptions.begin(), validAssumptions.end(), assumption) != validAssumptions.end(); + } + template class AssumptionChecker; } } diff --git a/src/storm-pars/analysis/AssumptionChecker.h b/src/storm-pars/analysis/AssumptionChecker.h index 6a11f7e6f..059315bfe 100644 --- a/src/storm-pars/analysis/AssumptionChecker.h +++ b/src/storm-pars/analysis/AssumptionChecker.h @@ -59,7 +59,8 @@ namespace storm { * @return true if the assumption has been validated and holds, false otherwise */ bool validated(std::shared_ptr assumption); - + bool valid(std::shared_ptr assumption); + private: std::shared_ptr formula; @@ -69,6 +70,8 @@ namespace storm { std::set> validatedAssumptions; + std::set> validAssumptions; + bool validateAssumptionFunction(storm::analysis::Lattice* lattice, typename storm::storage::SparseMatrix::iterator state1succ1, typename storm::storage::SparseMatrix::iterator state1succ2, diff --git a/src/storm-pars/analysis/AssumptionMaker.cpp b/src/storm-pars/analysis/AssumptionMaker.cpp index 280183184..9e95a0392 100644 --- a/src/storm-pars/analysis/AssumptionMaker.cpp +++ b/src/storm-pars/analysis/AssumptionMaker.cpp @@ -55,6 +55,7 @@ namespace storm { std::tuple criticalTriple = this->latticeExtender->extendLattice(lattice, assumptions.back()); if (validate && assumptionChecker->validated(assumptions.back())) { + assert (assumptionChecker->valid(assumptions.back())); assumptions.pop_back(); } @@ -91,9 +92,17 @@ namespace storm { if (assumptionChecker->checkOnSamples(assumption)) { if (validate) { assumptionChecker->validateAssumption(assumption, lattice); + if (!assumptionChecker->validated(assumption) || assumptionChecker->valid(assumption)) { + assumptions.push_back( + std::shared_ptr(assumption)); + result = (runRecursive(lattice, assumptions)); + } + } else { + assumptions.push_back(std::shared_ptr(assumption)); + result = (runRecursive(lattice, assumptions)); } - assumptions.push_back(std::shared_ptr(assumption)); - result = (runRecursive(lattice, assumptions)); + + } else { delete lattice; } @@ -101,8 +110,6 @@ namespace storm { return result; } - - template class AssumptionMaker; } } From 901105f9e4e2395383e736cdb695ceeaf0468341 Mon Sep 17 00:00:00 2001 From: Jip Spel Date: Fri, 5 Oct 2018 13:44:21 +0200 Subject: [PATCH 102/178] Only divide by denominator when function is not constant --- .../storage/expressions/RationalFunctionToExpression.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/storm/storage/expressions/RationalFunctionToExpression.cpp b/src/storm/storage/expressions/RationalFunctionToExpression.cpp index 8929a58db..81abc8f36 100644 --- a/src/storm/storage/expressions/RationalFunctionToExpression.cpp +++ b/src/storm/storage/expressions/RationalFunctionToExpression.cpp @@ -37,7 +37,6 @@ namespace storm { STORM_LOG_DEBUG("Expecting the denominator to be constant"); } - storm::expressions::Expression denominatorVal = manager->rational(storm::utility::convertNumber(denominator.constantPart())); storm::expressions::Expression result; if (function.isConstant()) { result = manager->rational(storm::utility::convertNumber(function.constantPart())); @@ -56,8 +55,10 @@ namespace storm { result = result + nominatorPartExpr; } } + storm::expressions::Expression denominatorVal = manager->rational(storm::utility::convertNumber(denominator.constantPart())); + result = result / denominatorVal; } - result = result / denominatorVal; + return result; } From 59afd1375a5613dd42a3123a1789862df51dd729 Mon Sep 17 00:00:00 2001 From: Jip Spel Date: Fri, 5 Oct 2018 13:53:06 +0200 Subject: [PATCH 103/178] Update documentation --- src/storm-pars/analysis/AssumptionChecker.h | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/storm-pars/analysis/AssumptionChecker.h b/src/storm-pars/analysis/AssumptionChecker.h index 059315bfe..9ad2aee08 100644 --- a/src/storm-pars/analysis/AssumptionChecker.h +++ b/src/storm-pars/analysis/AssumptionChecker.h @@ -44,21 +44,28 @@ namespace storm { bool checkOnSamples(std::shared_ptr assumption); /*! - * Checks if an assumption can be validated based on the lattice and underlying transition matrix. + * Tries to validate an assumption based on the lattice and underlying transition matrix. * * @param assumption The assumption to validate. * @param lattice The lattice. - * @return true if the assumption is validated and holds, false otherwise + * @return true if the assumption can be validated and holds, false otherwise */ bool validateAssumption(std::shared_ptr assumption, storm::analysis::Lattice* lattice); /*! - * Looks up if assumption has been validated and holds. + * Looks up if assumption has been validated. * * @param assumption The assumption. - * @return true if the assumption has been validated and holds, false otherwise + * @return true if the assumption has been validated. */ bool validated(std::shared_ptr assumption); + + /*! + * Looks up if assumption is valid. Requires the function to be validated. + * + * @param assumption The assumption. + * @return true if the assumption is valid. + */ bool valid(std::shared_ptr assumption); private: From 5a438991e2c337bc2e48588f9324214c502aff8b Mon Sep 17 00:00:00 2001 From: Jip Spel Date: Mon, 8 Oct 2018 09:07:58 +0200 Subject: [PATCH 104/178] Delete lattice when assumption is not valid --- src/storm-pars/analysis/AssumptionMaker.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/storm-pars/analysis/AssumptionMaker.cpp b/src/storm-pars/analysis/AssumptionMaker.cpp index 9e95a0392..deb3913cd 100644 --- a/src/storm-pars/analysis/AssumptionMaker.cpp +++ b/src/storm-pars/analysis/AssumptionMaker.cpp @@ -96,6 +96,8 @@ namespace storm { assumptions.push_back( std::shared_ptr(assumption)); result = (runRecursive(lattice, assumptions)); + } else if (assumptionChecker->validated(assumption) && !assumptionChecker->valid(assumption)) { + delete lattice; } } else { assumptions.push_back(std::shared_ptr(assumption)); From 8c7808b0df794e4855bc392efc0a59788055978a Mon Sep 17 00:00:00 2001 From: Jip Spel Date: Mon, 8 Oct 2018 09:09:36 +0200 Subject: [PATCH 105/178] No need to check for state breaking the SCC --- src/storm-pars/analysis/LatticeExtender.cpp | 24 +++------------------ 1 file changed, 3 insertions(+), 21 deletions(-) diff --git a/src/storm-pars/analysis/LatticeExtender.cpp b/src/storm-pars/analysis/LatticeExtender.cpp index 24058fd8a..324c8be8f 100644 --- a/src/storm-pars/analysis/LatticeExtender.cpp +++ b/src/storm-pars/analysis/LatticeExtender.cpp @@ -37,27 +37,9 @@ namespace storm { auto scc = decomposition.getBlock(i); if (scc.size() > 1) { auto states = scc.getStates(); - bool added = false; - for (auto itr = states.begin(); !added && itr != states.end(); ++itr) { - auto state = *itr; - storm::storage::BitVector subSystem = storm::storage::BitVector(model->getNumberOfStates()); - subSystem.set(states.begin(), states.end(), true); - subSystem.set(state, false); - auto subDecomposition = storm::storage::StronglyConnectedComponentDecomposition(model->getTransitionMatrix(), subSystem, false, false); - bool acyclic = true; - for (auto i = 0; acyclic && i < subDecomposition.size(); ++i) { - auto subScc = subDecomposition.getBlock(i); - acyclic = subScc.size() <= 1; - } - if (acyclic) { - initialMiddleStates.set(state); - added = true; - } - } - if (!added) { - // Add one of the states of the scc - initialMiddleStates.set(*(states.begin())); - } + // TODO: Smarter state picking + // Add one of the states of the scc + initialMiddleStates.set(*(states.begin())); } } } From cca2ad474e2adc2b5881f2bdb2a6861caf0f0ad9 Mon Sep 17 00:00:00 2001 From: Jip Spel Date: Mon, 8 Oct 2018 11:12:15 +0200 Subject: [PATCH 106/178] First check on samples for monotonicity --- src/storm-pars-cli/storm-pars.cpp | 40 +----- .../analysis/MonotonicityChecker.cpp | 120 +++++++++++++++++- src/storm-pars/analysis/MonotonicityChecker.h | 28 +++- .../analysis/MonotonicityCheckerTest.cpp | 64 +++++++++- 4 files changed, 210 insertions(+), 42 deletions(-) diff --git a/src/storm-pars-cli/storm-pars.cpp b/src/storm-pars-cli/storm-pars.cpp index a32a92f3d..0e4a61bf6 100644 --- a/src/storm-pars-cli/storm-pars.cpp +++ b/src/storm-pars-cli/storm-pars.cpp @@ -1,9 +1,5 @@ - -#include "storm-pars/analysis/AssumptionMaker.h" -#include "storm-pars/analysis/Lattice.h" -#include "storm-pars/analysis/LatticeExtender.h" #include "storm-pars/analysis/MonotonicityChecker.h" #include "storm-cli-utilities/cli.h" @@ -529,40 +525,12 @@ namespace storm { std::cout << "Hello, Jip2" << std::endl; std::vector> formulas = storm::api::extractFormulasFromProperties(input.properties); - std::shared_ptr> sparseModel = model->as>(); - - // Transform to Lattices - storm::utility::Stopwatch latticeWatch(true); - storm::analysis::LatticeExtender *extender = new storm::analysis::LatticeExtender(sparseModel); - std::tuple criticalTuple = extender->toLattice(formulas); - std::map>> result; - if (model->isOfType(storm::models::ModelType::Dtmc)) { - auto dtmcModel = model->as>(); - auto assumptionChecker = storm::analysis::AssumptionChecker(formulas[0], dtmcModel, 3); - auto assumptionMaker = storm::analysis::AssumptionMaker(extender, &assumptionChecker, sparseModel->getNumberOfStates(), parSettings.isValidateAssumptionsSet()); - result = assumptionMaker.makeAssumptions(std::get<0>(criticalTuple), std::get<1>(criticalTuple), std::get<2>(criticalTuple)); - } else if (model->isOfType(storm::models::ModelType::Dtmc)) { - auto mdpModel = model->as>(); - auto assumptionChecker = storm::analysis::AssumptionChecker(formulas[0], mdpModel, 3); - auto assumptionMaker = storm::analysis::AssumptionMaker(extender, &assumptionChecker, sparseModel->getNumberOfStates(), parSettings.isValidateAssumptionsSet()); - result = assumptionMaker.makeAssumptions(std::get<0>(criticalTuple), std::get<1>(criticalTuple), std::get<2>(criticalTuple)); - } else { - STORM_LOG_THROW(false, storm::exceptions::InvalidOperationException, "Unable to perform monotonicity analysis on the provided model type."); - } - - - latticeWatch.stop(); - STORM_PRINT(std::endl << "Time for lattice creation: " << latticeWatch << "." << std::endl << std::endl); - // Monotonicity? + // Monotonicity storm::utility::Stopwatch monotonicityWatch(true); - if (result.size() > 0) { - auto monotonicityChecker = storm::analysis::MonotonicityChecker(); - monotonicityChecker.checkMonotonicity(result, sparseModel->getTransitionMatrix()); - monotonicityWatch.stop(); - } else { - STORM_PRINT(std::endl << "Could not find monotonicity, no lattices created" << std::endl); - } + auto monotonicityChecker = storm::analysis::MonotonicityChecker(model, formulas, parSettings.isValidateAssumptionsSet()); + monotonicityChecker.checkMonotonicity(); + monotonicityWatch.stop(); STORM_PRINT(std::endl << "Time for monotonicity: " << monotonicityWatch << "." << std::endl << std::endl); diff --git a/src/storm-pars/analysis/MonotonicityChecker.cpp b/src/storm-pars/analysis/MonotonicityChecker.cpp index 3a97e200b..eb8d74bf2 100644 --- a/src/storm-pars/analysis/MonotonicityChecker.cpp +++ b/src/storm-pars/analysis/MonotonicityChecker.cpp @@ -3,11 +3,50 @@ // #include "MonotonicityChecker.h" +#include "storm-pars/analysis/AssumptionMaker.h" +#include "storm-pars/analysis/AssumptionChecker.h" +#include "storm-pars/analysis/Lattice.h" +#include "storm-pars/analysis/LatticeExtender.h" + #include "storm/exceptions/NotSupportedException.h" -#include "storm/exceptions/UnexpectedException.h" +#include "storm/exceptions/UnexpectedException.h" +#include "storm/exceptions/InvalidOperationException.h" + +#include "storm/utility/Stopwatch.h" +#include "storm/models/ModelType.h" + +#include "storm/modelchecker/results/CheckResult.h" +#include "storm/modelchecker/results/ExplicitQuantitativeCheckResult.h" + namespace storm { namespace analysis { + template + MonotonicityChecker::MonotonicityChecker(std::shared_ptr model, std::vector> formulas, bool validate) { + this->model = model; + this->formulas = formulas; + this->validate = validate; + } + + template + std::map>> MonotonicityChecker::checkMonotonicity() { + bool maybeMonotone = true; + if (model->isOfType(storm::models::ModelType::Dtmc)) { + auto dtmcModel = model->as>(); + maybeMonotone = checkOnSamples(dtmcModel,3); + } //TODO mdp + if (maybeMonotone) { + auto map = createLattice(); + std::shared_ptr> sparseModel = model->as>(); + auto matrix = sparseModel->getTransitionMatrix(); + return checkMonotonicity(map, matrix); + } else { + std::map>> result; + std::cout << "Not monotone" << std::endl; + return result; + } + } + template std::map>> MonotonicityChecker::checkMonotonicity(std::map>> map, storm::storage::SparseMatrix matrix) { auto i = 0; @@ -65,6 +104,33 @@ namespace storm { return result; } + template + std::map>> MonotonicityChecker::createLattice() { + // Transform to Lattices + storm::utility::Stopwatch latticeWatch(true); + std::shared_ptr> sparseModel = model->as>(); + storm::analysis::LatticeExtender *extender = new storm::analysis::LatticeExtender(sparseModel); + std::tuple criticalTuple = extender->toLattice(formulas); + std::map>> result; + if (model->isOfType(storm::models::ModelType::Dtmc)) { + auto dtmcModel = model->as>(); + auto assumptionChecker = storm::analysis::AssumptionChecker(formulas[0], dtmcModel, 3); + auto assumptionMaker = storm::analysis::AssumptionMaker(extender, &assumptionChecker, sparseModel->getNumberOfStates(), validate); + result = assumptionMaker.makeAssumptions(std::get<0>(criticalTuple), std::get<1>(criticalTuple), std::get<2>(criticalTuple)); + } else if (model->isOfType(storm::models::ModelType::Dtmc)) { + auto mdpModel = model->as>(); + auto assumptionChecker = storm::analysis::AssumptionChecker(formulas[0], mdpModel, 3); + auto assumptionMaker = storm::analysis::AssumptionMaker(extender, &assumptionChecker, sparseModel->getNumberOfStates(), validate); + result = assumptionMaker.makeAssumptions(std::get<0>(criticalTuple), std::get<1>(criticalTuple), std::get<2>(criticalTuple)); + } else { + STORM_LOG_THROW(false, storm::exceptions::InvalidOperationException, "Unable to perform monotonicity analysis on the provided model type."); + } + + latticeWatch.stop(); + STORM_PRINT(std::endl << "Time for lattice creation: " << latticeWatch << "." << std::endl << std::endl); + return result; + } + template std::map> MonotonicityChecker::analyseMonotonicity(uint_fast64_t j, storm::analysis::Lattice* lattice, storm::storage::SparseMatrix matrix) { std::map> varsMonotone; @@ -163,6 +229,58 @@ namespace storm { return varsMonotone; } + template + bool MonotonicityChecker::checkOnSamples(std::shared_ptr> model, uint_fast64_t numberOfSamples) { + bool monDecr = true; + bool monIncr = true; + + auto instantiator = storm::utility::ModelInstantiator, storm::models::sparse::Dtmc>(*model); + auto matrix = model->getTransitionMatrix(); + std::set variables = storm::models::sparse::getProbabilityParameters(*model); + double previous = -1; + for (auto i = 0; i < numberOfSamples; ++i) { + auto valuation = storm::utility::parametric::Valuation(); + for (auto itr = variables.begin(); itr != variables.end(); ++itr) { + // TODO: Type + auto val = std::pair((*itr), storm::utility::convertNumber(boost::lexical_cast((i+1)/(double (numberOfSamples + 1))))); + valuation.insert(val); + } + storm::models::sparse::Dtmc sampleModel = instantiator.instantiate(valuation); + auto checker = storm::modelchecker::SparseDtmcPrctlModelChecker>(sampleModel); + std::unique_ptr checkResult; + auto formula = formulas[0]; + if (formula->isProbabilityOperatorFormula() && + formula->asProbabilityOperatorFormula().getSubformula().isUntilFormula()) { + const storm::modelchecker::CheckTask checkTask = storm::modelchecker::CheckTask( + (*formula).asProbabilityOperatorFormula().getSubformula().asUntilFormula()); + checkResult = checker.computeUntilProbabilities(Environment(), checkTask); + } else if (formula->isProbabilityOperatorFormula() && + formula->asProbabilityOperatorFormula().getSubformula().isEventuallyFormula()) { + const storm::modelchecker::CheckTask checkTask = storm::modelchecker::CheckTask( + (*formula).asProbabilityOperatorFormula().getSubformula().asEventuallyFormula()); + checkResult = checker.computeReachabilityProbabilities(Environment(), checkTask); + } else { + STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, + "Expecting until or eventually formula"); + } + auto quantitativeResult = checkResult->asExplicitQuantitativeCheckResult(); + std::vector values = quantitativeResult.getValueVector(); + auto initialStates = model->getInitialStates(); + double initial = 0; + for (auto i = initialStates.getNextSetIndex(0); i < model->getNumberOfStates(); i = initialStates.getNextSetIndex(i+1)) { + initial += values[i]; + } + if (previous != -1) { + monDecr &= previous >= initial; + monIncr &= previous <= initial; + } + previous = initial; + } + + bool result = monDecr || monIncr; + return result; + } + template class MonotonicityChecker; } } diff --git a/src/storm-pars/analysis/MonotonicityChecker.h b/src/storm-pars/analysis/MonotonicityChecker.h index 9fe48067e..81300897c 100644 --- a/src/storm-pars/analysis/MonotonicityChecker.h +++ b/src/storm-pars/analysis/MonotonicityChecker.h @@ -8,8 +8,13 @@ #include #include "Lattice.h" #include "storm/storage/expressions/BinaryRelationExpression.h" -#include "storm/storage/SparseMatrix.h" + #include "carl/core/Variable.h" +#include "storm/models/ModelBase.h" +#include "storm/models/sparse/Dtmc.h" +#include "storm/models/sparse/Mdp.h" +#include "storm/logic/Formula.h" +#include "storm/storage/SparseMatrix.h" namespace storm { namespace analysis { @@ -18,17 +23,38 @@ namespace storm { class MonotonicityChecker { public: + MonotonicityChecker(std::shared_ptr model, std::vector> formulas, bool validate); /*! * Checks for all lattices in the map if they are monotone increasing or monotone decreasing. * * @param map The map with lattices and the assumptions made to create the lattices. * @param matrix The transition matrix. + * @return TODO */ std::map>> checkMonotonicity(std::map>> map, storm::storage::SparseMatrix matrix); + /*! + * TODO + * @param model + * @param formulas + * @param validate + * @return + */ + std::map>> checkMonotonicity(); + private: + //TODO: variabele type std::map> analyseMonotonicity(uint_fast64_t i, storm::analysis::Lattice* lattice, storm::storage::SparseMatrix matrix) ; + std::map>> createLattice(); + + bool checkOnSamples(std::shared_ptr> model, uint_fast64_t numberOfSamples); + + std::shared_ptr model; + + std::vector> formulas; + + bool validate; }; } } diff --git a/src/test/storm-pars/analysis/MonotonicityCheckerTest.cpp b/src/test/storm-pars/analysis/MonotonicityCheckerTest.cpp index b7d40675a..7912bf7b0 100644 --- a/src/test/storm-pars/analysis/MonotonicityCheckerTest.cpp +++ b/src/test/storm-pars/analysis/MonotonicityCheckerTest.cpp @@ -10,8 +10,27 @@ #include "storm/storage/SparseMatrix.h" #include "storm/adapters/RationalFunctionAdapter.h" -TEST(MonotonicityCheckerTest, Monotone) { - auto checker = storm::analysis::MonotonicityChecker(); +#include "storm-parsers/parser/FormulaParser.h" +#include "storm/logic/Formulas.h" +#include "storm/models/sparse/StandardRewardModel.h" +#include "storm/modelchecker/prctl/SparseDtmcPrctlModelChecker.h" +#include "storm/modelchecker/results/ExplicitQuantitativeCheckResult.h" +#include "storm-parsers/parser/AutoParser.h" +#include "storm-parsers/parser/PrismParser.h" +#include "storm/storage/expressions/ExpressionManager.h" +#include "storm/api/builder.h" + +#include "storm-pars/transformer/SparseParametricDtmcSimplifier.h" + +#include "storm-pars/api/storm-pars.h" +#include "storm/api/storm.h" + +#include "storm-parsers/api/storm-parsers.h" + +TEST(MonotonicityCheckerTest, Monotone_no_model) { + std::shared_ptr model; + std::vector> formulas; + auto checker = storm::analysis::MonotonicityChecker(model, formulas, false); // Build lattice auto numberOfStates = 4; auto above = storm::storage::BitVector(numberOfStates); @@ -53,8 +72,10 @@ TEST(MonotonicityCheckerTest, Monotone) { EXPECT_TRUE(entry2->second.second); } -TEST(MonotonicityCheckerTest, NotMonotone) { - auto checker = storm::analysis::MonotonicityChecker(); +TEST(MonotonicityCheckerTest, Not_monotone_no_model) { + std::shared_ptr model; + std::vector> formulas; + auto checker = storm::analysis::MonotonicityChecker(model, formulas, false); // Build lattice auto numberOfStates = 4; auto above = storm::storage::BitVector(numberOfStates); @@ -89,4 +110,39 @@ TEST(MonotonicityCheckerTest, NotMonotone) { ASSERT_EQ("p", entry1->first.name()); EXPECT_FALSE(entry1->second.first); EXPECT_FALSE(entry1->second.second); +} + +TEST(MonotonicityCheckerTest, Brp_with_bisimulation) { + std::string programFile = STORM_TEST_RESOURCES_DIR "/pdtmc/brp16_2.pm"; + std::string formulaAsString = "P=? [F s=4 & i=N ]"; + std::string constantsAsString = ""; //e.g. pL=0.9,TOACK=0.5 + + // Program and formula + storm::prism::Program program = storm::api::parseProgram(programFile); + program = storm::utility::prism::preprocess(program, constantsAsString); + std::vector> formulas = storm::api::extractFormulasFromProperties(storm::api::parsePropertiesForPrismProgram(formulaAsString, program)); + std::shared_ptr> model = storm::api::buildSparseModel(program, formulas)->as>(); + std::shared_ptr> dtmc = model->as>(); + auto simplifier = storm::transformer::SparseParametricDtmcSimplifier>(*dtmc); + ASSERT_TRUE(simplifier.simplify(*(formulas[0]))); + model = simplifier.getSimplifiedModel(); + + // Apply bisimulation + storm::storage::BisimulationType bisimType = storm::storage::BisimulationType::Strong; + if (storm::settings::getModule().isWeakBisimulationSet()) { + bisimType = storm::storage::BisimulationType::Weak; + } + + dtmc = storm::api::performBisimulationMinimization(model, formulas, bisimType)->as>(); + + ASSERT_EQ(dtmc->getNumberOfStates(), 99ull); + ASSERT_EQ(dtmc->getNumberOfTransitions(), 195ull); + + storm::analysis::MonotonicityChecker monotonicityChecker = storm::analysis::MonotonicityChecker(dtmc, formulas, true); + auto result = monotonicityChecker.checkMonotonicity(); + EXPECT_EQ(result.size(), 1); + EXPECT_EQ(result.begin()->second.size(), 2); + auto monotone = result.begin()->second.begin(); + EXPECT_EQ(monotone->second.first, true); + EXPECT_EQ(monotone->second.second, false); } \ No newline at end of file From f098daf2f3fd0863311c51496c8c942db03a1a1e Mon Sep 17 00:00:00 2001 From: Jip Spel Date: Mon, 8 Oct 2018 11:40:14 +0200 Subject: [PATCH 107/178] Add stopwatches --- src/storm-pars-cli/storm-pars.cpp | 2 +- src/storm-pars/analysis/LatticeExtender.cpp | 8 ++++++++ src/storm-pars/analysis/MonotonicityChecker.cpp | 7 ++++++- 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/src/storm-pars-cli/storm-pars.cpp b/src/storm-pars-cli/storm-pars.cpp index 0e4a61bf6..9e44097ee 100644 --- a/src/storm-pars-cli/storm-pars.cpp +++ b/src/storm-pars-cli/storm-pars.cpp @@ -531,7 +531,7 @@ namespace storm { auto monotonicityChecker = storm::analysis::MonotonicityChecker(model, formulas, parSettings.isValidateAssumptionsSet()); monotonicityChecker.checkMonotonicity(); monotonicityWatch.stop(); - STORM_PRINT(std::endl << "Time for monotonicity: " << monotonicityWatch << "." << std::endl + STORM_PRINT(std::endl << "Total time for monotonicity checking: " << monotonicityWatch << "." << std::endl << std::endl); std::cout << "Bye, Jip2" << std::endl; diff --git a/src/storm-pars/analysis/LatticeExtender.cpp b/src/storm-pars/analysis/LatticeExtender.cpp index 324c8be8f..acb2a8952 100644 --- a/src/storm-pars/analysis/LatticeExtender.cpp +++ b/src/storm-pars/analysis/LatticeExtender.cpp @@ -22,6 +22,8 @@ #include "storm/storage/BitVector.h" #include "storm/utility/macros.h" +#include "storm/utility/Stopwatch.h" + namespace storm { namespace analysis { @@ -46,6 +48,8 @@ namespace storm { template std::tuple LatticeExtender::toLattice(std::vector> formulas) { + storm::utility::Stopwatch latticeWatch(true); + STORM_LOG_THROW((++formulas.begin()) == formulas.end(), storm::exceptions::NotSupportedException, "Only one formula allowed for monotonicity analysis"); STORM_LOG_THROW((*(formulas[0])).isProbabilityOperatorFormula() && ((*(formulas[0])).asProbabilityOperatorFormula().getSubformula().isUntilFormula() @@ -92,6 +96,10 @@ namespace storm { for (auto state = initialMiddleStates.getNextSetIndex(0); state != numberOfStates; state = initialMiddleStates.getNextSetIndex(state + 1)) { lattice->add(state); } + + + latticeWatch.stop(); + STORM_PRINT(std::endl << "Time for initialization of lattice: " << latticeWatch << "." << std::endl << std::endl); return this->extendLattice(lattice); } diff --git a/src/storm-pars/analysis/MonotonicityChecker.cpp b/src/storm-pars/analysis/MonotonicityChecker.cpp index eb8d74bf2..2d99dcc45 100644 --- a/src/storm-pars/analysis/MonotonicityChecker.cpp +++ b/src/storm-pars/analysis/MonotonicityChecker.cpp @@ -49,6 +49,8 @@ namespace storm { template std::map>> MonotonicityChecker::checkMonotonicity(std::map>> map, storm::storage::SparseMatrix matrix) { + storm::utility::Stopwatch finalCheckWatch(true); + auto i = 0; std::map>> result; for (auto itr = map.begin(); i < map.size() && itr != map.end(); ++itr) { @@ -101,6 +103,9 @@ namespace storm { } ++i; } + + finalCheckWatch.stop(); + STORM_PRINT(std::endl << "Time for monotonicitycheck on lattice: " << finalCheckWatch << "." << std::endl << std::endl); return result; } @@ -127,7 +132,7 @@ namespace storm { } latticeWatch.stop(); - STORM_PRINT(std::endl << "Time for lattice creation: " << latticeWatch << "." << std::endl << std::endl); + STORM_PRINT(std::endl << "Total time for lattice creation: " << latticeWatch << "." << std::endl << std::endl); return result; } From 229ce127e683a733ab057cc2b331a8c0c315dab3 Mon Sep 17 00:00:00 2001 From: Jip Spel Date: Wed, 10 Oct 2018 09:48:50 +0200 Subject: [PATCH 108/178] Fix TODO and improve initial check on samples --- .../analysis/MonotonicityChecker.cpp | 316 ++++++++++++------ src/storm-pars/analysis/MonotonicityChecker.h | 6 +- 2 files changed, 224 insertions(+), 98 deletions(-) diff --git a/src/storm-pars/analysis/MonotonicityChecker.cpp b/src/storm-pars/analysis/MonotonicityChecker.cpp index 2d99dcc45..998a8481d 100644 --- a/src/storm-pars/analysis/MonotonicityChecker.cpp +++ b/src/storm-pars/analysis/MonotonicityChecker.cpp @@ -30,19 +30,32 @@ namespace storm { template std::map>> MonotonicityChecker::checkMonotonicity() { - bool maybeMonotone = true; + std::map> maybeMonotone; if (model->isOfType(storm::models::ModelType::Dtmc)) { - auto dtmcModel = model->as>(); - maybeMonotone = checkOnSamples(dtmcModel,3); - } //TODO mdp - if (maybeMonotone) { + auto dtmc = model->as>(); + maybeMonotone = checkOnSamples(dtmc,3); + } else if (model->isOfType(storm::models::ModelType::Mdp)) { + auto mdp = model->as>(); + maybeMonotone = checkOnSamples(mdp,3); + } else { + STORM_LOG_THROW(false, storm::exceptions::InvalidOperationException, "Unable to perform monotonicity analysis on the provided model type."); + } + + bool allNotMonotone = true; + for (auto itr = maybeMonotone.begin(); itr != maybeMonotone.end(); ++itr) { + if (itr->second.first || itr->second.second) { + allNotMonotone = false; + } + } + + if (!allNotMonotone) { auto map = createLattice(); std::shared_ptr> sparseModel = model->as>(); auto matrix = sparseModel->getTransitionMatrix(); return checkMonotonicity(map, matrix); } else { std::map>> result; - std::cout << "Not monotone" << std::endl; + STORM_PRINT(std::endl << "Not monotone in all parameters" << std::endl); return result; } } @@ -86,15 +99,19 @@ namespace storm { STORM_PRINT("Result is constant" << std::endl); } else { for (auto itr2 = varsMonotone.begin(); itr2 != varsMonotone.end(); ++itr2) { - if (itr2->second.first) { - STORM_PRINT(" - Monotone increasing in: " << itr2->first << std::endl); + if (!resultCheckOnSamples[itr2->first].first && !resultCheckOnSamples[itr2->first].second) { + STORM_PRINT(" - Not monotone in: " << itr2->first << std::endl); } else { - STORM_PRINT(" - Do not know if monotone increasing in: " << itr2->first << std::endl); - } - if (itr2->second.second) { - STORM_PRINT(" - Monotone decreasing in: " << itr2->first << std::endl); - } else { - STORM_PRINT(" - Do not know if monotone decreasing in: " << itr2->first << std::endl); + if (itr2->second.first) { + STORM_PRINT(" - Monotone increasing in: " << itr2->first << std::endl); + } else { + STORM_PRINT(" - Do not know if monotone increasing in: " << itr2->first << std::endl); + } + if (itr2->second.second) { + STORM_PRINT(" - Monotone decreasing in: " << itr2->first << std::endl); + } else { + STORM_PRINT(" - Do not know if monotone decreasing in: " << itr2->first << std::endl); + } } } result.insert( @@ -118,13 +135,13 @@ namespace storm { std::tuple criticalTuple = extender->toLattice(formulas); std::map>> result; if (model->isOfType(storm::models::ModelType::Dtmc)) { - auto dtmcModel = model->as>(); - auto assumptionChecker = storm::analysis::AssumptionChecker(formulas[0], dtmcModel, 3); + auto dtmc = model->as>(); + auto assumptionChecker = storm::analysis::AssumptionChecker(formulas[0], dtmc, 3); auto assumptionMaker = storm::analysis::AssumptionMaker(extender, &assumptionChecker, sparseModel->getNumberOfStates(), validate); result = assumptionMaker.makeAssumptions(std::get<0>(criticalTuple), std::get<1>(criticalTuple), std::get<2>(criticalTuple)); } else if (model->isOfType(storm::models::ModelType::Dtmc)) { - auto mdpModel = model->as>(); - auto assumptionChecker = storm::analysis::AssumptionChecker(formulas[0], mdpModel, 3); + auto mdp = model->as>(); + auto assumptionChecker = storm::analysis::AssumptionChecker(formulas[0], mdp, 3); auto assumptionMaker = storm::analysis::AssumptionMaker(extender, &assumptionChecker, sparseModel->getNumberOfStates(), validate); result = assumptionMaker.makeAssumptions(std::get<0>(criticalTuple), std::get<1>(criticalTuple), std::get<2>(criticalTuple)); } else { @@ -138,6 +155,8 @@ namespace storm { template std::map> MonotonicityChecker::analyseMonotonicity(uint_fast64_t j, storm::analysis::Lattice* lattice, storm::storage::SparseMatrix matrix) { + storm::utility::Stopwatch analyseWatch(true); + std::map> varsMonotone; std::ofstream myfile; std::string filename = "mc" + std::to_string(j) + ".dot"; @@ -165,47 +184,57 @@ namespace storm { auto val = first.getValue(); auto vars = val.gatherVariables(); for (auto itr = vars.begin(); itr != vars.end(); ++itr) { - if (varsMonotone.find(*itr) == varsMonotone.end()) { - varsMonotone[*itr].first = true; - varsMonotone[*itr].second = true; - } - std::pair* value = &varsMonotone.find(*itr)->second; - std::pair old = *value; - - for (auto itr2 = transitions.begin(); itr2 != transitions.end(); ++itr2) { - for (auto itr3 = transitions.begin(); itr3 != transitions.end(); ++itr3) { - auto derivative2 = (*itr2).second.derivative(*itr); - auto derivative3 = (*itr3).second.derivative(*itr); - STORM_LOG_THROW(derivative2.isConstant() && derivative3.isConstant(), storm::exceptions::NotSupportedException, "Expecting derivative to be constant"); - - auto compare = lattice->compare((*itr2).first, (*itr3).first); - - if (compare == storm::analysis::Lattice::ABOVE) { - // As the first state (itr2) is above the second state (itr3) it is sufficient to look at the derivative of itr2. - value->first &=derivative2.constantPart() >= 0; - value->second &=derivative2.constantPart() <= 0; - } else if (compare == storm::analysis::Lattice::BELOW) { - // As the second state (itr3) is above the first state (itr2) it is sufficient to look at the derivative of itr3. - value->first &=derivative3.constantPart() >= 0; - value->second &=derivative3.constantPart() <= 0; - } else if (compare == storm::analysis::Lattice::SAME) { - // Behaviour doesn't matter, as the states are at the same level. - } else { - // As the relation between the states is unknown, we can't claim anything about the monotonicity. - value->first = false; - value->second = false; + if (!resultCheckOnSamples[*itr].first && !resultCheckOnSamples[*itr].second) { + if (varsMonotone.find(*itr) == varsMonotone.end()) { + varsMonotone[*itr].first = false; + varsMonotone[*itr].second = false; + } + color = "color = red, "; + } else { + if (varsMonotone.find(*itr) == varsMonotone.end()) { + varsMonotone[*itr].first = true; + varsMonotone[*itr].second = true; + } + std::pair *value = &varsMonotone.find(*itr)->second; + std::pair old = *value; + + for (auto itr2 = transitions.begin(); itr2 != transitions.end(); ++itr2) { + for (auto itr3 = transitions.begin(); itr3 != transitions.end(); ++itr3) { + auto derivative2 = (*itr2).second.derivative(*itr); + auto derivative3 = (*itr3).second.derivative(*itr); + STORM_LOG_THROW(derivative2.isConstant() && derivative3.isConstant(), + storm::exceptions::NotSupportedException, + "Expecting derivative to be constant"); + + auto compare = lattice->compare((*itr2).first, (*itr3).first); + + if (compare == storm::analysis::Lattice::ABOVE) { + // As the first state (itr2) is above the second state (itr3) it is sufficient to look at the derivative of itr2. + value->first &= derivative2.constantPart() >= 0; + value->second &= derivative2.constantPart() <= 0; + } else if (compare == storm::analysis::Lattice::BELOW) { + // As the second state (itr3) is above the first state (itr2) it is sufficient to look at the derivative of itr3. + value->first &= derivative3.constantPart() >= 0; + value->second &= derivative3.constantPart() <= 0; + } else if (compare == storm::analysis::Lattice::SAME) { + // Behaviour doesn't matter, as the states are at the same level. + } else { + // As the relation between the states is unknown, we can't claim anything about the monotonicity. + value->first = false; + value->second = false; + } } } - } - if ((value->first != old.first) && (value->second != old.second)) { - color = "color = red, "; - } else if ((value->first != old.first)) { - myfile << "\t edge[style=dashed];" << std::endl; - color = "color = blue, "; - } else if ((value->second != old.second)) { - myfile << "\t edge[style=dotted];" << std::endl; - color = "color = blue, "; + if ((value->first != old.first) && (value->second != old.second)) { + color = "color = red, "; + } else if ((value->first != old.first)) { + myfile << "\t edge[style=dashed];" << std::endl; + color = "color = blue, "; + } else if ((value->second != old.second)) { + myfile << "\t edge[style=dotted];" << std::endl; + color = "color = blue, "; + } } } @@ -231,58 +260,151 @@ namespace storm { myfile << "\t}" << std::endl; myfile << "}" << std::endl; myfile.close(); + + analyseWatch.stop(); + STORM_PRINT(std::endl << "Time to check monotonicity based on the lattice: " << analyseWatch << "." << std::endl << std::endl); return varsMonotone; } template - bool MonotonicityChecker::checkOnSamples(std::shared_ptr> model, uint_fast64_t numberOfSamples) { - bool monDecr = true; - bool monIncr = true; + std::map> MonotonicityChecker::checkOnSamples(std::shared_ptr> model, uint_fast64_t numberOfSamples) { + storm::utility::Stopwatch samplesWatch(true); + + std::map> result; auto instantiator = storm::utility::ModelInstantiator, storm::models::sparse::Dtmc>(*model); auto matrix = model->getTransitionMatrix(); - std::set variables = storm::models::sparse::getProbabilityParameters(*model); - double previous = -1; - for (auto i = 0; i < numberOfSamples; ++i) { - auto valuation = storm::utility::parametric::Valuation(); - for (auto itr = variables.begin(); itr != variables.end(); ++itr) { - // TODO: Type - auto val = std::pair((*itr), storm::utility::convertNumber(boost::lexical_cast((i+1)/(double (numberOfSamples + 1))))); - valuation.insert(val); - } - storm::models::sparse::Dtmc sampleModel = instantiator.instantiate(valuation); - auto checker = storm::modelchecker::SparseDtmcPrctlModelChecker>(sampleModel); - std::unique_ptr checkResult; - auto formula = formulas[0]; - if (formula->isProbabilityOperatorFormula() && - formula->asProbabilityOperatorFormula().getSubformula().isUntilFormula()) { - const storm::modelchecker::CheckTask checkTask = storm::modelchecker::CheckTask( - (*formula).asProbabilityOperatorFormula().getSubformula().asUntilFormula()); - checkResult = checker.computeUntilProbabilities(Environment(), checkTask); - } else if (formula->isProbabilityOperatorFormula() && - formula->asProbabilityOperatorFormula().getSubformula().isEventuallyFormula()) { - const storm::modelchecker::CheckTask checkTask = storm::modelchecker::CheckTask( - (*formula).asProbabilityOperatorFormula().getSubformula().asEventuallyFormula()); - checkResult = checker.computeReachabilityProbabilities(Environment(), checkTask); - } else { - STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, - "Expecting until or eventually formula"); - } - auto quantitativeResult = checkResult->asExplicitQuantitativeCheckResult(); - std::vector values = quantitativeResult.getValueVector(); - auto initialStates = model->getInitialStates(); - double initial = 0; - for (auto i = initialStates.getNextSetIndex(0); i < model->getNumberOfStates(); i = initialStates.getNextSetIndex(i+1)) { - initial += values[i]; + std::set variables = storm::models::sparse::getProbabilityParameters(*model); + + for (auto itr = variables.begin(); itr != variables.end(); ++itr) { + double previous = -1; + bool monDecr = true; + bool monIncr = true; + + for (auto i = 0; i < numberOfSamples; ++i) { + auto valuation = storm::utility::parametric::Valuation(); + for (auto itr2 = variables.begin(); itr2 != variables.end(); ++itr2) { + // Only change value for current variable + if ((*itr) == (*itr2)) { + auto val = std::pair( + (*itr2), storm::utility::convertNumber( + boost::lexical_cast((i + 1) / (double(numberOfSamples + 1))))); + valuation.insert(val); + } else { + auto val = std::pair( + (*itr2), storm::utility::convertNumber( + boost::lexical_cast((1) / (double(numberOfSamples + 1))))); + valuation.insert(val); + } + } + storm::models::sparse::Dtmc sampleModel = instantiator.instantiate(valuation); + auto checker = storm::modelchecker::SparseDtmcPrctlModelChecker>(sampleModel); + std::unique_ptr checkResult; + auto formula = formulas[0]; + if (formula->isProbabilityOperatorFormula() && + formula->asProbabilityOperatorFormula().getSubformula().isUntilFormula()) { + const storm::modelchecker::CheckTask checkTask = storm::modelchecker::CheckTask( + (*formula).asProbabilityOperatorFormula().getSubformula().asUntilFormula()); + checkResult = checker.computeUntilProbabilities(Environment(), checkTask); + } else if (formula->isProbabilityOperatorFormula() && + formula->asProbabilityOperatorFormula().getSubformula().isEventuallyFormula()) { + const storm::modelchecker::CheckTask checkTask = storm::modelchecker::CheckTask( + (*formula).asProbabilityOperatorFormula().getSubformula().asEventuallyFormula()); + checkResult = checker.computeReachabilityProbabilities(Environment(), checkTask); + } else { + STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, + "Expecting until or eventually formula"); + } + auto quantitativeResult = checkResult->asExplicitQuantitativeCheckResult(); + std::vector values = quantitativeResult.getValueVector(); + auto initialStates = model->getInitialStates(); + double initial = 0; + for (auto i = initialStates.getNextSetIndex(0); i < model->getNumberOfStates(); i = initialStates.getNextSetIndex(i+1)) { + initial += values[i]; + } + if (previous != -1) { + monDecr &= previous >= initial; + monIncr &= previous <= initial; + } + previous = initial; } - if (previous != -1) { - monDecr &= previous >= initial; - monIncr &= previous <= initial; + result.insert(std::pair>(*itr, std::pair(monIncr, monDecr))); + } + + samplesWatch.stop(); + STORM_PRINT(std::endl << "Time to check monotonicity on samples: " << samplesWatch << "." << std::endl << std::endl); + resultCheckOnSamples = result; + return result; + } + + template + std::map> MonotonicityChecker::checkOnSamples(std::shared_ptr> model, uint_fast64_t numberOfSamples) { + storm::utility::Stopwatch samplesWatch(true); + + std::map> result; + + auto instantiator = storm::utility::ModelInstantiator, storm::models::sparse::Mdp>(*model); + auto matrix = model->getTransitionMatrix(); + std::set variables = storm::models::sparse::getProbabilityParameters(*model); + + for (auto itr = variables.begin(); itr != variables.end(); ++itr) { + double previous = -1; + bool monDecr = true; + bool monIncr = true; + + for (auto i = 0; i < numberOfSamples; ++i) { + auto valuation = storm::utility::parametric::Valuation(); + for (auto itr2 = variables.begin(); itr2 != variables.end(); ++itr2) { + // Only change value for current variable + if ((*itr) == (*itr2)) { + auto val = std::pair( + (*itr2), storm::utility::convertNumber( + boost::lexical_cast((i + 1) / (double(numberOfSamples + 1))))); + valuation.insert(val); + } else { + auto val = std::pair( + (*itr2), storm::utility::convertNumber( + boost::lexical_cast((1) / (double(numberOfSamples + 1))))); + valuation.insert(val); + } + } + storm::models::sparse::Mdp sampleModel = instantiator.instantiate(valuation); + auto checker = storm::modelchecker::SparseMdpPrctlModelChecker>(sampleModel); + std::unique_ptr checkResult; + auto formula = formulas[0]; + if (formula->isProbabilityOperatorFormula() && + formula->asProbabilityOperatorFormula().getSubformula().isUntilFormula()) { + const storm::modelchecker::CheckTask checkTask = storm::modelchecker::CheckTask( + (*formula).asProbabilityOperatorFormula().getSubformula().asUntilFormula()); + checkResult = checker.computeUntilProbabilities(Environment(), checkTask); + } else if (formula->isProbabilityOperatorFormula() && + formula->asProbabilityOperatorFormula().getSubformula().isEventuallyFormula()) { + const storm::modelchecker::CheckTask checkTask = storm::modelchecker::CheckTask( + (*formula).asProbabilityOperatorFormula().getSubformula().asEventuallyFormula()); + checkResult = checker.computeReachabilityProbabilities(Environment(), checkTask); + } else { + STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, + "Expecting until or eventually formula"); + } + auto quantitativeResult = checkResult->asExplicitQuantitativeCheckResult(); + std::vector values = quantitativeResult.getValueVector(); + auto initialStates = model->getInitialStates(); + double initial = 0; + for (auto i = initialStates.getNextSetIndex(0); i < model->getNumberOfStates(); i = initialStates.getNextSetIndex(i+1)) { + initial += values[i]; + } + if (previous != -1) { + monDecr &= previous >= initial; + monIncr &= previous <= initial; + } + previous = initial; } - previous = initial; + result.insert(std::pair>(*itr, std::pair(monIncr, monDecr))); } - bool result = monDecr || monIncr; + samplesWatch.stop(); + STORM_PRINT(std::endl << "Time to check monotonicity on samples: " << samplesWatch << "." << std::endl << std::endl); + resultCheckOnSamples = result; return result; } diff --git a/src/storm-pars/analysis/MonotonicityChecker.h b/src/storm-pars/analysis/MonotonicityChecker.h index 81300897c..44676aa2c 100644 --- a/src/storm-pars/analysis/MonotonicityChecker.h +++ b/src/storm-pars/analysis/MonotonicityChecker.h @@ -48,13 +48,17 @@ namespace storm { std::map>> createLattice(); - bool checkOnSamples(std::shared_ptr> model, uint_fast64_t numberOfSamples); + std::map> checkOnSamples(std::shared_ptr> model, uint_fast64_t numberOfSamples); + + std::map> checkOnSamples(std::shared_ptr> model, uint_fast64_t numberOfSamples); std::shared_ptr model; std::vector> formulas; bool validate; + + std::map> resultCheckOnSamples; }; } } From d64ba97d2f2c3efb68d15ba2efd715dcf4b8cc58 Mon Sep 17 00:00:00 2001 From: Jip Spel Date: Wed, 10 Oct 2018 12:56:26 +0200 Subject: [PATCH 109/178] Change bounds to strictly greater/smaller --- src/storm-pars/analysis/AssumptionChecker.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/storm-pars/analysis/AssumptionChecker.cpp b/src/storm-pars/analysis/AssumptionChecker.cpp index ac6b202ae..b8cfd9d19 100644 --- a/src/storm-pars/analysis/AssumptionChecker.cpp +++ b/src/storm-pars/analysis/AssumptionChecker.cpp @@ -258,7 +258,7 @@ namespace storm { storm::expressions::Expression exprBounds = manager->boolean(true); auto variables = manager->getVariables(); for (auto var : variables) { - exprBounds = exprBounds && var >= 0 && var <= 1; + exprBounds = exprBounds && var > 0 && var < 1; } s.add(exprGiven); @@ -335,7 +335,7 @@ namespace storm { auto variables = manager->getVariables(); for (auto var : variables) { - exprBounds = exprBounds && var >= 0 && var <= 1; + exprBounds = exprBounds && var > 0 && var < 1; } s.add(exprGiven); From e8e87d26d62bf486b5a7a6fa8a8af9c60a763282 Mon Sep 17 00:00:00 2001 From: Jip Spel Date: Wed, 10 Oct 2018 13:48:28 +0200 Subject: [PATCH 110/178] Add check if result actually contains the given variable --- src/storm-pars/analysis/MonotonicityChecker.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/storm-pars/analysis/MonotonicityChecker.cpp b/src/storm-pars/analysis/MonotonicityChecker.cpp index 998a8481d..b6178dfa5 100644 --- a/src/storm-pars/analysis/MonotonicityChecker.cpp +++ b/src/storm-pars/analysis/MonotonicityChecker.cpp @@ -26,6 +26,7 @@ namespace storm { this->model = model; this->formulas = formulas; this->validate = validate; + this->resultCheckOnSamples = std::map>(); } template @@ -99,7 +100,8 @@ namespace storm { STORM_PRINT("Result is constant" << std::endl); } else { for (auto itr2 = varsMonotone.begin(); itr2 != varsMonotone.end(); ++itr2) { - if (!resultCheckOnSamples[itr2->first].first && !resultCheckOnSamples[itr2->first].second) { + if (resultCheckOnSamples.find(itr2->first) != resultCheckOnSamples.end() && + (!resultCheckOnSamples[itr2->first].first && !resultCheckOnSamples[itr2->first].second)) { STORM_PRINT(" - Not monotone in: " << itr2->first << std::endl); } else { if (itr2->second.first) { @@ -184,7 +186,8 @@ namespace storm { auto val = first.getValue(); auto vars = val.gatherVariables(); for (auto itr = vars.begin(); itr != vars.end(); ++itr) { - if (!resultCheckOnSamples[*itr].first && !resultCheckOnSamples[*itr].second) { + if (resultCheckOnSamples.find(*itr) != resultCheckOnSamples.end() && + (!resultCheckOnSamples[*itr].first && !resultCheckOnSamples[*itr].second)) { if (varsMonotone.find(*itr) == varsMonotone.end()) { varsMonotone[*itr].first = false; varsMonotone[*itr].second = false; From 6b216d7fd69276f7888ec3c6b3e8e3c8cb7ad723 Mon Sep 17 00:00:00 2001 From: Jip Spel Date: Thu, 11 Oct 2018 16:09:14 +0200 Subject: [PATCH 111/178] Add additional testsituation --- .../analysis/AssumptionCheckerTest.cpp | 28 ++++++++++++++++--- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/src/test/storm-pars/analysis/AssumptionCheckerTest.cpp b/src/test/storm-pars/analysis/AssumptionCheckerTest.cpp index 86a992c9e..95345eb66 100644 --- a/src/test/storm-pars/analysis/AssumptionCheckerTest.cpp +++ b/src/test/storm-pars/analysis/AssumptionCheckerTest.cpp @@ -28,7 +28,7 @@ #include "storm-parsers/api/storm-parsers.h" // TODO: extend for cases in which checkOnSamples and validateAssumption return true -TEST(AssumptionCheckerTest, Brp) { +TEST(AssumptionCheckerTest, Brp_no_bisimulation) { std::string programFile = STORM_TEST_RESOURCES_DIR "/pdtmc/brp16_2.pm"; std::string formulaAsString = "P=? [F s=4 & i=N ]"; std::string constantsAsString = ""; //e.g. pL=0.9,TOACK=0.5 @@ -62,9 +62,29 @@ TEST(AssumptionCheckerTest, Brp) { storm::expressions::BinaryRelationExpression::RelationType::GreaterOrEqual)); EXPECT_TRUE(checker.checkOnSamples(assumption)); - auto emptyLattice = new storm::analysis::Lattice(storm::storage::BitVector(8), storm::storage::BitVector(8), 8); - // Validate assumptions - EXPECT_FALSE(checker.validateAssumption(assumption, emptyLattice)); + auto dummyLattice = new storm::analysis::Lattice(storm::storage::BitVector(8), storm::storage::BitVector(8), 8); + // Validate assumption + EXPECT_FALSE(checker.validateAssumption(assumption, dummyLattice)); EXPECT_FALSE(checker.validated(assumption)); + + expressionManager->declareRationalVariable("6"); + expressionManager->declareRationalVariable("8"); + assumption = std::make_shared( + storm::expressions::BinaryRelationExpression(*expressionManager, expressionManager->getBooleanType(), + expressionManager->getVariable("6").getExpression().getBaseExpressionPointer(), + expressionManager->getVariable("8").getExpression().getBaseExpressionPointer(), + storm::expressions::BinaryRelationExpression::RelationType::GreaterOrEqual)); + storm::storage::BitVector above(13); + above.set(12); + storm::storage::BitVector below(13); + below.set(9); + dummyLattice = new storm::analysis::Lattice(above, below, 13); + EXPECT_TRUE(checker.checkOnSamples(assumption)); + EXPECT_TRUE(checker.validateAssumption(assumption, dummyLattice)); + EXPECT_TRUE(checker.validated(assumption)); + EXPECT_TRUE(checker.valid(assumption)); } + + + From fbdce446b33c26eb61946c5a03d261257eb902ff Mon Sep 17 00:00:00 2001 From: Jip Spel Date: Thu, 11 Oct 2018 16:12:03 +0200 Subject: [PATCH 112/178] Fix SMT validation of assumptions --- src/storm-pars/analysis/AssumptionChecker.cpp | 209 +++++++++++------- 1 file changed, 126 insertions(+), 83 deletions(-) diff --git a/src/storm-pars/analysis/AssumptionChecker.cpp b/src/storm-pars/analysis/AssumptionChecker.cpp index b8cfd9d19..b454cf451 100644 --- a/src/storm-pars/analysis/AssumptionChecker.cpp +++ b/src/storm-pars/analysis/AssumptionChecker.cpp @@ -146,27 +146,32 @@ namespace storm { } if (state1succ1->getColumn() == state2succ1->getColumn() && state1succ2->getColumn() == state2succ2->getColumn()) { - result = validateAssumptionFunction(lattice, state1succ1, state1succ2, state2succ1, state2succ2); + auto comp = lattice->compare(state1succ1->getColumn(), state1succ2->getColumn()); + if (comp != storm::analysis::Lattice::UNKNOWN) { + result = validateAssumptionFunction(lattice, state1succ1, state1succ2, state2succ1, + state2succ2); if (!result) { - result = validateAssumptionSMTSolver(lattice, state1succ1, state1succ2, state2succ1, state2succ2); + result = validateAssumptionSMTSolver(lattice, state1succ1, state1succ2, state2succ1, + state2succ2); } - validatedAssumptions.insert(assumption); - if (result) { - validAssumptions.insert(assumption); + validatedAssumptions.insert(assumption); + if (result) { + validAssumptions.insert(assumption); + } } } } else { bool subset = true; - auto row1 = matrix.getRow(std::stoi(assumption->getFirstOperand()->asVariableExpression().getVariableName())); - auto row2 = matrix.getRow(std::stoi(assumption->getSecondOperand()->asVariableExpression().getVariableName())); if (row1.getNumberOfEntries() > row2.getNumberOfEntries()) { std::swap(row1, row2); } + storm::storage::BitVector stateNumbers(matrix.getColumnCount()); for (auto itr1 = row1.begin(); subset && itr1 != row1.end(); ++itr1) { bool found = false; + stateNumbers.set(itr1->getColumn()); for (auto itr2 = row2.begin(); !found && itr2 != row2.end(); ++itr2) { found = itr1->getColumn() == itr2->getColumn(); } @@ -174,10 +179,21 @@ namespace storm { } if (subset) { - result = validateAssumptionSMTSolver(lattice, assumption); - validatedAssumptions.insert(assumption); - if (result) { - validAssumptions.insert(assumption); + // Check if they all are in the lattice + bool allInLattice = true; + for (auto i = stateNumbers.getNextSetIndex(0); allInLattice && i < stateNumbers.size(); i = stateNumbers.getNextSetIndex(i+1)) { + for (auto j = stateNumbers.getNextSetIndex(i+1); allInLattice && j < stateNumbers.size(); j = stateNumbers.getNextSetIndex(j+1)) { + auto comp = lattice->compare(i,j); + allInLattice &= comp == storm::analysis::Lattice::ABOVE || comp == storm::analysis::Lattice::BELOW || comp == storm::analysis::Lattice::SAME; + } + } + + if (allInLattice) { + result = validateAssumptionSMTSolver(lattice, assumption); + validatedAssumptions.insert(assumption); + if (result) { + validAssumptions.insert(assumption); + } } } } @@ -195,15 +211,18 @@ namespace storm { && state1succ2->getColumn() == state2succ2->getColumn()) || (state1succ1->getColumn() == state2succ2->getColumn() && state1succ2->getColumn() == state2succ1->getColumn())); + bool result = true; ValueType prob; auto comp = lattice->compare(state1succ1->getColumn(), state1succ2->getColumn()); + assert (comp == storm::analysis::Lattice::ABOVE || comp == storm::analysis::Lattice::BELOW); if (comp == storm::analysis::Lattice::ABOVE) { prob = state1succ1->getValue() - state2succ1->getValue(); } else if (comp == storm::analysis::Lattice::BELOW) { prob = state1succ2->getValue() - state2succ2->getValue(); } + auto vars = prob.gatherVariables(); // TODO: Type @@ -239,112 +258,136 @@ namespace storm { storm::solver::Z3SmtSolver s(*manager); storm::solver::SmtSolver::CheckResult smtResult = storm::solver::SmtSolver::CheckResult::Unknown; + storm::expressions::Variable succ1 = manager->declareRationalVariable(std::to_string(state1succ1->getColumn())); storm::expressions::Variable succ2 = manager->declareRationalVariable(std::to_string(state1succ2->getColumn())); auto comp = lattice->compare(state1succ1->getColumn(), state1succ2->getColumn()); - if (comp == storm::analysis::Lattice::ABOVE || comp == storm::analysis::Lattice::BELOW) { - if (comp == storm::analysis::Lattice::BELOW) { - std::swap(succ1, succ2); - } - storm::expressions::Expression exprGiven = succ1 >= succ2; - - auto valueTypeToExpression = storm::expressions::RationalFunctionToExpression(manager); - storm::expressions::Expression exprToCheck = - (valueTypeToExpression.toExpression(state1succ1->getValue())*succ1 - + valueTypeToExpression.toExpression(state1succ2->getValue())*succ2 - >= valueTypeToExpression.toExpression(state2succ1->getValue())*succ1 - + valueTypeToExpression.toExpression(state2succ2->getValue())*succ2); - - storm::expressions::Expression exprBounds = manager->boolean(true); - auto variables = manager->getVariables(); - for (auto var : variables) { - exprBounds = exprBounds && var > 0 && var < 1; - } - s.add(exprGiven); - s.add(exprToCheck); - s.add(exprBounds); - smtResult = s.check(); + storm::expressions::Expression exprGiven; + if (comp == storm::analysis::Lattice::ABOVE) { + exprGiven = succ1 >= succ2; + } else if (comp == storm::analysis::Lattice::BELOW) { + exprGiven = succ1 <= succ2; + } else { + assert (comp != storm::analysis::Lattice::UNKNOWN); + exprGiven = succ1 = succ2; + } + + auto valueTypeToExpression = storm::expressions::RationalFunctionToExpression(manager); + storm::expressions::Expression exprToCheck = + (valueTypeToExpression.toExpression(state1succ1->getValue())*succ1 + + valueTypeToExpression.toExpression(state1succ2->getValue())*succ2 + >= valueTypeToExpression.toExpression(state2succ1->getValue())*succ1 + + valueTypeToExpression.toExpression(state2succ2->getValue())*succ2); + + storm::expressions::Expression exprBounds = manager->boolean(true); + auto variables = manager->getVariables(); + for (auto var : variables) { + if (var != succ1 && var != succ2) { + // ensure graph-preserving + exprBounds = exprBounds && manager->rational(0) <= var && manager->rational(1) >= var; + } else { + exprBounds = exprBounds && var >= manager->rational(0) && var <= manager->rational(1); + } } + + s.add(exprGiven); + s.add(exprToCheck); + s.add(exprBounds); + smtResult = s.check(); + return smtResult == storm::solver::SmtSolver::CheckResult::Sat; } template bool AssumptionChecker::validateAssumptionSMTSolver(storm::analysis::Lattice* lattice, std::shared_ptr assumption) { + assert (!validated(assumption)); + std::shared_ptr smtSolverFactory = std::make_shared(); std::shared_ptr manager(new storm::expressions::ExpressionManager()); + bool result = true; auto row1 = matrix.getRow(std::stoi(assumption->getFirstOperand()->asVariableExpression().getVariableName())); auto row2 = matrix.getRow(std::stoi(assumption->getSecondOperand()->asVariableExpression().getVariableName())); - if (result) { - storm::solver::Z3SmtSolver s(*manager); - if (row1.getNumberOfEntries() >= row2.getNumberOfEntries()) { - for (auto itr1 = row1.begin(); itr1 != row1.end(); ++itr1) { - manager->declareRationalVariable(std::to_string(itr1->getColumn())); - } - } else { - for (auto itr1 = row2.begin(); itr1 != row2.end(); ++itr1) { - manager->declareRationalVariable(std::to_string(itr1->getColumn())); - } + storm::solver::Z3SmtSolver s(*manager); + std::set stateVariables; + if (row1.getNumberOfEntries() >= row2.getNumberOfEntries()) { + for (auto itr = row1.begin(); itr != row1.end(); ++itr) { + stateVariables.insert(manager->declareRationalVariable(std::to_string(itr->getColumn()))); } + } else { + for (auto itr = row2.begin(); itr != row2.end(); ++itr) { + stateVariables.insert(manager->declareRationalVariable(std::to_string(itr->getColumn()))); + } + } - storm::expressions::Expression exprGiven = manager->boolean(true); + storm::expressions::Expression exprGiven = manager->boolean(true); - for (auto itr1 = row1.begin(); result && itr1 != row1.end(); ++itr1) { - for (auto itr2 = (itr1 + 1); result && itr2 != row1.end(); ++itr2) { + for (auto itr1 = row1.begin(); result && itr1 != row1.end(); ++itr1) { + for (auto itr2 = row1.begin(); result && itr2 != row1.end(); ++itr2) { + if (itr1->getColumn() != itr2->getColumn()) { auto comp = lattice->compare(itr1->getColumn(), itr2->getColumn()); + if (comp == storm::analysis::Lattice::ABOVE) { - exprGiven = exprGiven && (manager->getVariable(std::to_string(itr1->getColumn())) >= manager->getVariable(std::to_string(itr2->getColumn()))); + exprGiven = exprGiven && (manager->getVariable(std::to_string(itr1->getColumn())) >= + manager->getVariable(std::to_string(itr2->getColumn()))); } else if (comp == storm::analysis::Lattice::BELOW) { - exprGiven = exprGiven && (manager->getVariable(std::to_string(itr1->getColumn())) <= manager->getVariable(std::to_string(itr2->getColumn()))); - } else if (comp == storm::analysis::Lattice::SAME) { - exprGiven = exprGiven && (manager->getVariable(std::to_string(itr1->getColumn())) = manager->getVariable(std::to_string(itr2->getColumn()))); + exprGiven = exprGiven && (manager->getVariable(std::to_string(itr1->getColumn())) <= + manager->getVariable(std::to_string(itr2->getColumn()))); } else { - result = false; + assert (comp != storm::analysis::Lattice::UNKNOWN); + exprGiven = exprGiven && + (manager->getVariable(std::to_string(itr1->getColumn())) = manager->getVariable( + std::to_string(itr2->getColumn()))); } } } + } - auto valueTypeToExpression = storm::expressions::RationalFunctionToExpression(manager); - storm::expressions::Expression expr1 = manager->integer(0); - for (auto itr1 = row1.begin(); result && itr1 != row1.end(); ++itr1) { - expr1 = expr1 + (valueTypeToExpression.toExpression(itr1->getValue()) * manager->getVariable(std::to_string(itr1->getColumn()))); - } + auto valueTypeToExpression = storm::expressions::RationalFunctionToExpression(manager); + storm::expressions::Expression expr1 = manager->rational(0); + for (auto itr1 = row1.begin(); result && itr1 != row1.end(); ++itr1) { + expr1 = expr1 + (valueTypeToExpression.toExpression(itr1->getValue()) * manager->getVariable(std::to_string(itr1->getColumn()))); + } - storm::expressions::Expression expr2 = manager->integer(0); - for (auto itr2 = row2.begin(); result && itr2 != row2.end(); ++itr2) { - expr2 = expr2 + (valueTypeToExpression.toExpression(itr2->getValue()) * manager->getVariable(std::to_string(itr2->getColumn()))); - } - storm::expressions::Expression exprToCheck = expr1 >= expr2; + storm::expressions::Expression expr2 = manager->rational(0); + for (auto itr2 = row2.begin(); result && itr2 != row2.end(); ++itr2) { + expr2 = expr2 + (valueTypeToExpression.toExpression(itr2->getValue()) * manager->getVariable(std::to_string(itr2->getColumn()))); + } + storm::expressions::Expression exprToCheck = expr1 >= expr2; - storm::expressions::Expression exprProb1 = manager->integer(0); - for (auto itr1 = row1.begin(); result && itr1 != row1.end(); ++itr1) { - exprProb1 = exprProb1 + (valueTypeToExpression.toExpression(itr1->getValue())); - } + storm::expressions::Expression exprProb1 = manager->rational(0); + for (auto itr1 = row1.begin(); result && itr1 != row1.end(); ++itr1) { + exprProb1 = exprProb1 + (valueTypeToExpression.toExpression(itr1->getValue())); + } - storm::expressions::Expression exprProb2 = manager->integer(0); - for (auto itr2 = row2.begin(); result && itr2 != row2.end(); ++itr2) { - exprProb2 = exprProb2 + (valueTypeToExpression.toExpression(itr2->getValue())); - } + storm::expressions::Expression exprProb2 = manager->rational(0); + for (auto itr2 = row2.begin(); result && itr2 != row2.end(); ++itr2) { + exprProb2 = exprProb2 + (valueTypeToExpression.toExpression(itr2->getValue())); + } - storm::expressions::Expression exprBounds = exprProb1 >= manager->rational(0) - && exprProb1 <= manager->rational(1) - && exprProb2 >= manager->rational(0) - && exprProb2 <= manager->rational(1); + storm::expressions::Expression exprBounds = exprProb1 >= manager->rational(0) + && exprProb1 <= manager->rational(1) + && exprProb2 >= manager->rational(0) + && exprProb2 <= manager->rational(1); - auto variables = manager->getVariables(); - for (auto var : variables) { - exprBounds = exprBounds && var > 0 && var < 1; + auto variables = manager->getVariables(); + for (auto var : variables) { + if (find(stateVariables.begin(), stateVariables.end(), var) != stateVariables.end()) { + // ensure graph-preserving + exprBounds = exprBounds && manager->rational(0) <= var && manager->rational(1) >= var; + } else { + exprBounds = exprBounds && var >= manager->rational(0) && var <= manager->rational(1); } - - s.add(exprGiven); - s.add(exprBounds); - assert(s.check() == storm::solver::SmtSolver::CheckResult::Sat); - s.add(exprToCheck); - auto smtRes = s.check(); - result = result && smtRes == storm::solver::SmtSolver::CheckResult::Sat; } + + s.add(exprGiven); + s.add(exprBounds); + assert(s.check() == storm::solver::SmtSolver::CheckResult::Sat); + s.add(exprToCheck); + auto smtRes = s.check(); + result = result && smtRes == storm::solver::SmtSolver::CheckResult::Sat; return result; } From fbb355eadbb499f65ee4aeeeeeeac4341ca11d07 Mon Sep 17 00:00:00 2001 From: Jip Spel Date: Tue, 16 Oct 2018 11:51:59 +0200 Subject: [PATCH 113/178] Keep assumptions when both assumptions can not be validated and there is some monotonicity --- src/storm-pars/analysis/AssumptionMaker.cpp | 117 +++-------- src/storm-pars/analysis/AssumptionMaker.h | 24 +-- src/storm-pars/analysis/Lattice.cpp | 4 + src/storm-pars/analysis/Lattice.h | 2 + src/storm-pars/analysis/LatticeExtender.cpp | 34 +++- .../analysis/MonotonicityChecker.cpp | 187 ++++++++++++++++-- src/storm-pars/analysis/MonotonicityChecker.h | 14 ++ .../analysis/AssumptionMakerTest.cpp | 33 +++- .../analysis/MonotonicityCheckerTest.cpp | 4 +- 9 files changed, 283 insertions(+), 136 deletions(-) diff --git a/src/storm-pars/analysis/AssumptionMaker.cpp b/src/storm-pars/analysis/AssumptionMaker.cpp index deb3913cd..ceb05ea72 100644 --- a/src/storm-pars/analysis/AssumptionMaker.cpp +++ b/src/storm-pars/analysis/AssumptionMaker.cpp @@ -7,8 +7,7 @@ namespace storm { namespace analysis { template - AssumptionMaker::AssumptionMaker(storm::analysis::LatticeExtender* latticeExtender, storm::analysis::AssumptionChecker* assumptionChecker, uint_fast64_t numberOfStates, bool validate) { - this->latticeExtender = latticeExtender; + AssumptionMaker::AssumptionMaker(storm::analysis::AssumptionChecker* assumptionChecker, uint_fast64_t numberOfStates, bool validate) { this->numberOfStates = numberOfStates; this->assumptionChecker = assumptionChecker; this->validate = validate; @@ -18,100 +17,40 @@ namespace storm { } } - template - std::map>> - AssumptionMaker::makeAssumptions(storm::analysis::Lattice *lattice, uint_fast64_t critical1, - uint_fast64_t critical2) { - std::map>> result; - - std::vector> emptySet; - if (critical1 == numberOfStates || critical2 == numberOfStates) { - result.insert(std::pair>>(lattice, emptySet)); - } else { - storm::expressions::Variable var1 = expressionManager->getVariable(std::to_string(critical1)); - storm::expressions::Variable var2 = expressionManager->getVariable(std::to_string(critical2)); - - std::vector> assumptions; - auto myMap = createAssumptions(var1, var2, new Lattice(lattice), assumptions); - result.insert(myMap.begin(), myMap.end()); - - std::vector> assumptions2; - myMap = createAssumptions(var2, var1, new Lattice(lattice), assumptions2); - result.insert(myMap.begin(), myMap.end()); - if (result.size() == 0) { - // No assumptions could be made, all not valid based on sampling, therefore returning original lattice - result.insert(std::pair>>(lattice, emptySet)); - } else { - delete lattice; - } - } - return result; - } - - template - std::map>> AssumptionMaker::runRecursive(storm::analysis::Lattice* lattice, std::vector> assumptions) { - std::map>> result; - // only the last assumption is new - std::tuple criticalTriple = this->latticeExtender->extendLattice(lattice, assumptions.back()); - - if (validate && assumptionChecker->validated(assumptions.back())) { - assert (assumptionChecker->valid(assumptions.back())); - assumptions.pop_back(); - } - - if (std::get<1>(criticalTriple) == numberOfStates) { - result.insert(std::pair>>(lattice, assumptions)); - } else { - auto val1 = std::get<1>(criticalTriple); - auto val2 = std::get<2>(criticalTriple); - storm::expressions::Variable var1 = expressionManager->getVariable(std::to_string(val1)); - storm::expressions::Variable var2 = expressionManager->getVariable(std::to_string(val2)); - // TODO: check of in lattice de relatie niet al andersom bestaat - - assert(lattice->compare(val1, val2) == storm::analysis::Lattice::UNKNOWN); - auto latticeCopy = new Lattice(lattice); - std::vector> assumptionsCopy = std::vector>( - assumptions); - auto myMap = createAssumptions(var1, var2, latticeCopy, assumptionsCopy); - result.insert(myMap.begin(), myMap.end()); + template + std::map, bool> AssumptionMaker::createAndCheckAssumption(uint_fast64_t val1, uint_fast64_t val2, storm::analysis::Lattice* lattice) { + std::map, bool> result; + + storm::expressions::Variable var1 = expressionManager->getVariable(std::to_string(val1)); + storm::expressions::Variable var2 = expressionManager->getVariable(std::to_string(val2)); + + std::shared_ptr assumption1 + = std::make_shared(storm::expressions::BinaryRelationExpression(*expressionManager, expressionManager->getBooleanType(), + var1.getExpression().getBaseExpressionPointer(), var2.getExpression().getBaseExpressionPointer(), + storm::expressions::BinaryRelationExpression::RelationType::GreaterOrEqual)); + bool result1 = (validate && assumptionChecker->validateAssumption(assumption1, lattice) && assumptionChecker->valid(assumption1)); + result[assumption1] = result1; + + std::shared_ptr assumption2 + = std::make_shared(storm::expressions::BinaryRelationExpression(*expressionManager, expressionManager->getBooleanType(), + var2.getExpression().getBaseExpressionPointer(), var1.getExpression().getBaseExpressionPointer(), + storm::expressions::BinaryRelationExpression::RelationType::GreaterOrEqual)); + bool result2 = (validate && assumptionChecker->validateAssumption(assumption2, lattice) && assumptionChecker->valid(assumption2)); + result[assumption2] = result2; - myMap = createAssumptions(var2, var1, lattice, assumptions); - result.insert(myMap.begin(), myMap.end()); - } return result; } template - std::map>> AssumptionMaker::createAssumptions(storm::expressions::Variable var1, storm::expressions::Variable var2, storm::analysis::Lattice* lattice, std::vector> assumptions) { - std::map>> result; - - std::shared_ptr assumption - = std::make_shared(storm::expressions::BinaryRelationExpression(*expressionManager, expressionManager->getBooleanType(), - var1.getExpression().getBaseExpressionPointer(), var2.getExpression().getBaseExpressionPointer(), - storm::expressions::BinaryRelationExpression::RelationType::GreaterOrEqual)); - if (assumptionChecker->checkOnSamples(assumption)) { - if (validate) { - assumptionChecker->validateAssumption(assumption, lattice); - if (!assumptionChecker->validated(assumption) || assumptionChecker->valid(assumption)) { - assumptions.push_back( - std::shared_ptr(assumption)); - result = (runRecursive(lattice, assumptions)); - } else if (assumptionChecker->validated(assumption) && !assumptionChecker->valid(assumption)) { - delete lattice; - } - } else { - assumptions.push_back(std::shared_ptr(assumption)); - result = (runRecursive(lattice, assumptions)); - } - - - } else { - delete lattice; - } - - return result; + std::shared_ptr AssumptionMaker::createEqualAssumption(uint_fast64_t val1, uint_fast64_t val2) { + storm::expressions::Variable var1 = expressionManager->getVariable(std::to_string(val1)); + storm::expressions::Variable var2 = expressionManager->getVariable(std::to_string(val2)); + return std::make_shared(storm::expressions::BinaryRelationExpression(*expressionManager, expressionManager->getBooleanType(), + var1.getExpression().getBaseExpressionPointer(), var2.getExpression().getBaseExpressionPointer(), + storm::expressions::BinaryRelationExpression::RelationType::Equal)); } + template class AssumptionMaker; } } diff --git a/src/storm-pars/analysis/AssumptionMaker.h b/src/storm-pars/analysis/AssumptionMaker.h index 1381d4ad0..190559a72 100644 --- a/src/storm-pars/analysis/AssumptionMaker.h +++ b/src/storm-pars/analysis/AssumptionMaker.h @@ -20,31 +20,18 @@ namespace storm { public: /*! * Constructs AssumptionMaker based on the lattice extender, the assumption checker and number of states of the model. - * + * TODO * @param latticeExtender The LatticeExtender which needs the assumptions made by the AssumptionMaker. * @param checker The AssumptionChecker which checks the assumptions at sample points. * @param numberOfStates The number of states of the model. */ - AssumptionMaker(storm::analysis::LatticeExtender* latticeExtender, storm::analysis::AssumptionChecker* checker, uint_fast64_t numberOfStates, bool validate); + AssumptionMaker( storm::analysis::AssumptionChecker* checker, uint_fast64_t numberOfStates, bool validate); - /*! - * Make the assumptions given a lattice and two states which could not be added to the lattice. Returns when no more assumptions can be made. - * - * @param lattice The lattice on which assumptions are needed to allow further extension. - * @param critical1 State number - * @param critical2 State number - * @return A mapping from pointers to different lattices and assumptions made to create the specific lattice. - */ - std::map>> makeAssumptions( - storm::analysis::Lattice *lattice, uint_fast64_t critical1, uint_fast64_t critical2); - - private: - std::map>> runRecursive(storm::analysis::Lattice* lattice, std::vector> assumptions); + std::map, bool> createAndCheckAssumption(uint_fast64_t val1, uint_fast64_t val2, storm::analysis::Lattice* lattice); - std::map>> createAssumptions(storm::expressions::Variable var1, storm::expressions::Variable var2, storm::analysis::Lattice* lattice,std::vector> assumptions); - - storm::analysis::LatticeExtender* latticeExtender; + std::shared_ptr createEqualAssumption(uint_fast64_t val1, uint_fast64_t val2); + private: storm::analysis::AssumptionChecker* assumptionChecker; std::shared_ptr expressionManager; @@ -58,3 +45,4 @@ namespace storm { } } #endif //STORM_ASSUMPTIONMAKER_H + diff --git a/src/storm-pars/analysis/Lattice.cpp b/src/storm-pars/analysis/Lattice.cpp index dbf2c0964..e015358cb 100644 --- a/src/storm-pars/analysis/Lattice.cpp +++ b/src/storm-pars/analysis/Lattice.cpp @@ -114,6 +114,10 @@ namespace storm { below->above.insert(above); } + void Lattice::mergeNodes(storm::analysis::Lattice::Node *n1, storm::analysis::Lattice::Node * n2) { + // TODO + } + int Lattice::compare(uint_fast64_t state1, uint_fast64_t state2) { return compare(getNode(state1), getNode(state2)); } diff --git a/src/storm-pars/analysis/Lattice.h b/src/storm-pars/analysis/Lattice.h index 37a86ea5e..b92570e65 100644 --- a/src/storm-pars/analysis/Lattice.h +++ b/src/storm-pars/analysis/Lattice.h @@ -61,6 +61,8 @@ namespace storm { */ void addRelationNodes(storm::analysis::Lattice::Node *above, storm::analysis::Lattice::Node * below); + void mergeNodes(storm::analysis::Lattice::Node *n1, storm::analysis::Lattice::Node * n2); + /*! * Compares the level of the nodes of the states. * Behaviour unknown when one or more of the states doesnot occur at any Node in the Lattice. diff --git a/src/storm-pars/analysis/LatticeExtender.cpp b/src/storm-pars/analysis/LatticeExtender.cpp index acb2a8952..004418d57 100644 --- a/src/storm-pars/analysis/LatticeExtender.cpp +++ b/src/storm-pars/analysis/LatticeExtender.cpp @@ -111,9 +111,34 @@ namespace storm { if (assumption != nullptr) { storm::expressions::BinaryRelationExpression expr = *assumption; STORM_LOG_THROW(expr.getRelationType() == - storm::expressions::BinaryRelationExpression::RelationType::GreaterOrEqual, - storm::exceptions::NotImplementedException, "Only GreaterOrEqual assumptions allowed"); - if (expr.getFirstOperand()->isVariable() && expr.getSecondOperand()->isVariable()) { + storm::expressions::BinaryRelationExpression::RelationType::GreaterOrEqual + || expr.getRelationType() == + storm::expressions::BinaryRelationExpression::RelationType::Equal, + storm::exceptions::NotImplementedException, "Only GreaterOrEqual or Equal assumptions allowed"); + if (expr.getRelationType() == storm::expressions::BinaryRelationExpression::RelationType::Equal) { + assert (expr.getFirstOperand()->isVariable() && expr.getSecondOperand()->isVariable()); + storm::expressions::Variable var1 = expr.getFirstOperand()->asVariableExpression().getVariable(); + storm::expressions::Variable var2 = expr.getSecondOperand()->asVariableExpression().getVariable(); + auto val1 = std::stoul(var1.getName(), nullptr, 0); + auto val2 = std::stoul(var2.getName(), nullptr, 0); + auto comp = lattice->compare(val1, val2); + assert (comp == storm::analysis::Lattice::UNKNOWN || comp == storm::analysis::Lattice::SAME); + storm::analysis::Lattice::Node *n1 = lattice->getNode(val1); + storm::analysis::Lattice::Node *n2 = lattice->getNode(val2); + + if (n1 != nullptr && n2 != nullptr) { + lattice->mergeNodes(n1, n2); + } else if (n1 != nullptr) { + lattice->addToNode(val2, n1); + } else if (n2 != nullptr) { + lattice->addToNode(val1, n2); + } else { + lattice->add(val1); + lattice->addToNode(val2, lattice->getNode(val1)); + + } + } else { + assert (expr.getFirstOperand()->isVariable() && expr.getSecondOperand()->isVariable()); storm::expressions::Variable largest = expr.getFirstOperand()->asVariableExpression().getVariable(); storm::expressions::Variable smallest = expr.getSecondOperand()->asVariableExpression().getVariable(); if (lattice->compare(std::stoul(largest.getName(), nullptr, 0), @@ -127,7 +152,8 @@ namespace storm { if (n1 != nullptr && n2 != nullptr) { lattice->addRelationNodes(n1, n2); } else if (n1 != nullptr) { - lattice->addBetween(std::stoul(smallest.getName(), nullptr, 0), n1, lattice->getBottom()); + lattice->addBetween(std::stoul(smallest.getName(), nullptr, 0), n1, + lattice->getBottom()); } else if (n2 != nullptr) { lattice->addBetween(std::stoul(largest.getName(), nullptr, 0), lattice->getTop(), n2); } else { diff --git a/src/storm-pars/analysis/MonotonicityChecker.cpp b/src/storm-pars/analysis/MonotonicityChecker.cpp index b6178dfa5..56daab152 100644 --- a/src/storm-pars/analysis/MonotonicityChecker.cpp +++ b/src/storm-pars/analysis/MonotonicityChecker.cpp @@ -27,6 +27,10 @@ namespace storm { this->formulas = formulas; this->validate = validate; this->resultCheckOnSamples = std::map>(); + if (model != nullptr) { + std::shared_ptr> sparseModel = model->as>(); + this->extender = new storm::analysis::LatticeExtender(sparseModel); + } } template @@ -124,7 +128,7 @@ namespace storm { } finalCheckWatch.stop(); - STORM_PRINT(std::endl << "Time for monotonicitycheck on lattice: " << finalCheckWatch << "." << std::endl << std::endl); + STORM_PRINT(std::endl << "Time for monotonicity check on lattice: " << finalCheckWatch << "." << std::endl << std::endl); return result; } @@ -132,29 +136,114 @@ namespace storm { std::map>> MonotonicityChecker::createLattice() { // Transform to Lattices storm::utility::Stopwatch latticeWatch(true); - std::shared_ptr> sparseModel = model->as>(); - storm::analysis::LatticeExtender *extender = new storm::analysis::LatticeExtender(sparseModel); std::tuple criticalTuple = extender->toLattice(formulas); + std::map>> result; - if (model->isOfType(storm::models::ModelType::Dtmc)) { - auto dtmc = model->as>(); - auto assumptionChecker = storm::analysis::AssumptionChecker(formulas[0], dtmc, 3); - auto assumptionMaker = storm::analysis::AssumptionMaker(extender, &assumptionChecker, sparseModel->getNumberOfStates(), validate); - result = assumptionMaker.makeAssumptions(std::get<0>(criticalTuple), std::get<1>(criticalTuple), std::get<2>(criticalTuple)); - } else if (model->isOfType(storm::models::ModelType::Dtmc)) { - auto mdp = model->as>(); - auto assumptionChecker = storm::analysis::AssumptionChecker(formulas[0], mdp, 3); - auto assumptionMaker = storm::analysis::AssumptionMaker(extender, &assumptionChecker, sparseModel->getNumberOfStates(), validate); - result = assumptionMaker.makeAssumptions(std::get<0>(criticalTuple), std::get<1>(criticalTuple), std::get<2>(criticalTuple)); + + auto val1 = std::get<1>(criticalTuple); + auto val2 = std::get<2>(criticalTuple); + auto numberOfStates = model->getNumberOfStates(); + std::vector> assumptions; + + if (val1 == numberOfStates && val2 == numberOfStates) { + result.insert(std::pair>>(std::get<0>(criticalTuple), assumptions)); + } else if (val1 != numberOfStates && val2 != numberOfStates) { + + storm::analysis::AssumptionChecker *assumptionChecker; + if (model->isOfType(storm::models::ModelType::Dtmc)) { + auto dtmc = model->as>(); + assumptionChecker = new storm::analysis::AssumptionChecker(formulas[0], dtmc, 3); + } else if (model->isOfType(storm::models::ModelType::Mdp)) { + auto mdp = model->as>(); + assumptionChecker = new storm::analysis::AssumptionChecker(formulas[0], mdp, 3); + } else { + STORM_LOG_THROW(false, storm::exceptions::InvalidOperationException, + "Unable to perform monotonicity analysis on the provided model type."); + } + auto assumptionMaker = new storm::analysis::AssumptionMaker(assumptionChecker, numberOfStates, validate); + result = extendLatticeWithAssumptions(std::get<0>(criticalTuple), assumptionMaker, val1, val2, assumptions); } else { - STORM_LOG_THROW(false, storm::exceptions::InvalidOperationException, "Unable to perform monotonicity analysis on the provided model type."); + assert(false); } - latticeWatch.stop(); STORM_PRINT(std::endl << "Total time for lattice creation: " << latticeWatch << "." << std::endl << std::endl); return result; } + template + std::map>> MonotonicityChecker::extendLatticeWithAssumptions(storm::analysis::Lattice* lattice, storm::analysis::AssumptionMaker* assumptionMaker, uint_fast64_t val1, uint_fast64_t val2, std::vector> assumptions) { + std::map>> result; + + auto numberOfStates = model->getNumberOfStates(); + if (val1 == numberOfStates || val2 == numberOfStates) { + assert (val1 == val2); + result.insert(std::pair>>(lattice, assumptions)); + } else { + auto assumptionPair = assumptionMaker->createAndCheckAssumption(val1, val2, lattice); + assert (assumptionPair.size() == 2); + auto itr = assumptionPair.begin(); + auto assumption1 = *itr; + ++itr; + auto assumption2 = *itr; + + if (!assumption1.second && !assumption2.second) { + // TODO check op lattice of er nog monotonicity is + auto assumptionsCopy = std::vector>(assumptions); + auto latticeCopy = new storm::analysis::Lattice(lattice); + assumptions.push_back(assumption1.first); + assumptionsCopy.push_back(assumption2.first); + + auto criticalTuple = extender->extendLattice(lattice, assumption1.first); + if (somewhereMonotonicity(std::get<0>(criticalTuple))) { + auto map = extendLatticeWithAssumptions(std::get<0>(criticalTuple), assumptionMaker, std::get<1>(criticalTuple), std::get<2>(criticalTuple), assumptions); + result.insert(map.begin(), map.end()); + } + + + criticalTuple = extender->extendLattice(latticeCopy, assumption2.first); + if (somewhereMonotonicity(std::get<0>(criticalTuple))) { + auto map = extendLatticeWithAssumptions(std::get<0>(criticalTuple), assumptionMaker, + std::get<1>(criticalTuple), std::get<2>(criticalTuple), + assumptionsCopy); + result.insert(map.begin(), map.end()); + } + } else if (assumption1.second && assumption2.second) { + auto assumption = assumptionMaker->createEqualAssumption(val1, val2); + if (!validate) { + assumptions.push_back(assumption); + } + // if validate is true and both hold, then they must be valid, so no need to add to assumptions + auto criticalTuple = extender->extendLattice(lattice, assumption); + if (somewhereMonotonicity(std::get<0>(criticalTuple))) { + result = extendLatticeWithAssumptions(std::get<0>(criticalTuple), assumptionMaker, std::get<1>(criticalTuple), std::get<2>(criticalTuple), assumptions); + } + } else if (assumption1.second) { + if (!validate) { + assumptions.push_back(assumption1.first); + } + // if validate is true and both hold, then they must be valid, so no need to add to assumptions + + auto criticalTuple = extender->extendLattice(lattice, assumption1.first); + + if (somewhereMonotonicity(std::get<0>(criticalTuple))) { + result = extendLatticeWithAssumptions(std::get<0>(criticalTuple), assumptionMaker, std::get<1>(criticalTuple), std::get<2>(criticalTuple), assumptions); + } + + } else { + assert (assumption2.second); + if (!validate) { + assumptions.push_back(assumption2.first); + } + // if validate is true and both hold, then they must be valid, so no need to add to assumptions + auto criticalTuple = extender->extendLattice(lattice, assumption2.first); + if (somewhereMonotonicity(std::get<0>(criticalTuple))) { + result = extendLatticeWithAssumptions(std::get<0>(criticalTuple), assumptionMaker, std::get<1>(criticalTuple), std::get<2>(criticalTuple), assumptions); + } + } + } + return result; + } + template std::map> MonotonicityChecker::analyseMonotonicity(uint_fast64_t j, storm::analysis::Lattice* lattice, storm::storage::SparseMatrix matrix) { storm::utility::Stopwatch analyseWatch(true); @@ -220,6 +309,7 @@ namespace storm { value->first &= derivative3.constantPart() >= 0; value->second &= derivative3.constantPart() <= 0; } else if (compare == storm::analysis::Lattice::SAME) { + // TODO: klopt dit // Behaviour doesn't matter, as the states are at the same level. } else { // As the relation between the states is unknown, we can't claim anything about the monotonicity. @@ -269,6 +359,73 @@ namespace storm { return varsMonotone; } + template + bool MonotonicityChecker::somewhereMonotonicity(storm::analysis::Lattice* lattice) { + std::shared_ptr> sparseModel = model->as>(); + auto matrix = sparseModel->getTransitionMatrix(); + + // TODO: tussenresultaten hergebruiken + std::map> varsMonotone; + + for (uint_fast64_t i = 0; i < matrix.getColumnCount(); ++i) { + // go over all rows + auto row = matrix.getRow(i); + auto first = (*row.begin()); + if (first.getValue() != ValueType(1)) { + std::map transitions; + + for (auto itr = row.begin(); itr != row.end(); ++itr) { + transitions.insert(std::pair((*itr).getColumn(), (*itr).getValue())); + } + + auto val = first.getValue(); + auto vars = val.gatherVariables(); + for (auto itr = vars.begin(); itr != vars.end(); ++itr) { + if (varsMonotone.find(*itr) == varsMonotone.end()) { + varsMonotone[*itr].first = true; + varsMonotone[*itr].second = true; + } + std::pair *value = &varsMonotone.find(*itr)->second; + std::pair old = *value; + + for (auto itr2 = transitions.begin(); itr2 != transitions.end(); ++itr2) { + for (auto itr3 = transitions.begin(); itr3 != transitions.end(); ++itr3) { + auto derivative2 = (*itr2).second.derivative(*itr); + auto derivative3 = (*itr3).second.derivative(*itr); + STORM_LOG_THROW(derivative2.isConstant() && derivative3.isConstant(), + storm::exceptions::NotSupportedException, + "Expecting derivative to be constant"); + + auto compare = lattice->compare((*itr2).first, (*itr3).first); + + if (compare == storm::analysis::Lattice::ABOVE) { + // As the first state (itr2) is above the second state (itr3) it is sufficient to look at the derivative of itr2. + value->first &= derivative2.constantPart() >= 0; + value->second &= derivative2.constantPart() <= 0; + } else if (compare == storm::analysis::Lattice::BELOW) { + // As the second state (itr3) is above the first state (itr2) it is sufficient to look at the derivative of itr3. + value->first &= derivative3.constantPart() >= 0; + value->second &= derivative3.constantPart() <= 0; + } else if (compare == storm::analysis::Lattice::SAME) { + // Behaviour doesn't matter, as the states are at the same level. + } else { + // As the relation between the states is unknown, we don't do anything + } + } + } + } + } + } + + bool result = false; + + for (auto itr = varsMonotone.begin(); !result && itr != varsMonotone.end(); ++itr) { + result = itr->second.first || itr->second.second; + } + return result; + } + + template std::map> MonotonicityChecker::checkOnSamples(std::shared_ptr> model, uint_fast64_t numberOfSamples) { storm::utility::Stopwatch samplesWatch(true); diff --git a/src/storm-pars/analysis/MonotonicityChecker.h b/src/storm-pars/analysis/MonotonicityChecker.h index 44676aa2c..c1590dd09 100644 --- a/src/storm-pars/analysis/MonotonicityChecker.h +++ b/src/storm-pars/analysis/MonotonicityChecker.h @@ -7,6 +7,8 @@ #include #include "Lattice.h" +#include "LatticeExtender.h" +#include "AssumptionMaker.h" #include "storm/storage/expressions/BinaryRelationExpression.h" #include "carl/core/Variable.h" @@ -42,6 +44,14 @@ namespace storm { */ std::map>> checkMonotonicity(); + /*! + * TODO + * @param lattice + * @param matrix + * @return + */ + bool somewhereMonotonicity(storm::analysis::Lattice* lattice) ; + private: //TODO: variabele type std::map> analyseMonotonicity(uint_fast64_t i, storm::analysis::Lattice* lattice, storm::storage::SparseMatrix matrix) ; @@ -52,6 +62,8 @@ namespace storm { std::map> checkOnSamples(std::shared_ptr> model, uint_fast64_t numberOfSamples); + std::map>> extendLatticeWithAssumptions(storm::analysis::Lattice* lattice, storm::analysis::AssumptionMaker* assumptionMaker, uint_fast64_t val1, uint_fast64_t val2, std::vector> assumptions); + std::shared_ptr model; std::vector> formulas; @@ -59,6 +71,8 @@ namespace storm { bool validate; std::map> resultCheckOnSamples; + + storm::analysis::LatticeExtender *extender; }; } } diff --git a/src/test/storm-pars/analysis/AssumptionMakerTest.cpp b/src/test/storm-pars/analysis/AssumptionMakerTest.cpp index 722ca69bf..f233d2563 100644 --- a/src/test/storm-pars/analysis/AssumptionMakerTest.cpp +++ b/src/test/storm-pars/analysis/AssumptionMakerTest.cpp @@ -53,12 +53,29 @@ TEST(AssumptionMakerTest, Brp_without_bisimulation) { ASSERT_EQ(186, std::get<2>(criticalTuple)); auto assumptionChecker = storm::analysis::AssumptionChecker(formulas[0], dtmc, 3); - auto assumptionMaker = storm::analysis::AssumptionMaker(extender, &assumptionChecker, dtmc->getNumberOfStates(), true); - auto result = assumptionMaker.makeAssumptions(std::get<0>(criticalTuple), std::get<1>(criticalTuple), std::get<2>(criticalTuple)); - EXPECT_EQ(1, result.size()); - auto lattice = result.begin()->first; - EXPECT_EQ(storm::analysis::Lattice::ABOVE, lattice->compare(186, 183)); - for (auto i = 0; i < dtmc->getNumberOfStates(); ++i) { - EXPECT_TRUE(lattice->getAddedStates()[i]); - } + auto assumptionMaker = storm::analysis::AssumptionMaker(&assumptionChecker, dtmc->getNumberOfStates(), true); + auto result = assumptionMaker.createAndCheckAssumption(std::get<1>(criticalTuple), std::get<2>(criticalTuple), std::get<0>(criticalTuple)); + + auto itr = result.begin(); + + auto var1 = itr->first->getManager().getVariable("183"); + auto var2 = itr->first->getManager().getVariable("186"); + + EXPECT_EQ(2, result.size()); + + EXPECT_EQ(false, itr->second); + EXPECT_EQ(true, itr->first->getFirstOperand()->isVariable()); + EXPECT_EQ(true, itr->first->getSecondOperand()->isVariable()); + EXPECT_EQ(var1, itr->first->getFirstOperand()->asVariableExpression().getVariable()); + EXPECT_EQ(var2, itr->first->getSecondOperand()->asVariableExpression().getVariable()); + EXPECT_EQ(storm::expressions::BinaryRelationExpression::RelationType::GreaterOrEqual, itr->first->getRelationType()); + + ++itr; + EXPECT_EQ(false, itr->second); + EXPECT_EQ(true, itr->first->getFirstOperand()->isVariable()); + EXPECT_EQ(true, itr->first->getSecondOperand()->isVariable()); + EXPECT_EQ(var2, itr->first->getFirstOperand()->asVariableExpression().getVariable()); + EXPECT_EQ(var1, itr->first->getSecondOperand()->asVariableExpression().getVariable()); + EXPECT_EQ(storm::expressions::BinaryRelationExpression::RelationType::GreaterOrEqual, itr->first->getRelationType()); + // TODO: createEqualsAssumption checken } diff --git a/src/test/storm-pars/analysis/MonotonicityCheckerTest.cpp b/src/test/storm-pars/analysis/MonotonicityCheckerTest.cpp index 7912bf7b0..af9f6628f 100644 --- a/src/test/storm-pars/analysis/MonotonicityCheckerTest.cpp +++ b/src/test/storm-pars/analysis/MonotonicityCheckerTest.cpp @@ -140,8 +140,8 @@ TEST(MonotonicityCheckerTest, Brp_with_bisimulation) { storm::analysis::MonotonicityChecker monotonicityChecker = storm::analysis::MonotonicityChecker(dtmc, formulas, true); auto result = monotonicityChecker.checkMonotonicity(); - EXPECT_EQ(result.size(), 1); - EXPECT_EQ(result.begin()->second.size(), 2); + EXPECT_EQ(1, result.size()); + EXPECT_EQ(2, result.begin()->second.size()); auto monotone = result.begin()->second.begin(); EXPECT_EQ(monotone->second.first, true); EXPECT_EQ(monotone->second.second, false); From b0551b540a6324f4afa7ceb1a28ab86c5f1954fd Mon Sep 17 00:00:00 2001 From: Jip Spel Date: Mon, 22 Oct 2018 09:45:48 +0200 Subject: [PATCH 114/178] Add message if nothing about monotonicity is known --- .../analysis/MonotonicityChecker.cpp | 105 ++++++++++-------- 1 file changed, 57 insertions(+), 48 deletions(-) diff --git a/src/storm-pars/analysis/MonotonicityChecker.cpp b/src/storm-pars/analysis/MonotonicityChecker.cpp index 56daab152..5ada44be4 100644 --- a/src/storm-pars/analysis/MonotonicityChecker.cpp +++ b/src/storm-pars/analysis/MonotonicityChecker.cpp @@ -68,63 +68,72 @@ namespace storm { template std::map>> MonotonicityChecker::checkMonotonicity(std::map>> map, storm::storage::SparseMatrix matrix) { storm::utility::Stopwatch finalCheckWatch(true); + std::map>> result; + + if (map.size() == 0) { + STORM_PRINT(std::endl << "Do not know about monotonicity" << std::endl); + } else { + auto i = 0; + + for (auto itr = map.begin(); i < map.size() && itr != map.end(); ++itr) { + auto lattice = itr->first; + auto assumptions = itr->second; + std::ofstream myfile; + std::string filename = "lattice" + std::to_string(i) + ".dot"; + myfile.open(filename); + lattice->toDotFile(myfile); + myfile.close(); + + if (assumptions.size() > 0) { + STORM_PRINT("Given assumptions: " << std::endl); + bool first = true; + for (auto itr2 = assumptions.begin(); itr2 != assumptions.end(); ++itr2) { + if (!first) { + STORM_PRINT(" ^ "); + } else { + STORM_PRINT(" "); + first = false; + } - auto i = 0; - std::map>> result; - for (auto itr = map.begin(); i < map.size() && itr != map.end(); ++itr) { - auto lattice = itr->first; - auto assumptions = itr->second; - std::ofstream myfile; - std::string filename = "lattice" + std::to_string(i) + ".dot"; - myfile.open (filename); - lattice->toDotFile(myfile); - myfile.close(); - - if (assumptions.size() > 0) { - STORM_PRINT("Given assumptions: " << std::endl); - bool first = true; - for (auto itr2 = assumptions.begin(); itr2 != assumptions.end(); ++itr2) { - if (!first) { - STORM_PRINT(" ^ "); - } else { - STORM_PRINT(" "); - first = false; + std::shared_ptr expression = *itr2; + auto var1 = expression->getFirstOperand(); + auto var2 = expression->getSecondOperand(); + STORM_PRINT(*expression); } - - std::shared_ptr expression = *itr2; - auto var1 = expression->getFirstOperand(); - auto var2 = expression->getSecondOperand(); - STORM_PRINT(*expression); + STORM_PRINT(std::endl); } - STORM_PRINT(std::endl); - } - std::map> varsMonotone = analyseMonotonicity(i, lattice, matrix); - if (varsMonotone.size() == 0) { - STORM_PRINT("Result is constant" << std::endl); - } else { - for (auto itr2 = varsMonotone.begin(); itr2 != varsMonotone.end(); ++itr2) { - if (resultCheckOnSamples.find(itr2->first) != resultCheckOnSamples.end() && - (!resultCheckOnSamples[itr2->first].first && !resultCheckOnSamples[itr2->first].second)) { - STORM_PRINT(" - Not monotone in: " << itr2->first << std::endl); - } else { - if (itr2->second.first) { - STORM_PRINT(" - Monotone increasing in: " << itr2->first << std::endl); - } else { - STORM_PRINT(" - Do not know if monotone increasing in: " << itr2->first << std::endl); - } - if (itr2->second.second) { - STORM_PRINT(" - Monotone decreasing in: " << itr2->first << std::endl); + std::map> varsMonotone = analyseMonotonicity(i, lattice, + matrix); + if (varsMonotone.size() == 0) { + STORM_PRINT("Result is constant" << std::endl); + } else { + for (auto itr2 = varsMonotone.begin(); itr2 != varsMonotone.end(); ++itr2) { + if (resultCheckOnSamples.find(itr2->first) != resultCheckOnSamples.end() && + (!resultCheckOnSamples[itr2->first].first && + !resultCheckOnSamples[itr2->first].second)) { + STORM_PRINT(" - Not monotone in: " << itr2->first << std::endl); } else { - STORM_PRINT(" - Do not know if monotone decreasing in: " << itr2->first << std::endl); + if (itr2->second.first) { + STORM_PRINT(" - Monotone increasing in: " << itr2->first << std::endl); + } else { + STORM_PRINT( + " - Do not know if monotone increasing in: " << itr2->first << std::endl); + } + if (itr2->second.second) { + STORM_PRINT(" - Monotone decreasing in: " << itr2->first << std::endl); + } else { + STORM_PRINT( + " - Do not know if monotone decreasing in: " << itr2->first << std::endl); + } } } + result.insert( + std::pair>>( + lattice, varsMonotone)); } - result.insert( - std::pair>>( - lattice, varsMonotone)); + ++i; } - ++i; } finalCheckWatch.stop(); From 954eb1f925aa220c101b5357992747dc0d66de22 Mon Sep 17 00:00:00 2001 From: Jip Spel Date: Wed, 24 Oct 2018 13:00:13 +0200 Subject: [PATCH 115/178] Comment out file creation, add precision check in difference between two samples --- .../analysis/MonotonicityChecker.cpp | 94 +++++++++---------- 1 file changed, 47 insertions(+), 47 deletions(-) diff --git a/src/storm-pars/analysis/MonotonicityChecker.cpp b/src/storm-pars/analysis/MonotonicityChecker.cpp index 5ada44be4..d29779181 100644 --- a/src/storm-pars/analysis/MonotonicityChecker.cpp +++ b/src/storm-pars/analysis/MonotonicityChecker.cpp @@ -69,7 +69,7 @@ namespace storm { std::map>> MonotonicityChecker::checkMonotonicity(std::map>> map, storm::storage::SparseMatrix matrix) { storm::utility::Stopwatch finalCheckWatch(true); std::map>> result; - + if (map.size() == 0) { STORM_PRINT(std::endl << "Do not know about monotonicity" << std::endl); } else { @@ -78,11 +78,11 @@ namespace storm { for (auto itr = map.begin(); i < map.size() && itr != map.end(); ++itr) { auto lattice = itr->first; auto assumptions = itr->second; - std::ofstream myfile; - std::string filename = "lattice" + std::to_string(i) + ".dot"; - myfile.open(filename); - lattice->toDotFile(myfile); - myfile.close(); +// std::ofstream myfile; +// std::string filename = "lattice" + std::to_string(i) + ".dot"; +// myfile.open(filename); +// lattice->toDotFile(myfile); +// myfile.close(); if (assumptions.size() > 0) { STORM_PRINT("Given assumptions: " << std::endl); @@ -196,7 +196,6 @@ namespace storm { auto assumption2 = *itr; if (!assumption1.second && !assumption2.second) { - // TODO check op lattice of er nog monotonicity is auto assumptionsCopy = std::vector>(assumptions); auto latticeCopy = new storm::analysis::Lattice(lattice); assumptions.push_back(assumption1.first); @@ -208,7 +207,6 @@ namespace storm { result.insert(map.begin(), map.end()); } - criticalTuple = extender->extendLattice(latticeCopy, assumption2.first); if (somewhereMonotonicity(std::get<0>(criticalTuple))) { auto map = extendLatticeWithAssumptions(std::get<0>(criticalTuple), assumptionMaker, @@ -258,16 +256,16 @@ namespace storm { storm::utility::Stopwatch analyseWatch(true); std::map> varsMonotone; - std::ofstream myfile; - std::string filename = "mc" + std::to_string(j) + ".dot"; - myfile.open (filename); - myfile << "digraph \"MC\" {" << std::endl; - myfile << "\t" << "node [shape=ellipse]" << std::endl; +// std::ofstream myfile; +// std::string filename = "mc" + std::to_string(j) + ".dot"; +// myfile.open (filename); +// myfile << "digraph \"MC\" {" << std::endl; +// myfile << "\t" << "node [shape=ellipse]" << std::endl; // print all nodes - for (uint_fast64_t i = 0; i < matrix.getColumnCount(); ++i) { - myfile << "\t\"" << i << "\" [label = \"" << i << "\"]" << std::endl; - } +// for (uint_fast64_t i = 0; i < matrix.getColumnCount(); ++i) { +// myfile << "\t\"" << i << "\" [label = \"" << i << "\"]" << std::endl; +// } for (uint_fast64_t i = 0; i < matrix.getColumnCount(); ++i) { // go over all rows @@ -280,7 +278,7 @@ namespace storm { transitions.insert(std::pair((*itr).getColumn(), (*itr).getValue())); } - std::string color = ""; +// std::string color = ""; auto val = first.getValue(); auto vars = val.gatherVariables(); for (auto itr = vars.begin(); itr != vars.end(); ++itr) { @@ -290,7 +288,7 @@ namespace storm { varsMonotone[*itr].first = false; varsMonotone[*itr].second = false; } - color = "color = red, "; +// color = "color = red, "; } else { if (varsMonotone.find(*itr) == varsMonotone.end()) { varsMonotone[*itr].first = true; @@ -328,40 +326,40 @@ namespace storm { } } - if ((value->first != old.first) && (value->second != old.second)) { - color = "color = red, "; - } else if ((value->first != old.first)) { - myfile << "\t edge[style=dashed];" << std::endl; - color = "color = blue, "; - } else if ((value->second != old.second)) { - myfile << "\t edge[style=dotted];" << std::endl; - color = "color = blue, "; - } +// if ((value->first != old.first) && (value->second != old.second)) { +// color = "color = red, "; +// } else if ((value->first != old.first)) { +// myfile << "\t edge[style=dashed];" << std::endl; +// color = "color = blue, "; +// } else if ((value->second != old.second)) { +// myfile << "\t edge[style=dotted];" << std::endl; +// color = "color = blue, "; +// } } } - for (auto itr = transitions.begin(); itr != transitions.end(); ++itr) { - myfile << "\t" << i << " -> " << itr->first << "[" << color << "label=\"" << itr->second << "\"];" - << std::endl; - } - - myfile << "\t edge[style=\"\"];" << std::endl; - } else { - myfile << "\t" << i << " -> " << first.getColumn() << "[label=\"" << first.getValue() << "\"];" - << std::endl; +// for (auto itr = transitions.begin(); itr != transitions.end(); ++itr) { +// myfile << "\t" << i << " -> " << itr->first << "[" << color << "label=\"" << itr->second << "\"];" +// << std::endl; +// } +// +// myfile << "\t edge[style=\"\"];" << std::endl; +// } else { +// myfile << "\t" << i << " -> " << first.getColumn() << "[label=\"" << first.getValue() << "\"];" +// << std::endl; } } - myfile << "\tsubgraph legend {" << std::endl; - myfile << "\t\tnode [color=white];" << std::endl; - myfile << "\t\tedge [style=invis];" << std::endl; - myfile << "\t\tt0 [label=\"incr? and decr?\", fontcolor=red];" << std::endl; - myfile << "\t\tt1 [label=\"incr? (dashed)\", fontcolor=blue];" << std::endl; - myfile << "\t\tt2 [label=\"decr? (dotted)\", fontcolor=blue];" << std::endl; - - myfile << "\t}" << std::endl; - myfile << "}" << std::endl; - myfile.close(); +// myfile << "\tsubgraph legend {" << std::endl; +// myfile << "\t\tnode [color=white];" << std::endl; +// myfile << "\t\tedge [style=invis];" << std::endl; +// myfile << "\t\tt0 [label=\"incr? and decr?\", fontcolor=red];" << std::endl; +// myfile << "\t\tt1 [label=\"incr? (dashed)\", fontcolor=blue];" << std::endl; +// myfile << "\t\tt2 [label=\"decr? (dotted)\", fontcolor=blue];" << std::endl; +// +// myfile << "\t}" << std::endl; +// myfile << "}" << std::endl; +// myfile.close(); analyseWatch.stop(); STORM_PRINT(std::endl << "Time to check monotonicity based on the lattice: " << analyseWatch << "." << std::endl << std::endl); @@ -491,7 +489,9 @@ namespace storm { for (auto i = initialStates.getNextSetIndex(0); i < model->getNumberOfStates(); i = initialStates.getNextSetIndex(i+1)) { initial += values[i]; } - if (previous != -1) { + float diff = previous - initial; + // TODO: define precission + if (previous != -1 && diff > 0.000005 && diff < -0.000005) { monDecr &= previous >= initial; monIncr &= previous <= initial; } From 728af9526b9166c77722efb6d0531491822d87b0 Mon Sep 17 00:00:00 2001 From: Jip Spel Date: Wed, 24 Oct 2018 13:00:31 +0200 Subject: [PATCH 116/178] Change Lattice implementation --- src/storm-pars/analysis/Lattice.cpp | 158 +++++++++++++++----- src/storm-pars/analysis/Lattice.h | 31 ++-- src/storm-pars/analysis/LatticeExtender.cpp | 44 ++++-- src/storm-pars/analysis/LatticeExtender.h | 2 +- 4 files changed, 172 insertions(+), 63 deletions(-) diff --git a/src/storm-pars/analysis/Lattice.cpp b/src/storm-pars/analysis/Lattice.cpp index e015358cb..a0dc25d47 100644 --- a/src/storm-pars/analysis/Lattice.cpp +++ b/src/storm-pars/analysis/Lattice.cpp @@ -12,10 +12,13 @@ namespace storm { storm::storage::BitVector bottomStates, uint_fast64_t numberOfStates) { top = new Node(); top->states = topStates; + setStatesAbove(top, storm::storage::BitVector(numberOfStates), false); + setStatesBelow(top, bottomStates, false); + bottom = new Node(); bottom->states = bottomStates; - top->below.insert(bottom); - bottom->above.insert(top); + setStatesBelow(bottom, storm::storage::BitVector(numberOfStates), false); + setStatesAbove(bottom, topStates, false); nodes = std::vector(numberOfStates); for (auto i = topStates.getNextSetIndex(0); i < numberOfStates; i = topStates.getNextSetIndex(i+1)) { @@ -36,13 +39,19 @@ namespace storm { Lattice::Lattice(Lattice* lattice) { top = new Node(); top->states = storm::storage::BitVector(lattice->getTop()->states); + setStatesAbove(top, lattice->getTop()->statesAbove, false); + setStatesBelow(top, lattice->getTop()->statesBelow, false); + bottom = new Node(); bottom->states = storm::storage::BitVector(lattice->getBottom()->states); + setStatesAbove(bottom, lattice->getBottom()->statesAbove, false); + setStatesBelow(bottom, lattice->getBottom()->statesBelow, false); + numberOfStates = top->states.size(); nodes = std::vector(numberOfStates); addedStates = storm::storage::BitVector(numberOfStates); - addedStates.operator|=(top->states); - addedStates.operator|=(bottom->states); + addedStates |= (top->states); + addedStates |= (bottom->states); for (auto i = top->states.getNextSetIndex(0); i < numberOfStates; i = top->states.getNextSetIndex(i+1)) { nodes.at(i) = top; @@ -59,6 +68,8 @@ namespace storm { if (oldNode != nullptr) { Node *newNode = new Node(); newNode->states = storm::storage::BitVector(oldNode->states); + setStatesAbove(newNode, oldNode->statesAbove, false); + setStatesBelow(newNode, oldNode->statesBelow, false); for (auto i = newNode->states.getNextSetIndex(0); i < numberOfStates; i = newNode->states.getNextSetIndex(i + 1)) { addedStates.set(i); @@ -67,17 +78,7 @@ namespace storm { } } - // Create transitions - for (auto itr = oldNodes.begin(); itr != oldNodes.end(); ++itr) { - Node* oldNode = (*itr); - if (oldNode != nullptr) { - auto state = (*itr)->states.getNextSetIndex(0); - for (auto itr2 = (*itr)->below.begin(); itr2 != (*itr)->below.end(); ++itr2) { - auto stateBelow = (*itr2)->states.getNextSetIndex(0); - addRelationNodes(getNode((state)), getNode((stateBelow))); - } - } - } + assert(addedStates == lattice->getAddedStates()); } void Lattice::addBetween(uint_fast64_t state, Node *above, Node *below) { @@ -87,12 +88,28 @@ namespace storm { Node *newNode = new Node(); newNode->states = storm::storage::BitVector(numberOfStates); newNode->states.set(state); - newNode->above = std::set({above}); - newNode->below = std::set({below}); - below->above.erase(above); - above->below.erase(below); - (below->above).insert(newNode); - above->below.insert(newNode); + + setStatesAbove(newNode, above->statesAbove | above->states, false); + setStatesBelow(newNode, below->statesBelow | below->states, false); + + newNode->statesAbove = above->statesAbove | above->states; + newNode->statesBelow = below->statesBelow | below->states; + newNode->recentlyAddedAbove = storm::storage::BitVector(above->statesAbove | above->states); + newNode->recentlyAddedBelow = storm::storage::BitVector(below->statesBelow | below->states); + setStatesBelow(above, state); + setStatesAbove(below, state); + + auto nodesBelow = getNodesBelow(below); + for (auto itr = nodesBelow.begin(); itr != nodesBelow.end(); ++itr) { + assert((*itr)->statesAbove.size() == numberOfStates); + setStatesAbove((*itr), state); + } + + auto nodesAbove = getNodesAbove(above); + for (auto itr = nodesAbove.begin(); itr != nodesAbove.end(); ++itr) { + assert((*itr)->statesBelow.size() == numberOfStates); + setStatesBelow((*itr), state); + } nodes.at(state) = newNode; addedStates.set(state); } @@ -102,6 +119,14 @@ namespace storm { node->states.set(state); nodes.at(state) = node; addedStates.set(state); + auto nodesBelow = getNodesBelow(node); + for (auto itr = nodesBelow.begin(); itr != nodesBelow.end(); ++itr) { + setStatesAbove((*itr), state); + } + auto nodesAbove = getNodesAbove(node); + for (auto itr = nodesAbove.begin(); nodesAbove.size() != 0 &&itr != nodesAbove.end(); ++itr) { + setStatesBelow((*itr), state); + } } void Lattice::add(uint_fast64_t state) { @@ -109,13 +134,16 @@ namespace storm { } void Lattice::addRelationNodes(storm::analysis::Lattice::Node *above, storm::analysis::Lattice::Node * below) { - assert(compare(above, below) == UNKNOWN || compare(above, below) == ABOVE); - above->below.insert(below); - below->above.insert(above); - } - - void Lattice::mergeNodes(storm::analysis::Lattice::Node *n1, storm::analysis::Lattice::Node * n2) { - // TODO + above->statesBelow |= below->states; + below->statesAbove |= above->states; + auto nodesBelow = getNodesBelow(below); + for (auto itr = nodesBelow.begin(); itr != nodesBelow.end(); ++itr) { + setStatesAbove((*itr), above->states, true); + } + auto nodesAbove = getNodesAbove(above); + for (auto itr = nodesAbove.begin() ; itr != nodesAbove.end(); ++itr) { + setStatesBelow((*itr), below->states, true); + } } int Lattice::compare(uint_fast64_t state1, uint_fast64_t state2) { @@ -128,12 +156,12 @@ namespace storm { return SAME; } - if (above(node1, node2, new std::set({}))) { - assert(!above(node2, node1, new std::set({}))); + if (above(node1, node2, std::make_shared>(std::set({})))) { + assert(!above(node2, node1, std::make_shared>(std::set({})))); return ABOVE; } - if (above(node2, node1, new std::set({}))) { + if (above(node2, node1, std::make_shared>(std::set({})))) { return BELOW; } } @@ -144,6 +172,26 @@ namespace storm { return nodes.at(stateNumber); } + std::set Lattice::getNodesAbove(Lattice::Node * node) { + if (node->recentlyAddedAbove.getNumberOfSetBits() != 0) { + for (auto i = node->recentlyAddedAbove.getNextSetIndex(0); i < node->recentlyAddedAbove.size(); i = node->recentlyAddedAbove.getNextSetIndex(i+1)) { + node->above.insert(getNode(i)); + } + node->recentlyAddedAbove.clear(); + } + return node->above; + } + + std::set Lattice::getNodesBelow(Lattice::Node * node) { + if (node->recentlyAddedBelow.getNumberOfSetBits() != 0) { + for (auto i = node->recentlyAddedBelow.getNextSetIndex(0); i < node->recentlyAddedBelow.size(); i = node->recentlyAddedBelow.getNextSetIndex(i+1)) { + node->below.insert(getNode(i)); + } + node->recentlyAddedBelow.clear(); + } + return node->above; + } + Lattice::Node *Lattice::getTop() { return top; } @@ -160,6 +208,8 @@ namespace storm { return addedStates; } + + void Lattice::toString(std::ostream &out) { std::vector printedNodes = std::vector({}); for (auto itr = nodes.begin(); itr != nodes.end(); ++itr) { @@ -180,6 +230,7 @@ namespace storm { out << " Address: " << node << "\n"; out << " Above: {"; + getNodesAbove(node); // such that it is updated for (auto itr2 = node->above.begin(); itr2 != node->above.end(); ++itr2) { Node *above = *itr2; index = above->states.getNextSetIndex(0); @@ -198,6 +249,8 @@ namespace storm { out << " Below: {"; + getNodesBelow(node); // To make sure it is updated + // TODO verbeteren for (auto itr2 = node->below.begin(); itr2 != node->below.end(); ++itr2) { Node *below = *itr2; out << "{"; @@ -256,15 +309,42 @@ namespace storm { out << "}" << std::endl; } - bool Lattice::above(Node *node1, Node *node2, std::set* seenNodes) { - bool result = !node1->below.empty() && std::find(node1->below.begin(), node1->below.end(), node2) != node1->below.end(); - for (auto itr = node1->below.begin(); !result && node1->below.end() != itr; ++itr) { - if (std::find(seenNodes->begin(), seenNodes->end(), (*itr)) == seenNodes->end()) { - seenNodes->insert(*itr); - result |= above(*itr, node2, seenNodes); - } + bool Lattice::above(Node *node1, Node *node2, std::shared_ptr> seenNodes) { + return node1->statesBelow.get(node2->states.getNextSetIndex(0)); + } + + void Lattice::setStatesAbove(storm::analysis::Lattice::Node *node, uint_fast64_t state) { + node->statesAbove.set(state); + node->recentlyAddedAbove.set(state); + } + + void Lattice::setStatesBelow(storm::analysis::Lattice::Node *node, uint_fast64_t state) { + node->statesBelow.set(state); + node->recentlyAddedBelow.set(state); + } + + void Lattice::setStatesAbove(storm::analysis::Lattice::Node *node, storm::storage::BitVector states, bool alreadyInitialized) { + if (alreadyInitialized) { + node->statesAbove |= states; + node->recentlyAddedAbove |= states; + } else { + node->statesAbove = storm::storage::BitVector(states); + node->recentlyAddedAbove = storm::storage::BitVector(states); } - return result; } + + void Lattice::setStatesBelow(storm::analysis::Lattice::Node *node, storm::storage::BitVector states, bool alreadyInitialized) { + if (alreadyInitialized) { + node->statesBelow |= states; + node->recentlyAddedBelow |= states; + } else { + node->statesBelow = storm::storage::BitVector(states); + node->recentlyAddedBelow = storm::storage::BitVector(states); + } + } + + + + } } diff --git a/src/storm-pars/analysis/Lattice.h b/src/storm-pars/analysis/Lattice.h index b92570e65..ce9cb7ce7 100644 --- a/src/storm-pars/analysis/Lattice.h +++ b/src/storm-pars/analysis/Lattice.h @@ -18,8 +18,12 @@ namespace storm { public: struct Node { storm::storage::BitVector states; - std::set above; - std::set below; + storm::storage::BitVector statesAbove; + storm::storage::BitVector statesBelow; + storm::storage::BitVector recentlyAddedAbove; + storm::storage::BitVector recentlyAddedBelow; + std::set above; + std::set below; }; /*! @@ -55,14 +59,12 @@ namespace storm { void add(uint_fast64_t state); /*! - * Adds a new relation between two nodes to the lattice - * @param above The node closest to the top Node of the Lattice. - * @param below The node closest to the bottom Node of the Lattice. - */ + * Adds a new relation between two nodes to the lattice + * @param above The node closest to the top Node of the Lattice. + * @param below The node closest to the bottom Node of the Lattice. + */ void addRelationNodes(storm::analysis::Lattice::Node *above, storm::analysis::Lattice::Node * below); - void mergeNodes(storm::analysis::Lattice::Node *n1, storm::analysis::Lattice::Node * n2); - /*! * Compares the level of the nodes of the states. * Behaviour unknown when one or more of the states doesnot occur at any Node in the Lattice. @@ -107,6 +109,9 @@ namespace storm { */ std::vector getNodes(); + std::set getNodesBelow(Node* node); + std::set getNodesAbove(Node* node); + /*! * Returns a BitVector in which all added states are set. * @@ -149,9 +154,17 @@ namespace storm { uint_fast64_t numberOfStates; - bool above(Node * node1, Node * node2, std::set* seenNodes); + bool above(Node * node1, Node * node2, std::shared_ptr> seenNodes); int compare(Node* node1, Node* node2); + + void setStatesAbove(Node* node, uint_fast64_t state); + + void setStatesBelow(Node* node, uint_fast64_t state); + + void setStatesAbove(storm::analysis::Lattice::Node *node, storm::storage::BitVector states, bool alreadyInitialized); + + void setStatesBelow(storm::analysis::Lattice::Node *node, storm::storage::BitVector states, bool alreadyInitialized); }; } } diff --git a/src/storm-pars/analysis/LatticeExtender.cpp b/src/storm-pars/analysis/LatticeExtender.cpp index 004418d57..89d4d6ec9 100644 --- a/src/storm-pars/analysis/LatticeExtender.cpp +++ b/src/storm-pars/analysis/LatticeExtender.cpp @@ -31,19 +31,6 @@ namespace storm { template LatticeExtender::LatticeExtender(std::shared_ptr> model) { this->model = model; - - initialMiddleStates = storm::storage::BitVector(model->getNumberOfStates()); - // Check if MC is acyclic - auto decomposition = storm::storage::StronglyConnectedComponentDecomposition(model->getTransitionMatrix(), false, false); - for (auto i = 0; i < decomposition.size(); ++i) { - auto scc = decomposition.getBlock(i); - if (scc.size() > 1) { - auto states = scc.getStates(); - // TODO: Smarter state picking - // Add one of the states of the scc - initialMiddleStates.set(*(states.begin())); - } - } } template @@ -91,6 +78,34 @@ namespace storm { } } + auto initialMiddleStates = storm::storage::BitVector(model->getNumberOfStates()); + // Check if MC is acyclic + auto decomposition = storm::storage::StronglyConnectedComponentDecomposition(model->getTransitionMatrix(), false, false); + for (auto i = 0; i < decomposition.size(); ++i) { + auto scc = decomposition.getBlock(i); + if (scc.size() > 1) { + auto states = scc.getStates(); + // check if the state has already one successor in bottom of top, in that case pick it + bool found = false; + for (auto stateItr = states.begin(); !found && stateItr < states.end(); ++stateItr) { + auto successors = stateMap[*stateItr]; + if (successors.getNumberOfSetBits() == 2) { + auto succ1 = successors.getNextSetIndex(0); + auto succ2 = successors.getNextSetIndex(succ1 + 1); + auto intersection = bottomStates | topStates; + if ((intersection[succ1] && ! intersection[succ2]) + || (intersection[succ2] && !intersection[succ1])) { + initialMiddleStates.set(*stateItr); + found = true; + } else if (intersection[succ1] && intersection[succ2]) { + found = true; + } + } + + } + } + } + // Create the Lattice storm::analysis::Lattice *lattice = new storm::analysis::Lattice(topStates, bottomStates, numberOfStates); for (auto state = initialMiddleStates.getNextSetIndex(0); state != numberOfStates; state = initialMiddleStates.getNextSetIndex(state + 1)) { @@ -127,7 +142,8 @@ namespace storm { storm::analysis::Lattice::Node *n2 = lattice->getNode(val2); if (n1 != nullptr && n2 != nullptr) { - lattice->mergeNodes(n1, n2); + assert(false); +// lattice->mergeNodes(n1, n2); } else if (n1 != nullptr) { lattice->addToNode(val2, n1); } else if (n2 != nullptr) { diff --git a/src/storm-pars/analysis/LatticeExtender.h b/src/storm-pars/analysis/LatticeExtender.h index 8737c8f9e..01b0554a8 100644 --- a/src/storm-pars/analysis/LatticeExtender.h +++ b/src/storm-pars/analysis/LatticeExtender.h @@ -54,7 +54,7 @@ namespace storm { std::map stateMap; - storm::storage::BitVector initialMiddleStates; +// storm::storage::BitVector initialMiddleStates; }; } } From f0f74d1d0a8d347efba8e55f10623ff844a8edd5 Mon Sep 17 00:00:00 2001 From: Jip Spel Date: Wed, 24 Oct 2018 14:08:42 +0200 Subject: [PATCH 117/178] Make use of provided methods when extending the lattice --- src/storm-pars/analysis/Lattice.cpp | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) diff --git a/src/storm-pars/analysis/Lattice.cpp b/src/storm-pars/analysis/Lattice.cpp index a0dc25d47..f6c6ddb05 100644 --- a/src/storm-pars/analysis/Lattice.cpp +++ b/src/storm-pars/analysis/Lattice.cpp @@ -85,17 +85,13 @@ namespace storm { assert(!addedStates[state]); auto res = compare(above, below); assert(res == ABOVE || res == UNKNOWN); + Node *newNode = new Node(); newNode->states = storm::storage::BitVector(numberOfStates); newNode->states.set(state); - setStatesAbove(newNode, above->statesAbove | above->states, false); setStatesBelow(newNode, below->statesBelow | below->states, false); - newNode->statesAbove = above->statesAbove | above->states; - newNode->statesBelow = below->statesBelow | below->states; - newNode->recentlyAddedAbove = storm::storage::BitVector(above->statesAbove | above->states); - newNode->recentlyAddedBelow = storm::storage::BitVector(below->statesBelow | below->states); setStatesBelow(above, state); setStatesAbove(below, state); @@ -134,8 +130,8 @@ namespace storm { } void Lattice::addRelationNodes(storm::analysis::Lattice::Node *above, storm::analysis::Lattice::Node * below) { - above->statesBelow |= below->states; - below->statesAbove |= above->states; + setStatesBelow(above, below->states, true); + setStatesAbove(below, above->states, true); auto nodesBelow = getNodesBelow(below); for (auto itr = nodesBelow.begin(); itr != nodesBelow.end(); ++itr) { setStatesAbove((*itr), above->states, true); @@ -208,8 +204,6 @@ namespace storm { return addedStates; } - - void Lattice::toString(std::ostream &out) { std::vector printedNodes = std::vector({}); for (auto itr = nodes.begin(); itr != nodes.end(); ++itr) { @@ -342,9 +336,5 @@ namespace storm { node->recentlyAddedBelow = storm::storage::BitVector(states); } } - - - - } } From 78e5108e42a384d2fea7478c5f04c12f31a5fff8 Mon Sep 17 00:00:00 2001 From: Jip Spel Date: Fri, 26 Oct 2018 14:28:32 +0200 Subject: [PATCH 118/178] Extend Lattice test --- src/test/storm-pars/analysis/LatticeTest.cpp | 63 +++++++++++++++++++- 1 file changed, 62 insertions(+), 1 deletion(-) diff --git a/src/test/storm-pars/analysis/LatticeTest.cpp b/src/test/storm-pars/analysis/LatticeTest.cpp index 7df231912..14cd55c38 100644 --- a/src/test/storm-pars/analysis/LatticeTest.cpp +++ b/src/test/storm-pars/analysis/LatticeTest.cpp @@ -10,7 +10,7 @@ #include "storm/storage/BitVector.h" TEST(LatticeTest, Simple) { - auto numberOfStates = 5; + auto numberOfStates = 7; auto above = storm::storage::BitVector(numberOfStates); above.set(0); auto below = storm::storage::BitVector(numberOfStates); @@ -35,4 +35,65 @@ TEST(LatticeTest, Simple) { EXPECT_EQ(storm::analysis::Lattice::ABOVE, lattice.compare(4,1)); EXPECT_EQ(storm::analysis::Lattice::UNKNOWN, lattice.compare(4,3)); EXPECT_EQ(storm::analysis::Lattice::UNKNOWN, lattice.compare(3,4)); + + lattice.addBetween(5, lattice.getNode(0), lattice.getNode(3)); + + EXPECT_EQ(storm::analysis::Lattice::BELOW, lattice.compare(5,0)); + EXPECT_EQ(storm::analysis::Lattice::ABOVE, lattice.compare(5,3)); + EXPECT_EQ(storm::analysis::Lattice::ABOVE, lattice.compare(5,1)); + EXPECT_EQ(storm::analysis::Lattice::UNKNOWN, lattice.compare(5,2)); + EXPECT_EQ(storm::analysis::Lattice::UNKNOWN, lattice.compare(5,4)); + + lattice.addBetween(6, lattice.getNode(5), lattice.getNode(3)); + EXPECT_EQ(storm::analysis::Lattice::BELOW, lattice.compare(6,0)); + EXPECT_EQ(storm::analysis::Lattice::ABOVE, lattice.compare(6,1)); + EXPECT_EQ(storm::analysis::Lattice::UNKNOWN, lattice.compare(6,2)); + EXPECT_EQ(storm::analysis::Lattice::ABOVE, lattice.compare(6,3)); + EXPECT_EQ(storm::analysis::Lattice::UNKNOWN, lattice.compare(6,4)); + EXPECT_EQ(storm::analysis::Lattice::BELOW, lattice.compare(6,5)); } + +TEST(LatticeTest, copy_lattice) { + auto numberOfStates = 7; + auto above = storm::storage::BitVector(numberOfStates); + above.set(0); + auto below = storm::storage::BitVector(numberOfStates); + below.set(1); + + auto lattice = storm::analysis::Lattice(above, below, numberOfStates); + lattice.add(2); + lattice.add(3); + lattice.addToNode(4, lattice.getNode(2)); + lattice.addBetween(5, lattice.getNode(0), lattice.getNode(3)); + lattice.addBetween(6, lattice.getNode(5), lattice.getNode(3)); + + + auto latticeCopy = storm::analysis::Lattice(lattice); + EXPECT_EQ(storm::analysis::Lattice::ABOVE, latticeCopy.compare(0,1)); + EXPECT_EQ(storm::analysis::Lattice::BELOW, latticeCopy.compare(1,0)); + + EXPECT_EQ(storm::analysis::Lattice::ABOVE, latticeCopy.compare(0,2)); + EXPECT_EQ(storm::analysis::Lattice::ABOVE, latticeCopy.compare(2,1)); + + EXPECT_EQ(storm::analysis::Lattice::UNKNOWN, latticeCopy.compare(2,3)); + EXPECT_EQ(storm::analysis::Lattice::UNKNOWN, latticeCopy.compare(3,2)); + + EXPECT_EQ(storm::analysis::Lattice::SAME, latticeCopy.compare(2,4)); + EXPECT_EQ(storm::analysis::Lattice::ABOVE, latticeCopy.compare(0,4)); + EXPECT_EQ(storm::analysis::Lattice::ABOVE, latticeCopy.compare(4,1)); + EXPECT_EQ(storm::analysis::Lattice::UNKNOWN, latticeCopy.compare(4,3)); + EXPECT_EQ(storm::analysis::Lattice::UNKNOWN, latticeCopy.compare(3,4)); + + EXPECT_EQ(storm::analysis::Lattice::BELOW, latticeCopy.compare(5,0)); + EXPECT_EQ(storm::analysis::Lattice::ABOVE, latticeCopy.compare(5,3)); + EXPECT_EQ(storm::analysis::Lattice::ABOVE, latticeCopy.compare(5,1)); + EXPECT_EQ(storm::analysis::Lattice::UNKNOWN, latticeCopy.compare(5,2)); + EXPECT_EQ(storm::analysis::Lattice::UNKNOWN, latticeCopy.compare(5,4)); + + EXPECT_EQ(storm::analysis::Lattice::BELOW, latticeCopy.compare(6,0)); + EXPECT_EQ(storm::analysis::Lattice::ABOVE, latticeCopy.compare(6,1)); + EXPECT_EQ(storm::analysis::Lattice::UNKNOWN, latticeCopy.compare(6,2)); + EXPECT_EQ(storm::analysis::Lattice::ABOVE, latticeCopy.compare(6,3)); + EXPECT_EQ(storm::analysis::Lattice::UNKNOWN, latticeCopy.compare(6,4)); + EXPECT_EQ(storm::analysis::Lattice::BELOW, latticeCopy.compare(6,5)); +} \ No newline at end of file From 9fa297b2aa64a29d190d6cd429fe4352873a4186 Mon Sep 17 00:00:00 2001 From: Jip Spel Date: Fri, 26 Oct 2018 15:05:01 +0200 Subject: [PATCH 119/178] Fix test --- src/test/storm-pars/analysis/AssumptionCheckerTest.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/test/storm-pars/analysis/AssumptionCheckerTest.cpp b/src/test/storm-pars/analysis/AssumptionCheckerTest.cpp index 95345eb66..2e59d1b13 100644 --- a/src/test/storm-pars/analysis/AssumptionCheckerTest.cpp +++ b/src/test/storm-pars/analysis/AssumptionCheckerTest.cpp @@ -62,7 +62,11 @@ TEST(AssumptionCheckerTest, Brp_no_bisimulation) { storm::expressions::BinaryRelationExpression::RelationType::GreaterOrEqual)); EXPECT_TRUE(checker.checkOnSamples(assumption)); - auto dummyLattice = new storm::analysis::Lattice(storm::storage::BitVector(8), storm::storage::BitVector(8), 8); + storm::storage::BitVector above(8); + above.set(0); + storm::storage::BitVector below(8); + below.set(1); + auto dummyLattice = new storm::analysis::Lattice(above, below, 8); // Validate assumption EXPECT_FALSE(checker.validateAssumption(assumption, dummyLattice)); EXPECT_FALSE(checker.validated(assumption)); @@ -74,9 +78,9 @@ TEST(AssumptionCheckerTest, Brp_no_bisimulation) { expressionManager->getVariable("6").getExpression().getBaseExpressionPointer(), expressionManager->getVariable("8").getExpression().getBaseExpressionPointer(), storm::expressions::BinaryRelationExpression::RelationType::GreaterOrEqual)); - storm::storage::BitVector above(13); + above = storm::storage::BitVector(13); above.set(12); - storm::storage::BitVector below(13); + below = storm::storage::BitVector(13); below.set(9); dummyLattice = new storm::analysis::Lattice(above, below, 13); EXPECT_TRUE(checker.checkOnSamples(assumption)); From e0cc7525b587abe88ee9e8e998e631dc1e72aac1 Mon Sep 17 00:00:00 2001 From: Jip Spel Date: Fri, 26 Oct 2018 16:09:23 +0200 Subject: [PATCH 120/178] Extend Lattice Test --- src/test/storm-pars/analysis/LatticeTest.cpp | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/test/storm-pars/analysis/LatticeTest.cpp b/src/test/storm-pars/analysis/LatticeTest.cpp index 14cd55c38..14a02675c 100644 --- a/src/test/storm-pars/analysis/LatticeTest.cpp +++ b/src/test/storm-pars/analysis/LatticeTest.cpp @@ -51,6 +51,10 @@ TEST(LatticeTest, Simple) { EXPECT_EQ(storm::analysis::Lattice::ABOVE, lattice.compare(6,3)); EXPECT_EQ(storm::analysis::Lattice::UNKNOWN, lattice.compare(6,4)); EXPECT_EQ(storm::analysis::Lattice::BELOW, lattice.compare(6,5)); + + lattice.addRelationNodes(lattice.getNode(6), lattice.getNode(4)); + EXPECT_EQ(storm::analysis::Lattice::ABOVE, lattice.compare(6,4)); + } TEST(LatticeTest, copy_lattice) { @@ -68,6 +72,7 @@ TEST(LatticeTest, copy_lattice) { lattice.addBetween(6, lattice.getNode(5), lattice.getNode(3)); + auto latticeCopy = storm::analysis::Lattice(lattice); EXPECT_EQ(storm::analysis::Lattice::ABOVE, latticeCopy.compare(0,1)); EXPECT_EQ(storm::analysis::Lattice::BELOW, latticeCopy.compare(1,0)); @@ -90,10 +95,12 @@ TEST(LatticeTest, copy_lattice) { EXPECT_EQ(storm::analysis::Lattice::UNKNOWN, latticeCopy.compare(5,2)); EXPECT_EQ(storm::analysis::Lattice::UNKNOWN, latticeCopy.compare(5,4)); + lattice.addRelationNodes(lattice.getNode(6), lattice.getNode(4)); + latticeCopy = storm::analysis::Lattice(lattice); EXPECT_EQ(storm::analysis::Lattice::BELOW, latticeCopy.compare(6,0)); EXPECT_EQ(storm::analysis::Lattice::ABOVE, latticeCopy.compare(6,1)); - EXPECT_EQ(storm::analysis::Lattice::UNKNOWN, latticeCopy.compare(6,2)); + EXPECT_EQ(storm::analysis::Lattice::ABOVE, latticeCopy.compare(6,2)); EXPECT_EQ(storm::analysis::Lattice::ABOVE, latticeCopy.compare(6,3)); - EXPECT_EQ(storm::analysis::Lattice::UNKNOWN, latticeCopy.compare(6,4)); + EXPECT_EQ(storm::analysis::Lattice::ABOVE, latticeCopy.compare(6,4)); EXPECT_EQ(storm::analysis::Lattice::BELOW, latticeCopy.compare(6,5)); -} \ No newline at end of file +} From 9efea2969b7de71eb9b182e3bcab6484be74b60e Mon Sep 17 00:00:00 2001 From: Jip Spel Date: Fri, 26 Oct 2018 16:16:31 +0200 Subject: [PATCH 121/178] Change implementation of Lattice --- src/storm-pars/analysis/Lattice.cpp | 255 ++++++++++++++++------------ src/storm-pars/analysis/Lattice.h | 15 +- 2 files changed, 153 insertions(+), 117 deletions(-) diff --git a/src/storm-pars/analysis/Lattice.cpp b/src/storm-pars/analysis/Lattice.cpp index f6c6ddb05..d16aad8ad 100644 --- a/src/storm-pars/analysis/Lattice.cpp +++ b/src/storm-pars/analysis/Lattice.cpp @@ -10,26 +10,43 @@ namespace storm { namespace analysis { Lattice::Lattice(storm::storage::BitVector topStates, storm::storage::BitVector bottomStates, uint_fast64_t numberOfStates) { + assert(topStates.getNumberOfSetBits() != 0); + assert(bottomStates.getNumberOfSetBits() != 0); + assert((topStates & bottomStates).getNumberOfSetBits() == 0); + nodes = std::vector(numberOfStates); + top = new Node(); top->states = topStates; - setStatesAbove(top, storm::storage::BitVector(numberOfStates), false); - setStatesBelow(top, bottomStates, false); - - bottom = new Node(); - bottom->states = bottomStates; - setStatesBelow(bottom, storm::storage::BitVector(numberOfStates), false); - setStatesAbove(bottom, topStates, false); - - nodes = std::vector(numberOfStates); - for (auto i = topStates.getNextSetIndex(0); i < numberOfStates; i = topStates.getNextSetIndex(i+1)) { + for (auto i = topStates.getNextSetIndex(0); i < topStates.size(); i = topStates.getNextSetIndex(i+1)) { nodes.at(i) = top; - } - for (auto i = bottomStates.getNextSetIndex(0); i < numberOfStates; i = bottomStates.getNextSetIndex(i+1)) { + bottom = new Node(); + bottom->states = bottomStates; + for (auto i = bottomStates.getNextSetIndex(0); i < bottomStates.size(); i = bottomStates.getNextSetIndex(i+1)) { nodes.at(i) = bottom; } + top->above = new std::set({}); + top->statesAbove = storm::storage::BitVector(numberOfStates); + setStatesBelow(top, bottomStates, false); + assert(top->statesAbove.size() == numberOfStates); + assert(top->statesBelow.size() == numberOfStates); + assert(top->statesAbove.getNumberOfSetBits() == 0); + assert(top->statesBelow.getNumberOfSetBits() == bottomStates.getNumberOfSetBits()); + assert(top->above->size() == 0); + assert(top->below->size() == bottomStates.getNumberOfSetBits()); + + bottom->below = new std::set({}); + bottom->statesBelow = storm::storage::BitVector(numberOfStates); + setStatesAbove(bottom, topStates, false); + assert(bottom->statesAbove.size() == numberOfStates); + assert(bottom->statesBelow.size() == numberOfStates); + assert(bottom->statesBelow.getNumberOfSetBits() == 0); + assert(bottom->statesAbove.getNumberOfSetBits() == topStates.getNumberOfSetBits()); + assert(bottom->below->size() == 0); + assert(bottom->above->size() == topStates.getNumberOfSetBits()); + this->numberOfStates = numberOfStates; this->addedStates = storm::storage::BitVector(numberOfStates); this->addedStates |= (topStates); @@ -37,76 +54,96 @@ namespace storm { } Lattice::Lattice(Lattice* lattice) { + numberOfStates = lattice->getAddedStates().size(); + nodes = std::vector(numberOfStates); + top = new Node(); top->states = storm::storage::BitVector(lattice->getTop()->states); - setStatesAbove(top, lattice->getTop()->statesAbove, false); - setStatesBelow(top, lattice->getTop()->statesBelow, false); + for (auto i = top->states.getNextSetIndex(0); i < top->states.size(); i = top->states.getNextSetIndex(i+1)) { + nodes.at(i) = top; + } bottom = new Node(); bottom->states = storm::storage::BitVector(lattice->getBottom()->states); - setStatesAbove(bottom, lattice->getBottom()->statesAbove, false); - setStatesBelow(bottom, lattice->getBottom()->statesBelow, false); + for (auto i = bottom->states.getNextSetIndex(0); i < bottom->states.size(); i = bottom->states.getNextSetIndex(i+1)) { + nodes.at(i) = bottom; + } - numberOfStates = top->states.size(); - nodes = std::vector(numberOfStates); addedStates = storm::storage::BitVector(numberOfStates); addedStates |= (top->states); addedStates |= (bottom->states); - for (auto i = top->states.getNextSetIndex(0); i < numberOfStates; i = top->states.getNextSetIndex(i+1)) { - nodes.at(i) = top; - } - - for (auto i = bottom->states.getNextSetIndex(0); i < numberOfStates; i = bottom->states.getNextSetIndex(i+1)) { - nodes.at(i) = bottom; - } - auto oldNodes = lattice->getNodes(); // Create nodes for (auto itr = oldNodes.begin(); itr != oldNodes.end(); ++itr) { - Node* oldNode = (*itr); - if (oldNode != nullptr) { + Node *oldNode = (*itr); + if (oldNode != nullptr && oldNode != lattice->getTop() && oldNode != lattice->getBottom()) { Node *newNode = new Node(); newNode->states = storm::storage::BitVector(oldNode->states); - setStatesAbove(newNode, oldNode->statesAbove, false); - setStatesBelow(newNode, oldNode->statesBelow, false); for (auto i = newNode->states.getNextSetIndex(0); - i < numberOfStates; i = newNode->states.getNextSetIndex(i + 1)) { + i < newNode->states.size(); i = newNode->states.getNextSetIndex(i + 1)) { addedStates.set(i); nodes.at(i) = newNode; } } } - assert(addedStates == lattice->getAddedStates()); + + // set all states above and below + for (auto itr = oldNodes.begin(); itr != oldNodes.end(); ++itr) { + Node *oldNode = (*itr); + if (oldNode != nullptr && oldNode != lattice->getTop() && oldNode != lattice->getBottom()) { + Node *newNode = getNode(oldNode->states.getNextSetIndex(0)); + setStatesAbove(newNode, oldNode->statesAbove, false); + setStatesBelow(newNode, oldNode->statesBelow, false); + } else if (oldNode != nullptr && oldNode == lattice->getBottom()) { + setStatesAbove(bottom, lattice->getBottom()->statesAbove, false); + assert(lattice->getBottom()->statesBelow.getNumberOfSetBits() == 0); + bottom->below = new std::set({}); + bottom->statesBelow = storm::storage::BitVector(numberOfStates); + assert(bottom->statesAbove.size() == numberOfStates); + assert(bottom->statesBelow.size() == numberOfStates); + } else if (oldNode != nullptr && oldNode == lattice->getTop()) { + top->above = new std::set({}); + top->statesAbove = storm::storage::BitVector(numberOfStates); + assert(lattice->getTop()->statesAbove.getNumberOfSetBits() == 0); + setStatesBelow(top, lattice->getTop()->statesBelow, false); + assert(top->statesAbove.size() == numberOfStates); + assert(top->statesBelow.size() == numberOfStates); + } + + if (oldNode!= nullptr) { + Node *newNode = getNode(oldNode->states.getNextSetIndex(0)); + assert((newNode->statesAbove & newNode->statesBelow).getNumberOfSetBits() == 0); + assert(newNode->statesAbove == oldNode->statesAbove); + assert(newNode->statesBelow == oldNode->statesBelow); + assert(newNode->above->size() == oldNode->above->size()); + assert(newNode->below->size() == oldNode->below->size()); + } + } } void Lattice::addBetween(uint_fast64_t state, Node *above, Node *below) { assert(!addedStates[state]); - auto res = compare(above, below); - assert(res == ABOVE || res == UNKNOWN); + assert(compare(above, below) == ABOVE); Node *newNode = new Node(); + nodes.at(state) = newNode; + newNode->states = storm::storage::BitVector(numberOfStates); newNode->states.set(state); setStatesAbove(newNode, above->statesAbove | above->states, false); setStatesBelow(newNode, below->statesBelow | below->states, false); + setStatesBelow(above, state, true); + setStatesAbove(below, state, true); - setStatesBelow(above, state); - setStatesAbove(below, state); - - auto nodesBelow = getNodesBelow(below); - for (auto itr = nodesBelow.begin(); itr != nodesBelow.end(); ++itr) { - assert((*itr)->statesAbove.size() == numberOfStates); - setStatesAbove((*itr), state); + for (auto i = below->statesBelow.getNextSetIndex(0); i < below->statesBelow.size(); i = below->statesBelow.getNextSetIndex(i + 1)) { + setStatesAbove(getNode(i), state, true); } - auto nodesAbove = getNodesAbove(above); - for (auto itr = nodesAbove.begin(); itr != nodesAbove.end(); ++itr) { - assert((*itr)->statesBelow.size() == numberOfStates); - setStatesBelow((*itr), state); + for (auto i = above->statesAbove.getNextSetIndex(0); i < above->statesAbove.size(); i = above->statesAbove.getNextSetIndex(i + 1)) { + setStatesBelow(getNode(i), state, true); } - nodes.at(state) = newNode; addedStates.set(state); } @@ -115,13 +152,12 @@ namespace storm { node->states.set(state); nodes.at(state) = node; addedStates.set(state); - auto nodesBelow = getNodesBelow(node); - for (auto itr = nodesBelow.begin(); itr != nodesBelow.end(); ++itr) { - setStatesAbove((*itr), state); + for (auto i = node->statesBelow.getNextSetIndex(0); i < node->statesBelow.size(); i = node->statesBelow.getNextSetIndex(i + 1)) { + setStatesAbove(getNode(i), state, true); } - auto nodesAbove = getNodesAbove(node); - for (auto itr = nodesAbove.begin(); nodesAbove.size() != 0 &&itr != nodesAbove.end(); ++itr) { - setStatesBelow((*itr), state); + + for (auto i = node->statesAbove.getNextSetIndex(0); i < node->statesAbove.size(); i = node->statesAbove.getNextSetIndex(i + 1)) { + setStatesBelow(getNode(i), state, true); } } @@ -129,16 +165,19 @@ namespace storm { addBetween(state, top, bottom); } - void Lattice::addRelationNodes(storm::analysis::Lattice::Node *above, storm::analysis::Lattice::Node * below) { + void Lattice::addRelationNodes(Lattice::Node *above, Lattice::Node * below) { + assert(compare(above, below) == UNKNOWN); + assert((above->statesAbove & below->statesBelow).getNumberOfSetBits() == 0); + setStatesBelow(above, below->states, true); setStatesAbove(below, above->states, true); - auto nodesBelow = getNodesBelow(below); - for (auto itr = nodesBelow.begin(); itr != nodesBelow.end(); ++itr) { - setStatesAbove((*itr), above->states, true); + + for (auto i = below->statesBelow.getNextSetIndex(0); i < below->statesBelow.size(); i = below->statesBelow.getNextSetIndex(i + 1)) { + setStatesAbove(getNode(i), above->states, true); } - auto nodesAbove = getNodesAbove(above); - for (auto itr = nodesAbove.begin() ; itr != nodesAbove.end(); ++itr) { - setStatesBelow((*itr), below->states, true); + + for (auto i = above->statesAbove.getNextSetIndex(0); i < above->statesAbove.size(); i = above->statesAbove.getNextSetIndex(i + 1)) { + setStatesBelow(getNode(i), below->states, true); } } @@ -152,12 +191,12 @@ namespace storm { return SAME; } - if (above(node1, node2, std::make_shared>(std::set({})))) { - assert(!above(node2, node1, std::make_shared>(std::set({})))); + if (above(node1, node2)) { + assert(!above(node2, node1)); return ABOVE; } - if (above(node2, node1, std::make_shared>(std::set({})))) { + if (above(node2, node1)) { return BELOW; } } @@ -168,26 +207,6 @@ namespace storm { return nodes.at(stateNumber); } - std::set Lattice::getNodesAbove(Lattice::Node * node) { - if (node->recentlyAddedAbove.getNumberOfSetBits() != 0) { - for (auto i = node->recentlyAddedAbove.getNextSetIndex(0); i < node->recentlyAddedAbove.size(); i = node->recentlyAddedAbove.getNextSetIndex(i+1)) { - node->above.insert(getNode(i)); - } - node->recentlyAddedAbove.clear(); - } - return node->above; - } - - std::set Lattice::getNodesBelow(Lattice::Node * node) { - if (node->recentlyAddedBelow.getNumberOfSetBits() != 0) { - for (auto i = node->recentlyAddedBelow.getNextSetIndex(0); i < node->recentlyAddedBelow.size(); i = node->recentlyAddedBelow.getNextSetIndex(i+1)) { - node->below.insert(getNode(i)); - } - node->recentlyAddedBelow.clear(); - } - return node->above; - } - Lattice::Node *Lattice::getTop() { return top; } @@ -213,10 +232,10 @@ namespace storm { printedNodes.push_back(*itr); out << "Node: {"; uint_fast64_t index = node->states.getNextSetIndex(0); - while (index < numberOfStates) { + while (index < node->states.size()) { out << index; index = node->states.getNextSetIndex(index + 1); - if (index < numberOfStates) { + if (index < node->states.size()) { out << ", "; } } @@ -224,15 +243,14 @@ namespace storm { out << " Address: " << node << "\n"; out << " Above: {"; - getNodesAbove(node); // such that it is updated - for (auto itr2 = node->above.begin(); itr2 != node->above.end(); ++itr2) { + for (auto itr2 = node->above->begin(); itr2 != node->above->end(); ++itr2) { Node *above = *itr2; index = above->states.getNextSetIndex(0); out << "{"; - while (index < numberOfStates) { + while (index < above->states.size()) { out << index; index = above->states.getNextSetIndex(index + 1); - if (index < numberOfStates) { + if (index < above->states.size()) { out << ", "; } } @@ -243,16 +261,14 @@ namespace storm { out << " Below: {"; - getNodesBelow(node); // To make sure it is updated - // TODO verbeteren - for (auto itr2 = node->below.begin(); itr2 != node->below.end(); ++itr2) { + for (auto itr2 = node->below->begin(); itr2 != node->below->end(); ++itr2) { Node *below = *itr2; out << "{"; index = below->states.getNextSetIndex(0); - while (index < numberOfStates) { + while (index < below->states.size()) { out << index; index = below->states.getNextSetIndex(index + 1); - if (index < numberOfStates) { + if (index < below->states.size()) { out << ", "; } } @@ -275,10 +291,10 @@ namespace storm { if ((*itr) != nullptr && find(printed.begin(), printed.end(), (*itr)) == printed.end()) { out << "\t\"" << (*itr) << "\" [label = \""; uint_fast64_t index = (*itr)->states.getNextSetIndex(0); - while (index < numberOfStates) { + while (index < (*itr)->states.size()) { out << index; index = (*itr)->states.getNextSetIndex(index + 1); - if (index < numberOfStates) { + if (index < (*itr)->states.size()) { out << ", "; } } @@ -293,7 +309,7 @@ namespace storm { for (auto itr = nodes.begin(); itr != nodes.end(); ++itr) { if ((*itr) != nullptr && find(printed.begin(), printed.end(), (*itr)) == printed.end()) { auto below = (*itr)->below; - for (auto itr2 = below.begin(); itr2 != below.end(); ++itr2) { + for (auto itr2 = below->begin(); itr2 != below->end(); ++itr2) { out << "\t\"" << (*itr) << "\" -> \"" << (*itr2) << "\";" << std::endl; } printed.push_back(*itr); @@ -303,37 +319,62 @@ namespace storm { out << "}" << std::endl; } - bool Lattice::above(Node *node1, Node *node2, std::shared_ptr> seenNodes) { + bool Lattice::above(Node *node1, Node *node2) { return node1->statesBelow.get(node2->states.getNextSetIndex(0)); } - void Lattice::setStatesAbove(storm::analysis::Lattice::Node *node, uint_fast64_t state) { + void Lattice::setStatesAbove(Lattice::Node *node, uint_fast64_t state, bool alreadyInitialized) { + assert (!node->states.get(state)); + if (!alreadyInitialized) { + node->statesAbove = storm::storage::BitVector(numberOfStates); + node->above = new std::set({}); + } node->statesAbove.set(state); - node->recentlyAddedAbove.set(state); + node->above->insert(getNode(state)); } - void Lattice::setStatesBelow(storm::analysis::Lattice::Node *node, uint_fast64_t state) { + void Lattice::setStatesBelow(Lattice::Node *node, uint_fast64_t state, bool alreadyInitialized) { + assert (!node->states.get(state)); + if (!alreadyInitialized) { + node->statesBelow = storm::storage::BitVector(numberOfStates); + node->below = new std::set({}); + } node->statesBelow.set(state); - node->recentlyAddedBelow.set(state); + node->below->insert(getNode(state)); } - void Lattice::setStatesAbove(storm::analysis::Lattice::Node *node, storm::storage::BitVector states, bool alreadyInitialized) { + void Lattice::setStatesAbove(Lattice::Node *node, storm::storage::BitVector states, bool alreadyInitialized) { + assert((states.getNumberOfSetBits() - (node->states & states).getNumberOfSetBits()) != 0); + if (alreadyInitialized) { node->statesAbove |= states; - node->recentlyAddedAbove |= states; } else { node->statesAbove = storm::storage::BitVector(states); - node->recentlyAddedAbove = storm::storage::BitVector(states); + node->above = new std::set({}); + } + for (auto i = states.getNextSetIndex(0); i < states.size(); i = states.getNextSetIndex(i + 1)) { + if (node->states.get(i)) { + node->statesAbove.set(i, false); + } else { + node->above->insert(getNode(i)); + } } } - void Lattice::setStatesBelow(storm::analysis::Lattice::Node *node, storm::storage::BitVector states, bool alreadyInitialized) { + void Lattice::setStatesBelow(Lattice::Node *node, storm::storage::BitVector states, bool alreadyInitialized) { + assert((states.getNumberOfSetBits() - (node->states & states).getNumberOfSetBits()) != 0); if (alreadyInitialized) { node->statesBelow |= states; - node->recentlyAddedBelow |= states; } else { node->statesBelow = storm::storage::BitVector(states); - node->recentlyAddedBelow = storm::storage::BitVector(states); + node->below = new std::set({}); + } + for (auto i = states.getNextSetIndex(0); i < states.size(); i = states.getNextSetIndex(i + 1)) { + if (node->states.get(i)) { + node->statesBelow.set(i, false); + } else { + node->below->insert(getNode(i)); + } } } } diff --git a/src/storm-pars/analysis/Lattice.h b/src/storm-pars/analysis/Lattice.h index ce9cb7ce7..9d433b602 100644 --- a/src/storm-pars/analysis/Lattice.h +++ b/src/storm-pars/analysis/Lattice.h @@ -20,10 +20,8 @@ namespace storm { storm::storage::BitVector states; storm::storage::BitVector statesAbove; storm::storage::BitVector statesBelow; - storm::storage::BitVector recentlyAddedAbove; - storm::storage::BitVector recentlyAddedBelow; - std::set above; - std::set below; + std::set* above; + std::set* below; }; /*! @@ -109,9 +107,6 @@ namespace storm { */ std::vector getNodes(); - std::set getNodesBelow(Node* node); - std::set getNodesAbove(Node* node); - /*! * Returns a BitVector in which all added states are set. * @@ -154,13 +149,13 @@ namespace storm { uint_fast64_t numberOfStates; - bool above(Node * node1, Node * node2, std::shared_ptr> seenNodes); + bool above(Node * node1, Node * node2); int compare(Node* node1, Node* node2); - void setStatesAbove(Node* node, uint_fast64_t state); + void setStatesAbove(Node* node, uint_fast64_t state, bool alreadyInitialized); - void setStatesBelow(Node* node, uint_fast64_t state); + void setStatesBelow(Node* node, uint_fast64_t state, bool alreadyInitialized); void setStatesAbove(storm::analysis::Lattice::Node *node, storm::storage::BitVector states, bool alreadyInitialized); From ae7d334171bba49cd3b332a1136b7763f871e886 Mon Sep 17 00:00:00 2001 From: Jip Spel Date: Fri, 26 Oct 2018 18:14:45 +0200 Subject: [PATCH 122/178] Extend test --- src/test/storm-pars/analysis/LatticeTest.cpp | 33 ++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/src/test/storm-pars/analysis/LatticeTest.cpp b/src/test/storm-pars/analysis/LatticeTest.cpp index 14a02675c..3b36a7ada 100644 --- a/src/test/storm-pars/analysis/LatticeTest.cpp +++ b/src/test/storm-pars/analysis/LatticeTest.cpp @@ -23,7 +23,9 @@ TEST(LatticeTest, Simple) { lattice.add(2); EXPECT_EQ(storm::analysis::Lattice::ABOVE, lattice.compare(0,2)); + EXPECT_EQ(storm::analysis::Lattice::BELOW, lattice.compare(2,0)); EXPECT_EQ(storm::analysis::Lattice::ABOVE, lattice.compare(2,1)); + EXPECT_EQ(storm::analysis::Lattice::BELOW, lattice.compare(1,2)); lattice.add(3); EXPECT_EQ(storm::analysis::Lattice::UNKNOWN, lattice.compare(2,3)); @@ -31,29 +33,44 @@ TEST(LatticeTest, Simple) { lattice.addToNode(4, lattice.getNode(2)); EXPECT_EQ(storm::analysis::Lattice::SAME, lattice.compare(2,4)); + EXPECT_EQ(storm::analysis::Lattice::SAME, lattice.compare(4,2)); EXPECT_EQ(storm::analysis::Lattice::ABOVE, lattice.compare(0,4)); + EXPECT_EQ(storm::analysis::Lattice::BELOW, lattice.compare(4,0)); EXPECT_EQ(storm::analysis::Lattice::ABOVE, lattice.compare(4,1)); + EXPECT_EQ(storm::analysis::Lattice::BELOW, lattice.compare(1,4)); EXPECT_EQ(storm::analysis::Lattice::UNKNOWN, lattice.compare(4,3)); EXPECT_EQ(storm::analysis::Lattice::UNKNOWN, lattice.compare(3,4)); lattice.addBetween(5, lattice.getNode(0), lattice.getNode(3)); EXPECT_EQ(storm::analysis::Lattice::BELOW, lattice.compare(5,0)); + EXPECT_EQ(storm::analysis::Lattice::ABOVE, lattice.compare(0,5)); EXPECT_EQ(storm::analysis::Lattice::ABOVE, lattice.compare(5,3)); + EXPECT_EQ(storm::analysis::Lattice::BELOW, lattice.compare(3,5)); EXPECT_EQ(storm::analysis::Lattice::ABOVE, lattice.compare(5,1)); + EXPECT_EQ(storm::analysis::Lattice::BELOW, lattice.compare(1,5)); EXPECT_EQ(storm::analysis::Lattice::UNKNOWN, lattice.compare(5,2)); + EXPECT_EQ(storm::analysis::Lattice::UNKNOWN, lattice.compare(2,5)); EXPECT_EQ(storm::analysis::Lattice::UNKNOWN, lattice.compare(5,4)); + EXPECT_EQ(storm::analysis::Lattice::UNKNOWN, lattice.compare(4,5)); lattice.addBetween(6, lattice.getNode(5), lattice.getNode(3)); EXPECT_EQ(storm::analysis::Lattice::BELOW, lattice.compare(6,0)); + EXPECT_EQ(storm::analysis::Lattice::ABOVE, lattice.compare(0,6)); EXPECT_EQ(storm::analysis::Lattice::ABOVE, lattice.compare(6,1)); + EXPECT_EQ(storm::analysis::Lattice::BELOW, lattice.compare(1,6)); EXPECT_EQ(storm::analysis::Lattice::UNKNOWN, lattice.compare(6,2)); + EXPECT_EQ(storm::analysis::Lattice::UNKNOWN, lattice.compare(2,6)); EXPECT_EQ(storm::analysis::Lattice::ABOVE, lattice.compare(6,3)); + EXPECT_EQ(storm::analysis::Lattice::BELOW, lattice.compare(3,6)); + EXPECT_EQ(storm::analysis::Lattice::UNKNOWN, lattice.compare(6,4)); EXPECT_EQ(storm::analysis::Lattice::UNKNOWN, lattice.compare(6,4)); EXPECT_EQ(storm::analysis::Lattice::BELOW, lattice.compare(6,5)); + EXPECT_EQ(storm::analysis::Lattice::ABOVE, lattice.compare(5,6)); lattice.addRelationNodes(lattice.getNode(6), lattice.getNode(4)); EXPECT_EQ(storm::analysis::Lattice::ABOVE, lattice.compare(6,4)); + EXPECT_EQ(storm::analysis::Lattice::BELOW, lattice.compare(4,6)); } @@ -78,29 +95,45 @@ TEST(LatticeTest, copy_lattice) { EXPECT_EQ(storm::analysis::Lattice::BELOW, latticeCopy.compare(1,0)); EXPECT_EQ(storm::analysis::Lattice::ABOVE, latticeCopy.compare(0,2)); + EXPECT_EQ(storm::analysis::Lattice::BELOW, latticeCopy.compare(2,0)); EXPECT_EQ(storm::analysis::Lattice::ABOVE, latticeCopy.compare(2,1)); + EXPECT_EQ(storm::analysis::Lattice::BELOW, latticeCopy.compare(1,2)); EXPECT_EQ(storm::analysis::Lattice::UNKNOWN, latticeCopy.compare(2,3)); EXPECT_EQ(storm::analysis::Lattice::UNKNOWN, latticeCopy.compare(3,2)); EXPECT_EQ(storm::analysis::Lattice::SAME, latticeCopy.compare(2,4)); + EXPECT_EQ(storm::analysis::Lattice::SAME, latticeCopy.compare(4,2)); EXPECT_EQ(storm::analysis::Lattice::ABOVE, latticeCopy.compare(0,4)); + EXPECT_EQ(storm::analysis::Lattice::BELOW, latticeCopy.compare(4,0)); EXPECT_EQ(storm::analysis::Lattice::ABOVE, latticeCopy.compare(4,1)); + EXPECT_EQ(storm::analysis::Lattice::BELOW, latticeCopy.compare(1,4)); EXPECT_EQ(storm::analysis::Lattice::UNKNOWN, latticeCopy.compare(4,3)); EXPECT_EQ(storm::analysis::Lattice::UNKNOWN, latticeCopy.compare(3,4)); EXPECT_EQ(storm::analysis::Lattice::BELOW, latticeCopy.compare(5,0)); + EXPECT_EQ(storm::analysis::Lattice::ABOVE, latticeCopy.compare(0,5)); EXPECT_EQ(storm::analysis::Lattice::ABOVE, latticeCopy.compare(5,3)); + EXPECT_EQ(storm::analysis::Lattice::BELOW, latticeCopy.compare(3,5)); EXPECT_EQ(storm::analysis::Lattice::ABOVE, latticeCopy.compare(5,1)); + EXPECT_EQ(storm::analysis::Lattice::BELOW, latticeCopy.compare(1,5)); + EXPECT_EQ(storm::analysis::Lattice::UNKNOWN, latticeCopy.compare(5,2)); EXPECT_EQ(storm::analysis::Lattice::UNKNOWN, latticeCopy.compare(5,2)); EXPECT_EQ(storm::analysis::Lattice::UNKNOWN, latticeCopy.compare(5,4)); + EXPECT_EQ(storm::analysis::Lattice::UNKNOWN, latticeCopy.compare(5,4)); lattice.addRelationNodes(lattice.getNode(6), lattice.getNode(4)); latticeCopy = storm::analysis::Lattice(lattice); EXPECT_EQ(storm::analysis::Lattice::BELOW, latticeCopy.compare(6,0)); + EXPECT_EQ(storm::analysis::Lattice::ABOVE, latticeCopy.compare(0,6)); EXPECT_EQ(storm::analysis::Lattice::ABOVE, latticeCopy.compare(6,1)); + EXPECT_EQ(storm::analysis::Lattice::BELOW, latticeCopy.compare(1,6)); EXPECT_EQ(storm::analysis::Lattice::ABOVE, latticeCopy.compare(6,2)); + EXPECT_EQ(storm::analysis::Lattice::BELOW, latticeCopy.compare(2,6)); EXPECT_EQ(storm::analysis::Lattice::ABOVE, latticeCopy.compare(6,3)); + EXPECT_EQ(storm::analysis::Lattice::BELOW, latticeCopy.compare(3,6)); EXPECT_EQ(storm::analysis::Lattice::ABOVE, latticeCopy.compare(6,4)); + EXPECT_EQ(storm::analysis::Lattice::BELOW, latticeCopy.compare(4,6)); EXPECT_EQ(storm::analysis::Lattice::BELOW, latticeCopy.compare(6,5)); + EXPECT_EQ(storm::analysis::Lattice::ABOVE, latticeCopy.compare(5,6)); } From 7563d168e4fbc0070462cf64a5f0931b8f0a42b7 Mon Sep 17 00:00:00 2001 From: Jip Spel Date: Fri, 26 Oct 2018 18:18:37 +0200 Subject: [PATCH 123/178] Make sure statesAbove/Below are set correctly --- src/storm-pars/analysis/Lattice.cpp | 109 +++++++++--------- src/storm-pars/analysis/Lattice.h | 10 +- src/storm-pars/analysis/LatticeExtender.cpp | 42 ++++--- .../analysis/MonotonicityChecker.cpp | 1 + 4 files changed, 89 insertions(+), 73 deletions(-) diff --git a/src/storm-pars/analysis/Lattice.cpp b/src/storm-pars/analysis/Lattice.cpp index d16aad8ad..e8d351097 100644 --- a/src/storm-pars/analysis/Lattice.cpp +++ b/src/storm-pars/analysis/Lattice.cpp @@ -27,25 +27,19 @@ namespace storm { nodes.at(i) = bottom; } - top->above = new std::set({}); top->statesAbove = storm::storage::BitVector(numberOfStates); setStatesBelow(top, bottomStates, false); assert(top->statesAbove.size() == numberOfStates); assert(top->statesBelow.size() == numberOfStates); assert(top->statesAbove.getNumberOfSetBits() == 0); assert(top->statesBelow.getNumberOfSetBits() == bottomStates.getNumberOfSetBits()); - assert(top->above->size() == 0); - assert(top->below->size() == bottomStates.getNumberOfSetBits()); - bottom->below = new std::set({}); bottom->statesBelow = storm::storage::BitVector(numberOfStates); setStatesAbove(bottom, topStates, false); assert(bottom->statesAbove.size() == numberOfStates); assert(bottom->statesBelow.size() == numberOfStates); assert(bottom->statesBelow.getNumberOfSetBits() == 0); assert(bottom->statesAbove.getNumberOfSetBits() == topStates.getNumberOfSetBits()); - assert(bottom->below->size() == 0); - assert(bottom->above->size() == topStates.getNumberOfSetBits()); this->numberOfStates = numberOfStates; this->addedStates = storm::storage::BitVector(numberOfStates); @@ -56,28 +50,13 @@ namespace storm { Lattice::Lattice(Lattice* lattice) { numberOfStates = lattice->getAddedStates().size(); nodes = std::vector(numberOfStates); - - top = new Node(); - top->states = storm::storage::BitVector(lattice->getTop()->states); - for (auto i = top->states.getNextSetIndex(0); i < top->states.size(); i = top->states.getNextSetIndex(i+1)) { - nodes.at(i) = top; - } - - bottom = new Node(); - bottom->states = storm::storage::BitVector(lattice->getBottom()->states); - for (auto i = bottom->states.getNextSetIndex(0); i < bottom->states.size(); i = bottom->states.getNextSetIndex(i+1)) { - nodes.at(i) = bottom; - } - addedStates = storm::storage::BitVector(numberOfStates); - addedStates |= (top->states); - addedStates |= (bottom->states); auto oldNodes = lattice->getNodes(); // Create nodes for (auto itr = oldNodes.begin(); itr != oldNodes.end(); ++itr) { Node *oldNode = (*itr); - if (oldNode != nullptr && oldNode != lattice->getTop() && oldNode != lattice->getBottom()) { + if (oldNode != nullptr) { Node *newNode = new Node(); newNode->states = storm::storage::BitVector(oldNode->states); for (auto i = newNode->states.getNextSetIndex(0); @@ -85,6 +64,11 @@ namespace storm { addedStates.set(i); nodes.at(i) = newNode; } + if (oldNode == lattice->getTop()) { + top = newNode; + } else if (oldNode == lattice->getBottom()) { + bottom = newNode; + } } } assert(addedStates == lattice->getAddedStates()); @@ -98,27 +82,18 @@ namespace storm { setStatesBelow(newNode, oldNode->statesBelow, false); } else if (oldNode != nullptr && oldNode == lattice->getBottom()) { setStatesAbove(bottom, lattice->getBottom()->statesAbove, false); - assert(lattice->getBottom()->statesBelow.getNumberOfSetBits() == 0); - bottom->below = new std::set({}); bottom->statesBelow = storm::storage::BitVector(numberOfStates); - assert(bottom->statesAbove.size() == numberOfStates); - assert(bottom->statesBelow.size() == numberOfStates); } else if (oldNode != nullptr && oldNode == lattice->getTop()) { - top->above = new std::set({}); top->statesAbove = storm::storage::BitVector(numberOfStates); - assert(lattice->getTop()->statesAbove.getNumberOfSetBits() == 0); setStatesBelow(top, lattice->getTop()->statesBelow, false); - assert(top->statesAbove.size() == numberOfStates); - assert(top->statesBelow.size() == numberOfStates); } + // To check if everything went well if (oldNode!= nullptr) { Node *newNode = getNode(oldNode->states.getNextSetIndex(0)); assert((newNode->statesAbove & newNode->statesBelow).getNumberOfSetBits() == 0); assert(newNode->statesAbove == oldNode->statesAbove); assert(newNode->statesBelow == oldNode->statesBelow); - assert(newNode->above->size() == oldNode->above->size()); - assert(newNode->below->size() == oldNode->below->size()); } } } @@ -166,18 +141,17 @@ namespace storm { } void Lattice::addRelationNodes(Lattice::Node *above, Lattice::Node * below) { - assert(compare(above, below) == UNKNOWN); - assert((above->statesAbove & below->statesBelow).getNumberOfSetBits() == 0); + assert (compare(above, below) == UNKNOWN); - setStatesBelow(above, below->states, true); - setStatesAbove(below, above->states, true); + setStatesBelow(above, below->states | below->statesBelow, true); + setStatesAbove(below, above->states | above->statesAbove, true); for (auto i = below->statesBelow.getNextSetIndex(0); i < below->statesBelow.size(); i = below->statesBelow.getNextSetIndex(i + 1)) { - setStatesAbove(getNode(i), above->states, true); + setStatesAbove(getNode(i), above->states | above->statesAbove, true); } for (auto i = above->statesAbove.getNextSetIndex(0); i < above->statesAbove.size(); i = above->statesAbove.getNextSetIndex(i + 1)) { - setStatesBelow(getNode(i), below->states, true); + setStatesBelow(getNode(i), below->states | below->statesBelow, true); } } @@ -223,6 +197,30 @@ namespace storm { return addedStates; } + std::set Lattice::getAbove(uint_fast64_t state) { + return getAbove(getNode(state)); + } + + std::set Lattice::getBelow(uint_fast64_t state) { + return getBelow(getNode(state)); + } + + std::set Lattice::getAbove(Lattice::Node* node) { + std::set result({}); + for (auto i = node->statesAbove.getNextSetIndex(0); i < node->statesAbove.size(); i = node->statesAbove.getNextSetIndex(i + 1)) { + result.insert(getNode(i)); + } + return result; + } + + std::set Lattice::getBelow(Lattice::Node* node) { + std::set result({}); + for (auto i = node->statesBelow.getNextSetIndex(0); i < node->statesBelow.size(); i = node->statesBelow.getNextSetIndex(i + 1)) { + result.insert(getNode(i)); + } + return result; + } + void Lattice::toString(std::ostream &out) { std::vector printedNodes = std::vector({}); for (auto itr = nodes.begin(); itr != nodes.end(); ++itr) { @@ -243,7 +241,8 @@ namespace storm { out << " Address: " << node << "\n"; out << " Above: {"; - for (auto itr2 = node->above->begin(); itr2 != node->above->end(); ++itr2) { + auto statesAbove = getAbove(node); + for (auto itr2 = statesAbove.begin(); itr2 != statesAbove.end(); ++itr2) { Node *above = *itr2; index = above->states.getNextSetIndex(0); out << "{"; @@ -261,7 +260,8 @@ namespace storm { out << " Below: {"; - for (auto itr2 = node->below->begin(); itr2 != node->below->end(); ++itr2) { + auto statesBelow = getBelow(node); + for (auto itr2 = statesBelow.begin(); itr2 != statesBelow.end(); ++itr2) { Node *below = *itr2; out << "{"; index = below->states.getNextSetIndex(0); @@ -308,8 +308,8 @@ namespace storm { printed.clear(); for (auto itr = nodes.begin(); itr != nodes.end(); ++itr) { if ((*itr) != nullptr && find(printed.begin(), printed.end(), (*itr)) == printed.end()) { - auto below = (*itr)->below; - for (auto itr2 = below->begin(); itr2 != below->end(); ++itr2) { + auto below = getBelow(*itr); + for (auto itr2 = below.begin(); itr2 != below.end(); ++itr2) { out << "\t\"" << (*itr) << "\" -> \"" << (*itr2) << "\";" << std::endl; } printed.push_back(*itr); @@ -320,6 +320,21 @@ namespace storm { } bool Lattice::above(Node *node1, Node *node2) { + bool check = node1->statesBelow.get(node2->states.getNextSetIndex(0)); + for (auto i = node2->states.getNextSetIndex(0); i < node2->states.size(); i = node2->states.getNextSetIndex(i+1)) { + if (check) { + assert(node1->statesBelow.get(i)); + } else { + assert(!node1->statesBelow.get(i)); + } + } + for (auto i = node1->states.getNextSetIndex(0); i < node1->states.size(); i = node1->states.getNextSetIndex(i+1)) { + if (check) { + assert(node2->statesAbove.get(i)); + } else { + assert(!node2->statesAbove.get(i)); + } + } return node1->statesBelow.get(node2->states.getNextSetIndex(0)); } @@ -327,20 +342,16 @@ namespace storm { assert (!node->states.get(state)); if (!alreadyInitialized) { node->statesAbove = storm::storage::BitVector(numberOfStates); - node->above = new std::set({}); } node->statesAbove.set(state); - node->above->insert(getNode(state)); } void Lattice::setStatesBelow(Lattice::Node *node, uint_fast64_t state, bool alreadyInitialized) { assert (!node->states.get(state)); if (!alreadyInitialized) { node->statesBelow = storm::storage::BitVector(numberOfStates); - node->below = new std::set({}); } node->statesBelow.set(state); - node->below->insert(getNode(state)); } void Lattice::setStatesAbove(Lattice::Node *node, storm::storage::BitVector states, bool alreadyInitialized) { @@ -350,13 +361,10 @@ namespace storm { node->statesAbove |= states; } else { node->statesAbove = storm::storage::BitVector(states); - node->above = new std::set({}); } for (auto i = states.getNextSetIndex(0); i < states.size(); i = states.getNextSetIndex(i + 1)) { if (node->states.get(i)) { node->statesAbove.set(i, false); - } else { - node->above->insert(getNode(i)); } } } @@ -367,13 +375,10 @@ namespace storm { node->statesBelow |= states; } else { node->statesBelow = storm::storage::BitVector(states); - node->below = new std::set({}); } for (auto i = states.getNextSetIndex(0); i < states.size(); i = states.getNextSetIndex(i + 1)) { if (node->states.get(i)) { node->statesBelow.set(i, false); - } else { - node->below->insert(getNode(i)); } } } diff --git a/src/storm-pars/analysis/Lattice.h b/src/storm-pars/analysis/Lattice.h index 9d433b602..aeec31fb3 100644 --- a/src/storm-pars/analysis/Lattice.h +++ b/src/storm-pars/analysis/Lattice.h @@ -20,8 +20,6 @@ namespace storm { storm::storage::BitVector states; storm::storage::BitVector statesAbove; storm::storage::BitVector statesBelow; - std::set* above; - std::set* below; }; /*! @@ -114,6 +112,14 @@ namespace storm { */ storm::storage::BitVector getAddedStates(); + std::set getAbove(uint_fast64_t state); + + std::set getBelow(uint_fast64_t state); + + std::set getAbove(Lattice::Node* node); + + std::set getBelow(Lattice::Node* node); + /*! * Prints a string representation of the lattice to the output stream. * diff --git a/src/storm-pars/analysis/LatticeExtender.cpp b/src/storm-pars/analysis/LatticeExtender.cpp index 89d4d6ec9..4cc596571 100644 --- a/src/storm-pars/analysis/LatticeExtender.cpp +++ b/src/storm-pars/analysis/LatticeExtender.cpp @@ -34,7 +34,7 @@ namespace storm { } template - std::tuple LatticeExtender::toLattice(std::vector> formulas) { + std::tuple LatticeExtender::toLattice(std::vector> formulas) { storm::utility::Stopwatch latticeWatch(true); STORM_LOG_THROW((++formulas.begin()) == formulas.end(), storm::exceptions::NotSupportedException, "Only one formula allowed for monotonicity analysis"); @@ -107,7 +107,7 @@ namespace storm { } // Create the Lattice - storm::analysis::Lattice *lattice = new storm::analysis::Lattice(topStates, bottomStates, numberOfStates); + Lattice *lattice = new Lattice(topStates, bottomStates, numberOfStates); for (auto state = initialMiddleStates.getNextSetIndex(0); state != numberOfStates; state = initialMiddleStates.getNextSetIndex(state + 1)) { lattice->add(state); } @@ -119,7 +119,7 @@ namespace storm { } template - std::tuple LatticeExtender::extendLattice(storm::analysis::Lattice* lattice, std::shared_ptr assumption) { + std::tuple LatticeExtender::extendLattice(Lattice* lattice, std::shared_ptr assumption) { // TODO: split up auto numberOfStates = this->model->getNumberOfStates(); // First handle assumption @@ -137,9 +137,9 @@ namespace storm { auto val1 = std::stoul(var1.getName(), nullptr, 0); auto val2 = std::stoul(var2.getName(), nullptr, 0); auto comp = lattice->compare(val1, val2); - assert (comp == storm::analysis::Lattice::UNKNOWN || comp == storm::analysis::Lattice::SAME); - storm::analysis::Lattice::Node *n1 = lattice->getNode(val1); - storm::analysis::Lattice::Node *n2 = lattice->getNode(val2); + assert (comp == Lattice::UNKNOWN || comp == Lattice::SAME); + Lattice::Node *n1 = lattice->getNode(val1); + Lattice::Node *n2 = lattice->getNode(val2); if (n1 != nullptr && n2 != nullptr) { assert(false); @@ -157,12 +157,13 @@ namespace storm { assert (expr.getFirstOperand()->isVariable() && expr.getSecondOperand()->isVariable()); storm::expressions::Variable largest = expr.getFirstOperand()->asVariableExpression().getVariable(); storm::expressions::Variable smallest = expr.getSecondOperand()->asVariableExpression().getVariable(); - if (lattice->compare(std::stoul(largest.getName(), nullptr, 0), - std::stoul(smallest.getName(), nullptr, 0)) != - storm::analysis::Lattice::ABOVE) { - storm::analysis::Lattice::Node *n1 = lattice->getNode( + auto compareRes = lattice->compare(std::stoul(largest.getName(), nullptr, 0), + std::stoul(smallest.getName(), nullptr, 0)); + assert(compareRes == Lattice::UNKNOWN); + if (compareRes != Lattice::ABOVE) { + Lattice::Node *n1 = lattice->getNode( std::stoul(largest.getName(), nullptr, 0)); - storm::analysis::Lattice::Node *n2 = lattice->getNode( + Lattice::Node *n2 = lattice->getNode( std::stoul(smallest.getName(), nullptr, 0)); if (n1 != nullptr && n2 != nullptr) { @@ -209,24 +210,25 @@ namespace storm { uint_fast64_t successor2 = successors.getNextSetIndex(successor1 + 1); int compareResult = lattice->compare(successor1, successor2); - if (compareResult == storm::analysis::Lattice::ABOVE) { + if (compareResult == Lattice::ABOVE) { // successor 1 is closer to top than successor 2 lattice->addBetween(stateNumber, lattice->getNode(successor1), lattice->getNode(successor2)); - } else if (compareResult == storm::analysis::Lattice::BELOW) { + } else if (compareResult == Lattice::BELOW) { // successor 2 is closer to top than successor 1 lattice->addBetween(stateNumber, lattice->getNode(successor2), lattice->getNode(successor1)); - } else if (compareResult == storm::analysis::Lattice::SAME) { + } else if (compareResult == Lattice::SAME) { // the successors are at the same level lattice->addToNode(stateNumber, lattice->getNode(successor1)); } else { + assert(lattice->compare(successor1, successor2) == Lattice::UNKNOWN); return std::make_tuple(lattice, successor1, successor2); } } else if (check && successors.getNumberOfSetBits() > 2) { for (auto i = successors.getNextSetIndex(0); i < successors.size(); i = successors.getNextSetIndex(i+1)) { for (auto j = successors.getNextSetIndex(i+1); j < successors.size(); j = successors.getNextSetIndex(j+1)) { - if (lattice->compare(i,j) == storm::analysis::Lattice::UNKNOWN) { + if (lattice->compare(i,j) == Lattice::UNKNOWN) { return std::make_tuple(lattice, i, j); } } @@ -235,16 +237,18 @@ namespace storm { auto highest = successors.getNextSetIndex(0); auto lowest = highest; for (auto i = successors.getNextSetIndex(highest+1); i < successors.size(); i = successors.getNextSetIndex(i+1)) { - if (lattice->compare(i, highest) == storm::analysis::Lattice::ABOVE) { + if (lattice->compare(i, highest) == Lattice::ABOVE) { highest = i; } - if (lattice->compare(lowest, i) == storm::analysis::Lattice::ABOVE) { + if (lattice->compare(lowest, i) == Lattice::ABOVE) { lowest = i; } } lattice->addBetween(stateNumber, lattice->getNode(highest), lattice->getNode(lowest)); } + + // Checking for states which are already added to the lattice, and only have one successor left which haven't been added yet bool checkOneSuccLeft = seenStates[stateNumber] && successors.getNumberOfSetBits() <= 2; bool helper = true; for (auto succIndex = successors.getNextSetIndex(0); (check || checkOneSuccLeft) && succIndex != numberOfStates; succIndex = successors.getNextSetIndex(++succIndex)) { @@ -268,9 +272,9 @@ namespace storm { assert (seenStates[succ1]); auto nodeSucc = lattice->getNode(succ1); auto compare = lattice->compare(stateNumber, succ1); - if (compare == storm::analysis::Lattice::ABOVE) { + if (compare == Lattice::ABOVE) { lattice->addBetween(succ2, lattice->getTop(), lattice->getNode(stateNumber)); - } else if (compare == storm::analysis::Lattice::BELOW) { + } else if (compare == Lattice::BELOW) { lattice->addBetween(succ2, lattice->getNode(stateNumber), lattice->getBottom()); } } diff --git a/src/storm-pars/analysis/MonotonicityChecker.cpp b/src/storm-pars/analysis/MonotonicityChecker.cpp index d29779181..464cffe7b 100644 --- a/src/storm-pars/analysis/MonotonicityChecker.cpp +++ b/src/storm-pars/analysis/MonotonicityChecker.cpp @@ -196,6 +196,7 @@ namespace storm { auto assumption2 = *itr; if (!assumption1.second && !assumption2.second) { + // TODO: hier niet verder gaan als je iets gevonden hebt? auto assumptionsCopy = std::vector>(assumptions); auto latticeCopy = new storm::analysis::Lattice(lattice); assumptions.push_back(assumption1.first); From dd1540b4c6f5aa5deaafb6f8c6a88283ee6f8bcd Mon Sep 17 00:00:00 2001 From: Jip Spel Date: Mon, 29 Oct 2018 09:19:11 +0100 Subject: [PATCH 124/178] Update lattice --- src/storm-pars/analysis/Lattice.cpp | 62 ++++++++--------------------- src/storm-pars/analysis/Lattice.h | 29 ++++++++++++++ 2 files changed, 46 insertions(+), 45 deletions(-) diff --git a/src/storm-pars/analysis/Lattice.cpp b/src/storm-pars/analysis/Lattice.cpp index e8d351097..461962f3d 100644 --- a/src/storm-pars/analysis/Lattice.cpp +++ b/src/storm-pars/analysis/Lattice.cpp @@ -29,17 +29,9 @@ namespace storm { top->statesAbove = storm::storage::BitVector(numberOfStates); setStatesBelow(top, bottomStates, false); - assert(top->statesAbove.size() == numberOfStates); - assert(top->statesBelow.size() == numberOfStates); - assert(top->statesAbove.getNumberOfSetBits() == 0); - assert(top->statesBelow.getNumberOfSetBits() == bottomStates.getNumberOfSetBits()); bottom->statesBelow = storm::storage::BitVector(numberOfStates); setStatesAbove(bottom, topStates, false); - assert(bottom->statesAbove.size() == numberOfStates); - assert(bottom->statesBelow.size() == numberOfStates); - assert(bottom->statesBelow.getNumberOfSetBits() == 0); - assert(bottom->statesAbove.getNumberOfSetBits() == topStates.getNumberOfSetBits()); this->numberOfStates = numberOfStates; this->addedStates = storm::storage::BitVector(numberOfStates); @@ -71,6 +63,7 @@ namespace storm { } } } + assert(addedStates == lattice->getAddedStates()); // set all states above and below @@ -87,14 +80,6 @@ namespace storm { top->statesAbove = storm::storage::BitVector(numberOfStates); setStatesBelow(top, lattice->getTop()->statesBelow, false); } - - // To check if everything went well - if (oldNode!= nullptr) { - Node *newNode = getNode(oldNode->states.getNextSetIndex(0)); - assert((newNode->statesAbove & newNode->statesBelow).getNumberOfSetBits() == 0); - assert(newNode->statesAbove == oldNode->statesAbove); - assert(newNode->statesBelow == oldNode->statesBelow); - } } } @@ -119,14 +104,17 @@ namespace storm { for (auto i = above->statesAbove.getNextSetIndex(0); i < above->statesAbove.size(); i = above->statesAbove.getNextSetIndex(i + 1)) { setStatesBelow(getNode(i), state, true); } + addedStates.set(state); } void Lattice::addToNode(uint_fast64_t state, Node *node) { assert(!addedStates[state]); + node->states.set(state); nodes.at(state) = node; addedStates.set(state); + for (auto i = node->statesBelow.getNextSetIndex(0); i < node->statesBelow.size(); i = node->statesBelow.getNextSetIndex(i + 1)) { setStatesAbove(getNode(i), state, true); } @@ -320,66 +308,50 @@ namespace storm { } bool Lattice::above(Node *node1, Node *node2) { - bool check = node1->statesBelow.get(node2->states.getNextSetIndex(0)); - for (auto i = node2->states.getNextSetIndex(0); i < node2->states.size(); i = node2->states.getNextSetIndex(i+1)) { - if (check) { - assert(node1->statesBelow.get(i)); - } else { - assert(!node1->statesBelow.get(i)); - } - } - for (auto i = node1->states.getNextSetIndex(0); i < node1->states.size(); i = node1->states.getNextSetIndex(i+1)) { - if (check) { - assert(node2->statesAbove.get(i)); - } else { - assert(!node2->statesAbove.get(i)); - } - } return node1->statesBelow.get(node2->states.getNextSetIndex(0)); } void Lattice::setStatesAbove(Lattice::Node *node, uint_fast64_t state, bool alreadyInitialized) { assert (!node->states.get(state)); + if (!alreadyInitialized) { node->statesAbove = storm::storage::BitVector(numberOfStates); } + node->statesAbove.set(state); } void Lattice::setStatesBelow(Lattice::Node *node, uint_fast64_t state, bool alreadyInitialized) { assert (!node->states.get(state)); + if (!alreadyInitialized) { node->statesBelow = storm::storage::BitVector(numberOfStates); } + node->statesBelow.set(state); } void Lattice::setStatesAbove(Lattice::Node *node, storm::storage::BitVector states, bool alreadyInitialized) { assert((states.getNumberOfSetBits() - (node->states & states).getNumberOfSetBits()) != 0); + auto complement = storm::storage::BitVector(node->states); + complement.complement(); if (alreadyInitialized) { - node->statesAbove |= states; + node->statesAbove |= (states & complement); } else { - node->statesAbove = storm::storage::BitVector(states); - } - for (auto i = states.getNextSetIndex(0); i < states.size(); i = states.getNextSetIndex(i + 1)) { - if (node->states.get(i)) { - node->statesAbove.set(i, false); - } + node->statesAbove = (storm::storage::BitVector(states) & complement); } } void Lattice::setStatesBelow(Lattice::Node *node, storm::storage::BitVector states, bool alreadyInitialized) { assert((states.getNumberOfSetBits() - (node->states & states).getNumberOfSetBits()) != 0); + + auto complement = storm::storage::BitVector(node->states); + complement.complement(); if (alreadyInitialized) { - node->statesBelow |= states; + node->statesBelow |= (states & complement); } else { - node->statesBelow = storm::storage::BitVector(states); - } - for (auto i = states.getNextSetIndex(0); i < states.size(); i = states.getNextSetIndex(i + 1)) { - if (node->states.get(i)) { - node->statesBelow.set(i, false); - } + node->statesBelow = (storm::storage::BitVector(states) & complement); } } } diff --git a/src/storm-pars/analysis/Lattice.h b/src/storm-pars/analysis/Lattice.h index aeec31fb3..e2938cd79 100644 --- a/src/storm-pars/analysis/Lattice.h +++ b/src/storm-pars/analysis/Lattice.h @@ -31,6 +31,11 @@ namespace storm { Lattice(storm::storage::BitVector topStates, storm::storage::BitVector bottomStates, uint_fast64_t numberOfStates); + /*! + * Constructs a copy of the given lattice. + * + * @param lattice The original lattice. + */ Lattice(Lattice* lattice); /*! @@ -112,12 +117,36 @@ namespace storm { */ storm::storage::BitVector getAddedStates(); + /*! + * Returns a set with the nodes which are above the state. + * + * @param state The state number. + * @return The set with all nodes which are above the state. + */ std::set getAbove(uint_fast64_t state); + /*! + * Returns a set with the nodes which are below the state. + * + * @param state The state number. + * @return The set with all nodes which are below the state. + */ std::set getBelow(uint_fast64_t state); + /*! + * Returns a set with the nodes which are above the node. + * + * @param node The node. + * @return The set with all nodes which are above the node. + */ std::set getAbove(Lattice::Node* node); + /*! + * Returns a set with the nodes which are below the node. + * + * @param node The node. + * @return The set with all nodes which are below the node. + */ std::set getBelow(Lattice::Node* node); /*! From af23545a7b9ed90f324307d03093151623536a12 Mon Sep 17 00:00:00 2001 From: Jip Spel Date: Mon, 29 Oct 2018 10:27:22 +0100 Subject: [PATCH 125/178] Clean up Lattice Extender --- src/storm-pars/analysis/Lattice.cpp | 8 +- src/storm-pars/analysis/Lattice.h | 4 +- src/storm-pars/analysis/LatticeExtender.cpp | 279 +++++++++--------- src/storm-pars/analysis/LatticeExtender.h | 4 +- .../analysis/AssumptionCheckerTest.cpp | 7 +- src/test/storm-pars/analysis/LatticeTest.cpp | 6 +- .../analysis/MonotonicityCheckerTest.cpp | 6 +- 7 files changed, 164 insertions(+), 150 deletions(-) diff --git a/src/storm-pars/analysis/Lattice.cpp b/src/storm-pars/analysis/Lattice.cpp index 461962f3d..9a1bacbc4 100644 --- a/src/storm-pars/analysis/Lattice.cpp +++ b/src/storm-pars/analysis/Lattice.cpp @@ -9,7 +9,9 @@ namespace storm { namespace analysis { Lattice::Lattice(storm::storage::BitVector topStates, - storm::storage::BitVector bottomStates, uint_fast64_t numberOfStates) { + storm::storage::BitVector bottomStates, + storm::storage::BitVector initialMiddleStates, + uint_fast64_t numberOfStates) { assert(topStates.getNumberOfSetBits() != 0); assert(bottomStates.getNumberOfSetBits() != 0); assert((topStates & bottomStates).getNumberOfSetBits() == 0); @@ -37,6 +39,10 @@ namespace storm { this->addedStates = storm::storage::BitVector(numberOfStates); this->addedStates |= (topStates); this->addedStates |= (bottomStates); + + for (auto state = initialMiddleStates.getNextSetIndex(0); state < numberOfStates; state = initialMiddleStates.getNextSetIndex(state + 1)) { + add(state); + } } Lattice::Lattice(Lattice* lattice) { diff --git a/src/storm-pars/analysis/Lattice.h b/src/storm-pars/analysis/Lattice.h index e2938cd79..4bf9a68ee 100644 --- a/src/storm-pars/analysis/Lattice.h +++ b/src/storm-pars/analysis/Lattice.h @@ -29,7 +29,9 @@ namespace storm { * @param bottomNode The bottom node of the resulting lattice. */ Lattice(storm::storage::BitVector topStates, - storm::storage::BitVector bottomStates, uint_fast64_t numberOfStates); + storm::storage::BitVector bottomStates, + storm::storage::BitVector initialMiddleStates, + uint_fast64_t numberOfStates); /*! * Constructs a copy of the given lattice. diff --git a/src/storm-pars/analysis/LatticeExtender.cpp b/src/storm-pars/analysis/LatticeExtender.cpp index 4cc596571..d378f7e0a 100644 --- a/src/storm-pars/analysis/LatticeExtender.cpp +++ b/src/storm-pars/analysis/LatticeExtender.cpp @@ -78,8 +78,8 @@ namespace storm { } } - auto initialMiddleStates = storm::storage::BitVector(model->getNumberOfStates()); - // Check if MC is acyclic + auto initialMiddleStates = storm::storage::BitVector(numberOfStates); + // Check if MC contains cycles auto decomposition = storm::storage::StronglyConnectedComponentDecomposition(model->getTransitionMatrix(), false, false); for (auto i = 0; i < decomposition.size(); ++i) { auto scc = decomposition.getBlock(i); @@ -93,25 +93,17 @@ namespace storm { auto succ1 = successors.getNextSetIndex(0); auto succ2 = successors.getNextSetIndex(succ1 + 1); auto intersection = bottomStates | topStates; - if ((intersection[succ1] && ! intersection[succ2]) - || (intersection[succ2] && !intersection[succ1])) { + if (intersection[succ1] || intersection[succ2]) { initialMiddleStates.set(*stateItr); found = true; - } else if (intersection[succ1] && intersection[succ2]) { - found = true; } } - } } } // Create the Lattice - Lattice *lattice = new Lattice(topStates, bottomStates, numberOfStates); - for (auto state = initialMiddleStates.getNextSetIndex(0); state != numberOfStates; state = initialMiddleStates.getNextSetIndex(state + 1)) { - lattice->add(state); - } - + Lattice *lattice = new Lattice(topStates, bottomStates, initialMiddleStates, numberOfStates); latticeWatch.stop(); STORM_PRINT(std::endl << "Time for initialization of lattice: " << latticeWatch << "." << std::endl << std::endl); @@ -119,164 +111,169 @@ namespace storm { } template - std::tuple LatticeExtender::extendLattice(Lattice* lattice, std::shared_ptr assumption) { - // TODO: split up - auto numberOfStates = this->model->getNumberOfStates(); - // First handle assumption - if (assumption != nullptr) { - storm::expressions::BinaryRelationExpression expr = *assumption; - STORM_LOG_THROW(expr.getRelationType() == - storm::expressions::BinaryRelationExpression::RelationType::GreaterOrEqual - || expr.getRelationType() == - storm::expressions::BinaryRelationExpression::RelationType::Equal, - storm::exceptions::NotImplementedException, "Only GreaterOrEqual or Equal assumptions allowed"); - if (expr.getRelationType() == storm::expressions::BinaryRelationExpression::RelationType::Equal) { - assert (expr.getFirstOperand()->isVariable() && expr.getSecondOperand()->isVariable()); - storm::expressions::Variable var1 = expr.getFirstOperand()->asVariableExpression().getVariable(); - storm::expressions::Variable var2 = expr.getSecondOperand()->asVariableExpression().getVariable(); - auto val1 = std::stoul(var1.getName(), nullptr, 0); - auto val2 = std::stoul(var2.getName(), nullptr, 0); - auto comp = lattice->compare(val1, val2); - assert (comp == Lattice::UNKNOWN || comp == Lattice::SAME); - Lattice::Node *n1 = lattice->getNode(val1); - Lattice::Node *n2 = lattice->getNode(val2); - - if (n1 != nullptr && n2 != nullptr) { - assert(false); -// lattice->mergeNodes(n1, n2); - } else if (n1 != nullptr) { - lattice->addToNode(val2, n1); - } else if (n2 != nullptr) { - lattice->addToNode(val1, n2); - } else { - lattice->add(val1); - lattice->addToNode(val2, lattice->getNode(val1)); + void LatticeExtender::handleAssumption(Lattice* lattice, std::shared_ptr assumption) { + assert (assumption != nullptr); + + storm::expressions::BinaryRelationExpression expr = *assumption; + assert (expr.getRelationType() == storm::expressions::BinaryRelationExpression::RelationType::GreaterOrEqual + || expr.getRelationType() == storm::expressions::BinaryRelationExpression::RelationType::Equal); + + if (expr.getRelationType() == storm::expressions::BinaryRelationExpression::RelationType::Equal) { + assert (expr.getFirstOperand()->isVariable() && expr.getSecondOperand()->isVariable()); + storm::expressions::Variable var1 = expr.getFirstOperand()->asVariableExpression().getVariable(); + storm::expressions::Variable var2 = expr.getSecondOperand()->asVariableExpression().getVariable(); + auto val1 = std::stoul(var1.getName(), nullptr, 0); + auto val2 = std::stoul(var2.getName(), nullptr, 0); + auto comp = lattice->compare(val1, val2); + + assert (comp == Lattice::UNKNOWN); + Lattice::Node *n1 = lattice->getNode(val1); + Lattice::Node *n2 = lattice->getNode(val2); + + if (n1 != nullptr && n2 != nullptr) { + // TODO: mergeNode method + assert(false); + } else if (n1 != nullptr) { + lattice->addToNode(val2, n1); + } else if (n2 != nullptr) { + lattice->addToNode(val1, n2); + } else { + lattice->add(val1); + lattice->addToNode(val2, lattice->getNode(val1)); + } + } else { + assert (expr.getFirstOperand()->isVariable() && expr.getSecondOperand()->isVariable()); + storm::expressions::Variable largest = expr.getFirstOperand()->asVariableExpression().getVariable(); + storm::expressions::Variable smallest = expr.getSecondOperand()->asVariableExpression().getVariable(); + auto val1 = std::stoul(largest.getName(), nullptr, 0); + auto val2 = std::stoul(smallest.getName(), nullptr, 0); + auto compareRes = lattice->compare(val1, val2); + + assert(compareRes == Lattice::UNKNOWN); + Lattice::Node *n1 = lattice->getNode(val1); + Lattice::Node *n2 = lattice->getNode(val2); + + if (n1 != nullptr && n2 != nullptr) { + lattice->addRelationNodes(n1, n2); + } else if (n1 != nullptr) { + lattice->addBetween(val2, n1, lattice->getBottom()); + } else if (n2 != nullptr) { + lattice->addBetween(val1, lattice->getTop(), n2); + } else { + lattice->add(val1); + lattice->addBetween(val2, lattice->getNode(val1), lattice->getBottom()); + } + } + } - } + template + std::tuple LatticeExtender::extendAllSuccAdded(Lattice* lattice, uint_fast64_t stateNumber, storm::storage::BitVector successors) { + auto numberOfStates = successors.size(); + assert (lattice->getAddedStates().size() == numberOfStates); + + if (successors.getNumberOfSetBits() == 1) { + // As there is only one successor the current state and its successor must be at the same nodes. + lattice->addToNode(stateNumber, lattice->getNode(successors.getNextSetIndex(0))); + } else if (successors.getNumberOfSetBits() == 2) { + // Otherwise, check how the two states compare, and add if the comparison is possible. + uint_fast64_t successor1 = successors.getNextSetIndex(0); + uint_fast64_t successor2 = successors.getNextSetIndex(successor1 + 1); + + int compareResult = lattice->compare(successor1, successor2); + if (compareResult == Lattice::ABOVE) { + // successor 1 is closer to top than successor 2 + lattice->addBetween(stateNumber, lattice->getNode(successor1), + lattice->getNode(successor2)); + } else if (compareResult == Lattice::BELOW) { + // successor 2 is closer to top than successor 1 + lattice->addBetween(stateNumber, lattice->getNode(successor2), + lattice->getNode(successor1)); + } else if (compareResult == Lattice::SAME) { + // the successors are at the same level + lattice->addToNode(stateNumber, lattice->getNode(successor1)); } else { - assert (expr.getFirstOperand()->isVariable() && expr.getSecondOperand()->isVariable()); - storm::expressions::Variable largest = expr.getFirstOperand()->asVariableExpression().getVariable(); - storm::expressions::Variable smallest = expr.getSecondOperand()->asVariableExpression().getVariable(); - auto compareRes = lattice->compare(std::stoul(largest.getName(), nullptr, 0), - std::stoul(smallest.getName(), nullptr, 0)); - assert(compareRes == Lattice::UNKNOWN); - if (compareRes != Lattice::ABOVE) { - Lattice::Node *n1 = lattice->getNode( - std::stoul(largest.getName(), nullptr, 0)); - Lattice::Node *n2 = lattice->getNode( - std::stoul(smallest.getName(), nullptr, 0)); - - if (n1 != nullptr && n2 != nullptr) { - lattice->addRelationNodes(n1, n2); - } else if (n1 != nullptr) { - lattice->addBetween(std::stoul(smallest.getName(), nullptr, 0), n1, - lattice->getBottom()); - } else if (n2 != nullptr) { - lattice->addBetween(std::stoul(largest.getName(), nullptr, 0), lattice->getTop(), n2); - } else { - lattice->add(std::stoul(largest.getName(), nullptr, 0)); - lattice->addBetween(std::stoul(smallest.getName(), nullptr, 0), - lattice->getNode(std::stoul(largest.getName(), nullptr, 0)), - lattice->getBottom()); + assert(lattice->compare(successor1, successor2) == Lattice::UNKNOWN); + return std::make_tuple(lattice, successor1, successor2); + } + } else if (successors.getNumberOfSetBits() > 2) { + for (auto i = successors.getNextSetIndex(0); i < numberOfStates; i = successors.getNextSetIndex(i+1)) { + for (auto j = successors.getNextSetIndex(i+1); j < numberOfStates; j = successors.getNextSetIndex(j+1)) { + if (lattice->compare(i,j) == Lattice::UNKNOWN) { + return std::make_tuple(lattice, i, j); } } } + + auto highest = successors.getNextSetIndex(0); + auto lowest = highest; + for (auto i = successors.getNextSetIndex(highest+1); i < numberOfStates; i = successors.getNextSetIndex(i+1)) { + if (lattice->compare(i, highest) == Lattice::ABOVE) { + highest = i; + } + if (lattice->compare(lowest, i) == Lattice::ABOVE) { + lowest = i; + } + } + lattice->addBetween(stateNumber, lattice->getNode(highest), lattice->getNode(lowest)); + } + return std::make_tuple(lattice, numberOfStates, numberOfStates); + } + + template + std::tuple LatticeExtender::extendLattice(Lattice* lattice, std::shared_ptr assumption) { + auto numberOfStates = this->model->getNumberOfStates(); + + if (assumption != nullptr) { + handleAssumption(lattice, assumption); } auto oldNumberSet = numberOfStates; while (oldNumberSet != lattice->getAddedStates().getNumberOfSetBits()) { oldNumberSet = lattice->getAddedStates().getNumberOfSetBits(); + // TODO: kan dit niet efficienter for (auto stateItr = stateMap.begin(); stateItr != stateMap.end(); ++stateItr) { - storm::storage::BitVector seenStates = (lattice->getAddedStates()); // Iterate over all states auto stateNumber = stateItr->first; storm::storage::BitVector successors = stateItr->second; + auto seenStates = (lattice->getAddedStates()); + // Check if current state has not been added yet, and all successors have bool check = !seenStates[stateNumber]; - for (auto succIndex = successors.getNextSetIndex(0); check && succIndex != numberOfStates; succIndex = successors.getNextSetIndex(++succIndex)) { + for (auto succIndex = successors.getNextSetIndex(0); check && succIndex != successors.size(); succIndex = successors.getNextSetIndex(++succIndex)) { + // if the stateNumber equals succIndex we have a self-loop, ignoring selfloop as seenStates[stateNumber] = false if (succIndex != stateNumber) { check &= seenStates[succIndex]; } - // if the stateNumber equals succIndex we have a self-loop } - if (check && successors.getNumberOfSetBits() == 1) { - // As there is only one successor the current state and its successor must be at the same nodes. - lattice->addToNode(stateNumber, lattice->getNode(successors.getNextSetIndex(0))); - } else if (check && successors.getNumberOfSetBits() == 2) { - // Otherwise, check how the two states compare, and add if the comparison is possible. - uint_fast64_t successor1 = successors.getNextSetIndex(0); - uint_fast64_t successor2 = successors.getNextSetIndex(successor1 + 1); - - int compareResult = lattice->compare(successor1, successor2); - if (compareResult == Lattice::ABOVE) { - // successor 1 is closer to top than successor 2 - lattice->addBetween(stateNumber, lattice->getNode(successor1), - lattice->getNode(successor2)); - } else if (compareResult == Lattice::BELOW) { - // successor 2 is closer to top than successor 1 - lattice->addBetween(stateNumber, lattice->getNode(successor2), - lattice->getNode(successor1)); - } else if (compareResult == Lattice::SAME) { - // the successors are at the same level - lattice->addToNode(stateNumber, lattice->getNode(successor1)); - } else { - assert(lattice->compare(successor1, successor2) == Lattice::UNKNOWN); - return std::make_tuple(lattice, successor1, successor2); - } - } else if (check && successors.getNumberOfSetBits() > 2) { - for (auto i = successors.getNextSetIndex(0); i < successors.size(); i = successors.getNextSetIndex(i+1)) { - for (auto j = successors.getNextSetIndex(i+1); j < successors.size(); j = successors.getNextSetIndex(j+1)) { - if (lattice->compare(i,j) == Lattice::UNKNOWN) { - return std::make_tuple(lattice, i, j); - } - } - } - - auto highest = successors.getNextSetIndex(0); - auto lowest = highest; - for (auto i = successors.getNextSetIndex(highest+1); i < successors.size(); i = successors.getNextSetIndex(i+1)) { - if (lattice->compare(i, highest) == Lattice::ABOVE) { - highest = i; - } - if (lattice->compare(lowest, i) == Lattice::ABOVE) { - lowest = i; - } + if (check) { + auto result = extendAllSuccAdded(lattice, stateNumber, successors); + if (std::get<1>(result) != successors.size()) { + return result; } - lattice->addBetween(stateNumber, lattice->getNode(highest), lattice->getNode(lowest)); } - // Checking for states which are already added to the lattice, and only have one successor left which haven't been added yet - bool checkOneSuccLeft = seenStates[stateNumber] && successors.getNumberOfSetBits() <= 2; - bool helper = true; - for (auto succIndex = successors.getNextSetIndex(0); (check || checkOneSuccLeft) && succIndex != numberOfStates; succIndex = successors.getNextSetIndex(++succIndex)) { - checkOneSuccLeft &= !(!helper && !seenStates[succIndex]); - helper &= seenStates[succIndex]; - } + auto succ1 = successors.getNextSetIndex(0); + auto succ2 = successors.getNextSetIndex(succ1 + 1); - checkOneSuccLeft &= !helper; + if (seenStates[stateNumber] && successors.size() == 2 + && (seenStates[succ1] || seenStates[succ2]) + && (!seenStates[succ1] || !seenStates[succ2])) { + if (!seenStates[succ1]) { + std::swap(succ1, succ2); + } - if (checkOneSuccLeft) { - // at most 2 successors - auto succ1 = successors.getNextSetIndex(0); - auto succ2 = successors.getNextSetIndex(succ1+1); - // Otherwise there is just one transition, this is already handled above - if (succ2 != numberOfStates) { - auto nodeCurr = lattice->getNode(stateNumber); - if (!seenStates[succ1]) { - std::swap(succ1, succ2); - } - assert (seenStates[succ1]); - auto nodeSucc = lattice->getNode(succ1); - auto compare = lattice->compare(stateNumber, succ1); - if (compare == Lattice::ABOVE) { - lattice->addBetween(succ2, lattice->getTop(), lattice->getNode(stateNumber)); - } else if (compare == Lattice::BELOW) { - lattice->addBetween(succ2, lattice->getNode(stateNumber), lattice->getBottom()); - } + auto compare = lattice->compare(stateNumber, succ1); + if (compare == Lattice::ABOVE) { + lattice->addBetween(succ2, lattice->getTop(), lattice->getNode(stateNumber)); + } else if (compare == Lattice::BELOW) { + lattice->addBetween(succ2, lattice->getNode(stateNumber), lattice->getBottom()); + } else { + // TODO: implement? + assert(false); } } } diff --git a/src/storm-pars/analysis/LatticeExtender.h b/src/storm-pars/analysis/LatticeExtender.h index 01b0554a8..e4cd8b0c4 100644 --- a/src/storm-pars/analysis/LatticeExtender.h +++ b/src/storm-pars/analysis/LatticeExtender.h @@ -54,7 +54,9 @@ namespace storm { std::map stateMap; -// storm::storage::BitVector initialMiddleStates; + void handleAssumption(Lattice* lattice, std::shared_ptr assumption); + + std::tuple extendAllSuccAdded(Lattice* lattice, uint_fast64_t stateNumber, storm::storage::BitVector successors); }; } } diff --git a/src/test/storm-pars/analysis/AssumptionCheckerTest.cpp b/src/test/storm-pars/analysis/AssumptionCheckerTest.cpp index 2e59d1b13..3880a525f 100644 --- a/src/test/storm-pars/analysis/AssumptionCheckerTest.cpp +++ b/src/test/storm-pars/analysis/AssumptionCheckerTest.cpp @@ -66,7 +66,9 @@ TEST(AssumptionCheckerTest, Brp_no_bisimulation) { above.set(0); storm::storage::BitVector below(8); below.set(1); - auto dummyLattice = new storm::analysis::Lattice(above, below, 8); + storm::storage::BitVector initialMiddle(8); + + auto dummyLattice = new storm::analysis::Lattice(above, below, initialMiddle, 8); // Validate assumption EXPECT_FALSE(checker.validateAssumption(assumption, dummyLattice)); EXPECT_FALSE(checker.validated(assumption)); @@ -82,7 +84,8 @@ TEST(AssumptionCheckerTest, Brp_no_bisimulation) { above.set(12); below = storm::storage::BitVector(13); below.set(9); - dummyLattice = new storm::analysis::Lattice(above, below, 13); + initialMiddle = storm::storage::BitVector(13); + dummyLattice = new storm::analysis::Lattice(above, below, initialMiddle, 13); EXPECT_TRUE(checker.checkOnSamples(assumption)); EXPECT_TRUE(checker.validateAssumption(assumption, dummyLattice)); EXPECT_TRUE(checker.validated(assumption)); diff --git a/src/test/storm-pars/analysis/LatticeTest.cpp b/src/test/storm-pars/analysis/LatticeTest.cpp index 3b36a7ada..5fba6eac4 100644 --- a/src/test/storm-pars/analysis/LatticeTest.cpp +++ b/src/test/storm-pars/analysis/LatticeTest.cpp @@ -15,8 +15,9 @@ TEST(LatticeTest, Simple) { above.set(0); auto below = storm::storage::BitVector(numberOfStates); below.set(1); + auto initialMiddle = storm::storage::BitVector(numberOfStates); - auto lattice = storm::analysis::Lattice(above, below, numberOfStates); + auto lattice = storm::analysis::Lattice(above, below, initialMiddle, numberOfStates); EXPECT_EQ(storm::analysis::Lattice::ABOVE, lattice.compare(0,1)); EXPECT_EQ(storm::analysis::Lattice::BELOW, lattice.compare(1,0)); EXPECT_EQ(nullptr, lattice.getNode(2)); @@ -80,8 +81,9 @@ TEST(LatticeTest, copy_lattice) { above.set(0); auto below = storm::storage::BitVector(numberOfStates); below.set(1); + auto initialMiddle = storm::storage::BitVector(numberOfStates); - auto lattice = storm::analysis::Lattice(above, below, numberOfStates); + auto lattice = storm::analysis::Lattice(above, below, initialMiddle, numberOfStates); lattice.add(2); lattice.add(3); lattice.addToNode(4, lattice.getNode(2)); diff --git a/src/test/storm-pars/analysis/MonotonicityCheckerTest.cpp b/src/test/storm-pars/analysis/MonotonicityCheckerTest.cpp index af9f6628f..12631b65a 100644 --- a/src/test/storm-pars/analysis/MonotonicityCheckerTest.cpp +++ b/src/test/storm-pars/analysis/MonotonicityCheckerTest.cpp @@ -37,7 +37,8 @@ TEST(MonotonicityCheckerTest, Monotone_no_model) { above.set(1); auto below = storm::storage::BitVector(numberOfStates); below.set(0); - auto lattice = storm::analysis::Lattice(above, below, numberOfStates); + auto initialMiddle = storm::storage::BitVector(numberOfStates); + auto lattice = storm::analysis::Lattice(above, below, initialMiddle, numberOfStates); lattice.add(2); lattice.add(3); // Build map @@ -82,7 +83,8 @@ TEST(MonotonicityCheckerTest, Not_monotone_no_model) { above.set(1); auto below = storm::storage::BitVector(numberOfStates); below.set(0); - auto lattice = storm::analysis::Lattice(above, below, numberOfStates); + auto initialMiddle = storm::storage::BitVector(numberOfStates); + auto lattice = storm::analysis::Lattice(above, below, initialMiddle, numberOfStates); lattice.add(2); lattice.add(3); // Build map From b04a853319a9425f31456a578fb83f0878808e5d Mon Sep 17 00:00:00 2001 From: Jip Spel Date: Mon, 29 Oct 2018 12:33:41 +0100 Subject: [PATCH 126/178] Check on number of set bits instead of vector size --- src/storm-pars/analysis/LatticeExtender.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/storm-pars/analysis/LatticeExtender.cpp b/src/storm-pars/analysis/LatticeExtender.cpp index d378f7e0a..dc80e3106 100644 --- a/src/storm-pars/analysis/LatticeExtender.cpp +++ b/src/storm-pars/analysis/LatticeExtender.cpp @@ -258,7 +258,7 @@ namespace storm { auto succ1 = successors.getNextSetIndex(0); auto succ2 = successors.getNextSetIndex(succ1 + 1); - if (seenStates[stateNumber] && successors.size() == 2 + if (seenStates[stateNumber] && successors.getNumberOfSetBits() == 2 && (seenStates[succ1] || seenStates[succ2]) && (!seenStates[succ1] || !seenStates[succ2])) { From 748098e8918ddcf0fe92cfce20098b05d20e2411 Mon Sep 17 00:00:00 2001 From: Jip Spel Date: Mon, 29 Oct 2018 13:35:07 +0100 Subject: [PATCH 127/178] Output to results.txt file --- src/storm-pars-cli/storm-pars.cpp | 5 +- .../analysis/MonotonicityChecker.cpp | 140 +++++++----------- src/storm-pars/analysis/MonotonicityChecker.h | 9 +- 3 files changed, 62 insertions(+), 92 deletions(-) diff --git a/src/storm-pars-cli/storm-pars.cpp b/src/storm-pars-cli/storm-pars.cpp index 9e44097ee..0c5ea4b40 100644 --- a/src/storm-pars-cli/storm-pars.cpp +++ b/src/storm-pars-cli/storm-pars.cpp @@ -1,5 +1,4 @@ - #include "storm-pars/analysis/MonotonicityChecker.h" #include "storm-cli-utilities/cli.h" @@ -527,6 +526,10 @@ namespace storm { std::vector> formulas = storm::api::extractFormulasFromProperties(input.properties); // Monotonicity + std::ofstream outfile; + outfile.open("results.txt", std::ios_base::app); + outfile << std::endl << ioSettings.getPrismInputFilename() << "; "; + outfile.close(); storm::utility::Stopwatch monotonicityWatch(true); auto monotonicityChecker = storm::analysis::MonotonicityChecker(model, formulas, parSettings.isValidateAssumptionsSet()); monotonicityChecker.checkMonotonicity(); diff --git a/src/storm-pars/analysis/MonotonicityChecker.cpp b/src/storm-pars/analysis/MonotonicityChecker.cpp index 464cffe7b..10d61e6a0 100644 --- a/src/storm-pars/analysis/MonotonicityChecker.cpp +++ b/src/storm-pars/analysis/MonotonicityChecker.cpp @@ -23,6 +23,7 @@ namespace storm { namespace analysis { template MonotonicityChecker::MonotonicityChecker(std::shared_ptr model, std::vector> formulas, bool validate) { + outfile.open(filename, std::ios_base::app); this->model = model; this->formulas = formulas; this->validate = validate; @@ -30,39 +31,20 @@ namespace storm { if (model != nullptr) { std::shared_ptr> sparseModel = model->as>(); this->extender = new storm::analysis::LatticeExtender(sparseModel); + outfile << model->getNumberOfStates() << "; " << model->getNumberOfTransitions() << "; "; } + outfile.close(); + totalWatch = storm::utility::Stopwatch(true); } template std::map>> MonotonicityChecker::checkMonotonicity() { - std::map> maybeMonotone; - if (model->isOfType(storm::models::ModelType::Dtmc)) { - auto dtmc = model->as>(); - maybeMonotone = checkOnSamples(dtmc,3); - } else if (model->isOfType(storm::models::ModelType::Mdp)) { - auto mdp = model->as>(); - maybeMonotone = checkOnSamples(mdp,3); - } else { - STORM_LOG_THROW(false, storm::exceptions::InvalidOperationException, "Unable to perform monotonicity analysis on the provided model type."); - } - - bool allNotMonotone = true; - for (auto itr = maybeMonotone.begin(); itr != maybeMonotone.end(); ++itr) { - if (itr->second.first || itr->second.second) { - allNotMonotone = false; - } - } - - if (!allNotMonotone) { - auto map = createLattice(); - std::shared_ptr> sparseModel = model->as>(); - auto matrix = sparseModel->getTransitionMatrix(); - return checkMonotonicity(map, matrix); - } else { - std::map>> result; - STORM_PRINT(std::endl << "Not monotone in all parameters" << std::endl); - return result; - } + totalWatch = storm::utility::Stopwatch(true); + // TODO: check on samples or not? + auto map = createLattice(); + std::shared_ptr> sparseModel = model->as>(); + auto matrix = sparseModel->getTransitionMatrix(); + return checkMonotonicity(map, matrix); } template @@ -70,26 +52,31 @@ namespace storm { storm::utility::Stopwatch finalCheckWatch(true); std::map>> result; + if (map.size() == 0) { + outfile.open(filename, std::ios_base::app); + outfile << " | No assumptions, ? | ;"; + outfile.close(); STORM_PRINT(std::endl << "Do not know about monotonicity" << std::endl); } else { auto i = 0; - for (auto itr = map.begin(); i < map.size() && itr != map.end(); ++itr) { auto lattice = itr->first; - auto assumptions = itr->second; -// std::ofstream myfile; -// std::string filename = "lattice" + std::to_string(i) + ".dot"; -// myfile.open(filename); -// lattice->toDotFile(myfile); -// myfile.close(); + outfile.open(filename, std::ios_base::app); + outfile << "|"; + outfile.close(); + std::map> varsMonotone = analyseMonotonicity(i, lattice, + matrix); + outfile.open(filename, std::ios_base::app); + auto assumptions = itr->second; if (assumptions.size() > 0) { STORM_PRINT("Given assumptions: " << std::endl); bool first = true; for (auto itr2 = assumptions.begin(); itr2 != assumptions.end(); ++itr2) { if (!first) { STORM_PRINT(" ^ "); + outfile << (" ^ "); } else { STORM_PRINT(" "); first = false; @@ -99,45 +86,63 @@ namespace storm { auto var1 = expression->getFirstOperand(); auto var2 = expression->getSecondOperand(); STORM_PRINT(*expression); + outfile << (*expression); } STORM_PRINT(std::endl); + outfile << ", "; + } else { + outfile << "No assumptions, "; } - std::map> varsMonotone = analyseMonotonicity(i, lattice, - matrix); + if (varsMonotone.size() == 0) { STORM_PRINT("Result is constant" << std::endl); + outfile << "No params"; } else { - for (auto itr2 = varsMonotone.begin(); itr2 != varsMonotone.end(); ++itr2) { + auto itr2 = varsMonotone.begin(); + while (itr2 != varsMonotone.end()) { if (resultCheckOnSamples.find(itr2->first) != resultCheckOnSamples.end() && (!resultCheckOnSamples[itr2->first].first && !resultCheckOnSamples[itr2->first].second)) { STORM_PRINT(" - Not monotone in: " << itr2->first << std::endl); + outfile << "X " << itr2->first; } else { - if (itr2->second.first) { + if (itr2->second.first && itr2->second.second) { + STORM_PRINT(" - Constant in" << itr2->first); + outfile << "C " << itr2->first; + } else if (itr2->second.first) { STORM_PRINT(" - Monotone increasing in: " << itr2->first << std::endl); - } else { - STORM_PRINT( - " - Do not know if monotone increasing in: " << itr2->first << std::endl); - } - if (itr2->second.second) { + outfile << "I " << itr2->first; + } else if (itr2->second.second) { STORM_PRINT(" - Monotone decreasing in: " << itr2->first << std::endl); + outfile << "D " << itr2->first; } else { STORM_PRINT( - " - Do not know if monotone decreasing in: " << itr2->first << std::endl); + " - Do not know if monotone incr/decreasing in: " << itr2->first << std::endl); + outfile << "? " << itr2->first; } } + ++itr2; + if (itr2 != varsMonotone.end()) { + outfile << ", "; + } } result.insert( std::pair>>( lattice, varsMonotone)); } + outfile << "| "; + outfile.close(); ++i; } } finalCheckWatch.stop(); STORM_PRINT(std::endl << "Time for monotonicity check on lattice: " << finalCheckWatch << "." << std::endl << std::endl); + outfile.open(filename, std::ios_base::app); + totalWatch.stop(); + outfile << totalWatch << "; "; + outfile.close(); return result; } @@ -176,6 +181,7 @@ namespace storm { } latticeWatch.stop(); STORM_PRINT(std::endl << "Total time for lattice creation: " << latticeWatch << "." << std::endl << std::endl); + outfile << latticeWatch << "; "; return result; } @@ -257,16 +263,6 @@ namespace storm { storm::utility::Stopwatch analyseWatch(true); std::map> varsMonotone; -// std::ofstream myfile; -// std::string filename = "mc" + std::to_string(j) + ".dot"; -// myfile.open (filename); -// myfile << "digraph \"MC\" {" << std::endl; -// myfile << "\t" << "node [shape=ellipse]" << std::endl; - - // print all nodes -// for (uint_fast64_t i = 0; i < matrix.getColumnCount(); ++i) { -// myfile << "\t\"" << i << "\" [label = \"" << i << "\"]" << std::endl; -// } for (uint_fast64_t i = 0; i < matrix.getColumnCount(); ++i) { // go over all rows @@ -279,7 +275,6 @@ namespace storm { transitions.insert(std::pair((*itr).getColumn(), (*itr).getValue())); } -// std::string color = ""; auto val = first.getValue(); auto vars = val.gatherVariables(); for (auto itr = vars.begin(); itr != vars.end(); ++itr) { @@ -289,7 +284,6 @@ namespace storm { varsMonotone[*itr].first = false; varsMonotone[*itr].second = false; } -// color = "color = red, "; } else { if (varsMonotone.find(*itr) == varsMonotone.end()) { varsMonotone[*itr].first = true; @@ -326,44 +320,14 @@ namespace storm { } } } - -// if ((value->first != old.first) && (value->second != old.second)) { -// color = "color = red, "; -// } else if ((value->first != old.first)) { -// myfile << "\t edge[style=dashed];" << std::endl; -// color = "color = blue, "; -// } else if ((value->second != old.second)) { -// myfile << "\t edge[style=dotted];" << std::endl; -// color = "color = blue, "; -// } } } - -// for (auto itr = transitions.begin(); itr != transitions.end(); ++itr) { -// myfile << "\t" << i << " -> " << itr->first << "[" << color << "label=\"" << itr->second << "\"];" -// << std::endl; -// } -// -// myfile << "\t edge[style=\"\"];" << std::endl; -// } else { -// myfile << "\t" << i << " -> " << first.getColumn() << "[label=\"" << first.getValue() << "\"];" -// << std::endl; } } -// myfile << "\tsubgraph legend {" << std::endl; -// myfile << "\t\tnode [color=white];" << std::endl; -// myfile << "\t\tedge [style=invis];" << std::endl; -// myfile << "\t\tt0 [label=\"incr? and decr?\", fontcolor=red];" << std::endl; -// myfile << "\t\tt1 [label=\"incr? (dashed)\", fontcolor=blue];" << std::endl; -// myfile << "\t\tt2 [label=\"decr? (dotted)\", fontcolor=blue];" << std::endl; -// -// myfile << "\t}" << std::endl; -// myfile << "}" << std::endl; -// myfile.close(); - analyseWatch.stop(); STORM_PRINT(std::endl << "Time to check monotonicity based on the lattice: " << analyseWatch << "." << std::endl << std::endl); + outfile << analyseWatch << "; "; return varsMonotone; } diff --git a/src/storm-pars/analysis/MonotonicityChecker.h b/src/storm-pars/analysis/MonotonicityChecker.h index c1590dd09..b625b538c 100644 --- a/src/storm-pars/analysis/MonotonicityChecker.h +++ b/src/storm-pars/analysis/MonotonicityChecker.h @@ -37,9 +37,6 @@ namespace storm { /*! * TODO - * @param model - * @param formulas - * @param validate * @return */ std::map>> checkMonotonicity(); @@ -73,6 +70,12 @@ namespace storm { std::map> resultCheckOnSamples; storm::analysis::LatticeExtender *extender; + + std::ofstream outfile; + + std::string filename = "results.txt"; + + storm::utility::Stopwatch totalWatch; }; } } From 55eab08ed5def26c98f68fb502445535dc8e5eff Mon Sep 17 00:00:00 2001 From: Jip Spel Date: Tue, 30 Oct 2018 10:49:58 +0100 Subject: [PATCH 128/178] Allow non constant derivatives in monotonicity analysis --- .../analysis/MonotonicityChecker.cpp | 112 ++++++++++++++---- src/storm-pars/analysis/MonotonicityChecker.h | 2 + 2 files changed, 92 insertions(+), 22 deletions(-) diff --git a/src/storm-pars/analysis/MonotonicityChecker.cpp b/src/storm-pars/analysis/MonotonicityChecker.cpp index 10d61e6a0..2340e57be 100644 --- a/src/storm-pars/analysis/MonotonicityChecker.cpp +++ b/src/storm-pars/analysis/MonotonicityChecker.cpp @@ -17,6 +17,10 @@ #include "storm/modelchecker/results/CheckResult.h" #include "storm/modelchecker/results/ExplicitQuantitativeCheckResult.h" +#include "storm/solver/Z3SmtSolver.h" +#include "storm/storage/expressions/ExpressionManager.h" + +#include "storm/storage/expressions/RationalFunctionToExpression.h" namespace storm { @@ -108,7 +112,7 @@ namespace storm { outfile << "X " << itr2->first; } else { if (itr2->second.first && itr2->second.second) { - STORM_PRINT(" - Constant in" << itr2->first); + STORM_PRINT(" - Constant in" << itr2->first << std::endl); outfile << "C " << itr2->first; } else if (itr2->second.first) { STORM_PRINT(" - Monotone increasing in: " << itr2->first << std::endl); @@ -294,22 +298,31 @@ namespace storm { for (auto itr2 = transitions.begin(); itr2 != transitions.end(); ++itr2) { for (auto itr3 = transitions.begin(); itr3 != transitions.end(); ++itr3) { - auto derivative2 = (*itr2).second.derivative(*itr); - auto derivative3 = (*itr3).second.derivative(*itr); - STORM_LOG_THROW(derivative2.isConstant() && derivative3.isConstant(), - storm::exceptions::NotSupportedException, - "Expecting derivative to be constant"); + auto derivative2 = itr2->second.derivative(*itr); + auto derivative3 = itr3->second.derivative(*itr); - auto compare = lattice->compare((*itr2).first, (*itr3).first); + auto compare = lattice->compare(itr2->first, itr3->first); if (compare == storm::analysis::Lattice::ABOVE) { // As the first state (itr2) is above the second state (itr3) it is sufficient to look at the derivative of itr2. - value->first &= derivative2.constantPart() >= 0; - value->second &= derivative2.constantPart() <= 0; + std::pair mon2; + if (derivative2.isConstant()) { + mon2 = std::pair(derivative2.constantPart() >= 0, derivative2.constantPart() <=0); + } else { + mon2 = checkDerivative(derivative2); + } + value->first &= mon2.first; + value->second &= mon2.second; } else if (compare == storm::analysis::Lattice::BELOW) { // As the second state (itr3) is above the first state (itr2) it is sufficient to look at the derivative of itr3. - value->first &= derivative3.constantPart() >= 0; - value->second &= derivative3.constantPart() <= 0; + std::pair mon3; + if (derivative2.isConstant()) { + mon3 = std::pair(derivative3.constantPart() >= 0, derivative3.constantPart() <=0); + } else { + mon3 = checkDerivative(derivative3); + } + value->first &= mon3.first; + value->second &= mon3.second; } else if (compare == storm::analysis::Lattice::SAME) { // TODO: klopt dit // Behaviour doesn't matter, as the states are at the same level. @@ -331,6 +344,51 @@ namespace storm { return varsMonotone; } + template + std::pair MonotonicityChecker::checkDerivative(ValueType derivative) { + bool monIncr = false; + bool monDecr = false; + + std::shared_ptr smtSolverFactory = std::make_shared(); + std::shared_ptr manager( + new storm::expressions::ExpressionManager()); + + storm::solver::Z3SmtSolver s(*manager); + storm::solver::SmtSolver::CheckResult smtResult = storm::solver::SmtSolver::CheckResult::Unknown; + + std::set variables = derivative.gatherVariables(); + + + for (auto variable : variables) { + manager->declareRationalVariable(variable.name()); + + } + storm::expressions::Expression exprBounds = manager->boolean(true); + auto managervars = manager->getVariables(); + for (auto var : managervars) { + exprBounds = exprBounds && manager->rational(0) <= var && manager->rational(1) >= var; + } + + auto converter = storm::expressions::RationalFunctionToExpression(manager); + + storm::expressions::Expression exprToCheck1 = converter.toExpression(derivative) >= manager->rational(0); + s.add(exprBounds); + s.add(exprToCheck1); + smtResult = s.check(); + monIncr = smtResult == storm::solver::SmtSolver::CheckResult::Sat; + + storm::expressions::Expression exprToCheck2 = converter.toExpression(derivative) <= manager->rational(0); + s.reset(); + smtResult = storm::solver::SmtSolver::CheckResult::Unknown; + s.add(exprBounds); + s.add(exprToCheck2); + smtResult = s.check(); + monDecr = smtResult == storm::solver::SmtSolver::CheckResult::Sat; + + return std::pair(monIncr, monDecr); + } + + template bool MonotonicityChecker::somewhereMonotonicity(storm::analysis::Lattice* lattice) { std::shared_ptr> sparseModel = model->as>(); @@ -359,26 +417,36 @@ namespace storm { } std::pair *value = &varsMonotone.find(*itr)->second; std::pair old = *value; - +// TODO deze ook aanpassen aan deel met smt solver for (auto itr2 = transitions.begin(); itr2 != transitions.end(); ++itr2) { for (auto itr3 = transitions.begin(); itr3 != transitions.end(); ++itr3) { - auto derivative2 = (*itr2).second.derivative(*itr); - auto derivative3 = (*itr3).second.derivative(*itr); - STORM_LOG_THROW(derivative2.isConstant() && derivative3.isConstant(), - storm::exceptions::NotSupportedException, - "Expecting derivative to be constant"); + auto derivative2 = itr2->second.derivative(*itr); + auto derivative3 = itr3->second.derivative(*itr); - auto compare = lattice->compare((*itr2).first, (*itr3).first); + auto compare = lattice->compare(itr2->first, itr3->first); if (compare == storm::analysis::Lattice::ABOVE) { // As the first state (itr2) is above the second state (itr3) it is sufficient to look at the derivative of itr2. - value->first &= derivative2.constantPart() >= 0; - value->second &= derivative2.constantPart() <= 0; + std::pair mon2; + if (derivative2.isConstant()) { + mon2 = std::pair(derivative2.constantPart() >= 0, derivative2.constantPart() <=0); + } else { + mon2 = checkDerivative(derivative2); + } + value->first &= mon2.first; + value->second &= mon2.second; } else if (compare == storm::analysis::Lattice::BELOW) { // As the second state (itr3) is above the first state (itr2) it is sufficient to look at the derivative of itr3. - value->first &= derivative3.constantPart() >= 0; - value->second &= derivative3.constantPart() <= 0; + std::pair mon3; + if (derivative2.isConstant()) { + mon3 = std::pair(derivative3.constantPart() >= 0, derivative3.constantPart() <=0); + } else { + mon3 = checkDerivative(derivative3); + } + value->first &= mon3.first; + value->second &= mon3.second; } else if (compare == storm::analysis::Lattice::SAME) { + // TODO: klopt dit // Behaviour doesn't matter, as the states are at the same level. } else { // As the relation between the states is unknown, we don't do anything diff --git a/src/storm-pars/analysis/MonotonicityChecker.h b/src/storm-pars/analysis/MonotonicityChecker.h index b625b538c..8a2404d73 100644 --- a/src/storm-pars/analysis/MonotonicityChecker.h +++ b/src/storm-pars/analysis/MonotonicityChecker.h @@ -59,6 +59,8 @@ namespace storm { std::map> checkOnSamples(std::shared_ptr> model, uint_fast64_t numberOfSamples); + std::pair checkDerivative(ValueType derivative); + std::map>> extendLatticeWithAssumptions(storm::analysis::Lattice* lattice, storm::analysis::AssumptionMaker* assumptionMaker, uint_fast64_t val1, uint_fast64_t val2, std::vector> assumptions); std::shared_ptr model; From 26ee89a856f51c971580dfd552e417153bcdda70 Mon Sep 17 00:00:00 2001 From: Jip Spel Date: Thu, 29 Nov 2018 12:48:50 +0100 Subject: [PATCH 129/178] Check assumptions on a region --- .../analysis/MonotonicityChecker.cpp | 109 +++++++++++++++--- src/storm-pars/analysis/MonotonicityChecker.h | 3 + src/storm-pars/api/region.h | 42 ++++++- 3 files changed, 131 insertions(+), 23 deletions(-) diff --git a/src/storm-pars/analysis/MonotonicityChecker.cpp b/src/storm-pars/analysis/MonotonicityChecker.cpp index 2340e57be..91d9b6929 100644 --- a/src/storm-pars/analysis/MonotonicityChecker.cpp +++ b/src/storm-pars/analysis/MonotonicityChecker.cpp @@ -15,14 +15,20 @@ #include "storm/utility/Stopwatch.h" #include "storm/models/ModelType.h" +#include "storm/api/verification.h" +#include "storm-pars/api/storm-pars.h" + #include "storm/modelchecker/results/CheckResult.h" #include "storm/modelchecker/results/ExplicitQuantitativeCheckResult.h" +#include "storm-pars/modelchecker/region/SparseDtmcParameterLiftingModelChecker.h" + #include "storm/solver/Z3SmtSolver.h" #include "storm/storage/expressions/ExpressionManager.h" #include "storm/storage/expressions/RationalFunctionToExpression.h" + namespace storm { namespace analysis { template @@ -51,6 +57,73 @@ namespace storm { return checkMonotonicity(map, matrix); } + template + std::vector> MonotonicityChecker::checkAssumptionsOnRegion(std::vector> assumptions) { + assert (formulas[0]->isProbabilityOperatorFormula()); + assert (formulas[0]->asProbabilityOperatorFormula().getSubformula().isUntilFormula() || formulas[0]->asProbabilityOperatorFormula().getSubformula().isEventuallyFormula()); + Environment env = Environment(); + std::shared_ptr> sparseModel = model->as>(); + bool generateSplitEstimates = false; + bool allowModelSimplification = false; + auto task = storm::api::createTask(formulas[0], true); + // TODO: storm::RationalNumber or double? + + // TODO: Also allow different models + STORM_LOG_THROW (sparseModel->isOfType(storm::models::ModelType::Dtmc), storm::exceptions::NotImplementedException, + "Checking assumptions on a region not implemented for this type of model"); + auto modelChecker = storm::api::initializeParameterLiftingDtmcModelChecker(env, sparseModel, task, generateSplitEstimates, allowModelSimplification); + + std::stack, int>> regions; + std::vector> satRegions; + std::string regionText = ""; + auto parameters = storm::models::sparse::getProbabilityParameters(*sparseModel); + for (auto itr = parameters.begin(); itr != parameters.end(); ++itr) { + if (regionText != "") { + regionText += ","; + } + // TODO: region bounds + regionText += "0.1 <= " + itr->name() + " <= 0.9"; + } + + auto initialRegion = storm::api::parseRegion(regionText, parameters); + regions.push(std::pair, int>(initialRegion,0)); + while (!regions.empty()) { + auto lastElement = regions.top(); + regions.pop(); + storm::storage::ParameterRegion currentRegion = lastElement.first; + + // TODO: depth + if (lastElement.second < 5) { + auto upperBound = modelChecker->getBound(env, currentRegion, storm::solver::OptimizationDirection::Maximize); + auto lowerBound = modelChecker->getBound(env, currentRegion, storm::solver::OptimizationDirection::Minimize); + std::vector valuesUpper = upperBound->template asExplicitQuantitativeCheckResult().getValueVector(); + std::vector valuesLower = lowerBound->template asExplicitQuantitativeCheckResult().getValueVector(); + bool assumptionsHold = true; + for (auto itr = assumptions.begin(); assumptionsHold && itr != assumptions.end(); ++itr) { + auto assumption = *itr; + assert (assumption->getRelationType() == storm::expressions::BinaryRelationExpression::RelationType::GreaterOrEqual); + auto state1 = std::stoi(assumption->getFirstOperand()->asVariableExpression().getVariableName()); + auto state2 = std::stoi(assumption->getSecondOperand()->asVariableExpression().getVariableName()); + assumptionsHold &= valuesLower[state1] >= valuesUpper[state2]; + } + if (!assumptionsHold) { + std::vector> newRegions; + currentRegion.split(currentRegion.getCenterPoint(), newRegions); + for (auto itr = newRegions.begin(); itr != newRegions.end(); ++itr) { + regions.push(std::pair, int>(*itr, + lastElement.second + + 1)); + } + } else { + satRegions.push_back(currentRegion); + } + } + } + return satRegions; + } + + + template std::map>> MonotonicityChecker::checkMonotonicity(std::map>> map, storm::storage::SparseMatrix matrix) { storm::utility::Stopwatch finalCheckWatch(true); @@ -74,35 +147,36 @@ namespace storm { outfile.open(filename, std::ios_base::app); auto assumptions = itr->second; + bool validSomewhere = true; if (assumptions.size() > 0) { - STORM_PRINT("Given assumptions: " << std::endl); + auto regions = checkAssumptionsOnRegion(assumptions); + if (regions.size() > 0) { + STORM_PRINT("For regions: " << std::endl); + } bool first = true; - for (auto itr2 = assumptions.begin(); itr2 != assumptions.end(); ++itr2) { - if (!first) { - STORM_PRINT(" ^ "); - outfile << (" ^ "); - } else { + for (auto itr2 = regions.begin(); itr2 != regions.end(); ++itr2) { + if (first) { STORM_PRINT(" "); first = false; } - - std::shared_ptr expression = *itr2; - auto var1 = expression->getFirstOperand(); - auto var2 = expression->getSecondOperand(); - STORM_PRINT(*expression); - outfile << (*expression); + STORM_PRINT(*itr2); + outfile << (*itr2); } - STORM_PRINT(std::endl); - outfile << ", "; - } else { + if (regions.size() > 0) { + STORM_PRINT(std::endl); + outfile << ", "; + } + } + + if (validSomewhere && assumptions.size() == 0) { outfile << "No assumptions, "; } - if (varsMonotone.size() == 0) { + if (validSomewhere && varsMonotone.size() == 0) { STORM_PRINT("Result is constant" << std::endl); outfile << "No params"; - } else { + } else if (validSomewhere) { auto itr2 = varsMonotone.begin(); while (itr2 != varsMonotone.end()) { if (resultCheckOnSamples.find(itr2->first) != resultCheckOnSamples.end() && @@ -121,6 +195,7 @@ namespace storm { STORM_PRINT(" - Monotone decreasing in: " << itr2->first << std::endl); outfile << "D " << itr2->first; } else { + STORM_PRINT( " - Do not know if monotone incr/decreasing in: " << itr2->first << std::endl); outfile << "? " << itr2->first; diff --git a/src/storm-pars/analysis/MonotonicityChecker.h b/src/storm-pars/analysis/MonotonicityChecker.h index 8a2404d73..b4b6db84c 100644 --- a/src/storm-pars/analysis/MonotonicityChecker.h +++ b/src/storm-pars/analysis/MonotonicityChecker.h @@ -17,6 +17,7 @@ #include "storm/models/sparse/Mdp.h" #include "storm/logic/Formula.h" #include "storm/storage/SparseMatrix.h" +#include "storm-pars/api/region.h" namespace storm { namespace analysis { @@ -61,6 +62,8 @@ namespace storm { std::pair checkDerivative(ValueType derivative); + std::vector> checkAssumptionsOnRegion(std::vector> assumptions); + std::map>> extendLatticeWithAssumptions(storm::analysis::Lattice* lattice, storm::analysis::AssumptionMaker* assumptionMaker, uint_fast64_t val1, uint_fast64_t val2, std::vector> assumptions); std::shared_ptr model; diff --git a/src/storm-pars/api/region.h b/src/storm-pars/api/region.h index 56aba0cf3..8c21c64f6 100644 --- a/src/storm-pars/api/region.h +++ b/src/storm-pars/api/region.h @@ -79,14 +79,14 @@ namespace storm { STORM_LOG_THROW(res.size() == 1, storm::exceptions::InvalidOperationException, "Parsed " << res.size() << " regions but exactly one was expected."); return res.front(); } - + template std::shared_ptr> initializeParameterLiftingRegionModelChecker(Environment const& env, std::shared_ptr> const& model, storm::modelchecker::CheckTask const& task, bool generateSplitEstimates = false, bool allowModelSimplification = true) { - + STORM_LOG_WARN_COND(storm::utility::parameterlifting::validateParameterLiftingSound(*model, task.getFormula()), "Could not validate whether parameter lifting is applicable. Please validate manually..."); std::shared_ptr> consideredModel = model; - + // Treat continuous time models if (consideredModel->isOfType(storm::models::ModelType::Ctmc) || consideredModel->isOfType(storm::models::ModelType::MarkovAutomaton)) { STORM_LOG_WARN("Parameter lifting not supported for continuous time models. Transforming continuous model to discrete model..."); @@ -94,7 +94,7 @@ namespace storm { consideredModel = storm::api::transformContinuousToDiscreteTimeSparseModel(consideredModel, taskFormulaAsVector); STORM_LOG_THROW(consideredModel->isOfType(storm::models::ModelType::Dtmc) || consideredModel->isOfType(storm::models::ModelType::Mdp), storm::exceptions::UnexpectedException, "Transformation to discrete time model has failed."); } - + // Obtain the region model checker std::shared_ptr> checker; if (consideredModel->isOfType(storm::models::ModelType::Dtmc)) { @@ -104,11 +104,41 @@ namespace storm { } else { STORM_LOG_THROW(false, storm::exceptions::InvalidOperationException, "Unable to perform parameterLifting on the provided model type."); } - + checker->specify(env, consideredModel, task, generateSplitEstimates, allowModelSimplification); - + return checker; } + + // TODO: make more generic + template + std::shared_ptr, ConstantType>> initializeParameterLiftingDtmcModelChecker(Environment const& env, std::shared_ptr> const& model, storm::modelchecker::CheckTask const& task, bool generateSplitEstimates = false, bool allowModelSimplification = true) { + + STORM_LOG_WARN_COND(storm::utility::parameterlifting::validateParameterLiftingSound(*model, task.getFormula()), "Could not validate whether parameter lifting is applicable. Please validate manually..."); + + std::shared_ptr> consideredModel = model; + + // Treat continuous time models + if (consideredModel->isOfType(storm::models::ModelType::Ctmc) || consideredModel->isOfType(storm::models::ModelType::MarkovAutomaton)) { + STORM_LOG_WARN("Parameter lifting not supported for continuous time models. Transforming continuous model to discrete model..."); + std::vector> taskFormulaAsVector { task.getFormula().asSharedPointer() }; + consideredModel = storm::api::transformContinuousToDiscreteTimeSparseModel(consideredModel, taskFormulaAsVector); + STORM_LOG_THROW(consideredModel->isOfType(storm::models::ModelType::Dtmc) || consideredModel->isOfType(storm::models::ModelType::Mdp), storm::exceptions::UnexpectedException, "Transformation to discrete time model has failed."); + } + + // Obtain the region model checker + std::shared_ptr, ConstantType>> checker; + if (consideredModel->isOfType(storm::models::ModelType::Dtmc)) { + checker = std::make_shared, ConstantType>>(); + } else { + STORM_LOG_THROW(false, storm::exceptions::InvalidOperationException, "Unable to perform parameterLifting on the provided model type."); + } + + checker->specify(env, consideredModel, task, generateSplitEstimates, allowModelSimplification); + + return checker; + } + template std::shared_ptr> initializeValidatingRegionModelChecker(Environment const& env, std::shared_ptr> const& model, storm::modelchecker::CheckTask const& task, bool generateSplitEstimates = false, bool allowModelSimplification = true) { From 8d95e71c3e20f052f3819bfc9acdffdb3d884592 Mon Sep 17 00:00:00 2001 From: Jip Spel Date: Tue, 29 Jan 2019 10:33:50 +0100 Subject: [PATCH 130/178] Change output, Fix some small bugs --- src/storm-pars-cli/storm-pars.cpp | 13 +- src/storm-pars/analysis/AssumptionChecker.cpp | 18 +- src/storm-pars/analysis/AssumptionMaker.cpp | 11 +- src/storm-pars/analysis/Lattice.cpp | 57 ++++-- src/storm-pars/analysis/Lattice.h | 7 + src/storm-pars/analysis/LatticeExtender.cpp | 177 +++++++++++------- src/storm-pars/analysis/LatticeExtender.h | 18 +- .../analysis/MonotonicityChecker.cpp | 159 ++++++++++------ .../analysis/AssumptionCheckerTest.cpp | 22 ++- .../analysis/AssumptionMakerTest.cpp | 14 +- src/test/storm-pars/analysis/LatticeTest.cpp | 34 ++++ 11 files changed, 368 insertions(+), 162 deletions(-) diff --git a/src/storm-pars-cli/storm-pars.cpp b/src/storm-pars-cli/storm-pars.cpp index 03a43e395..572562302 100644 --- a/src/storm-pars-cli/storm-pars.cpp +++ b/src/storm-pars-cli/storm-pars.cpp @@ -514,6 +514,11 @@ namespace storm { std::cout << "Hello, Jip1" << std::endl; // Simplify the model storm::utility::Stopwatch simplifyingWatch(true); + std::ofstream outfile; + outfile.open("results.txt", std::ios_base::app); + outfile << ioSettings.getPrismInputFilename() << ", "; + + if (model->isOfType(storm::models::ModelType::Dtmc)) { auto consideredModel = (model->as>()); auto simplifier = storm::transformer::SparseParametricDtmcSimplifier>(*consideredModel); @@ -543,6 +548,9 @@ namespace storm { simplifyingWatch.stop(); STORM_PRINT(std::endl << "Time for model simplification: " << simplifyingWatch << "." << std::endl << std::endl); model->printModelInformationToStream(std::cout); + outfile << simplifyingWatch << ", "; + outfile.close(); + std::cout << "Bye, Jip1" << std::endl; } @@ -562,8 +570,6 @@ namespace storm { // Monotonicity std::ofstream outfile; outfile.open("results.txt", std::ios_base::app); - outfile << std::endl << ioSettings.getPrismInputFilename() << "; "; - outfile.close(); storm::utility::Stopwatch monotonicityWatch(true); auto monotonicityChecker = storm::analysis::MonotonicityChecker(model, formulas, parSettings.isValidateAssumptionsSet()); monotonicityChecker.checkMonotonicity(); @@ -571,7 +577,10 @@ namespace storm { STORM_PRINT(std::endl << "Total time for monotonicity checking: " << monotonicityWatch << "." << std::endl << std::endl); + outfile << monotonicityWatch << std::endl; + outfile.close(); std::cout << "Bye, Jip2" << std::endl; + return; } diff --git a/src/storm-pars/analysis/AssumptionChecker.cpp b/src/storm-pars/analysis/AssumptionChecker.cpp index b454cf451..e27cd2610 100644 --- a/src/storm-pars/analysis/AssumptionChecker.cpp +++ b/src/storm-pars/analysis/AssumptionChecker.cpp @@ -34,7 +34,8 @@ namespace storm { auto valuation = storm::utility::parametric::Valuation(); for (auto itr = variables.begin(); itr != variables.end(); ++itr) { // TODO: Type - auto val = std::pair((*itr), storm::utility::convertNumber(boost::lexical_cast((i+1)/(double (numberOfSamples + 1))))); + // Creates samples between 0 and 1, 1/(#samples+2), 2/(#samples+2), ..., (#samples+1)/(#samples+2) + auto val = std::pair((*itr), storm::utility::convertNumber(boost::lexical_cast((i+1)/(double (numberOfSamples + 2))))); valuation.insert(val); } storm::models::sparse::Dtmc sampleModel = instantiator.instantiate(valuation); @@ -127,10 +128,12 @@ namespace storm { assumption->gatherVariables(vars); STORM_LOG_THROW(assumption->getRelationType() == - storm::expressions::BinaryRelationExpression::RelationType::GreaterOrEqual, + storm::expressions::BinaryRelationExpression::RelationType::Greater ||assumption->getRelationType() == + storm::expressions::BinaryRelationExpression::RelationType::Equal, storm::exceptions::NotSupportedException, "Only Greater Or Equal assumptions supported"); + // TODO: implement validation of equal/greater equations auto row1 = matrix.getRow(std::stoi(assumption->getFirstOperand()->asVariableExpression().getVariableName())); auto row2 = matrix.getRow(std::stoi(assumption->getSecondOperand()->asVariableExpression().getVariableName())); @@ -239,7 +242,9 @@ namespace storm { result = false; } } - return result && prob.evaluate(substitutions) >= 0; +// return result && prob.evaluate(substitutions) >= 0; +//TODO check for > and = + return false; } template @@ -296,7 +301,9 @@ namespace storm { s.add(exprBounds); smtResult = s.check(); - return smtResult == storm::solver::SmtSolver::CheckResult::Sat; +// return smtResult == storm::solver::SmtSolver::CheckResult::Sat; +//TODO check for > and = + return false; } template @@ -387,8 +394,9 @@ namespace storm { assert(s.check() == storm::solver::SmtSolver::CheckResult::Sat); s.add(exprToCheck); auto smtRes = s.check(); + //TODO check for > and = result = result && smtRes == storm::solver::SmtSolver::CheckResult::Sat; - return result; + return false; } template diff --git a/src/storm-pars/analysis/AssumptionMaker.cpp b/src/storm-pars/analysis/AssumptionMaker.cpp index ceb05ea72..0a5ab376e 100644 --- a/src/storm-pars/analysis/AssumptionMaker.cpp +++ b/src/storm-pars/analysis/AssumptionMaker.cpp @@ -27,17 +27,24 @@ namespace storm { std::shared_ptr assumption1 = std::make_shared(storm::expressions::BinaryRelationExpression(*expressionManager, expressionManager->getBooleanType(), var1.getExpression().getBaseExpressionPointer(), var2.getExpression().getBaseExpressionPointer(), - storm::expressions::BinaryRelationExpression::RelationType::GreaterOrEqual)); + storm::expressions::BinaryRelationExpression::RelationType::Greater)); bool result1 = (validate && assumptionChecker->validateAssumption(assumption1, lattice) && assumptionChecker->valid(assumption1)); result[assumption1] = result1; std::shared_ptr assumption2 = std::make_shared(storm::expressions::BinaryRelationExpression(*expressionManager, expressionManager->getBooleanType(), var2.getExpression().getBaseExpressionPointer(), var1.getExpression().getBaseExpressionPointer(), - storm::expressions::BinaryRelationExpression::RelationType::GreaterOrEqual)); + storm::expressions::BinaryRelationExpression::RelationType::Greater)); bool result2 = (validate && assumptionChecker->validateAssumption(assumption2, lattice) && assumptionChecker->valid(assumption2)); result[assumption2] = result2; + std::shared_ptr assumption3 + = std::make_shared(storm::expressions::BinaryRelationExpression(*expressionManager, expressionManager->getBooleanType(), + var2.getExpression().getBaseExpressionPointer(), var1.getExpression().getBaseExpressionPointer(), + storm::expressions::BinaryRelationExpression::RelationType::Equal)); + bool result3 = (validate && assumptionChecker->validateAssumption(assumption3, lattice) && assumptionChecker->valid(assumption3)); + result[assumption3] = result3; + return result; } diff --git a/src/storm-pars/analysis/Lattice.cpp b/src/storm-pars/analysis/Lattice.cpp index 9a1bacbc4..07bc5b01f 100644 --- a/src/storm-pars/analysis/Lattice.cpp +++ b/src/storm-pars/analysis/Lattice.cpp @@ -112,11 +112,11 @@ namespace storm { } addedStates.set(state); + } void Lattice::addToNode(uint_fast64_t state, Node *node) { assert(!addedStates[state]); - node->states.set(state); nodes.at(state) = node; addedStates.set(state); @@ -131,12 +131,13 @@ namespace storm { } void Lattice::add(uint_fast64_t state) { + assert(!addedStates[state]); addBetween(state, top, bottom); } void Lattice::addRelationNodes(Lattice::Node *above, Lattice::Node * below) { assert (compare(above, below) == UNKNOWN); - + assert ((above->statesAbove & below->statesBelow).getNumberOfSetBits() == 0); setStatesBelow(above, below->states | below->statesBelow, true); setStatesAbove(below, above->states | above->statesAbove, true); @@ -147,6 +148,7 @@ namespace storm { for (auto i = above->statesAbove.getNextSetIndex(0); i < above->statesAbove.size(); i = above->statesAbove.getNextSetIndex(i + 1)) { setStatesBelow(getNode(i), below->states | below->statesBelow, true); } + } int Lattice::compare(uint_fast64_t state1, uint_fast64_t state2) { @@ -314,16 +316,17 @@ namespace storm { } bool Lattice::above(Node *node1, Node *node2) { - return node1->statesBelow.get(node2->states.getNextSetIndex(0)); + return node1->statesBelow[node2->states.getNextSetIndex(0)]; } void Lattice::setStatesAbove(Lattice::Node *node, uint_fast64_t state, bool alreadyInitialized) { - assert (!node->states.get(state)); + assert (!node->states[state]); if (!alreadyInitialized) { node->statesAbove = storm::storage::BitVector(numberOfStates); } + assert (!node->statesBelow[state]); node->statesAbove.set(state); } @@ -333,32 +336,60 @@ namespace storm { if (!alreadyInitialized) { node->statesBelow = storm::storage::BitVector(numberOfStates); } - + assert (!node->statesAbove[state]); node->statesBelow.set(state); } void Lattice::setStatesAbove(Lattice::Node *node, storm::storage::BitVector states, bool alreadyInitialized) { assert((states.getNumberOfSetBits() - (node->states & states).getNumberOfSetBits()) != 0); + // the states to add to the above state of the current node shouldnt occur in either statesbelow or states of ndoe - auto complement = storm::storage::BitVector(node->states); - complement.complement(); + assert ((node->states & states).getNumberOfSetBits() ==0); if (alreadyInitialized) { - node->statesAbove |= (states & complement); + assert ((node->statesBelow & states).getNumberOfSetBits() == 0); + + node->statesAbove |= (states); } else { - node->statesAbove = (storm::storage::BitVector(states) & complement); + node->statesAbove = (storm::storage::BitVector(states)); } } void Lattice::setStatesBelow(Lattice::Node *node, storm::storage::BitVector states, bool alreadyInitialized) { assert((states.getNumberOfSetBits() - (node->states & states).getNumberOfSetBits()) != 0); - auto complement = storm::storage::BitVector(node->states); - complement.complement(); + assert ((node->states & states).getNumberOfSetBits() ==0); if (alreadyInitialized) { - node->statesBelow |= (states & complement); + assert ((node->statesAbove & states).getNumberOfSetBits() == 0); + node->statesBelow |= (states); } else { - node->statesBelow = (storm::storage::BitVector(states) & complement); + node->statesBelow = (storm::storage::BitVector(states)); } } + + void Lattice::mergeNodes(storm::analysis::Lattice::Node *node1, storm::analysis::Lattice::Node *node2) { + // Merges node2 into node 1 + // everything above n2 also above n1 + node1->statesAbove |= node2->statesAbove; + // everything below node 2 also below node 1 + node1->statesBelow |= node2->statesBelow; + + // add states of node 2 to node 1 + node1->states|= node2->states; + for(auto i = node2->states.getNextSetIndex(0); i < node2->states.size(); i = node2->states.getNextSetIndex(i+1)) { + nodes.at(i) = node1; + } + + // TODO hier gaat het op magische wijze nog fout + // Add all states of combined node to states Above of all states Below of node1 + for (auto i = node1->statesBelow.getNextSetIndex(0); i < node1->statesBelow.size(); i= node1->statesBelow.getNextSetIndex(i+1)) { + getNode(i)->statesAbove |= node1->states | node1->statesAbove; + } + + // Add all states of combined node to states Below of all states Above of node1 + for (auto i = node1->statesAbove.getNextSetIndex(0); i < node1->statesAbove.size(); i= node1->statesAbove.getNextSetIndex(i+1)) { + getNode(i)->statesBelow |= node1->states | node1->statesBelow; + } + + } } } diff --git a/src/storm-pars/analysis/Lattice.h b/src/storm-pars/analysis/Lattice.h index 4bf9a68ee..057ff9f30 100644 --- a/src/storm-pars/analysis/Lattice.h +++ b/src/storm-pars/analysis/Lattice.h @@ -165,6 +165,13 @@ namespace storm { */ void toDotFile(std::ostream &out); + /*! + * Merges node2 into node1 + * @param node1 + * @param node2 + */ + void mergeNodes(Node* node1, Node* node2); + /*! * Constants for comparison of nodes/states */ diff --git a/src/storm-pars/analysis/LatticeExtender.cpp b/src/storm-pars/analysis/LatticeExtender.cpp index dc80e3106..4917da795 100644 --- a/src/storm-pars/analysis/LatticeExtender.cpp +++ b/src/storm-pars/analysis/LatticeExtender.cpp @@ -4,6 +4,7 @@ #include "LatticeExtender.h" #include "storm/utility/macros.h" +#include "storm/utility/graph.h" #include "storm/storage/SparseMatrix.h" #include "storm/utility/graph.h" #include @@ -35,7 +36,7 @@ namespace storm { template std::tuple LatticeExtender::toLattice(std::vector> formulas) { - storm::utility::Stopwatch latticeWatch(true); +// storm::utility::Stopwatch latticeWatch(true); STORM_LOG_THROW((++formulas.begin()) == formulas.end(), storm::exceptions::NotSupportedException, "Only one formula allowed for monotonicity analysis"); STORM_LOG_THROW((*(formulas[0])).isProbabilityOperatorFormula() @@ -66,36 +67,43 @@ namespace storm { // Transform to Lattice auto matrix = this->model->getTransitionMatrix(); - for (uint_fast64_t i = 0; i < numberOfStates; ++i) { - stateMap[i] = storm::storage::BitVector(numberOfStates, false); - - auto row = matrix.getRow(i); - for (auto rowItr = row.begin(); rowItr != row.end(); ++rowItr) { - // ignore self-loops when there are more transitions - if (i != rowItr->getColumn() || row.getNumberOfEntries() == 1) { - stateMap[i].set(rowItr->getColumn(), true); - } - } - } - auto initialMiddleStates = storm::storage::BitVector(numberOfStates); // Check if MC contains cycles auto decomposition = storm::storage::StronglyConnectedComponentDecomposition(model->getTransitionMatrix(), false, false); - for (auto i = 0; i < decomposition.size(); ++i) { - auto scc = decomposition.getBlock(i); - if (scc.size() > 1) { - auto states = scc.getStates(); - // check if the state has already one successor in bottom of top, in that case pick it - bool found = false; - for (auto stateItr = states.begin(); !found && stateItr < states.end(); ++stateItr) { - auto successors = stateMap[*stateItr]; - if (successors.getNumberOfSetBits() == 2) { - auto succ1 = successors.getNextSetIndex(0); - auto succ2 = successors.getNextSetIndex(succ1 + 1); - auto intersection = bottomStates | topStates; - if (intersection[succ1] || intersection[succ2]) { - initialMiddleStates.set(*stateItr); - found = true; + acyclic = true; + for (auto i = 0; acyclic && i < decomposition.size(); ++i) { + acyclic &= decomposition.getBlock(i).size() <= 1; + } + if (acyclic) { + states = storm::utility::graph::getTopologicalSort(matrix); + } else { + for (uint_fast64_t i = 0; i < numberOfStates; ++i) { + stateMap[i] = storm::storage::BitVector(numberOfStates, false); + + auto row = matrix.getRow(i); + for (auto rowItr = row.begin(); rowItr != row.end(); ++rowItr) { + // ignore self-loops when there are more transitions + if (i != rowItr->getColumn() || row.getNumberOfEntries() == 1) { + stateMap[i].set(rowItr->getColumn(), true); + } + } + } + for (auto i = 0; i < decomposition.size(); ++i) { + auto scc = decomposition.getBlock(i); + if (scc.size() > 1) { + auto states = scc.getStates(); + // check if the state has already one successor in bottom of top, in that case pick it + bool found = false; + for (auto stateItr = states.begin(); !found && stateItr < states.end(); ++stateItr) { + auto successors = stateMap[*stateItr]; + if (successors.getNumberOfSetBits() == 2) { + auto succ1 = successors.getNextSetIndex(0); + auto succ2 = successors.getNextSetIndex(succ1 + 1); + auto intersection = bottomStates | topStates; + if (intersection[succ1] || intersection[succ2]) { + initialMiddleStates.set(*stateItr); + found = true; + } } } } @@ -105,8 +113,8 @@ namespace storm { // Create the Lattice Lattice *lattice = new Lattice(topStates, bottomStates, initialMiddleStates, numberOfStates); - latticeWatch.stop(); - STORM_PRINT(std::endl << "Time for initialization of lattice: " << latticeWatch << "." << std::endl << std::endl); +// latticeWatch.stop(); +// STORM_PRINT(std::endl << "Time for initialization of lattice: " << latticeWatch << "." << std::endl << std::endl); return this->extendLattice(lattice); } @@ -115,7 +123,7 @@ namespace storm { assert (assumption != nullptr); storm::expressions::BinaryRelationExpression expr = *assumption; - assert (expr.getRelationType() == storm::expressions::BinaryRelationExpression::RelationType::GreaterOrEqual + assert (expr.getRelationType() == storm::expressions::BinaryRelationExpression::RelationType::Greater || expr.getRelationType() == storm::expressions::BinaryRelationExpression::RelationType::Equal); if (expr.getRelationType() == storm::expressions::BinaryRelationExpression::RelationType::Equal) { @@ -131,8 +139,7 @@ namespace storm { Lattice::Node *n2 = lattice->getNode(val2); if (n1 != nullptr && n2 != nullptr) { - // TODO: mergeNode method - assert(false); + lattice->mergeNodes(n1,n2); } else if (n1 != nullptr) { lattice->addToNode(val2, n1); } else if (n2 != nullptr) { @@ -219,6 +226,8 @@ namespace storm { return std::make_tuple(lattice, numberOfStates, numberOfStates); } + + template std::tuple LatticeExtender::extendLattice(Lattice* lattice, std::shared_ptr assumption) { auto numberOfStates = this->model->getNumberOfStates(); @@ -230,57 +239,93 @@ namespace storm { auto oldNumberSet = numberOfStates; while (oldNumberSet != lattice->getAddedStates().getNumberOfSetBits()) { oldNumberSet = lattice->getAddedStates().getNumberOfSetBits(); - // TODO: kan dit niet efficienter - for (auto stateItr = stateMap.begin(); stateItr != stateMap.end(); ++stateItr) { - // Iterate over all states - auto stateNumber = stateItr->first; - storm::storage::BitVector successors = stateItr->second; - - auto seenStates = (lattice->getAddedStates()); - - // Check if current state has not been added yet, and all successors have - bool check = !seenStates[stateNumber]; - for (auto succIndex = successors.getNextSetIndex(0); check && succIndex != successors.size(); succIndex = successors.getNextSetIndex(++succIndex)) { - // if the stateNumber equals succIndex we have a self-loop, ignoring selfloop as seenStates[stateNumber] = false - if (succIndex != stateNumber) { - check &= seenStates[succIndex]; - } + + if (acyclic && states.size() > 0) { + auto nextState = *(states.begin()); + while (lattice->getAddedStates().get(nextState) && states.size() > 0) { + states.erase(states.begin()); + + nextState = *(states.begin()); } - if (check) { - auto result = extendAllSuccAdded(lattice, stateNumber, successors); + if (! lattice->getAddedStates().get(nextState)) { + auto row = this->model->getTransitionMatrix().getRow(nextState); + auto successors = storm::storage::BitVector(lattice->getAddedStates().size()); + for (auto rowItr = row.begin(); rowItr != row.end(); ++rowItr) { + // ignore self-loops when there are more transitions + if (nextState != rowItr->getColumn()) { + successors.set(rowItr->getColumn()); + } + } + auto seenStates = (lattice->getAddedStates()); + assert ((seenStates & successors) == successors); + + auto result = extendAllSuccAdded(lattice, nextState, successors); if (std::get<1>(result) != successors.size()) { return result; + } else { + states.erase(states.begin()); } } + assert (lattice->getNode(nextState) != nullptr); + + } else if (!acyclic) { + // TODO: kan dit niet efficienter + auto addedStates = lattice->getAddedStates(); + for (auto stateNumber = addedStates.getNextUnsetIndex(0); stateNumber < addedStates.size(); stateNumber = addedStates.getNextUnsetIndex(stateNumber+1)) { + // Iterate over all states +// auto stateNumber = i; + storm::storage::BitVector successors = stateMap[stateNumber]; + + auto seenStates = (lattice->getAddedStates()); + + assert(!acyclic); + // Check if current state has not been added yet, and all successors have + bool check = !seenStates[stateNumber]; + for (auto succIndex = successors.getNextSetIndex(0); + check && succIndex != successors.size(); succIndex = successors.getNextSetIndex( + ++succIndex)) { + // if the stateNumber equals succIndex we have a self-loop, ignoring selfloop as seenStates[stateNumber] = false + if (succIndex != stateNumber) { + check &= seenStates[succIndex]; + } + } - // Checking for states which are already added to the lattice, and only have one successor left which haven't been added yet - auto succ1 = successors.getNextSetIndex(0); - auto succ2 = successors.getNextSetIndex(succ1 + 1); + if (check) { + auto result = extendAllSuccAdded(lattice, stateNumber, successors); + if (std::get<1>(result) != successors.size()) { + return result; + } + } + + // Checking for states which are already added to the lattice, and only have one successor left which haven't been added yet + auto succ1 = successors.getNextSetIndex(0); + auto succ2 = successors.getNextSetIndex(succ1 + 1); - if (seenStates[stateNumber] && successors.getNumberOfSetBits() == 2 + if (seenStates[stateNumber] && successors.getNumberOfSetBits() == 2 && (seenStates[succ1] || seenStates[succ2]) && (!seenStates[succ1] || !seenStates[succ2])) { - if (!seenStates[succ1]) { - std::swap(succ1, succ2); - } + if (!seenStates[succ1]) { + std::swap(succ1, succ2); + std::swap(succ1, succ2); + } - auto compare = lattice->compare(stateNumber, succ1); - if (compare == Lattice::ABOVE) { - lattice->addBetween(succ2, lattice->getTop(), lattice->getNode(stateNumber)); - } else if (compare == Lattice::BELOW) { - lattice->addBetween(succ2, lattice->getNode(stateNumber), lattice->getBottom()); - } else { - // TODO: implement? - assert(false); + auto compare = lattice->compare(stateNumber, succ1); + if (compare == Lattice::ABOVE) { + lattice->addBetween(succ2, lattice->getTop(), lattice->getNode(stateNumber)); + } else if (compare == Lattice::BELOW) { + lattice->addBetween(succ2, lattice->getNode(stateNumber), lattice->getBottom()); + } else { + // TODO: implement? + assert(false); + } } } } } return std::make_tuple(lattice, numberOfStates, numberOfStates); } - template class LatticeExtender; } } diff --git a/src/storm-pars/analysis/LatticeExtender.h b/src/storm-pars/analysis/LatticeExtender.h index e4cd8b0c4..7ff23ba05 100644 --- a/src/storm-pars/analysis/LatticeExtender.h +++ b/src/storm-pars/analysis/LatticeExtender.h @@ -29,31 +29,35 @@ namespace storm { LatticeExtender(std::shared_ptr> model); /*! - * Creates a lattice based on the given formula. + * Extends the lattice based on the given assumption. * - * @param formulas The formulas based on which the lattice is created, only the first is used. + * @param lattice The lattice. + * @param assumption The assumption on states. * @return A triple with a pointer to the lattice and two states of which the current place in the lattice * is unknown but needed. When the states have as number the number of states, no states are * unplaced but needed. */ - std::tuple toLattice(std::vector> formulas); + std::tuple extendLattice(storm::analysis::Lattice* lattice, std::shared_ptr assumption = nullptr); /*! - * Extends the lattice based on the given assumption. + * Creates a lattice based on the given formula. * - * @param lattice The lattice. - * @param assumption The assumption on states. + * @param formulas The formulas based on which the lattice is created, only the first is used. * @return A triple with a pointer to the lattice and two states of which the current place in the lattice * is unknown but needed. When the states have as number the number of states, no states are * unplaced but needed. */ - std::tuple extendLattice(storm::analysis::Lattice* lattice, std::shared_ptr assumption = nullptr); + std::tuple toLattice(std::vector> formulas); private: std::shared_ptr> model; std::map stateMap; + std::vector states; + + bool acyclic; + void handleAssumption(Lattice* lattice, std::shared_ptr assumption); std::tuple extendAllSuccAdded(Lattice* lattice, uint_fast64_t stateNumber, storm::storage::BitVector successors); diff --git a/src/storm-pars/analysis/MonotonicityChecker.cpp b/src/storm-pars/analysis/MonotonicityChecker.cpp index 91d9b6929..9c2a90b1f 100644 --- a/src/storm-pars/analysis/MonotonicityChecker.cpp +++ b/src/storm-pars/analysis/MonotonicityChecker.cpp @@ -27,8 +27,6 @@ #include "storm/storage/expressions/RationalFunctionToExpression.h" - - namespace storm { namespace analysis { template @@ -41,7 +39,7 @@ namespace storm { if (model != nullptr) { std::shared_ptr> sparseModel = model->as>(); this->extender = new storm::analysis::LatticeExtender(sparseModel); - outfile << model->getNumberOfStates() << "; " << model->getNumberOfTransitions() << "; "; + outfile << model->getNumberOfStates() << ", " << model->getNumberOfTransitions() << ", "; } outfile.close(); totalWatch = storm::utility::Stopwatch(true); @@ -49,9 +47,11 @@ namespace storm { template std::map>> MonotonicityChecker::checkMonotonicity() { - totalWatch = storm::utility::Stopwatch(true); // TODO: check on samples or not? + totalWatch = storm::utility::Stopwatch(true); + auto latticeWatch = storm::utility::Stopwatch(true); auto map = createLattice(); + // STORM_PRINT(std::endl << "Time for creating lattice: " << latticeWatch << "." << std::endl << std::endl); std::shared_ptr> sparseModel = model->as>(); auto matrix = sparseModel->getTransitionMatrix(); return checkMonotonicity(map, matrix); @@ -101,10 +101,21 @@ namespace storm { bool assumptionsHold = true; for (auto itr = assumptions.begin(); assumptionsHold && itr != assumptions.end(); ++itr) { auto assumption = *itr; - assert (assumption->getRelationType() == storm::expressions::BinaryRelationExpression::RelationType::GreaterOrEqual); - auto state1 = std::stoi(assumption->getFirstOperand()->asVariableExpression().getVariableName()); - auto state2 = std::stoi(assumption->getSecondOperand()->asVariableExpression().getVariableName()); - assumptionsHold &= valuesLower[state1] >= valuesUpper[state2]; + if (assumption->getRelationType() == storm::expressions::BinaryRelationExpression::RelationType::Greater) { + auto state1 = std::stoi( + assumption->getFirstOperand()->asVariableExpression().getVariableName()); + auto state2 = std::stoi( + assumption->getSecondOperand()->asVariableExpression().getVariableName()); + assumptionsHold &= valuesLower[state1] >= valuesUpper[state2]; + } else if (assumption->getRelationType() == storm::expressions::BinaryRelationExpression::RelationType::Equal) { + auto state1 = std::stoi( + assumption->getFirstOperand()->asVariableExpression().getVariableName()); + auto state2 = std::stoi( + assumption->getSecondOperand()->asVariableExpression().getVariableName()); + assumptionsHold &= valuesLower[state1] == valuesUpper[state2]; + } else { + assert(false); + } } if (!assumptionsHold) { std::vector> newRegions; @@ -126,55 +137,67 @@ namespace storm { template std::map>> MonotonicityChecker::checkMonotonicity(std::map>> map, storm::storage::SparseMatrix matrix) { - storm::utility::Stopwatch finalCheckWatch(true); + storm::utility::Stopwatch monotonicityCheckWatch(true); std::map>> result; + outfile.open(filename, std::ios_base::app); if (map.size() == 0) { - outfile.open(filename, std::ios_base::app); - outfile << " | No assumptions, ? | ;"; - outfile.close(); - STORM_PRINT(std::endl << "Do not know about monotonicity" << std::endl); + // Nothing is known + outfile << " No assumptions; ?"; + // STORM_PRINT(std::endl << "Do not know about monotonicity" << std::endl); } else { auto i = 0; for (auto itr = map.begin(); i < map.size() && itr != map.end(); ++itr) { auto lattice = itr->first; - outfile.open(filename, std::ios_base::app); - outfile << "|"; - outfile.close(); + if (itr != map.begin()) { + outfile << ";"; + } std::map> varsMonotone = analyseMonotonicity(i, lattice, matrix); - outfile.open(filename, std::ios_base::app); auto assumptions = itr->second; bool validSomewhere = true; if (assumptions.size() > 0) { - auto regions = checkAssumptionsOnRegion(assumptions); - if (regions.size() > 0) { - STORM_PRINT("For regions: " << std::endl); - } - bool first = true; - for (auto itr2 = regions.begin(); itr2 != regions.end(); ++itr2) { - if (first) { - STORM_PRINT(" "); - first = false; +// auto regions = checkAssumptionsOnRegion(assumptions); +// if (regions.size() > 0) { +// // STORM_PRINT("For regions: " << std::endl); +// bool first = true; +// for (auto itr2 = regions.begin(); itr2 != regions.end(); ++itr2) { +// if (first) { +// // STORM_PRINT(" "); +// first = false; +// } +// // STORM_PRINT(*itr2); +// outfile << (*itr2); +// } +// // STORM_PRINT(std::endl); +// outfile << ", "; +// } else { + // STORM_PRINT("Assumption(s): "); + bool first = true; + for (auto itr2 = assumptions.begin(); itr2 != assumptions.end(); ++itr2) { + if (!first) { + // STORM_PRINT(" ^ "); + outfile << (" ^ "); + } else { + first = false; + } + // STORM_PRINT(*(*itr2)); + outfile << (*(*itr2)); } - STORM_PRINT(*itr2); - outfile << (*itr2); - } - if (regions.size() > 0) { - STORM_PRINT(std::endl); - outfile << ", "; - } + // STORM_PRINT(std::endl); + outfile << " - "; +// } } if (validSomewhere && assumptions.size() == 0) { - outfile << "No assumptions, "; + outfile << "No assumptions - "; } if (validSomewhere && varsMonotone.size() == 0) { - STORM_PRINT("Result is constant" << std::endl); + // STORM_PRINT("Result is constant" << std::endl); outfile << "No params"; } else if (validSomewhere) { auto itr2 = varsMonotone.begin(); @@ -182,45 +205,41 @@ namespace storm { if (resultCheckOnSamples.find(itr2->first) != resultCheckOnSamples.end() && (!resultCheckOnSamples[itr2->first].first && !resultCheckOnSamples[itr2->first].second)) { - STORM_PRINT(" - Not monotone in: " << itr2->first << std::endl); + // STORM_PRINT(" - Not monotone in: " << itr2->first << std::endl); outfile << "X " << itr2->first; } else { if (itr2->second.first && itr2->second.second) { - STORM_PRINT(" - Constant in" << itr2->first << std::endl); + // STORM_PRINT(" - Constant in" << itr2->first << std::endl); outfile << "C " << itr2->first; } else if (itr2->second.first) { - STORM_PRINT(" - Monotone increasing in: " << itr2->first << std::endl); + // STORM_PRINT(" - Monotone increasing in: " << itr2->first << std::endl); outfile << "I " << itr2->first; } else if (itr2->second.second) { - STORM_PRINT(" - Monotone decreasing in: " << itr2->first << std::endl); + // STORM_PRINT(" - Monotone decreasing in: " << itr2->first << std::endl); outfile << "D " << itr2->first; } else { - STORM_PRINT( - " - Do not know if monotone incr/decreasing in: " << itr2->first << std::endl); + // STORM_PRINT(" - Do not know if monotone incr/decreasing in: " << itr2->first << std::endl); outfile << "? " << itr2->first; } } ++itr2; if (itr2 != varsMonotone.end()) { - outfile << ", "; + outfile << " "; } } result.insert( std::pair>>( lattice, varsMonotone)); } - outfile << "| "; - outfile.close(); ++i; } } + outfile << ", "; - finalCheckWatch.stop(); - STORM_PRINT(std::endl << "Time for monotonicity check on lattice: " << finalCheckWatch << "." << std::endl << std::endl); - outfile.open(filename, std::ios_base::app); - totalWatch.stop(); - outfile << totalWatch << "; "; + monotonicityCheckWatch.stop(); + outfile << monotonicityCheckWatch << ", "; + // STORM_PRINT(std::endl << "Time for monotonicity check on lattice: " << monotonicityCheckWatch << "." << std::endl << std::endl); outfile.close(); return result; } @@ -259,8 +278,10 @@ namespace storm { assert(false); } latticeWatch.stop(); - STORM_PRINT(std::endl << "Total time for lattice creation: " << latticeWatch << "." << std::endl << std::endl); - outfile << latticeWatch << "; "; + // STORM_PRINT(std::endl << "Total time for lattice creation: " << latticeWatch << "." << std::endl << std::endl); + outfile.open(filename, std::ios_base::app); + outfile << latticeWatch << ", "; + outfile.close(); return result; } @@ -273,19 +294,27 @@ namespace storm { assert (val1 == val2); result.insert(std::pair>>(lattice, assumptions)); } else { - auto assumptionPair = assumptionMaker->createAndCheckAssumption(val1, val2, lattice); - assert (assumptionPair.size() == 2); - auto itr = assumptionPair.begin(); + + // TODO: should be triple + auto assumptionTriple = assumptionMaker->createAndCheckAssumption(val1, val2, lattice); + assert (assumptionTriple.size() == 3); + auto itr = assumptionTriple.begin(); auto assumption1 = *itr; ++itr; auto assumption2 = *itr; + ++itr; + auto assumption3 = *itr; if (!assumption1.second && !assumption2.second) { + // Both assumption cannot be validated, so we need to keep them both // TODO: hier niet verder gaan als je iets gevonden hebt? auto assumptionsCopy = std::vector>(assumptions); + auto assumptionsCopy2 = std::vector>(assumptions); auto latticeCopy = new storm::analysis::Lattice(lattice); + auto latticeCopy2 = new storm::analysis::Lattice(lattice); assumptions.push_back(assumption1.first); assumptionsCopy.push_back(assumption2.first); + assumptionsCopy2.push_back(assumption2.first); auto criticalTuple = extender->extendLattice(lattice, assumption1.first); if (somewhereMonotonicity(std::get<0>(criticalTuple))) { @@ -300,7 +329,16 @@ namespace storm { assumptionsCopy); result.insert(map.begin(), map.end()); } + // TODO verbeteren +// criticalTuple = extender->extendLattice(latticeCopy2, assumption3.first); +// if (somewhereMonotonicity(std::get<0>(criticalTuple))) { +// auto map = extendLatticeWithAssumptions(std::get<0>(criticalTuple), assumptionMaker, +// std::get<1>(criticalTuple), std::get<2>(criticalTuple), +// assumptionsCopy2); +// result.insert(map.begin(), map.end()); +// } } else if (assumption1.second && assumption2.second) { + //TODO Both assumptions hold --> should not happen if we change it to < instead of <= auto assumption = assumptionMaker->createEqualAssumption(val1, val2); if (!validate) { assumptions.push_back(assumption); @@ -312,6 +350,7 @@ namespace storm { } } else if (assumption1.second) { if (!validate) { + assert(false); assumptions.push_back(assumption1.first); } // if validate is true and both hold, then they must be valid, so no need to add to assumptions @@ -339,7 +378,7 @@ namespace storm { template std::map> MonotonicityChecker::analyseMonotonicity(uint_fast64_t j, storm::analysis::Lattice* lattice, storm::storage::SparseMatrix matrix) { - storm::utility::Stopwatch analyseWatch(true); +// storm::utility::Stopwatch analyseWatch(true); std::map> varsMonotone; @@ -413,9 +452,9 @@ namespace storm { } } - analyseWatch.stop(); - STORM_PRINT(std::endl << "Time to check monotonicity based on the lattice: " << analyseWatch << "." << std::endl << std::endl); - outfile << analyseWatch << "; "; +// analyseWatch.stop(); + // STORM_PRINT(std::endl << "Time to check monotonicity based on the lattice: " << analyseWatch << "." << std::endl << std::endl); +// outfile << analyseWatch << "; "; return varsMonotone; } @@ -609,7 +648,7 @@ namespace storm { } samplesWatch.stop(); - STORM_PRINT(std::endl << "Time to check monotonicity on samples: " << samplesWatch << "." << std::endl << std::endl); + // STORM_PRINT(std::endl << "Time to check monotonicity on samples: " << samplesWatch << "." << std::endl << std::endl); resultCheckOnSamples = result; return result; } @@ -680,7 +719,7 @@ namespace storm { } samplesWatch.stop(); - STORM_PRINT(std::endl << "Time to check monotonicity on samples: " << samplesWatch << "." << std::endl << std::endl); + // STORM_PRINT(std::endl << "Time to check monotonicity on samples: " << samplesWatch << "." << std::endl << std::endl); resultCheckOnSamples = result; return result; } diff --git a/src/test/storm-pars/analysis/AssumptionCheckerTest.cpp b/src/test/storm-pars/analysis/AssumptionCheckerTest.cpp index 3880a525f..b8ac1981e 100644 --- a/src/test/storm-pars/analysis/AssumptionCheckerTest.cpp +++ b/src/test/storm-pars/analysis/AssumptionCheckerTest.cpp @@ -62,6 +62,20 @@ TEST(AssumptionCheckerTest, Brp_no_bisimulation) { storm::expressions::BinaryRelationExpression::RelationType::GreaterOrEqual)); EXPECT_TRUE(checker.checkOnSamples(assumption)); + assumption = std::make_shared( + storm::expressions::BinaryRelationExpression(*expressionManager, expressionManager->getBooleanType(), + expressionManager->getVariable("7").getExpression().getBaseExpressionPointer(), + expressionManager->getVariable("5").getExpression().getBaseExpressionPointer(), + storm::expressions::BinaryRelationExpression::RelationType::Greater)); + EXPECT_TRUE(checker.checkOnSamples(assumption)); + + assumption = std::make_shared( + storm::expressions::BinaryRelationExpression(*expressionManager, expressionManager->getBooleanType(), + expressionManager->getVariable("7").getExpression().getBaseExpressionPointer(), + expressionManager->getVariable("5").getExpression().getBaseExpressionPointer(), + storm::expressions::BinaryRelationExpression::RelationType::Equal)); + EXPECT_FALSE(checker.checkOnSamples(assumption)); + storm::storage::BitVector above(8); above.set(0); storm::storage::BitVector below(8); @@ -79,17 +93,17 @@ TEST(AssumptionCheckerTest, Brp_no_bisimulation) { storm::expressions::BinaryRelationExpression(*expressionManager, expressionManager->getBooleanType(), expressionManager->getVariable("6").getExpression().getBaseExpressionPointer(), expressionManager->getVariable("8").getExpression().getBaseExpressionPointer(), - storm::expressions::BinaryRelationExpression::RelationType::GreaterOrEqual)); + storm::expressions::BinaryRelationExpression::RelationType::Greater)); above = storm::storage::BitVector(13); above.set(12); below = storm::storage::BitVector(13); below.set(9); initialMiddle = storm::storage::BitVector(13); dummyLattice = new storm::analysis::Lattice(above, below, initialMiddle, 13); - EXPECT_TRUE(checker.checkOnSamples(assumption)); - EXPECT_TRUE(checker.validateAssumption(assumption, dummyLattice)); + EXPECT_FALSE(checker.checkOnSamples(assumption)); + EXPECT_FALSE(checker.validateAssumption(assumption, dummyLattice)); EXPECT_TRUE(checker.validated(assumption)); - EXPECT_TRUE(checker.valid(assumption)); + EXPECT_FALSE(checker.valid(assumption)); } diff --git a/src/test/storm-pars/analysis/AssumptionMakerTest.cpp b/src/test/storm-pars/analysis/AssumptionMakerTest.cpp index f233d2563..af6f0213d 100644 --- a/src/test/storm-pars/analysis/AssumptionMakerTest.cpp +++ b/src/test/storm-pars/analysis/AssumptionMakerTest.cpp @@ -61,14 +61,14 @@ TEST(AssumptionMakerTest, Brp_without_bisimulation) { auto var1 = itr->first->getManager().getVariable("183"); auto var2 = itr->first->getManager().getVariable("186"); - EXPECT_EQ(2, result.size()); + EXPECT_EQ(3, result.size()); EXPECT_EQ(false, itr->second); EXPECT_EQ(true, itr->first->getFirstOperand()->isVariable()); EXPECT_EQ(true, itr->first->getSecondOperand()->isVariable()); EXPECT_EQ(var1, itr->first->getFirstOperand()->asVariableExpression().getVariable()); EXPECT_EQ(var2, itr->first->getSecondOperand()->asVariableExpression().getVariable()); - EXPECT_EQ(storm::expressions::BinaryRelationExpression::RelationType::GreaterOrEqual, itr->first->getRelationType()); + EXPECT_EQ(storm::expressions::BinaryRelationExpression::RelationType::Greater, itr->first->getRelationType()); ++itr; EXPECT_EQ(false, itr->second); @@ -76,6 +76,14 @@ TEST(AssumptionMakerTest, Brp_without_bisimulation) { EXPECT_EQ(true, itr->first->getSecondOperand()->isVariable()); EXPECT_EQ(var2, itr->first->getFirstOperand()->asVariableExpression().getVariable()); EXPECT_EQ(var1, itr->first->getSecondOperand()->asVariableExpression().getVariable()); - EXPECT_EQ(storm::expressions::BinaryRelationExpression::RelationType::GreaterOrEqual, itr->first->getRelationType()); + EXPECT_EQ(storm::expressions::BinaryRelationExpression::RelationType::Greater, itr->first->getRelationType()); + + ++itr; + EXPECT_EQ(false, itr->second); + EXPECT_EQ(true, itr->first->getFirstOperand()->isVariable()); + EXPECT_EQ(true, itr->first->getSecondOperand()->isVariable()); + EXPECT_EQ(var2, itr->first->getFirstOperand()->asVariableExpression().getVariable()); + EXPECT_EQ(var1, itr->first->getSecondOperand()->asVariableExpression().getVariable()); + EXPECT_EQ(storm::expressions::BinaryRelationExpression::RelationType::Equal, itr->first->getRelationType()); // TODO: createEqualsAssumption checken } diff --git a/src/test/storm-pars/analysis/LatticeTest.cpp b/src/test/storm-pars/analysis/LatticeTest.cpp index 5fba6eac4..ad65b98c7 100644 --- a/src/test/storm-pars/analysis/LatticeTest.cpp +++ b/src/test/storm-pars/analysis/LatticeTest.cpp @@ -139,3 +139,37 @@ TEST(LatticeTest, copy_lattice) { EXPECT_EQ(storm::analysis::Lattice::BELOW, latticeCopy.compare(6,5)); EXPECT_EQ(storm::analysis::Lattice::ABOVE, latticeCopy.compare(5,6)); } + +TEST(LatticeTest, merge_nodes) { + auto numberOfStates = 7; + auto above = storm::storage::BitVector(numberOfStates); + above.set(0); + auto below = storm::storage::BitVector(numberOfStates); + below.set(1); + auto initialMiddle = storm::storage::BitVector(numberOfStates); + + auto lattice = storm::analysis::Lattice(above, below, initialMiddle, numberOfStates); + lattice.add(2); + lattice.add(3); + lattice.addToNode(4, lattice.getNode(2)); + lattice.addBetween(5, lattice.getNode(0), lattice.getNode(3)); + lattice.addBetween(6, lattice.getNode(5), lattice.getNode(3)); + + lattice.mergeNodes(lattice.getNode(4), lattice.getNode(5)); + EXPECT_EQ(storm::analysis::Lattice::SAME, lattice.compare(2,4)); + EXPECT_EQ(storm::analysis::Lattice::SAME, lattice.compare(2,5)); + + EXPECT_EQ(storm::analysis::Lattice::ABOVE, lattice.compare(0,5)); + EXPECT_EQ(storm::analysis::Lattice::ABOVE, lattice.compare(0,2)); + EXPECT_EQ(storm::analysis::Lattice::ABOVE, lattice.compare(0,4)); + + EXPECT_EQ(storm::analysis::Lattice::BELOW, lattice.compare(6,2)); + EXPECT_EQ(storm::analysis::Lattice::BELOW, lattice.compare(6,4)); + EXPECT_EQ(storm::analysis::Lattice::BELOW, lattice.compare(6,5)); + EXPECT_EQ(storm::analysis::Lattice::BELOW, lattice.compare(3,2)); + EXPECT_EQ(storm::analysis::Lattice::BELOW, lattice.compare(3,4)); + EXPECT_EQ(storm::analysis::Lattice::BELOW, lattice.compare(3,5)); + EXPECT_EQ(storm::analysis::Lattice::BELOW, lattice.compare(1,2)); + EXPECT_EQ(storm::analysis::Lattice::BELOW, lattice.compare(1,4)); + EXPECT_EQ(storm::analysis::Lattice::BELOW, lattice.compare(1,5)); +} From a72c7a244af2d4e56915ab456835b0eebe4b3f93 Mon Sep 17 00:00:00 2001 From: Jip Spel Date: Wed, 30 Jan 2019 14:45:06 +0100 Subject: [PATCH 131/178] Fix bug with acyclic pmcs and more than one assumption --- src/storm-pars/analysis/LatticeExtender.cpp | 22 +- src/storm-pars/analysis/LatticeExtender.h | 2 +- .../analysis/MonotonicityChecker.cpp | 217 ++++++++++-------- 3 files changed, 136 insertions(+), 105 deletions(-) diff --git a/src/storm-pars/analysis/LatticeExtender.cpp b/src/storm-pars/analysis/LatticeExtender.cpp index 4917da795..4161f8345 100644 --- a/src/storm-pars/analysis/LatticeExtender.cpp +++ b/src/storm-pars/analysis/LatticeExtender.cpp @@ -75,7 +75,7 @@ namespace storm { acyclic &= decomposition.getBlock(i).size() <= 1; } if (acyclic) { - states = storm::utility::graph::getTopologicalSort(matrix); + statesSorted = storm::utility::graph::getTopologicalSort(matrix); } else { for (uint_fast64_t i = 0; i < numberOfStates; ++i) { stateMap[i] = storm::storage::BitVector(numberOfStates, false); @@ -221,7 +221,11 @@ namespace storm { lowest = i; } } - lattice->addBetween(stateNumber, lattice->getNode(highest), lattice->getNode(lowest)); + if (lowest == highest) { + lattice->addToNode(stateNumber, lattice->getNode(highest)); + } else { + lattice->addBetween(stateNumber, lattice->getNode(highest), lattice->getNode(lowest)); + } } return std::make_tuple(lattice, numberOfStates, numberOfStates); } @@ -239,16 +243,17 @@ namespace storm { auto oldNumberSet = numberOfStates; while (oldNumberSet != lattice->getAddedStates().getNumberOfSetBits()) { oldNumberSet = lattice->getAddedStates().getNumberOfSetBits(); + auto states = statesSorted; if (acyclic && states.size() > 0) { auto nextState = *(states.begin()); - while (lattice->getAddedStates().get(nextState) && states.size() > 0) { + while (lattice->getAddedStates()[nextState] && states.size() > 1) { + // states.size()>1 such that there is at least one state left after erase states.erase(states.begin()); - nextState = *(states.begin()); } - if (! lattice->getAddedStates().get(nextState)) { + if (! lattice->getAddedStates()[nextState]) { auto row = this->model->getTransitionMatrix().getRow(nextState); auto successors = storm::storage::BitVector(lattice->getAddedStates().size()); for (auto rowItr = row.begin(); rowItr != row.end(); ++rowItr) { @@ -258,16 +263,20 @@ namespace storm { } } auto seenStates = (lattice->getAddedStates()); + assert ((seenStates & successors) == successors); auto result = extendAllSuccAdded(lattice, nextState, successors); - if (std::get<1>(result) != successors.size()) { + if (std::get<1>(result) != numberOfStates) { return result; } else { + assert (lattice->getNode(nextState) != nullptr); states.erase(states.begin()); } } + auto added = lattice->getAddedStates().getNumberOfSetBits(); assert (lattice->getNode(nextState) != nullptr); + assert (lattice->getAddedStates()[nextState]); } else if (!acyclic) { // TODO: kan dit niet efficienter @@ -324,6 +333,7 @@ namespace storm { } } } + assert (lattice->getAddedStates().getNumberOfSetBits() == numberOfStates); return std::make_tuple(lattice, numberOfStates, numberOfStates); } template class LatticeExtender; diff --git a/src/storm-pars/analysis/LatticeExtender.h b/src/storm-pars/analysis/LatticeExtender.h index 7ff23ba05..c087d6422 100644 --- a/src/storm-pars/analysis/LatticeExtender.h +++ b/src/storm-pars/analysis/LatticeExtender.h @@ -54,7 +54,7 @@ namespace storm { std::map stateMap; - std::vector states; + std::vector statesSorted; bool acyclic; diff --git a/src/storm-pars/analysis/MonotonicityChecker.cpp b/src/storm-pars/analysis/MonotonicityChecker.cpp index 9c2a90b1f..8f1a4efa0 100644 --- a/src/storm-pars/analysis/MonotonicityChecker.cpp +++ b/src/storm-pars/analysis/MonotonicityChecker.cpp @@ -150,14 +150,17 @@ namespace storm { auto i = 0; for (auto itr = map.begin(); i < map.size() && itr != map.end(); ++itr) { auto lattice = itr->first; - if (itr != map.begin()) { - outfile << ";"; - } + + auto addedStates = lattice->getAddedStates().getNumberOfSetBits(); + assert (addedStates == lattice->getAddedStates().size()); std::map> varsMonotone = analyseMonotonicity(i, lattice, matrix); auto assumptions = itr->second; - bool validSomewhere = true; + bool validSomewhere = false; + for (auto itr2 = varsMonotone.begin(); !validSomewhere && itr2 != varsMonotone.end(); ++itr2) { + validSomewhere = itr2->second.first || itr2->second.second; + } if (assumptions.size() > 0) { // auto regions = checkAssumptionsOnRegion(assumptions); // if (regions.size() > 0) { @@ -189,9 +192,7 @@ namespace storm { // STORM_PRINT(std::endl); outfile << " - "; // } - } - - if (validSomewhere && assumptions.size() == 0) { + } else if (assumptions.size() == 0) { outfile << "No assumptions - "; } @@ -202,12 +203,12 @@ namespace storm { } else if (validSomewhere) { auto itr2 = varsMonotone.begin(); while (itr2 != varsMonotone.end()) { - if (resultCheckOnSamples.find(itr2->first) != resultCheckOnSamples.end() && - (!resultCheckOnSamples[itr2->first].first && - !resultCheckOnSamples[itr2->first].second)) { - // STORM_PRINT(" - Not monotone in: " << itr2->first << std::endl); - outfile << "X " << itr2->first; - } else { +// if (resultCheckOnSamples.find(itr2->first) != resultCheckOnSamples.end() && +// (!resultCheckOnSamples[itr2->first].first && +// !resultCheckOnSamples[itr2->first].second)) { +// // STORM_PRINT(" - Not monotone in: " << itr2->first << std::endl); +// outfile << "X " << itr2->first; +// } else { if (itr2->second.first && itr2->second.second) { // STORM_PRINT(" - Constant in" << itr2->first << std::endl); outfile << "C " << itr2->first; @@ -222,7 +223,7 @@ namespace storm { // STORM_PRINT(" - Do not know if monotone incr/decreasing in: " << itr2->first << std::endl); outfile << "? " << itr2->first; } - } +// } ++itr2; if (itr2 != varsMonotone.end()) { outfile << " "; @@ -231,8 +232,14 @@ namespace storm { result.insert( std::pair>>( lattice, varsMonotone)); + } else { + result.insert( + std::pair>>( + lattice, varsMonotone)); + outfile << "no monotonicity found"; } ++i; + outfile << ";"; } } outfile << ", "; @@ -292,10 +299,10 @@ namespace storm { auto numberOfStates = model->getNumberOfStates(); if (val1 == numberOfStates || val2 == numberOfStates) { assert (val1 == val2); + assert (lattice->getAddedStates().size() == lattice->getAddedStates().getNumberOfSetBits()); result.insert(std::pair>>(lattice, assumptions)); } else { - // TODO: should be triple auto assumptionTriple = assumptionMaker->createAndCheckAssumption(val1, val2, lattice); assert (assumptionTriple.size() == 3); auto itr = assumptionTriple.begin(); @@ -305,11 +312,13 @@ namespace storm { ++itr; auto assumption3 = *itr; - if (!assumption1.second && !assumption2.second) { + if (!assumption1.second && !assumption2.second && !assumption3.second) { // Both assumption cannot be validated, so we need to keep them both // TODO: hier niet verder gaan als je iets gevonden hebt? - auto assumptionsCopy = std::vector>(assumptions); - auto assumptionsCopy2 = std::vector>(assumptions); + auto assumptionsCopy = std::vector>( + assumptions); + auto assumptionsCopy2 = std::vector>( + assumptions); auto latticeCopy = new storm::analysis::Lattice(lattice); auto latticeCopy2 = new storm::analysis::Lattice(lattice); assumptions.push_back(assumption1.first); @@ -318,60 +327,63 @@ namespace storm { auto criticalTuple = extender->extendLattice(lattice, assumption1.first); if (somewhereMonotonicity(std::get<0>(criticalTuple))) { - auto map = extendLatticeWithAssumptions(std::get<0>(criticalTuple), assumptionMaker, std::get<1>(criticalTuple), std::get<2>(criticalTuple), assumptions); + auto map = extendLatticeWithAssumptions(std::get<0>(criticalTuple), assumptionMaker, + std::get<1>(criticalTuple), std::get<2>(criticalTuple), + assumptions); result.insert(map.begin(), map.end()); } criticalTuple = extender->extendLattice(latticeCopy, assumption2.first); if (somewhereMonotonicity(std::get<0>(criticalTuple))) { auto map = extendLatticeWithAssumptions(std::get<0>(criticalTuple), assumptionMaker, - std::get<1>(criticalTuple), std::get<2>(criticalTuple), - assumptionsCopy); + std::get<1>(criticalTuple), std::get<2>(criticalTuple), + assumptionsCopy); result.insert(map.begin(), map.end()); } - // TODO verbeteren -// criticalTuple = extender->extendLattice(latticeCopy2, assumption3.first); -// if (somewhereMonotonicity(std::get<0>(criticalTuple))) { -// auto map = extendLatticeWithAssumptions(std::get<0>(criticalTuple), assumptionMaker, -// std::get<1>(criticalTuple), std::get<2>(criticalTuple), -// assumptionsCopy2); -// result.insert(map.begin(), map.end()); -// } - } else if (assumption1.second && assumption2.second) { - //TODO Both assumptions hold --> should not happen if we change it to < instead of <= - auto assumption = assumptionMaker->createEqualAssumption(val1, val2); - if (!validate) { - assumptions.push_back(assumption); - } - // if validate is true and both hold, then they must be valid, so no need to add to assumptions - auto criticalTuple = extender->extendLattice(lattice, assumption); - if (somewhereMonotonicity(std::get<0>(criticalTuple))) { - result = extendLatticeWithAssumptions(std::get<0>(criticalTuple), assumptionMaker, std::get<1>(criticalTuple), std::get<2>(criticalTuple), assumptions); - } - } else if (assumption1.second) { - if (!validate) { - assert(false); - assumptions.push_back(assumption1.first); - } - // if validate is true and both hold, then they must be valid, so no need to add to assumptions - - auto criticalTuple = extender->extendLattice(lattice, assumption1.first); - + criticalTuple = extender->extendLattice(latticeCopy2, assumption3.first); if (somewhereMonotonicity(std::get<0>(criticalTuple))) { - result = extendLatticeWithAssumptions(std::get<0>(criticalTuple), assumptionMaker, std::get<1>(criticalTuple), std::get<2>(criticalTuple), assumptions); - } - - } else { - assert (assumption2.second); - if (!validate) { - assumptions.push_back(assumption2.first); - } - // if validate is true and both hold, then they must be valid, so no need to add to assumptions - auto criticalTuple = extender->extendLattice(lattice, assumption2.first); - if (somewhereMonotonicity(std::get<0>(criticalTuple))) { - result = extendLatticeWithAssumptions(std::get<0>(criticalTuple), assumptionMaker, std::get<1>(criticalTuple), std::get<2>(criticalTuple), assumptions); + auto map = extendLatticeWithAssumptions(std::get<0>(criticalTuple), assumptionMaker, + std::get<1>(criticalTuple), std::get<2>(criticalTuple), + assumptionsCopy2); + result.insert(map.begin(), map.end()); } } +// } else if (assumption1.second && assumption2.second) { +// assert (false); +// //TODO Both assumptions hold --> should not happen if we change it to < instead of <= +// auto assumption = assumptionMaker->createEqualAssumption(val1, val2); +// if (!validate) { +// assumptions.push_back(assumption); +// } +// // if validate is true and both hold, then they must be valid, so no need to add to assumptions +// auto criticalTuple = extender->extendLattice(lattice, assumption); +// if (somewhereMonotonicity(std::get<0>(criticalTuple))) { +// result = extendLatticeWithAssumptions(std::get<0>(criticalTuple), assumptionMaker, std::get<1>(criticalTuple), std::get<2>(criticalTuple), assumptions); +// } +// } else if (assumption1.second) { +// if (!validate) { +// assert(false); +// assumptions.push_back(assumption1.first); +// } +// // if validate is true and both hold, then they must be valid, so no need to add to assumptions +// +// auto criticalTuple = extender->extendLattice(lattice, assumption1.first); +// +// if (somewhereMonotonicity(std::get<0>(criticalTuple))) { +// result = extendLatticeWithAssumptions(std::get<0>(criticalTuple), assumptionMaker, std::get<1>(criticalTuple), std::get<2>(criticalTuple), assumptions); +// } +// +// } else { +// assert (assumption2.second); +// if (!validate) { +// assumptions.push_back(assumption2.first); +// } +// // if validate is true and both hold, then they must be valid, so no need to add to assumptions +// auto criticalTuple = extender->extendLattice(lattice, assumption2.first); +// if (somewhereMonotonicity(std::get<0>(criticalTuple))) { +// result = extendLatticeWithAssumptions(std::get<0>(criticalTuple), assumptionMaker, std::get<1>(criticalTuple), std::get<2>(criticalTuple), assumptions); +// } +// } } return result; } @@ -396,13 +408,13 @@ namespace storm { auto val = first.getValue(); auto vars = val.gatherVariables(); for (auto itr = vars.begin(); itr != vars.end(); ++itr) { - if (resultCheckOnSamples.find(*itr) != resultCheckOnSamples.end() && - (!resultCheckOnSamples[*itr].first && !resultCheckOnSamples[*itr].second)) { - if (varsMonotone.find(*itr) == varsMonotone.end()) { - varsMonotone[*itr].first = false; - varsMonotone[*itr].second = false; - } - } else { +// if (resultCheckOnSamples.find(*itr) != resultCheckOnSamples.end() && +// (!resultCheckOnSamples[*itr].first && !resultCheckOnSamples[*itr].second)) { +// if (varsMonotone.find(*itr) == varsMonotone.end()) { +// varsMonotone[*itr].first = false; +// varsMonotone[*itr].second = false; +// } +// } else { if (varsMonotone.find(*itr) == varsMonotone.end()) { varsMonotone[*itr].first = true; varsMonotone[*itr].second = true; @@ -445,7 +457,7 @@ namespace storm { value->first = false; value->second = false; } - } +// } } } } @@ -463,41 +475,50 @@ namespace storm { bool monIncr = false; bool monDecr = false; - std::shared_ptr smtSolverFactory = std::make_shared(); - std::shared_ptr manager( - new storm::expressions::ExpressionManager()); + if (derivative.isZero()) { + monIncr = true; + monDecr = true; + } else { - storm::solver::Z3SmtSolver s(*manager); - storm::solver::SmtSolver::CheckResult smtResult = storm::solver::SmtSolver::CheckResult::Unknown; + std::shared_ptr smtSolverFactory = std::make_shared(); + std::shared_ptr manager( + new storm::expressions::ExpressionManager()); - std::set variables = derivative.gatherVariables(); + storm::solver::Z3SmtSolver s(*manager); + storm::solver::SmtSolver::CheckResult smtResult = storm::solver::SmtSolver::CheckResult::Unknown; + std::set variables = derivative.gatherVariables(); - for (auto variable : variables) { - manager->declareRationalVariable(variable.name()); - } - storm::expressions::Expression exprBounds = manager->boolean(true); - auto managervars = manager->getVariables(); - for (auto var : managervars) { - exprBounds = exprBounds && manager->rational(0) <= var && manager->rational(1) >= var; - } + for (auto variable : variables) { + manager->declareRationalVariable(variable.name()); + + } + storm::expressions::Expression exprBounds = manager->boolean(true); + auto managervars = manager->getVariables(); + for (auto var : managervars) { + exprBounds = exprBounds && manager->rational(0) <= var && manager->rational(1) >= var; + } - auto converter = storm::expressions::RationalFunctionToExpression(manager); - - storm::expressions::Expression exprToCheck1 = converter.toExpression(derivative) >= manager->rational(0); - s.add(exprBounds); - s.add(exprToCheck1); - smtResult = s.check(); - monIncr = smtResult == storm::solver::SmtSolver::CheckResult::Sat; - - storm::expressions::Expression exprToCheck2 = converter.toExpression(derivative) <= manager->rational(0); - s.reset(); - smtResult = storm::solver::SmtSolver::CheckResult::Unknown; - s.add(exprBounds); - s.add(exprToCheck2); - smtResult = s.check(); - monDecr = smtResult == storm::solver::SmtSolver::CheckResult::Sat; + auto converter = storm::expressions::RationalFunctionToExpression(manager); + + storm::expressions::Expression exprToCheck1 = + converter.toExpression(derivative) >= manager->rational(0); + s.add(exprBounds); + s.add(exprToCheck1); + smtResult = s.check(); + monIncr = smtResult == storm::solver::SmtSolver::CheckResult::Sat; + + storm::expressions::Expression exprToCheck2 = + converter.toExpression(derivative) <= manager->rational(0); + s.reset(); + smtResult = storm::solver::SmtSolver::CheckResult::Unknown; + s.add(exprBounds); + s.add(exprToCheck2); + smtResult = s.check(); + monDecr = smtResult == storm::solver::SmtSolver::CheckResult::Sat; + } + assert (!(monIncr && monDecr) || derivative.isZero()); return std::pair(monIncr, monDecr); } From 3397d6aec06cfe18c9da8fc95dad59bcdd1723b5 Mon Sep 17 00:00:00 2001 From: Jip Spel Date: Wed, 30 Jan 2019 17:01:09 +0100 Subject: [PATCH 132/178] Add state to reachability order, if there are not yet added states and nothing changed during loopiteration --- src/storm-pars/analysis/LatticeExtender.cpp | 106 ++++++++++++++------ src/storm-pars/analysis/LatticeExtender.h | 2 + 2 files changed, 80 insertions(+), 28 deletions(-) diff --git a/src/storm-pars/analysis/LatticeExtender.cpp b/src/storm-pars/analysis/LatticeExtender.cpp index 4161f8345..639ec0e20 100644 --- a/src/storm-pars/analysis/LatticeExtender.cpp +++ b/src/storm-pars/analysis/LatticeExtender.cpp @@ -32,6 +32,7 @@ namespace storm { template LatticeExtender::LatticeExtender(std::shared_ptr> model) { this->model = model; + assumptionSeen = false; } template @@ -121,6 +122,7 @@ namespace storm { template void LatticeExtender::handleAssumption(Lattice* lattice, std::shared_ptr assumption) { assert (assumption != nullptr); + assumptionSeen = true; storm::expressions::BinaryRelationExpression expr = *assumption; assert (expr.getRelationType() == storm::expressions::BinaryRelationExpression::RelationType::Greater @@ -243,40 +245,82 @@ namespace storm { auto oldNumberSet = numberOfStates; while (oldNumberSet != lattice->getAddedStates().getNumberOfSetBits()) { oldNumberSet = lattice->getAddedStates().getNumberOfSetBits(); - auto states = statesSorted; - - if (acyclic && states.size() > 0) { - auto nextState = *(states.begin()); - while (lattice->getAddedStates()[nextState] && states.size() > 1) { - // states.size()>1 such that there is at least one state left after erase - states.erase(states.begin()); - nextState = *(states.begin()); - } - if (! lattice->getAddedStates()[nextState]) { - auto row = this->model->getTransitionMatrix().getRow(nextState); - auto successors = storm::storage::BitVector(lattice->getAddedStates().size()); - for (auto rowItr = row.begin(); rowItr != row.end(); ++rowItr) { - // ignore self-loops when there are more transitions - if (nextState != rowItr->getColumn()) { - successors.set(rowItr->getColumn()); - } + if (!assumptionSeen && acyclic) { + + if (statesSorted.size() > 0) { + auto nextState = *(statesSorted.begin()); + while (lattice->getAddedStates()[nextState] && statesSorted.size() > 1) { + // states.size()>1 such that there is at least one state left after erase + statesSorted.erase(statesSorted.begin()); + nextState = *(statesSorted.begin()); } - auto seenStates = (lattice->getAddedStates()); - assert ((seenStates & successors) == successors); + if (!lattice->getAddedStates()[nextState]) { + auto row = this->model->getTransitionMatrix().getRow(nextState); + auto successors = storm::storage::BitVector(lattice->getAddedStates().size()); + for (auto rowItr = row.begin(); rowItr != row.end(); ++rowItr) { + // ignore self-loops when there are more transitions + if (nextState != rowItr->getColumn()) { + successors.set(rowItr->getColumn()); + } + } + auto seenStates = (lattice->getAddedStates()); + + assert ((seenStates & successors) == successors); - auto result = extendAllSuccAdded(lattice, nextState, successors); - if (std::get<1>(result) != numberOfStates) { - return result; - } else { - assert (lattice->getNode(nextState) != nullptr); + auto result = extendAllSuccAdded(lattice, nextState, successors); + if (std::get<1>(result) != numberOfStates) { + return result; + } else { + assert (lattice->getNode(nextState) != nullptr); + statesSorted.erase(statesSorted.begin()); + } + } + auto added = lattice->getAddedStates().getNumberOfSetBits(); + assert (lattice->getNode(nextState) != nullptr); + assert (lattice->getAddedStates()[nextState]); + } + } else if (assumptionSeen && acyclic) { + auto states = statesSorted; + + if (states.size() > 0) { + auto nextState = *(states.begin()); + while (lattice->getAddedStates()[nextState] && states.size() > 1) { + // states.size()>1 such that there is at least one state left after erase states.erase(states.begin()); + nextState = *(states.begin()); + } + + if (!lattice->getAddedStates()[nextState]) { + auto row = this->model->getTransitionMatrix().getRow(nextState); + auto successors = storm::storage::BitVector(lattice->getAddedStates().size()); + for (auto rowItr = row.begin(); rowItr != row.end(); ++rowItr) { + // ignore self-loops when there are more transitions + if (nextState != rowItr->getColumn()) { + successors.set(rowItr->getColumn()); + } + } + auto seenStates = (lattice->getAddedStates()); + + assert ((seenStates & successors) == successors); + + auto result = extendAllSuccAdded(lattice, nextState, successors); + if (std::get<1>(result) != numberOfStates) { + return result; + } else { + assert (lattice->getNode(nextState) != nullptr); + states.erase(states.begin()); + } + if (!assumptionSeen) { + statesSorted = states; + + } } + auto added = lattice->getAddedStates().getNumberOfSetBits(); + assert (lattice->getNode(nextState) != nullptr); + assert (lattice->getAddedStates()[nextState]); } - auto added = lattice->getAddedStates().getNumberOfSetBits(); - assert (lattice->getNode(nextState) != nullptr); - assert (lattice->getAddedStates()[nextState]); } else if (!acyclic) { // TODO: kan dit niet efficienter @@ -288,7 +332,6 @@ namespace storm { auto seenStates = (lattice->getAddedStates()); - assert(!acyclic); // Check if current state has not been added yet, and all successors have bool check = !seenStates[stateNumber]; for (auto succIndex = successors.getNextSetIndex(0); @@ -330,7 +373,14 @@ namespace storm { assert(false); } } + } + // if nothing changed, then add a state + if (oldNumberSet == lattice->getAddedStates().getNumberOfSetBits() && oldNumberSet != numberOfStates) { + lattice->add(lattice->getAddedStates().getNextUnsetIndex(0)); + } + + } } assert (lattice->getAddedStates().getNumberOfSetBits() == numberOfStates); diff --git a/src/storm-pars/analysis/LatticeExtender.h b/src/storm-pars/analysis/LatticeExtender.h index c087d6422..af848b094 100644 --- a/src/storm-pars/analysis/LatticeExtender.h +++ b/src/storm-pars/analysis/LatticeExtender.h @@ -58,6 +58,8 @@ namespace storm { bool acyclic; + bool assumptionSeen; + void handleAssumption(Lattice* lattice, std::shared_ptr assumption); std::tuple extendAllSuccAdded(Lattice* lattice, uint_fast64_t stateNumber, storm::storage::BitVector successors); From 48cba66d96f7e2fa3573693888e80c76fbf66a6e Mon Sep 17 00:00:00 2001 From: Jip Spel Date: Thu, 31 Jan 2019 13:10:51 +0100 Subject: [PATCH 133/178] Add scc elimination --- src/storm-pars-cli/storm-pars.cpp | 67 ++++++++++++++++++- src/storm-pars/analysis/LatticeExtender.cpp | 1 + .../analysis/MonotonicityChecker.cpp | 3 +- src/storm-pars/analysis/MonotonicityChecker.h | 4 +- .../settings/modules/ParametricSettings.cpp | 6 ++ .../settings/modules/ParametricSettings.h | 3 + 6 files changed, 79 insertions(+), 5 deletions(-) diff --git a/src/storm-pars-cli/storm-pars.cpp b/src/storm-pars-cli/storm-pars.cpp index 572562302..60fda624b 100644 --- a/src/storm-pars-cli/storm-pars.cpp +++ b/src/storm-pars-cli/storm-pars.cpp @@ -29,7 +29,7 @@ #include "storm/settings/SettingsManager.h" -#include "storm/solver/stateelimination/PrioritizedStateEliminator.h" +#include "storm/solver/stateelimination/NondeterministicModelStateEliminator.h" #include "storm/storage/StronglyConnectedComponentDecomposition.h" #include "storm/storage/SymbolicModelDescription.h" @@ -562,6 +562,67 @@ namespace storm { } } + if (parSettings.isSccEliminationSet()) { + // TODO: check for correct Model type + std::cout << "Applying scc elimination" << std::endl; + auto sparseModel = model->as>(); + auto matrix = sparseModel->getTransitionMatrix(); + auto backwardsTransitionMatrix = matrix.transpose(); + + auto decomposition = storm::storage::StronglyConnectedComponentDecomposition(matrix, false, false); + + storm::storage::BitVector selectedStates(matrix.getRowCount()); + for (auto i = 0; i < decomposition.size(); ++i) { + auto scc = decomposition.getBlock(i); + if (scc.size() > 1) { + auto nrInitial = 0; + auto statesScc = scc.getStates(); + std::vector entryStates; + for (auto state : statesScc) { + auto row = backwardsTransitionMatrix.getRow(state); + bool found = false; + for (auto backState : row) { + if (!scc.containsState(backState.getColumn())) { + found = true; + } + } + if (found) { + entryStates.push_back(state); + } else { + selectedStates.set(state); + } + } + + if (entryStates.size() != 1) { + STORM_LOG_THROW(entryStates.size() > 1, storm::exceptions::NotImplementedException, + "state elimination not implemented for scc with more than 1 entry points"); + } + } + } + + storm::storage::FlexibleSparseMatrix flexibleMatrix(matrix); + storm::storage::FlexibleSparseMatrix flexibleBackwardTransitions(backwardsTransitionMatrix, true); + auto actionRewards = std::vector(matrix.getRowCount(), storm::utility::zero()); + storm::solver::stateelimination::NondeterministicModelStateEliminator stateEliminator(flexibleMatrix, flexibleBackwardTransitions, actionRewards); + for(auto state : selectedStates) { + stateEliminator.eliminateState(state, true); + } + selectedStates.complement(); + auto keptRows = matrix.getRowFilter(selectedStates); + storm::storage::SparseMatrix newTransitionMatrix = flexibleMatrix.createSparseMatrix(keptRows, selectedStates); + // TODO: rewards get lost + // obtain the reward model for the resulting system +// std::unordered_map rewardModels; +// if(rewardModelName) { +// storm::utility::vector::filterVectorInPlace(actionRewards, keptRows); +// rewardModels.insert(std::make_pair(*rewardModelName, RewardModelType(boost::none, std::move(actionRewards)))); +// } + model = std::make_shared>(std::move(newTransitionMatrix), sparseModel->getStateLabeling().getSubLabeling(selectedStates)); + + + std::cout << "SCC Elimination applied" << std::endl; + } + if (parSettings.isMonotonicityAnalysisSet()) { std::cout << "Hello, Jip2" << std::endl; @@ -571,7 +632,7 @@ namespace storm { std::ofstream outfile; outfile.open("results.txt", std::ios_base::app); storm::utility::Stopwatch monotonicityWatch(true); - auto monotonicityChecker = storm::analysis::MonotonicityChecker(model, formulas, parSettings.isValidateAssumptionsSet()); + auto monotonicityChecker = storm::analysis::MonotonicityChecker(model, formulas, parSettings.isValidateAssumptionsSet(), parSettings.isSccEliminationSet()); monotonicityChecker.checkMonotonicity(); monotonicityWatch.stop(); STORM_PRINT(std::endl << "Total time for monotonicity checking: " << monotonicityWatch << "." << std::endl @@ -581,7 +642,7 @@ namespace storm { outfile.close(); std::cout << "Bye, Jip2" << std::endl; - return; +// return; } std::vector> regions = parseRegions(model); diff --git a/src/storm-pars/analysis/LatticeExtender.cpp b/src/storm-pars/analysis/LatticeExtender.cpp index 639ec0e20..97f4ce9c9 100644 --- a/src/storm-pars/analysis/LatticeExtender.cpp +++ b/src/storm-pars/analysis/LatticeExtender.cpp @@ -70,6 +70,7 @@ namespace storm { auto initialMiddleStates = storm::storage::BitVector(numberOfStates); // Check if MC contains cycles + // TODO maybe move to other place auto decomposition = storm::storage::StronglyConnectedComponentDecomposition(model->getTransitionMatrix(), false, false); acyclic = true; for (auto i = 0; acyclic && i < decomposition.size(); ++i) { diff --git a/src/storm-pars/analysis/MonotonicityChecker.cpp b/src/storm-pars/analysis/MonotonicityChecker.cpp index 8f1a4efa0..21ae0057e 100644 --- a/src/storm-pars/analysis/MonotonicityChecker.cpp +++ b/src/storm-pars/analysis/MonotonicityChecker.cpp @@ -30,11 +30,12 @@ namespace storm { namespace analysis { template - MonotonicityChecker::MonotonicityChecker(std::shared_ptr model, std::vector> formulas, bool validate) { + MonotonicityChecker::MonotonicityChecker(std::shared_ptr model, std::vector> formulas, bool validate, bool sccElimination) { outfile.open(filename, std::ios_base::app); this->model = model; this->formulas = formulas; this->validate = validate; + this->sccElimination = sccElimination; this->resultCheckOnSamples = std::map>(); if (model != nullptr) { std::shared_ptr> sparseModel = model->as>(); diff --git a/src/storm-pars/analysis/MonotonicityChecker.h b/src/storm-pars/analysis/MonotonicityChecker.h index b4b6db84c..f40f301bb 100644 --- a/src/storm-pars/analysis/MonotonicityChecker.h +++ b/src/storm-pars/analysis/MonotonicityChecker.h @@ -26,7 +26,7 @@ namespace storm { class MonotonicityChecker { public: - MonotonicityChecker(std::shared_ptr model, std::vector> formulas, bool validate); + MonotonicityChecker(std::shared_ptr model, std::vector> formulas, bool validate, bool sccElimination); /*! * Checks for all lattices in the map if they are monotone increasing or monotone decreasing. * @@ -71,6 +71,8 @@ namespace storm { std::vector> formulas; bool validate; + + bool sccElimination; std::map> resultCheckOnSamples; diff --git a/src/storm-pars/settings/modules/ParametricSettings.cpp b/src/storm-pars/settings/modules/ParametricSettings.cpp index 8c1be78d4..967d83ef8 100644 --- a/src/storm-pars/settings/modules/ParametricSettings.cpp +++ b/src/storm-pars/settings/modules/ParametricSettings.cpp @@ -22,6 +22,7 @@ namespace storm { const std::string ParametricSettings::samplesGraphPreservingOptionName = "samples-graph-preserving"; const std::string ParametricSettings::sampleExactOptionName = "sample-exact"; const std::string ParametricSettings::monotonicityAnalysis = "monotonicity-analysis"; + const std::string ParametricSettings::sccElimination = "elim-scc"; const std::string ParametricSettings::validateAssumptions = "validate-assumptions"; ParametricSettings::ParametricSettings() : ModuleSettings(moduleName) { @@ -35,6 +36,7 @@ namespace storm { this->addOption(storm::settings::OptionBuilder(moduleName, samplesGraphPreservingOptionName, false, "Sets whether it can be assumed that the samples are graph-preserving.").build()); this->addOption(storm::settings::OptionBuilder(moduleName, sampleExactOptionName, false, "Sets whether to sample using exact arithmetic.").build()); this->addOption(storm::settings::OptionBuilder(moduleName, monotonicityAnalysis, false, "Sets whether monotonicity analysis is done").build()); + this->addOption(storm::settings::OptionBuilder(moduleName, sccElimination, false, "Sets whether SCCs should be eliminated").build()); this->addOption(storm::settings::OptionBuilder(moduleName, validateAssumptions, false, "Sets whether assumptions made in monotonicity analysis are validated").build()); } @@ -74,6 +76,10 @@ namespace storm { return this->getOption(monotonicityAnalysis).getHasOptionBeenSet(); } + bool ParametricSettings::isSccEliminationSet() const { + return this->getOption(sccElimination).getHasOptionBeenSet(); + } + bool ParametricSettings::isValidateAssumptionsSet() const { return this->getOption(validateAssumptions).getHasOptionBeenSet(); } diff --git a/src/storm-pars/settings/modules/ParametricSettings.h b/src/storm-pars/settings/modules/ParametricSettings.h index 2fc386471..29cbb81bf 100644 --- a/src/storm-pars/settings/modules/ParametricSettings.h +++ b/src/storm-pars/settings/modules/ParametricSettings.h @@ -65,6 +65,8 @@ namespace storm { bool isSampleExactSet() const; bool isMonotonicityAnalysisSet() const; + // TODO: maybe move to other place + bool isSccEliminationSet() const; bool isValidateAssumptionsSet() const; @@ -80,6 +82,7 @@ namespace storm { const static std::string samplesGraphPreservingOptionName; const static std::string sampleExactOptionName; const static std::string monotonicityAnalysis; + const static std::string sccElimination; const static std::string validateAssumptions; }; From 44cde3314c79d6a0dae0b4b7d653e36fb9cfb8a6 Mon Sep 17 00:00:00 2001 From: Jip Spel Date: Thu, 31 Jan 2019 18:34:02 +0100 Subject: [PATCH 134/178] Fix checking derivative --- src/storm-pars/analysis/MonotonicityChecker.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/storm-pars/analysis/MonotonicityChecker.cpp b/src/storm-pars/analysis/MonotonicityChecker.cpp index 21ae0057e..dec5c4b08 100644 --- a/src/storm-pars/analysis/MonotonicityChecker.cpp +++ b/src/storm-pars/analysis/MonotonicityChecker.cpp @@ -498,7 +498,7 @@ namespace storm { storm::expressions::Expression exprBounds = manager->boolean(true); auto managervars = manager->getVariables(); for (auto var : managervars) { - exprBounds = exprBounds && manager->rational(0) <= var && manager->rational(1) >= var; + exprBounds = exprBounds && manager->rational(0) < var && var < manager->rational(1); } auto converter = storm::expressions::RationalFunctionToExpression(manager); @@ -518,6 +518,10 @@ namespace storm { s.add(exprToCheck2); smtResult = s.check(); monDecr = smtResult == storm::solver::SmtSolver::CheckResult::Sat; + if (monIncr && monDecr) { + monIncr = false; + monDecr = false; + } } assert (!(monIncr && monDecr) || derivative.isZero()); From c33a8df85ffd76a25a28cfe215f1cd0bad5a2528 Mon Sep 17 00:00:00 2001 From: Jip Spel Date: Thu, 31 Jan 2019 18:34:26 +0100 Subject: [PATCH 135/178] Eliminate selfloop introduced by SCC elimination --- src/storm-pars-cli/storm-pars.cpp | 10 ++++- .../stateelimination/EliminatorBase.cpp | 42 ++++++++++++++++++- .../solver/stateelimination/EliminatorBase.h | 4 +- 3 files changed, 52 insertions(+), 4 deletions(-) diff --git a/src/storm-pars-cli/storm-pars.cpp b/src/storm-pars-cli/storm-pars.cpp index 60fda624b..bfc81bf72 100644 --- a/src/storm-pars-cli/storm-pars.cpp +++ b/src/storm-pars-cli/storm-pars.cpp @@ -564,7 +564,7 @@ namespace storm { if (parSettings.isSccEliminationSet()) { // TODO: check for correct Model type - std::cout << "Applying scc elimination" << std::endl; + STORM_PRINT("Applying scc elimination" << std::endl); auto sparseModel = model->as>(); auto matrix = sparseModel->getTransitionMatrix(); auto backwardsTransitionMatrix = matrix.transpose(); @@ -572,6 +572,7 @@ namespace storm { auto decomposition = storm::storage::StronglyConnectedComponentDecomposition(matrix, false, false); storm::storage::BitVector selectedStates(matrix.getRowCount()); + storm::storage::BitVector selfLoopStates(matrix.getRowCount()); for (auto i = 0; i < decomposition.size(); ++i) { auto scc = decomposition.getBlock(i); if (scc.size() > 1) { @@ -588,6 +589,7 @@ namespace storm { } if (found) { entryStates.push_back(state); + selfLoopStates.set(state); } else { selectedStates.set(state); } @@ -607,6 +609,10 @@ namespace storm { for(auto state : selectedStates) { stateEliminator.eliminateState(state, true); } + for (auto state : selfLoopStates) { + auto row = flexibleMatrix.getRow(state); + stateEliminator.eliminateLoop(state); + } selectedStates.complement(); auto keptRows = matrix.getRowFilter(selectedStates); storm::storage::SparseMatrix newTransitionMatrix = flexibleMatrix.createSparseMatrix(keptRows, selectedStates); @@ -620,7 +626,7 @@ namespace storm { model = std::make_shared>(std::move(newTransitionMatrix), sparseModel->getStateLabeling().getSubLabeling(selectedStates)); - std::cout << "SCC Elimination applied" << std::endl; + STORM_PRINT("SCC Elimination applied" << std::endl); } if (parSettings.isMonotonicityAnalysisSet()) { diff --git a/src/storm/solver/stateelimination/EliminatorBase.cpp b/src/storm/solver/stateelimination/EliminatorBase.cpp index 041b610bf..bc523b073 100644 --- a/src/storm/solver/stateelimination/EliminatorBase.cpp +++ b/src/storm/solver/stateelimination/EliminatorBase.cpp @@ -249,7 +249,47 @@ namespace storm { elementsWithEntryInColumnEqualRow.shrink_to_fit(); } } - + + template + void EliminatorBase::eliminateLoop(uint64_t state) { + // Start by finding value of the selfloop. + bool hasEntryInColumn = false; + ValueType columnValue = storm::utility::zero(); + FlexibleRowType& entriesInRow = matrix.getRow(state); + for (auto entryIt = entriesInRow.begin(), entryIte = entriesInRow.end(); entryIt != entryIte; ++entryIt) { + if (entryIt->getColumn() == state) { + columnValue = entryIt->getValue(); + hasEntryInColumn = true; + } + } + + // Scale all entries in this row. + // Depending on the scaling mode, we scale the other entries of the row. + STORM_LOG_TRACE((hasEntryInColumn ? "State has entry in column." : "State does not have entry in column.")); + if (Mode == ScalingMode::Divide) { + STORM_LOG_ASSERT(hasEntryInColumn, "The scaling mode 'divide' requires an element in the given column."); + STORM_LOG_ASSERT(storm::utility::isZero(columnValue), "The scaling mode 'divide' requires a non-zero element in the given column."); + columnValue = storm::utility::one() / columnValue; + } else if (Mode == ScalingMode::DivideOneMinus) { + if (hasEntryInColumn) { + STORM_LOG_ASSERT(columnValue != storm::utility::one(), "The scaling mode 'divide-one-minus' requires a non-one value in the given column."); + columnValue = storm::utility::one() / (storm::utility::one() - columnValue); + columnValue = storm::utility::simplify(columnValue); + } + } + + if (hasEntryInColumn) { + for (auto entryIt = entriesInRow.begin(), entryIte = entriesInRow.end(); entryIt != entryIte; ++entryIt) { + // Scale the entries in a different column, set state transition probability to 0. + if (entryIt->getColumn() != state) { + entryIt->setValue(storm::utility::simplify((ValueType) (entryIt->getValue() * columnValue))); + } else { + entryIt->setValue(storm::utility::zero()); + } + } + } + } + template void EliminatorBase::updateValue(storm::storage::sparse::state_type const&, ValueType const&) { // Intentionally left empty. diff --git a/src/storm/solver/stateelimination/EliminatorBase.h b/src/storm/solver/stateelimination/EliminatorBase.h index 996da58e6..0d66ab18a 100644 --- a/src/storm/solver/stateelimination/EliminatorBase.h +++ b/src/storm/solver/stateelimination/EliminatorBase.h @@ -22,7 +22,9 @@ namespace storm { virtual ~EliminatorBase() = default; void eliminate(uint64_t row, uint64_t column, bool clearRow); - + + void eliminateLoop(uint64_t row); + // Provide virtual methods that can be customized by subclasses to govern side-effect of the elimination. virtual void updateValue(storm::storage::sparse::state_type const& state, ValueType const& loopProbability); virtual void updatePredecessor(storm::storage::sparse::state_type const& predecessor, ValueType const& probability, storm::storage::sparse::state_type const& state); From ab142453507aa71972cd05dc7ebbe41ad022c8f0 Mon Sep 17 00:00:00 2001 From: Jip Spel Date: Thu, 31 Jan 2019 18:55:21 +0100 Subject: [PATCH 136/178] Remove bool for stateElimination --- src/storm-pars-cli/storm-pars.cpp | 2 +- src/storm-pars/analysis/MonotonicityChecker.cpp | 2 +- src/storm-pars/analysis/MonotonicityChecker.h | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/storm-pars-cli/storm-pars.cpp b/src/storm-pars-cli/storm-pars.cpp index bfc81bf72..7a59114e6 100644 --- a/src/storm-pars-cli/storm-pars.cpp +++ b/src/storm-pars-cli/storm-pars.cpp @@ -638,7 +638,7 @@ namespace storm { std::ofstream outfile; outfile.open("results.txt", std::ios_base::app); storm::utility::Stopwatch monotonicityWatch(true); - auto monotonicityChecker = storm::analysis::MonotonicityChecker(model, formulas, parSettings.isValidateAssumptionsSet(), parSettings.isSccEliminationSet()); + auto monotonicityChecker = storm::analysis::MonotonicityChecker(model, formulas, parSettings.isValidateAssumptionsSet()); monotonicityChecker.checkMonotonicity(); monotonicityWatch.stop(); STORM_PRINT(std::endl << "Total time for monotonicity checking: " << monotonicityWatch << "." << std::endl diff --git a/src/storm-pars/analysis/MonotonicityChecker.cpp b/src/storm-pars/analysis/MonotonicityChecker.cpp index dec5c4b08..5018fb9e8 100644 --- a/src/storm-pars/analysis/MonotonicityChecker.cpp +++ b/src/storm-pars/analysis/MonotonicityChecker.cpp @@ -30,7 +30,7 @@ namespace storm { namespace analysis { template - MonotonicityChecker::MonotonicityChecker(std::shared_ptr model, std::vector> formulas, bool validate, bool sccElimination) { + MonotonicityChecker::MonotonicityChecker(std::shared_ptr model, std::vector> formulas, bool validate) { outfile.open(filename, std::ios_base::app); this->model = model; this->formulas = formulas; diff --git a/src/storm-pars/analysis/MonotonicityChecker.h b/src/storm-pars/analysis/MonotonicityChecker.h index f40f301bb..d8f6a94d0 100644 --- a/src/storm-pars/analysis/MonotonicityChecker.h +++ b/src/storm-pars/analysis/MonotonicityChecker.h @@ -26,7 +26,7 @@ namespace storm { class MonotonicityChecker { public: - MonotonicityChecker(std::shared_ptr model, std::vector> formulas, bool validate, bool sccElimination); + MonotonicityChecker(std::shared_ptr model, std::vector> formulas, bool validate); /*! * Checks for all lattices in the map if they are monotone increasing or monotone decreasing. * @@ -71,7 +71,7 @@ namespace storm { std::vector> formulas; bool validate; - + bool sccElimination; std::map> resultCheckOnSamples; From 9e690c95c6523f14a82bd3ceb04fc0e444cb8a36 Mon Sep 17 00:00:00 2001 From: Jip Spel Date: Thu, 31 Jan 2019 19:55:04 +0100 Subject: [PATCH 137/178] Fix cyclic monotonicity check --- src/storm-pars-cli/storm-pars.cpp | 2 +- src/storm-pars/analysis/Lattice.cpp | 4 +- src/storm-pars/analysis/LatticeExtender.cpp | 55 ++++++++++----------- 3 files changed, 28 insertions(+), 33 deletions(-) diff --git a/src/storm-pars-cli/storm-pars.cpp b/src/storm-pars-cli/storm-pars.cpp index 7a59114e6..957f48c7e 100644 --- a/src/storm-pars-cli/storm-pars.cpp +++ b/src/storm-pars-cli/storm-pars.cpp @@ -648,7 +648,7 @@ namespace storm { outfile.close(); std::cout << "Bye, Jip2" << std::endl; -// return; + return; } std::vector> regions = parseRegions(model); diff --git a/src/storm-pars/analysis/Lattice.cpp b/src/storm-pars/analysis/Lattice.cpp index 07bc5b01f..cf5981beb 100644 --- a/src/storm-pars/analysis/Lattice.cpp +++ b/src/storm-pars/analysis/Lattice.cpp @@ -89,8 +89,8 @@ namespace storm { } } - void Lattice::addBetween(uint_fast64_t state, Node *above, Node *below) { - assert(!addedStates[state]); + void Lattice::addBetween(uint_fast64_t state, Node *above, Node *below) { + assert(!addedStates[state]); assert(compare(above, below) == ABOVE); Node *newNode = new Node(); diff --git a/src/storm-pars/analysis/LatticeExtender.cpp b/src/storm-pars/analysis/LatticeExtender.cpp index 97f4ce9c9..f046c3d0a 100644 --- a/src/storm-pars/analysis/LatticeExtender.cpp +++ b/src/storm-pars/analysis/LatticeExtender.cpp @@ -70,7 +70,7 @@ namespace storm { auto initialMiddleStates = storm::storage::BitVector(numberOfStates); // Check if MC contains cycles - // TODO maybe move to other place + // TODO maybe move to other place? auto decomposition = storm::storage::StronglyConnectedComponentDecomposition(model->getTransitionMatrix(), false, false); acyclic = true; for (auto i = 0; acyclic && i < decomposition.size(); ++i) { @@ -325,22 +325,21 @@ namespace storm { } else if (!acyclic) { // TODO: kan dit niet efficienter - auto addedStates = lattice->getAddedStates(); - for (auto stateNumber = addedStates.getNextUnsetIndex(0); stateNumber < addedStates.size(); stateNumber = addedStates.getNextUnsetIndex(stateNumber+1)) { + for (auto stateNumber = 0; stateNumber < numberOfStates; stateNumber++) { + auto addedStates = lattice->getAddedStates(); + // Iterate over all states // auto stateNumber = i; storm::storage::BitVector successors = stateMap[stateNumber]; - auto seenStates = (lattice->getAddedStates()); - // Check if current state has not been added yet, and all successors have - bool check = !seenStates[stateNumber]; + bool check = !addedStates[stateNumber]; for (auto succIndex = successors.getNextSetIndex(0); check && succIndex != successors.size(); succIndex = successors.getNextSetIndex( ++succIndex)) { // if the stateNumber equals succIndex we have a self-loop, ignoring selfloop as seenStates[stateNumber] = false if (succIndex != stateNumber) { - check &= seenStates[succIndex]; + check &= addedStates[succIndex]; } } @@ -349,39 +348,35 @@ namespace storm { if (std::get<1>(result) != successors.size()) { return result; } - } + } else { + // Checking for states which are already added to the lattice, and only have one successor left which haven't been added yet + auto succ1 = successors.getNextSetIndex(0); + auto succ2 = successors.getNextSetIndex(succ1 + 1); - // Checking for states which are already added to the lattice, and only have one successor left which haven't been added yet - auto succ1 = successors.getNextSetIndex(0); - auto succ2 = successors.getNextSetIndex(succ1 + 1); + if (addedStates[stateNumber] && successors.getNumberOfSetBits() == 2 + && ((addedStates[succ1] && !addedStates[succ2]) + ||(!addedStates[succ1] && addedStates[succ2]))) { - if (seenStates[stateNumber] && successors.getNumberOfSetBits() == 2 - && (seenStates[succ1] || seenStates[succ2]) - && (!seenStates[succ1] || !seenStates[succ2])) { - - if (!seenStates[succ1]) { - std::swap(succ1, succ2); - std::swap(succ1, succ2); - } + if (!addedStates[succ1]) { + std::swap(succ1, succ2); + } - auto compare = lattice->compare(stateNumber, succ1); - if (compare == Lattice::ABOVE) { - lattice->addBetween(succ2, lattice->getTop(), lattice->getNode(stateNumber)); - } else if (compare == Lattice::BELOW) { - lattice->addBetween(succ2, lattice->getNode(stateNumber), lattice->getBottom()); - } else { - // TODO: implement? - assert(false); + auto compare = lattice->compare(stateNumber, succ1); + if (compare == Lattice::ABOVE) { + lattice->addBetween(succ2, lattice->getTop(), lattice->getNode(stateNumber)); + } else if (compare == Lattice::BELOW) { + lattice->addBetween(succ2, lattice->getNode(stateNumber), lattice->getBottom()); + } else { + assert(false); + } } } } - // if nothing changed, then add a state + // if nothing changed, then add a state between top and bottom if (oldNumberSet == lattice->getAddedStates().getNumberOfSetBits() && oldNumberSet != numberOfStates) { lattice->add(lattice->getAddedStates().getNextUnsetIndex(0)); } - - } } assert (lattice->getAddedStates().getNumberOfSetBits() == numberOfStates); From f41b61fb7bfee76328c898b4003b727baf37e4b7 Mon Sep 17 00:00:00 2001 From: Jip Spel Date: Sat, 2 Feb 2019 14:31:18 +0100 Subject: [PATCH 138/178] Make cyclic part faster --- src/storm-pars-cli/storm-pars.cpp | 12 +-- src/storm-pars/analysis/LatticeExtender.cpp | 93 +++++++++++-------- src/storm-pars/analysis/LatticeExtender.h | 2 + .../analysis/MonotonicityChecker.cpp | 1 - src/storm-pars/analysis/MonotonicityChecker.h | 2 - 5 files changed, 60 insertions(+), 50 deletions(-) diff --git a/src/storm-pars-cli/storm-pars.cpp b/src/storm-pars-cli/storm-pars.cpp index 957f48c7e..4c33bde22 100644 --- a/src/storm-pars-cli/storm-pars.cpp +++ b/src/storm-pars-cli/storm-pars.cpp @@ -563,6 +563,7 @@ namespace storm { } if (parSettings.isSccEliminationSet()) { + storm::utility::Stopwatch eliminationWatch(true); // TODO: check for correct Model type STORM_PRINT("Applying scc elimination" << std::endl); auto sparseModel = model->as>(); @@ -617,16 +618,11 @@ namespace storm { auto keptRows = matrix.getRowFilter(selectedStates); storm::storage::SparseMatrix newTransitionMatrix = flexibleMatrix.createSparseMatrix(keptRows, selectedStates); // TODO: rewards get lost - // obtain the reward model for the resulting system -// std::unordered_map rewardModels; -// if(rewardModelName) { -// storm::utility::vector::filterVectorInPlace(actionRewards, keptRows); -// rewardModels.insert(std::make_pair(*rewardModelName, RewardModelType(boost::none, std::move(actionRewards)))); -// } model = std::make_shared>(std::move(newTransitionMatrix), sparseModel->getStateLabeling().getSubLabeling(selectedStates)); - - STORM_PRINT("SCC Elimination applied" << std::endl); + eliminationWatch.stop(); + STORM_PRINT(std::endl << "Time for scc elimination: " << eliminationWatch << "." << std::endl << std::endl); + model->printModelInformationToStream(std::cout); } if (parSettings.isMonotonicityAnalysisSet()) { diff --git a/src/storm-pars/analysis/LatticeExtender.cpp b/src/storm-pars/analysis/LatticeExtender.cpp index f046c3d0a..4d3d8df7f 100644 --- a/src/storm-pars/analysis/LatticeExtender.cpp +++ b/src/storm-pars/analysis/LatticeExtender.cpp @@ -112,6 +112,8 @@ namespace storm { } } + statesToHandle = initialMiddleStates; + // Create the Lattice Lattice *lattice = new Lattice(topStates, bottomStates, initialMiddleStates, numberOfStates); @@ -325,57 +327,70 @@ namespace storm { } else if (!acyclic) { // TODO: kan dit niet efficienter - for (auto stateNumber = 0; stateNumber < numberOfStates; stateNumber++) { - auto addedStates = lattice->getAddedStates(); - - // Iterate over all states -// auto stateNumber = i; + auto addedStates = lattice->getAddedStates(); + if (assumptionSeen) { + statesToHandle = addedStates; + } + auto stateNumber = statesToHandle.getNextSetIndex(0); + while (stateNumber != numberOfStates) { + addedStates = lattice->getAddedStates(); storm::storage::BitVector successors = stateMap[stateNumber]; + // Checking for states which are already added to the lattice, and only have one successor left which haven't been added yet + auto succ1 = successors.getNextSetIndex(0); + auto succ2 = successors.getNextSetIndex(succ1 + 1); - // Check if current state has not been added yet, and all successors have - bool check = !addedStates[stateNumber]; - for (auto succIndex = successors.getNextSetIndex(0); - check && succIndex != successors.size(); succIndex = successors.getNextSetIndex( - ++succIndex)) { - // if the stateNumber equals succIndex we have a self-loop, ignoring selfloop as seenStates[stateNumber] = false - if (succIndex != stateNumber) { - check &= addedStates[succIndex]; + assert (addedStates[stateNumber]); + if (successors.getNumberOfSetBits() == 2 + && ((addedStates[succ1] && !addedStates[succ2]) + || (!addedStates[succ1] && addedStates[succ2]))) { + + if (!addedStates[succ1]) { + std::swap(succ1, succ2); } - } - if (check) { - auto result = extendAllSuccAdded(lattice, stateNumber, successors); - if (std::get<1>(result) != successors.size()) { - return result; + auto compare = lattice->compare(stateNumber, succ1); + if (compare == Lattice::ABOVE) { + lattice->addBetween(succ2, lattice->getTop(), lattice->getNode(stateNumber)); + } else if (compare == Lattice::BELOW) { + lattice->addBetween(succ2, lattice->getNode(stateNumber), lattice->getBottom()); + } else { + assert(false); } + statesToHandle.set(succ2); + statesToHandle.set(stateNumber, false); + stateNumber = statesToHandle.getNextSetIndex(0); + } else if (!((addedStates[succ1] && !addedStates[succ2]) + || (!addedStates[succ1] && addedStates[succ2]))) { + stateNumber = statesToHandle.getNextSetIndex(stateNumber + 1); } else { - // Checking for states which are already added to the lattice, and only have one successor left which haven't been added yet - auto succ1 = successors.getNextSetIndex(0); - auto succ2 = successors.getNextSetIndex(succ1 + 1); - - if (addedStates[stateNumber] && successors.getNumberOfSetBits() == 2 - && ((addedStates[succ1] && !addedStates[succ2]) - ||(!addedStates[succ1] && addedStates[succ2]))) { + assert (successors.getNumberOfSetBits() == 2); + statesToHandle.set(stateNumber, false); + stateNumber = statesToHandle.getNextSetIndex(0); + } + } - if (!addedStates[succ1]) { - std::swap(succ1, succ2); - } + addedStates = lattice->getAddedStates(); + for (auto stateNumber = addedStates.getNextUnsetIndex(0); stateNumber < numberOfStates; stateNumber = addedStates.getNextUnsetIndex(stateNumber + 1)) { + // Iterate over all not yet added states + storm::storage::BitVector successors = stateMap[stateNumber]; - auto compare = lattice->compare(stateNumber, succ1); - if (compare == Lattice::ABOVE) { - lattice->addBetween(succ2, lattice->getTop(), lattice->getNode(stateNumber)); - } else if (compare == Lattice::BELOW) { - lattice->addBetween(succ2, lattice->getNode(stateNumber), lattice->getBottom()); - } else { - assert(false); - } + // Check if current state has not been added yet, and all successors have, ignore selfloop in this + successors.set(stateNumber, false); + if ((successors & addedStates) == successors) { + auto result = extendAllSuccAdded(lattice, stateNumber, successors); + if (std::get<1>(result) != successors.size()) { + return result; } + statesToHandle.set(stateNumber); } - } - // if nothing changed, then add a state between top and bottom + + + // if nothing changed and there are states left, then add a state between top and bottom if (oldNumberSet == lattice->getAddedStates().getNumberOfSetBits() && oldNumberSet != numberOfStates) { - lattice->add(lattice->getAddedStates().getNextUnsetIndex(0)); + auto stateNumber = lattice->getAddedStates().getNextUnsetIndex(0); + lattice->add(stateNumber); + statesToHandle.set(stateNumber); } } } diff --git a/src/storm-pars/analysis/LatticeExtender.h b/src/storm-pars/analysis/LatticeExtender.h index af848b094..0d4787f00 100644 --- a/src/storm-pars/analysis/LatticeExtender.h +++ b/src/storm-pars/analysis/LatticeExtender.h @@ -60,6 +60,8 @@ namespace storm { bool assumptionSeen; + storm::storage::BitVector statesToHandle; + void handleAssumption(Lattice* lattice, std::shared_ptr assumption); std::tuple extendAllSuccAdded(Lattice* lattice, uint_fast64_t stateNumber, storm::storage::BitVector successors); diff --git a/src/storm-pars/analysis/MonotonicityChecker.cpp b/src/storm-pars/analysis/MonotonicityChecker.cpp index 5018fb9e8..26b23673e 100644 --- a/src/storm-pars/analysis/MonotonicityChecker.cpp +++ b/src/storm-pars/analysis/MonotonicityChecker.cpp @@ -35,7 +35,6 @@ namespace storm { this->model = model; this->formulas = formulas; this->validate = validate; - this->sccElimination = sccElimination; this->resultCheckOnSamples = std::map>(); if (model != nullptr) { std::shared_ptr> sparseModel = model->as>(); diff --git a/src/storm-pars/analysis/MonotonicityChecker.h b/src/storm-pars/analysis/MonotonicityChecker.h index d8f6a94d0..b4b6db84c 100644 --- a/src/storm-pars/analysis/MonotonicityChecker.h +++ b/src/storm-pars/analysis/MonotonicityChecker.h @@ -72,8 +72,6 @@ namespace storm { bool validate; - bool sccElimination; - std::map> resultCheckOnSamples; storm::analysis::LatticeExtender *extender; From 26429925d6ca48300930db340d6109032066e876 Mon Sep 17 00:00:00 2001 From: Jip Spel Date: Mon, 4 Feb 2019 20:03:32 +0100 Subject: [PATCH 139/178] Speedup --- src/storm-pars/analysis/Lattice.cpp | 475 ++++++++++-------- src/storm-pars/analysis/Lattice.h | 84 ++-- src/storm-pars/analysis/LatticeExtender.cpp | 138 +++-- src/storm-pars/analysis/LatticeExtender.h | 6 +- .../analysis/MonotonicityChecker.cpp | 156 ++++-- src/storm-pars/analysis/MonotonicityChecker.h | 4 + .../analysis/AssumptionCheckerTest.cpp | 4 +- .../analysis/LatticeExtenderTest.cpp | 2 +- src/test/storm-pars/analysis/LatticeTest.cpp | 6 +- .../analysis/MonotonicityCheckerTest.cpp | 4 +- 10 files changed, 517 insertions(+), 362 deletions(-) diff --git a/src/storm-pars/analysis/Lattice.cpp b/src/storm-pars/analysis/Lattice.cpp index cf5981beb..edead7737 100644 --- a/src/storm-pars/analysis/Lattice.cpp +++ b/src/storm-pars/analysis/Lattice.cpp @@ -8,47 +8,49 @@ namespace storm { namespace analysis { - Lattice::Lattice(storm::storage::BitVector topStates, - storm::storage::BitVector bottomStates, - storm::storage::BitVector initialMiddleStates, + Lattice::Lattice(storm::storage::BitVector* topStates, + storm::storage::BitVector* bottomStates, + storm::storage::BitVector* initialMiddleStates, uint_fast64_t numberOfStates) { - assert(topStates.getNumberOfSetBits() != 0); - assert(bottomStates.getNumberOfSetBits() != 0); - assert((topStates & bottomStates).getNumberOfSetBits() == 0); + assert(topStates->getNumberOfSetBits() != 0); + assert(bottomStates->getNumberOfSetBits() != 0); + assert((*topStates & *bottomStates).getNumberOfSetBits() == 0); nodes = std::vector(numberOfStates); top = new Node(); - top->states = topStates; - for (auto i = topStates.getNextSetIndex(0); i < topStates.size(); i = topStates.getNextSetIndex(i+1)) { - nodes.at(i) = top; + top->states = *topStates; + for (auto const& i : *topStates) { + nodes[i] = top; } bottom = new Node(); - bottom->states = bottomStates; - for (auto i = bottomStates.getNextSetIndex(0); i < bottomStates.size(); i = bottomStates.getNextSetIndex(i+1)) { - nodes.at(i) = bottom; + bottom->states = *bottomStates; + for (auto const& i : *bottomStates) { + nodes[i] = bottom; } top->statesAbove = storm::storage::BitVector(numberOfStates); - setStatesBelow(top, bottomStates, false); + bottom->statesAbove = *topStates; +// setStatesBelow(top, bottomStates, false); - bottom->statesBelow = storm::storage::BitVector(numberOfStates); - setStatesAbove(bottom, topStates, false); +// bottom->statesBelow = storm::storage::BitVector(numberOfStates); +// setStatesAbove(bottom, topStates, false); this->numberOfStates = numberOfStates; - this->addedStates = storm::storage::BitVector(numberOfStates); - this->addedStates |= (topStates); - this->addedStates |= (bottomStates); + this->addedStates = new storm::storage::BitVector(numberOfStates); + *addedStates |= *(topStates); + *addedStates |= *(bottomStates); - for (auto state = initialMiddleStates.getNextSetIndex(0); state < numberOfStates; state = initialMiddleStates.getNextSetIndex(state + 1)) { + for (auto const &state : *initialMiddleStates) { add(state); } } Lattice::Lattice(Lattice* lattice) { - numberOfStates = lattice->getAddedStates().size(); +// assert (false); + numberOfStates = lattice->getAddedStates()->size(); nodes = std::vector(numberOfStates); - addedStates = storm::storage::BitVector(numberOfStates); + addedStates = new storm::storage::BitVector(numberOfStates); auto oldNodes = lattice->getNodes(); // Create nodes @@ -59,8 +61,8 @@ namespace storm { newNode->states = storm::storage::BitVector(oldNode->states); for (auto i = newNode->states.getNextSetIndex(0); i < newNode->states.size(); i = newNode->states.getNextSetIndex(i + 1)) { - addedStates.set(i); - nodes.at(i) = newNode; + addedStates->set(i); + nodes[i] = newNode; } if (oldNode == lattice->getTop()) { top = newNode; @@ -77,77 +79,83 @@ namespace storm { Node *oldNode = (*itr); if (oldNode != nullptr && oldNode != lattice->getTop() && oldNode != lattice->getBottom()) { Node *newNode = getNode(oldNode->states.getNextSetIndex(0)); - setStatesAbove(newNode, oldNode->statesAbove, false); - setStatesBelow(newNode, oldNode->statesBelow, false); + newNode->statesAbove = storm::storage::BitVector(oldNode->statesAbove); +// setStatesAbove(newNode, oldNode->statesAbove, false); +// setStatesBelow(newNode, oldNode->statesBelow, false); } else if (oldNode != nullptr && oldNode == lattice->getBottom()) { - setStatesAbove(bottom, lattice->getBottom()->statesAbove, false); - bottom->statesBelow = storm::storage::BitVector(numberOfStates); - } else if (oldNode != nullptr && oldNode == lattice->getTop()) { - top->statesAbove = storm::storage::BitVector(numberOfStates); - setStatesBelow(top, lattice->getTop()->statesBelow, false); + bottom->statesAbove = storm::storage::BitVector(oldNode->statesAbove); +// setStatesAbove(bottom, lattice->getBottom()->statesAbove, false); +// bottom->statesBelow = storm::storage::BitVector(numberOfStates); +// } else if (oldNode != nullptr && oldNode == lattice->getTop()) { +// top->statesAbove = storm::storage::BitVector(numberOfStates); +// setStatesBelow(top, lattice->getTop()->statesBelow, false); } } } - void Lattice::addBetween(uint_fast64_t state, Node *above, Node *below) { - assert(!addedStates[state]); + void Lattice::addBetween(uint_fast64_t state, Node *above, Node *below) { + assert(!(*addedStates)[state]); assert(compare(above, below) == ABOVE); Node *newNode = new Node(); - nodes.at(state) = newNode; + nodes[state] = newNode; newNode->states = storm::storage::BitVector(numberOfStates); newNode->states.set(state); - setStatesAbove(newNode, above->statesAbove | above->states, false); - setStatesBelow(newNode, below->statesBelow | below->states, false); - setStatesBelow(above, state, true); - setStatesAbove(below, state, true); - - for (auto i = below->statesBelow.getNextSetIndex(0); i < below->statesBelow.size(); i = below->statesBelow.getNextSetIndex(i + 1)) { - setStatesAbove(getNode(i), state, true); - } - - for (auto i = above->statesAbove.getNextSetIndex(0); i < above->statesAbove.size(); i = above->statesAbove.getNextSetIndex(i + 1)) { - setStatesBelow(getNode(i), state, true); - } + newNode->statesAbove = above->states | above->statesAbove; + below->statesAbove |= newNode->states; +// setStatesAbove(newNode, above->statesAbove | above->states, false); +// setStatesBelow(newNode, below->statesBelow | below->states, false); +// setStatesBelow(above, state, true); +// setStatesAbove(below, state, true); + +// for (auto i = below->statesBelow.getNextSetIndex(0); i < below->statesBelow.size(); i = below->statesBelow.getNextSetIndex(i + 1)) { +// setStatesAbove(getNode(i), state, true); +// } +// +// for (auto i = above->statesAbove.getNextSetIndex(0); i < above->statesAbove.size(); i = above->statesAbove.getNextSetIndex(i + 1)) { +// setStatesBelow(getNode(i), state, true); +// } - addedStates.set(state); + addedStates->set(state); } void Lattice::addToNode(uint_fast64_t state, Node *node) { - assert(!addedStates[state]); + assert(!(*addedStates)[state]); node->states.set(state); - nodes.at(state) = node; - addedStates.set(state); - - for (auto i = node->statesBelow.getNextSetIndex(0); i < node->statesBelow.size(); i = node->statesBelow.getNextSetIndex(i + 1)) { - setStatesAbove(getNode(i), state, true); - } + nodes[state] = node; + addedStates->set(state); - for (auto i = node->statesAbove.getNextSetIndex(0); i < node->statesAbove.size(); i = node->statesAbove.getNextSetIndex(i + 1)) { - setStatesBelow(getNode(i), state, true); - } +// for (auto i = node->statesBelow.getNextSetIndex(0); i < node->statesBelow.size(); i = node->statesBelow.getNextSetIndex(i + 1)) { +// setStatesAbove(getNode(i), state, true); +// } +// +// for (auto i = node->statesAbove.getNextSetIndex(0); i < node->statesAbove.size(); i = node->statesAbove.getNextSetIndex(i + 1)) { +// setStatesBelow(getNode(i), state, true); +// } } void Lattice::add(uint_fast64_t state) { - assert(!addedStates[state]); + assert(!(*addedStates)[state]); addBetween(state, top, bottom); } void Lattice::addRelationNodes(Lattice::Node *above, Lattice::Node * below) { assert (compare(above, below) == UNKNOWN); - assert ((above->statesAbove & below->statesBelow).getNumberOfSetBits() == 0); - setStatesBelow(above, below->states | below->statesBelow, true); - setStatesAbove(below, above->states | above->statesAbove, true); - - for (auto i = below->statesBelow.getNextSetIndex(0); i < below->statesBelow.size(); i = below->statesBelow.getNextSetIndex(i + 1)) { - setStatesAbove(getNode(i), above->states | above->statesAbove, true); - } - - for (auto i = above->statesAbove.getNextSetIndex(0); i < above->statesAbove.size(); i = above->statesAbove.getNextSetIndex(i + 1)) { - setStatesBelow(getNode(i), below->states | below->statesBelow, true); - } + // TODO: welke assert +// assert ((above->statesAbove & below->statesBelow).getNumberOfSetBits() == 0); +// setStatesBelow(above, below->states | below->statesBelow, true); +// setStatesAbove(below, above->states | above->statesAbove, true); + below->statesAbove |= above->states | above->statesAbove; + +// for (auto i = below->statesBelow.getNextSetIndex(0); i < below->statesBelow.size(); i = below->statesBelow.getNextSetIndex(i + 1)) { +// setStatesAbove(getNode(i), above->states | above->statesAbove, true); +// } +// +// for (auto i = above->statesAbove.getNextSetIndex(0); i < above->statesAbove.size(); i = above->statesAbove.getNextSetIndex(i + 1)) { +// setStatesBelow(getNode(i), below->states | below->statesBelow, true); +// } } @@ -189,35 +197,66 @@ namespace storm { return nodes; } - storm::storage::BitVector Lattice::getAddedStates() { + storm::storage::BitVector* Lattice::getAddedStates() { return addedStates; } - std::set Lattice::getAbove(uint_fast64_t state) { - return getAbove(getNode(state)); - } - - std::set Lattice::getBelow(uint_fast64_t state) { - return getBelow(getNode(state)); - } - - std::set Lattice::getAbove(Lattice::Node* node) { - std::set result({}); - for (auto i = node->statesAbove.getNextSetIndex(0); i < node->statesAbove.size(); i = node->statesAbove.getNextSetIndex(i + 1)) { - result.insert(getNode(i)); + std::vector Lattice::sortStates(storm::storage::BitVector* states) { + auto result = std::vector(states->getNumberOfSetBits(), -1); + for (auto state : *states) { + if (result[0] == -1) { + result[0] = state; + } else { + for (auto i = 0; i < states->getNumberOfSetBits() && result[i] != -1; i++) { + auto compareRes = compare(state, result[i]); + if (compareRes == Lattice::ABOVE) { + for (auto j = i; j < states->getNumberOfSetBits() -1 && result[j+1] != -1; j++) { + auto temp = result[j]; + result[j] = state; + result[j+1] = temp; + } + } else if (compareRes == Lattice::UNKNOWN) { + break; + } else if (compareRes == Lattice::SAME) { + for (auto j = i+1; j < states->getNumberOfSetBits() -1 && result[j+1] != -1; j++) { + auto temp = result[j]; + result[j] = state; + result[j+1] = temp; + } + } + } + } } - return result; - } - std::set Lattice::getBelow(Lattice::Node* node) { - std::set result({}); - for (auto i = node->statesBelow.getNextSetIndex(0); i < node->statesBelow.size(); i = node->statesBelow.getNextSetIndex(i + 1)) { - result.insert(getNode(i)); - } return result; } +// std::set Lattice::getAbove(uint_fast64_t state) { +// return getAbove(getNode(state)); +// } +// +// std::set Lattice::getBelow(uint_fast64_t state) { +// return getBelow(getNode(state)); +// } +// +// std::set Lattice::getAbove(Lattice::Node* node) { +// std::set result({}); +// for (auto i = node->statesAbove.getNextSetIndex(0); i < node->statesAbove.size(); i = node->statesAbove.getNextSetIndex(i + 1)) { +// result.insert(getNode(i)); +// } +// return result; +// } +// +// std::set Lattice::getBelow(Lattice::Node* node) { +// std::set result({}); +// for (auto i = node->statesBelow.getNextSetIndex(0); i < node->statesBelow.size(); i = node->statesBelow.getNextSetIndex(i + 1)) { +// result.insert(getNode(i)); +// } +// return result; +// } + void Lattice::toString(std::ostream &out) { + assert (false); std::vector printedNodes = std::vector({}); for (auto itr = nodes.begin(); itr != nodes.end(); ++itr) { @@ -237,15 +276,15 @@ namespace storm { out << " Address: " << node << "\n"; out << " Above: {"; - auto statesAbove = getAbove(node); - for (auto itr2 = statesAbove.begin(); itr2 != statesAbove.end(); ++itr2) { - Node *above = *itr2; - index = above->states.getNextSetIndex(0); + auto statesAbove = node->statesAbove; + for (auto above : statesAbove) { + Node* nodeAbove = getNode(above); + index = nodeAbove->states.getNextSetIndex(0); out << "{"; - while (index < above->states.size()) { + while (index < nodeAbove->states.size()) { out << index; - index = above->states.getNextSetIndex(index + 1); - if (index < above->states.size()) { + index = nodeAbove->states.getNextSetIndex(index + 1); + if (index < nodeAbove->states.size()) { out << ", "; } } @@ -255,140 +294,176 @@ namespace storm { out << "}" << "\n"; - out << " Below: {"; - auto statesBelow = getBelow(node); - for (auto itr2 = statesBelow.begin(); itr2 != statesBelow.end(); ++itr2) { - Node *below = *itr2; - out << "{"; - index = below->states.getNextSetIndex(0); - while (index < below->states.size()) { - out << index; - index = below->states.getNextSetIndex(index + 1); - if (index < below->states.size()) { - out << ", "; - } - } - - out << "}"; - } +// out << " Below: {"; +// auto statesBelow = getBelow(node); +// for (auto itr2 = statesBelow.begin(); itr2 != statesBelow.end(); ++itr2) { +// Node *below = *itr2; +// out << "{"; +// index = below->states.getNextSetIndex(0); +// while (index < below->states.size()) { +// out << index; +// index = below->states.getNextSetIndex(index + 1); +// if (index < below->states.size()) { +// out << ", "; +// } +// } +// +// out << "}"; +// } out << "}" << "\n"; } } } void Lattice::toDotFile(std::ostream &out) { - out << "digraph \"Lattice\" {" << std::endl; - - // print all nodes - std::vector printed; - out << "\t" << "node [shape=ellipse]" << std::endl; - for (auto itr = nodes.begin(); itr != nodes.end(); ++itr) { + assert (false); +// out << "digraph \"Lattice\" {" << std::endl; +// +// // print all nodes +// std::vector printed; +// out << "\t" << "node [shape=ellipse]" << std::endl; +// for (auto itr = nodes.begin(); itr != nodes.end(); ++itr) { +// +// if ((*itr) != nullptr && find(printed.begin(), printed.end(), (*itr)) == printed.end()) { +// out << "\t\"" << (*itr) << "\" [label = \""; +// uint_fast64_t index = (*itr)->states.getNextSetIndex(0); +// while (index < (*itr)->states.size()) { +// out << index; +// index = (*itr)->states.getNextSetIndex(index + 1); +// if (index < (*itr)->states.size()) { +// out << ", "; +// } +// } +// +// out << "\"]" << std::endl; +// printed.push_back(*itr); +// } +// } +// +// // print arcs +// printed.clear(); +// for (auto itr = nodes.begin(); itr != nodes.end(); ++itr) { +// if ((*itr) != nullptr && find(printed.begin(), printed.end(), (*itr)) == printed.end()) { +// auto below = getBelow(*itr); +// for (auto itr2 = below.begin(); itr2 != below.end(); ++itr2) { +// out << "\t\"" << (*itr) << "\" -> \"" << (*itr2) << "\";" << std::endl; +// } +// printed.push_back(*itr); +// } +// } +// +// out << "}" << std::endl; + } - if ((*itr) != nullptr && find(printed.begin(), printed.end(), (*itr)) == printed.end()) { - out << "\t\"" << (*itr) << "\" [label = \""; - uint_fast64_t index = (*itr)->states.getNextSetIndex(0); - while (index < (*itr)->states.size()) { - out << index; - index = (*itr)->states.getNextSetIndex(index + 1); - if (index < (*itr)->states.size()) { - out << ", "; - } - } - out << "\"]" << std::endl; - printed.push_back(*itr); + bool Lattice::above(Node *node1, Node *node2) { + // ligt node 1 boven node 2 ? + // oftewel is er een state in node2.above die met een state in node1 matched + bool found = (node2->statesAbove & node1->states).getNumberOfSetBits() != 0; + storm::storage::BitVector statesSeen(node2->statesAbove); + for (auto const& i: node2->statesAbove) { + auto nodeI = getNode(i); + if ((nodeI->statesAbove & statesSeen) != nodeI->statesAbove) { + found = above(node1, nodeI, node2, &statesSeen); } - } - - // print arcs - printed.clear(); - for (auto itr = nodes.begin(); itr != nodes.end(); ++itr) { - if ((*itr) != nullptr && find(printed.begin(), printed.end(), (*itr)) == printed.end()) { - auto below = getBelow(*itr); - for (auto itr2 = below.begin(); itr2 != below.end(); ++itr2) { - out << "\t\"" << (*itr) << "\" -> \"" << (*itr2) << "\";" << std::endl; - } - printed.push_back(*itr); + if (found) { + break; } } - - out << "}" << std::endl; - } - - bool Lattice::above(Node *node1, Node *node2) { - return node1->statesBelow[node2->states.getNextSetIndex(0)]; - } - - void Lattice::setStatesAbove(Lattice::Node *node, uint_fast64_t state, bool alreadyInitialized) { - assert (!node->states[state]); - - if (!alreadyInitialized) { - node->statesAbove = storm::storage::BitVector(numberOfStates); - } - - assert (!node->statesBelow[state]); - node->statesAbove.set(state); - } - - void Lattice::setStatesBelow(Lattice::Node *node, uint_fast64_t state, bool alreadyInitialized) { - assert (!node->states.get(state)); - - if (!alreadyInitialized) { - node->statesBelow = storm::storage::BitVector(numberOfStates); - } - assert (!node->statesAbove[state]); - node->statesBelow.set(state); + return found; } - void Lattice::setStatesAbove(Lattice::Node *node, storm::storage::BitVector states, bool alreadyInitialized) { - assert((states.getNumberOfSetBits() - (node->states & states).getNumberOfSetBits()) != 0); - // the states to add to the above state of the current node shouldnt occur in either statesbelow or states of ndoe - - assert ((node->states & states).getNumberOfSetBits() ==0); - if (alreadyInitialized) { - assert ((node->statesBelow & states).getNumberOfSetBits() == 0); - - node->statesAbove |= (states); - } else { - node->statesAbove = (storm::storage::BitVector(states)); - } - } - - void Lattice::setStatesBelow(Lattice::Node *node, storm::storage::BitVector states, bool alreadyInitialized) { - assert((states.getNumberOfSetBits() - (node->states & states).getNumberOfSetBits()) != 0); - - assert ((node->states & states).getNumberOfSetBits() ==0); - if (alreadyInitialized) { - assert ((node->statesAbove & states).getNumberOfSetBits() == 0); - node->statesBelow |= (states); - } else { - node->statesBelow = (storm::storage::BitVector(states)); + bool Lattice::above(storm::analysis::Lattice::Node *node1, storm::analysis::Lattice::Node *node2, + storm::analysis::Lattice::Node *nodePrev, storm::storage::BitVector *statesSeen) { + bool found = (node2->statesAbove & node1->states).getNumberOfSetBits() != 0; + // TODO: kan dit niet anders? + statesSeen->operator|=(node2->statesAbove); + nodePrev->statesAbove |= node2->statesAbove; + + storm::storage::BitVector states = storm::storage::BitVector((node2->statesAbove & (statesSeen->operator~()))); + for (auto const& i: states) { +// assert (!statesSeen[i]); + auto nodeI = getNode(i); + if ((nodeI->statesAbove & *statesSeen) != nodeI->statesAbove) { + found = above(node1, nodeI, node2, statesSeen); + } + if (found) { + break; + } } + return found; } +// +// void Lattice::setStatesAbove(Lattice::Node *node, uint_fast64_t state, bool alreadyInitialized) { +// assert (!node->states[state]); +// +// if (!alreadyInitialized) { +// node->statesAbove = storm::storage::BitVector(numberOfStates); +// } +// +// assert (!node->statesBelow[state]); +// node->statesAbove.set(state); +// } +// +// void Lattice::setStatesBelow(Lattice::Node *node, uint_fast64_t state, bool alreadyInitialized) { +// assert (!node->states.get(state)); +// +// if (!alreadyInitialized) { +// node->statesBelow = storm::storage::BitVector(numberOfStates); +// } +// assert (!node->statesAbove[state]); +// node->statesBelow.set(state); +// } +// +// void Lattice::setStatesAbove(Lattice::Node *node, storm::storage::BitVector states, bool alreadyInitialized) { +// assert((states.getNumberOfSetBits() - (node->states & states).getNumberOfSetBits()) != 0); +// // the states to add to the above state of the current node shouldnt occur in either statesbelow or states of ndoe +// +// assert ((node->states & states).getNumberOfSetBits() ==0); +// if (alreadyInitialized) { +// assert ((node->statesBelow & states).getNumberOfSetBits() == 0); +// +// node->statesAbove |= (states); +// } else { +// node->statesAbove = (storm::storage::BitVector(states)); +// } +// } +// +// void Lattice::setStatesBelow(Lattice::Node *node, storm::storage::BitVector states, bool alreadyInitialized) { +// assert((states.getNumberOfSetBits() - (node->states & states).getNumberOfSetBits()) != 0); +// +// assert ((node->states & states).getNumberOfSetBits() ==0); +// if (alreadyInitialized) { +// assert ((node->statesAbove & states).getNumberOfSetBits() == 0); +// node->statesBelow |= (states); +// } else { +// node->statesBelow = (storm::storage::BitVector(states)); +// } +// } void Lattice::mergeNodes(storm::analysis::Lattice::Node *node1, storm::analysis::Lattice::Node *node2) { +// assert (false); // Merges node2 into node 1 // everything above n2 also above n1 node1->statesAbove |= node2->statesAbove; // everything below node 2 also below node 1 - node1->statesBelow |= node2->statesBelow; +// node1->statesBelow |= node2->statesBelow; // add states of node 2 to node 1 node1->states|= node2->states; for(auto i = node2->states.getNextSetIndex(0); i < node2->states.size(); i = node2->states.getNextSetIndex(i+1)) { - nodes.at(i) = node1; + nodes[i] = node1; } - // TODO hier gaat het op magische wijze nog fout - // Add all states of combined node to states Above of all states Below of node1 - for (auto i = node1->statesBelow.getNextSetIndex(0); i < node1->statesBelow.size(); i= node1->statesBelow.getNextSetIndex(i+1)) { - getNode(i)->statesAbove |= node1->states | node1->statesAbove; - } +// // Add all states of combined node to states Above of all states Below of node1 +// for (auto i = node1->statesBelow.getNextSetIndex(0); i < node1->statesBelow.size(); i= node1->statesBelow.getNextSetIndex(i+1)) { +// getNode(i)->statesAbove |= node1->states | node1->statesAbove; +// } // Add all states of combined node to states Below of all states Above of node1 - for (auto i = node1->statesAbove.getNextSetIndex(0); i < node1->statesAbove.size(); i= node1->statesAbove.getNextSetIndex(i+1)) { - getNode(i)->statesBelow |= node1->states | node1->statesBelow; - } +// for (auto i = node1->statesAbove.getNextSetIndex(0); i < node1->statesAbove.size(); i= node1->statesAbove.getNextSetIndex(i+1)) { +// getNode(i)->statesBelow |= node1->states | node1->statesBelow; +// } } } diff --git a/src/storm-pars/analysis/Lattice.h b/src/storm-pars/analysis/Lattice.h index 057ff9f30..d47d76bf9 100644 --- a/src/storm-pars/analysis/Lattice.h +++ b/src/storm-pars/analysis/Lattice.h @@ -19,7 +19,7 @@ namespace storm { struct Node { storm::storage::BitVector states; storm::storage::BitVector statesAbove; - storm::storage::BitVector statesBelow; +// storm::storage::BitVector statesBelow; }; /*! @@ -28,9 +28,9 @@ namespace storm { * @param topNode The top node of the resulting lattice. * @param bottomNode The bottom node of the resulting lattice. */ - Lattice(storm::storage::BitVector topStates, - storm::storage::BitVector bottomStates, - storm::storage::BitVector initialMiddleStates, + Lattice(storm::storage::BitVector* topStates, + storm::storage::BitVector* bottomStates, + storm::storage::BitVector* initialMiddleStates, uint_fast64_t numberOfStates); /*! @@ -117,39 +117,41 @@ namespace storm { * * @return The BitVector with all added states. */ - storm::storage::BitVector getAddedStates(); + storm::storage::BitVector* getAddedStates(); - /*! - * Returns a set with the nodes which are above the state. - * - * @param state The state number. - * @return The set with all nodes which are above the state. - */ - std::set getAbove(uint_fast64_t state); - - /*! - * Returns a set with the nodes which are below the state. - * - * @param state The state number. - * @return The set with all nodes which are below the state. - */ - std::set getBelow(uint_fast64_t state); - - /*! - * Returns a set with the nodes which are above the node. - * - * @param node The node. - * @return The set with all nodes which are above the node. - */ - std::set getAbove(Lattice::Node* node); + std::vector sortStates(storm::storage::BitVector* states); - /*! - * Returns a set with the nodes which are below the node. - * - * @param node The node. - * @return The set with all nodes which are below the node. - */ - std::set getBelow(Lattice::Node* node); +// /*! +// * Returns a set with the nodes which are above the state. +// * +// * @param state The state number. +// * @return The set with all nodes which are above the state. +// */ +// std::set getAbove(uint_fast64_t state); +// +// /*! +// * Returns a set with the nodes which are below the state. +// * +// * @param state The state number. +// * @return The set with all nodes which are below the state. +// */ +// std::set getBelow(uint_fast64_t state); +// +// /*! +// * Returns a set with the nodes which are above the node. +// * +// * @param node The node. +// * @return The set with all nodes which are above the node. +// */ +// std::set getAbove(Lattice::Node* node); +// +// /*! +// * Returns a set with the nodes which are below the node. +// * +// * @param node The node. +// * @return The set with all nodes which are below the node. +// */ +// std::set getBelow(Lattice::Node* node); /*! * Prints a string representation of the lattice to the output stream. @@ -185,7 +187,7 @@ namespace storm { private: std::vector nodes; - storm::storage::BitVector addedStates; + storm::storage::BitVector* addedStates; Node* top; @@ -195,15 +197,17 @@ namespace storm { bool above(Node * node1, Node * node2); + bool above(Node * node1, Node * node2, storm::analysis::Lattice::Node *nodePrev, storm::storage::BitVector *statesSeen); + int compare(Node* node1, Node* node2); - void setStatesAbove(Node* node, uint_fast64_t state, bool alreadyInitialized); +// void setStatesAbove(Node* node, uint_fast64_t state, bool alreadyInitialized); - void setStatesBelow(Node* node, uint_fast64_t state, bool alreadyInitialized); +// void setStatesBelow(Node* node, uint_fast64_t state, bool alreadyInitialized); - void setStatesAbove(storm::analysis::Lattice::Node *node, storm::storage::BitVector states, bool alreadyInitialized); +// void setStatesAbove(storm::analysis::Lattice::Node *node, storm::storage::BitVector states, bool alreadyInitialized); - void setStatesBelow(storm::analysis::Lattice::Node *node, storm::storage::BitVector states, bool alreadyInitialized); +// void setStatesBelow(storm::analysis::Lattice::Node *node, storm::storage::BitVector states, bool alreadyInitialized); }; } } diff --git a/src/storm-pars/analysis/LatticeExtender.cpp b/src/storm-pars/analysis/LatticeExtender.cpp index 4d3d8df7f..045fa6c9c 100644 --- a/src/storm-pars/analysis/LatticeExtender.cpp +++ b/src/storm-pars/analysis/LatticeExtender.cpp @@ -80,13 +80,13 @@ namespace storm { statesSorted = storm::utility::graph::getTopologicalSort(matrix); } else { for (uint_fast64_t i = 0; i < numberOfStates; ++i) { - stateMap[i] = storm::storage::BitVector(numberOfStates, false); + stateMap[i] = new storm::storage::BitVector(numberOfStates, false); auto row = matrix.getRow(i); for (auto rowItr = row.begin(); rowItr != row.end(); ++rowItr) { // ignore self-loops when there are more transitions if (i != rowItr->getColumn() || row.getNumberOfEntries() == 1) { - stateMap[i].set(rowItr->getColumn(), true); + stateMap[i]->set(rowItr->getColumn(), true); } } } @@ -95,16 +95,15 @@ namespace storm { if (scc.size() > 1) { auto states = scc.getStates(); // check if the state has already one successor in bottom of top, in that case pick it - bool found = false; - for (auto stateItr = states.begin(); !found && stateItr < states.end(); ++stateItr) { - auto successors = stateMap[*stateItr]; - if (successors.getNumberOfSetBits() == 2) { - auto succ1 = successors.getNextSetIndex(0); - auto succ2 = successors.getNextSetIndex(succ1 + 1); + for (auto const& state : states) { + auto successors = stateMap[state]; + if (successors->getNumberOfSetBits() == 2) { + auto succ1 = successors->getNextSetIndex(0); + auto succ2 = successors->getNextSetIndex(succ1 + 1); auto intersection = bottomStates | topStates; if (intersection[succ1] || intersection[succ2]) { - initialMiddleStates.set(*stateItr); - found = true; + initialMiddleStates.set(state); + break; } } } @@ -112,10 +111,10 @@ namespace storm { } } - statesToHandle = initialMiddleStates; + statesToHandle = &initialMiddleStates; // Create the Lattice - Lattice *lattice = new Lattice(topStates, bottomStates, initialMiddleStates, numberOfStates); + Lattice *lattice = new Lattice(&topStates, &bottomStates, &initialMiddleStates, numberOfStates); // latticeWatch.stop(); // STORM_PRINT(std::endl << "Time for initialization of lattice: " << latticeWatch << "." << std::endl << std::endl); @@ -179,17 +178,17 @@ namespace storm { } template - std::tuple LatticeExtender::extendAllSuccAdded(Lattice* lattice, uint_fast64_t stateNumber, storm::storage::BitVector successors) { - auto numberOfStates = successors.size(); - assert (lattice->getAddedStates().size() == numberOfStates); + std::tuple LatticeExtender::extendAllSuccAdded(Lattice* lattice, uint_fast64_t const & stateNumber, storm::storage::BitVector* successors) { + auto numberOfStates = successors->size(); + assert (lattice->getAddedStates()->size() == numberOfStates); - if (successors.getNumberOfSetBits() == 1) { + if (successors->getNumberOfSetBits() == 1) { // As there is only one successor the current state and its successor must be at the same nodes. - lattice->addToNode(stateNumber, lattice->getNode(successors.getNextSetIndex(0))); - } else if (successors.getNumberOfSetBits() == 2) { + lattice->addToNode(stateNumber, lattice->getNode(successors->getNextSetIndex(0))); + } else if (successors->getNumberOfSetBits() == 2) { // Otherwise, check how the two states compare, and add if the comparison is possible. - uint_fast64_t successor1 = successors.getNextSetIndex(0); - uint_fast64_t successor2 = successors.getNextSetIndex(successor1 + 1); + uint_fast64_t successor1 = successors->getNextSetIndex(0); + uint_fast64_t successor2 = successors->getNextSetIndex(successor1 + 1); int compareResult = lattice->compare(successor1, successor2); if (compareResult == Lattice::ABOVE) { @@ -207,18 +206,18 @@ namespace storm { assert(lattice->compare(successor1, successor2) == Lattice::UNKNOWN); return std::make_tuple(lattice, successor1, successor2); } - } else if (successors.getNumberOfSetBits() > 2) { - for (auto i = successors.getNextSetIndex(0); i < numberOfStates; i = successors.getNextSetIndex(i+1)) { - for (auto j = successors.getNextSetIndex(i+1); j < numberOfStates; j = successors.getNextSetIndex(j+1)) { + } else if (successors->getNumberOfSetBits() > 2) { + for (auto const& i : *successors) { + for (auto j = successors->getNextSetIndex(i+1); j < numberOfStates; j = successors->getNextSetIndex(j+1)) { if (lattice->compare(i,j) == Lattice::UNKNOWN) { return std::make_tuple(lattice, i, j); } } } - auto highest = successors.getNextSetIndex(0); + auto highest = successors->getNextSetIndex(0); auto lowest = highest; - for (auto i = successors.getNextSetIndex(highest+1); i < numberOfStates; i = successors.getNextSetIndex(i+1)) { + for (auto i = successors->getNextSetIndex(highest+1); i < numberOfStates; i = successors->getNextSetIndex(i+1)) { if (lattice->compare(i, highest) == Lattice::ABOVE) { highest = i; } @@ -246,31 +245,30 @@ namespace storm { } auto oldNumberSet = numberOfStates; - while (oldNumberSet != lattice->getAddedStates().getNumberOfSetBits()) { - oldNumberSet = lattice->getAddedStates().getNumberOfSetBits(); + while (oldNumberSet != lattice->getAddedStates()->getNumberOfSetBits()) { + oldNumberSet = lattice->getAddedStates()->getNumberOfSetBits(); if (!assumptionSeen && acyclic) { if (statesSorted.size() > 0) { auto nextState = *(statesSorted.begin()); - while (lattice->getAddedStates()[nextState] && statesSorted.size() > 1) { + while ((*(lattice->getAddedStates()))[nextState] && statesSorted.size() > 1) { // states.size()>1 such that there is at least one state left after erase statesSorted.erase(statesSorted.begin()); nextState = *(statesSorted.begin()); } - if (!lattice->getAddedStates()[nextState]) { + if (!(*(lattice->getAddedStates()))[nextState]) { auto row = this->model->getTransitionMatrix().getRow(nextState); - auto successors = storm::storage::BitVector(lattice->getAddedStates().size()); + auto successors = new storm::storage::BitVector(lattice->getAddedStates()->size()); for (auto rowItr = row.begin(); rowItr != row.end(); ++rowItr) { // ignore self-loops when there are more transitions if (nextState != rowItr->getColumn()) { - successors.set(rowItr->getColumn()); + successors->set(rowItr->getColumn()); } } - auto seenStates = (lattice->getAddedStates()); - assert ((seenStates & successors) == successors); + assert ((*(lattice->getAddedStates()) & *successors) == *successors); auto result = extendAllSuccAdded(lattice, nextState, successors); if (std::get<1>(result) != numberOfStates) { @@ -280,33 +278,32 @@ namespace storm { statesSorted.erase(statesSorted.begin()); } } - auto added = lattice->getAddedStates().getNumberOfSetBits(); + auto added = lattice->getAddedStates()->getNumberOfSetBits(); assert (lattice->getNode(nextState) != nullptr); - assert (lattice->getAddedStates()[nextState]); + assert ((*lattice->getAddedStates())[nextState]); } } else if (assumptionSeen && acyclic) { auto states = statesSorted; if (states.size() > 0) { auto nextState = *(states.begin()); - while (lattice->getAddedStates()[nextState] && states.size() > 1) { + while ((*(lattice->getAddedStates()))[nextState] && states.size() > 1) { // states.size()>1 such that there is at least one state left after erase states.erase(states.begin()); nextState = *(states.begin()); } - if (!lattice->getAddedStates()[nextState]) { + if (!(*(lattice->getAddedStates()))[nextState]) { auto row = this->model->getTransitionMatrix().getRow(nextState); - auto successors = storm::storage::BitVector(lattice->getAddedStates().size()); + auto successors = new storm::storage::BitVector(lattice->getAddedStates()->size()); for (auto rowItr = row.begin(); rowItr != row.end(); ++rowItr) { // ignore self-loops when there are more transitions if (nextState != rowItr->getColumn()) { - successors.set(rowItr->getColumn()); + successors->set(rowItr->getColumn()); } } - auto seenStates = (lattice->getAddedStates()); - assert ((seenStates & successors) == successors); + assert ((*(lattice->getAddedStates()) & *successors) == *successors); auto result = extendAllSuccAdded(lattice, nextState, successors); if (std::get<1>(result) != numberOfStates) { @@ -320,9 +317,8 @@ namespace storm { } } - auto added = lattice->getAddedStates().getNumberOfSetBits(); assert (lattice->getNode(nextState) != nullptr); - assert (lattice->getAddedStates()[nextState]); + assert ((*lattice->getAddedStates())[nextState]); } } else if (!acyclic) { @@ -331,20 +327,20 @@ namespace storm { if (assumptionSeen) { statesToHandle = addedStates; } - auto stateNumber = statesToHandle.getNextSetIndex(0); + auto stateNumber = statesToHandle->getNextSetIndex(0); while (stateNumber != numberOfStates) { addedStates = lattice->getAddedStates(); - storm::storage::BitVector successors = stateMap[stateNumber]; + storm::storage::BitVector* successors = stateMap[stateNumber]; // Checking for states which are already added to the lattice, and only have one successor left which haven't been added yet - auto succ1 = successors.getNextSetIndex(0); - auto succ2 = successors.getNextSetIndex(succ1 + 1); + auto succ1 = successors->getNextSetIndex(0); + auto succ2 = successors->getNextSetIndex(succ1 + 1); - assert (addedStates[stateNumber]); - if (successors.getNumberOfSetBits() == 2 - && ((addedStates[succ1] && !addedStates[succ2]) - || (!addedStates[succ1] && addedStates[succ2]))) { + assert ((*addedStates)[stateNumber]); + if (successors->getNumberOfSetBits() == 2 + && (((*(addedStates))[succ1] && !(*(addedStates))[succ2]) + || (!(*(addedStates))[succ1] && (*(addedStates))[succ2]))) { - if (!addedStates[succ1]) { + if (!(*(addedStates))[succ1]) { std::swap(succ1, succ2); } @@ -356,45 +352,45 @@ namespace storm { } else { assert(false); } - statesToHandle.set(succ2); - statesToHandle.set(stateNumber, false); - stateNumber = statesToHandle.getNextSetIndex(0); - } else if (!((addedStates[succ1] && !addedStates[succ2]) - || (!addedStates[succ1] && addedStates[succ2]))) { - stateNumber = statesToHandle.getNextSetIndex(stateNumber + 1); + statesToHandle->set(succ2); + statesToHandle->set(stateNumber, false); + stateNumber = statesToHandle->getNextSetIndex(0); + } else if (!(((*(addedStates))[succ1] && !(*(addedStates))[succ2]) + || (!(*(addedStates))[succ1] && (*(addedStates))[succ2]))) { + stateNumber = statesToHandle->getNextSetIndex(stateNumber + 1); } else { - assert (successors.getNumberOfSetBits() == 2); - statesToHandle.set(stateNumber, false); - stateNumber = statesToHandle.getNextSetIndex(0); + assert (successors->getNumberOfSetBits() == 2); + statesToHandle->set(stateNumber, false); + stateNumber = statesToHandle->getNextSetIndex(0); } } addedStates = lattice->getAddedStates(); - for (auto stateNumber = addedStates.getNextUnsetIndex(0); stateNumber < numberOfStates; stateNumber = addedStates.getNextUnsetIndex(stateNumber + 1)) { + for (auto stateNumber : *addedStates) { // Iterate over all not yet added states - storm::storage::BitVector successors = stateMap[stateNumber]; + storm::storage::BitVector* successors = stateMap[stateNumber]; // Check if current state has not been added yet, and all successors have, ignore selfloop in this - successors.set(stateNumber, false); - if ((successors & addedStates) == successors) { + successors->set(stateNumber, false); + if ((*successors & *addedStates) == *successors) { auto result = extendAllSuccAdded(lattice, stateNumber, successors); - if (std::get<1>(result) != successors.size()) { + if (std::get<1>(result) != successors->size()) { return result; } - statesToHandle.set(stateNumber); + statesToHandle->set(stateNumber); } } // if nothing changed and there are states left, then add a state between top and bottom - if (oldNumberSet == lattice->getAddedStates().getNumberOfSetBits() && oldNumberSet != numberOfStates) { - auto stateNumber = lattice->getAddedStates().getNextUnsetIndex(0); + if (oldNumberSet == lattice->getAddedStates()->getNumberOfSetBits() && oldNumberSet != numberOfStates) { + auto stateNumber = lattice->getAddedStates()->getNextUnsetIndex(0); lattice->add(stateNumber); - statesToHandle.set(stateNumber); + statesToHandle->set(stateNumber); } } } - assert (lattice->getAddedStates().getNumberOfSetBits() == numberOfStates); + assert (lattice->getAddedStates()->getNumberOfSetBits() == numberOfStates); return std::make_tuple(lattice, numberOfStates, numberOfStates); } template class LatticeExtender; diff --git a/src/storm-pars/analysis/LatticeExtender.h b/src/storm-pars/analysis/LatticeExtender.h index 0d4787f00..63f224792 100644 --- a/src/storm-pars/analysis/LatticeExtender.h +++ b/src/storm-pars/analysis/LatticeExtender.h @@ -52,7 +52,7 @@ namespace storm { private: std::shared_ptr> model; - std::map stateMap; + std::map stateMap; std::vector statesSorted; @@ -60,11 +60,11 @@ namespace storm { bool assumptionSeen; - storm::storage::BitVector statesToHandle; + storm::storage::BitVector* statesToHandle; void handleAssumption(Lattice* lattice, std::shared_ptr assumption); - std::tuple extendAllSuccAdded(Lattice* lattice, uint_fast64_t stateNumber, storm::storage::BitVector successors); + std::tuple extendAllSuccAdded(Lattice* lattice, uint_fast64_t const & stateNumber, storm::storage::BitVector* successors); }; } } diff --git a/src/storm-pars/analysis/MonotonicityChecker.cpp b/src/storm-pars/analysis/MonotonicityChecker.cpp index 26b23673e..8c5214ca0 100644 --- a/src/storm-pars/analysis/MonotonicityChecker.cpp +++ b/src/storm-pars/analysis/MonotonicityChecker.cpp @@ -26,6 +26,7 @@ #include "storm/storage/expressions/ExpressionManager.h" #include "storm/storage/expressions/RationalFunctionToExpression.h" +#include "storm/utility/constants.h" namespace storm { namespace analysis { @@ -151,8 +152,8 @@ namespace storm { for (auto itr = map.begin(); i < map.size() && itr != map.end(); ++itr) { auto lattice = itr->first; - auto addedStates = lattice->getAddedStates().getNumberOfSetBits(); - assert (addedStates == lattice->getAddedStates().size()); + auto addedStates = lattice->getAddedStates()->getNumberOfSetBits(); + assert (addedStates == lattice->getAddedStates()->size()); std::map> varsMonotone = analyseMonotonicity(i, lattice, matrix); @@ -299,7 +300,7 @@ namespace storm { auto numberOfStates = model->getNumberOfStates(); if (val1 == numberOfStates || val2 == numberOfStates) { assert (val1 == val2); - assert (lattice->getAddedStates().size() == lattice->getAddedStates().getNumberOfSetBits()); + assert (lattice->getAddedStates()->size() == lattice->getAddedStates()->getNumberOfSetBits()); result.insert(std::pair>>(lattice, assumptions)); } else { @@ -388,26 +389,55 @@ namespace storm { return result; } + template + ValueType MonotonicityChecker::getDerivative(ValueType function, carl::Variable var) { + if (function.isConstant()) { + return storm::utility::zero(); + } + if ((derivatives[function]).find(var) == (derivatives[function]).end()) { + (derivatives[function])[var] = function.derivative(var); + } + + return (derivatives[function])[var]; + } + template std::map> MonotonicityChecker::analyseMonotonicity(uint_fast64_t j, storm::analysis::Lattice* lattice, storm::storage::SparseMatrix matrix) { // storm::utility::Stopwatch analyseWatch(true); + std::cout << "Analyzing monotonicity" << std::endl; std::map> varsMonotone; for (uint_fast64_t i = 0; i < matrix.getColumnCount(); ++i) { // go over all rows auto row = matrix.getRow(i); - auto first = (*row.begin()); - if (first.getValue() != ValueType(1)) { + // only enter if you are in a state with at least two successors (so there must be successors, + // and first prob shouldnt be 1) + if (row.begin() != row.end() && !row.begin()->getValue().isOne()) { std::map transitions; - for (auto itr = row.begin(); itr != row.end(); ++itr) { - transitions.insert(std::pair((*itr).getColumn(), (*itr).getValue())); + auto states = new storm::storage::BitVector(matrix.getColumnCount()); + std::set vars; + for (auto const& entry : row) { + if (!entry.getValue().isConstant()) { + // only analyse take non constant transitions + transitions.insert(std::pair(entry.getColumn(), entry.getValue())); + for (auto const& var:entry.getValue().gatherVariables()) { + vars.insert(var); + states->set(entry.getColumn()); + } + } } - auto val = first.getValue(); - auto vars = val.gatherVariables(); - for (auto itr = vars.begin(); itr != vars.end(); ++itr) { + auto sortedStates = lattice->sortStates(states); + + assert (sortedStates.size() >=2); + + assert (sortedStates.size() == states->getNumberOfSetBits()); + if (sortedStates[sortedStates.size() - 1] == -1) { +// auto val = first.getValue(); +// auto vars = val.gatherVariables(); + for (auto itr = vars.begin(); itr != vars.end(); ++itr) { // if (resultCheckOnSamples.find(*itr) != resultCheckOnSamples.end() && // (!resultCheckOnSamples[*itr].first && !resultCheckOnSamples[*itr].second)) { // if (varsMonotone.find(*itr) == varsMonotone.end()) { @@ -422,42 +452,85 @@ namespace storm { std::pair *value = &varsMonotone.find(*itr)->second; std::pair old = *value; + + // states are not properly sorted for (auto itr2 = transitions.begin(); itr2 != transitions.end(); ++itr2) { for (auto itr3 = transitions.begin(); itr3 != transitions.end(); ++itr3) { - auto derivative2 = itr2->second.derivative(*itr); - auto derivative3 = itr3->second.derivative(*itr); - - auto compare = lattice->compare(itr2->first, itr3->first); - - if (compare == storm::analysis::Lattice::ABOVE) { - // As the first state (itr2) is above the second state (itr3) it is sufficient to look at the derivative of itr2. - std::pair mon2; - if (derivative2.isConstant()) { - mon2 = std::pair(derivative2.constantPart() >= 0, derivative2.constantPart() <=0); - } else { - mon2 = checkDerivative(derivative2); - } - value->first &= mon2.first; - value->second &= mon2.second; - } else if (compare == storm::analysis::Lattice::BELOW) { - // As the second state (itr3) is above the first state (itr2) it is sufficient to look at the derivative of itr3. - std::pair mon3; - if (derivative2.isConstant()) { - mon3 = std::pair(derivative3.constantPart() >= 0, derivative3.constantPart() <=0); + if (itr2->first < itr3->first) { + + auto derivative2 = getDerivative(itr2->second, *itr); + auto derivative3 = getDerivative(itr3->second, *itr); + + auto compare = lattice->compare(itr2->first, itr3->first); + + if (compare == storm::analysis::Lattice::ABOVE) { + // As the first state (itr2) is above the second state (itr3) it is sufficient to look at the derivative of itr2. + std::pair mon2; + if (derivative2.isConstant()) { + mon2 = std::pair(derivative2.constantPart() >= 0, + derivative2.constantPart() <= 0); + } else { + mon2 = checkDerivative(derivative2); + } + value->first &= mon2.first; + value->second &= mon2.second; + } else if (compare == storm::analysis::Lattice::BELOW) { + // As the second state (itr3) is above the first state (itr2) it is sufficient to look at the derivative of itr3. + std::pair mon3; + if (derivative2.isConstant()) { + mon3 = std::pair(derivative3.constantPart() >= 0, + derivative3.constantPart() <= 0); + } else { + mon3 = checkDerivative(derivative3); + } + value->first &= mon3.first; + value->second &= mon3.second; + } else if (compare == storm::analysis::Lattice::SAME) { + // TODO: klopt dit + // Behaviour doesn't matter, as the states are at the same level. } else { - mon3 = checkDerivative(derivative3); + // As the relation between the states is unknown, we can't claim anything about the monotonicity. + value->first = false; + value->second = false; } - value->first &= mon3.first; - value->second &= mon3.second; - } else if (compare == storm::analysis::Lattice::SAME) { - // TODO: klopt dit - // Behaviour doesn't matter, as the states are at the same level. - } else { - // As the relation between the states is unknown, we can't claim anything about the monotonicity. - value->first = false; - value->second = false; } // } + } + } + } + } else { + bool change = false; + for (auto var : vars) { +// if (resultCheckOnSamples.find(*itr) != resultCheckOnSamples.end() && +// (!resultCheckOnSamples[*itr].first && !resultCheckOnSamples[*itr].second)) { +// if (varsMonotone.find(*itr) == varsMonotone.end()) { +// varsMonotone[*itr].first = false; +// varsMonotone[*itr].second = false; +// } +// } else { + if (varsMonotone.find(var) == varsMonotone.end()) { + varsMonotone[var].first = true; + varsMonotone[var].second = true; + } + std::pair *value = &varsMonotone.find(var)->second; + + for (auto const &i : sortedStates) { +// auto res = checkDerivative(transitions[i].derivative(var)); + auto res = checkDerivative(getDerivative(transitions[i], var)); + change = change || (!(value->first && value->second) // they do not hold both + && ((value->first && !res.first) + || (value->second && !res.second))); + + if (change) { + value->first &= res.second; + value->second &= res.first; + } else { + value->first &= res.first; + value->second &= res.second; + } + if (!value->first && !value->second) { + break; + } } } } @@ -478,6 +551,9 @@ namespace storm { if (derivative.isZero()) { monIncr = true; monDecr = true; + } else if (derivative.isConstant()) { + monIncr = derivative.constantPart() >= 0; + monDecr = derivative.constantPart() <= 0; } else { std::shared_ptr smtSolverFactory = std::make_shared(); diff --git a/src/storm-pars/analysis/MonotonicityChecker.h b/src/storm-pars/analysis/MonotonicityChecker.h index b4b6db84c..94cb39ff3 100644 --- a/src/storm-pars/analysis/MonotonicityChecker.h +++ b/src/storm-pars/analysis/MonotonicityChecker.h @@ -62,6 +62,10 @@ namespace storm { std::pair checkDerivative(ValueType derivative); + std::unordered_map> derivatives; + + ValueType getDerivative(ValueType function, carl::Variable var); + std::vector> checkAssumptionsOnRegion(std::vector> assumptions); std::map>> extendLatticeWithAssumptions(storm::analysis::Lattice* lattice, storm::analysis::AssumptionMaker* assumptionMaker, uint_fast64_t val1, uint_fast64_t val2, std::vector> assumptions); diff --git a/src/test/storm-pars/analysis/AssumptionCheckerTest.cpp b/src/test/storm-pars/analysis/AssumptionCheckerTest.cpp index b8ac1981e..ab0b25d18 100644 --- a/src/test/storm-pars/analysis/AssumptionCheckerTest.cpp +++ b/src/test/storm-pars/analysis/AssumptionCheckerTest.cpp @@ -82,7 +82,7 @@ TEST(AssumptionCheckerTest, Brp_no_bisimulation) { below.set(1); storm::storage::BitVector initialMiddle(8); - auto dummyLattice = new storm::analysis::Lattice(above, below, initialMiddle, 8); + auto dummyLattice = new storm::analysis::Lattice(&above, &below, &initialMiddle, 8); // Validate assumption EXPECT_FALSE(checker.validateAssumption(assumption, dummyLattice)); EXPECT_FALSE(checker.validated(assumption)); @@ -99,7 +99,7 @@ TEST(AssumptionCheckerTest, Brp_no_bisimulation) { below = storm::storage::BitVector(13); below.set(9); initialMiddle = storm::storage::BitVector(13); - dummyLattice = new storm::analysis::Lattice(above, below, initialMiddle, 13); + dummyLattice = new storm::analysis::Lattice(&above, &below, &initialMiddle, 13); EXPECT_FALSE(checker.checkOnSamples(assumption)); EXPECT_FALSE(checker.validateAssumption(assumption, dummyLattice)); EXPECT_TRUE(checker.validated(assumption)); diff --git a/src/test/storm-pars/analysis/LatticeExtenderTest.cpp b/src/test/storm-pars/analysis/LatticeExtenderTest.cpp index 59f739b84..b174d3873 100644 --- a/src/test/storm-pars/analysis/LatticeExtenderTest.cpp +++ b/src/test/storm-pars/analysis/LatticeExtenderTest.cpp @@ -59,7 +59,7 @@ TEST(LatticeExtenderTest, Brp_with_bisimulation) { auto lattice = std::get<0>(criticalTuple); for (auto i = 0; i < dtmc->getNumberOfStates(); ++i) { - EXPECT_TRUE(lattice->getAddedStates()[i]); + EXPECT_TRUE((*lattice->getAddedStates())[i]); } // Check on some nodes diff --git a/src/test/storm-pars/analysis/LatticeTest.cpp b/src/test/storm-pars/analysis/LatticeTest.cpp index ad65b98c7..27806bc50 100644 --- a/src/test/storm-pars/analysis/LatticeTest.cpp +++ b/src/test/storm-pars/analysis/LatticeTest.cpp @@ -17,7 +17,7 @@ TEST(LatticeTest, Simple) { below.set(1); auto initialMiddle = storm::storage::BitVector(numberOfStates); - auto lattice = storm::analysis::Lattice(above, below, initialMiddle, numberOfStates); + auto lattice = storm::analysis::Lattice(&above, &below, &initialMiddle, numberOfStates); EXPECT_EQ(storm::analysis::Lattice::ABOVE, lattice.compare(0,1)); EXPECT_EQ(storm::analysis::Lattice::BELOW, lattice.compare(1,0)); EXPECT_EQ(nullptr, lattice.getNode(2)); @@ -83,7 +83,7 @@ TEST(LatticeTest, copy_lattice) { below.set(1); auto initialMiddle = storm::storage::BitVector(numberOfStates); - auto lattice = storm::analysis::Lattice(above, below, initialMiddle, numberOfStates); + auto lattice = storm::analysis::Lattice(&above, &below, &initialMiddle, numberOfStates); lattice.add(2); lattice.add(3); lattice.addToNode(4, lattice.getNode(2)); @@ -148,7 +148,7 @@ TEST(LatticeTest, merge_nodes) { below.set(1); auto initialMiddle = storm::storage::BitVector(numberOfStates); - auto lattice = storm::analysis::Lattice(above, below, initialMiddle, numberOfStates); + auto lattice = storm::analysis::Lattice(&above, &below, &initialMiddle, numberOfStates); lattice.add(2); lattice.add(3); lattice.addToNode(4, lattice.getNode(2)); diff --git a/src/test/storm-pars/analysis/MonotonicityCheckerTest.cpp b/src/test/storm-pars/analysis/MonotonicityCheckerTest.cpp index 12631b65a..3367f3d09 100644 --- a/src/test/storm-pars/analysis/MonotonicityCheckerTest.cpp +++ b/src/test/storm-pars/analysis/MonotonicityCheckerTest.cpp @@ -38,7 +38,7 @@ TEST(MonotonicityCheckerTest, Monotone_no_model) { auto below = storm::storage::BitVector(numberOfStates); below.set(0); auto initialMiddle = storm::storage::BitVector(numberOfStates); - auto lattice = storm::analysis::Lattice(above, below, initialMiddle, numberOfStates); + auto lattice = storm::analysis::Lattice(&above, &below, &initialMiddle, numberOfStates); lattice.add(2); lattice.add(3); // Build map @@ -84,7 +84,7 @@ TEST(MonotonicityCheckerTest, Not_monotone_no_model) { auto below = storm::storage::BitVector(numberOfStates); below.set(0); auto initialMiddle = storm::storage::BitVector(numberOfStates); - auto lattice = storm::analysis::Lattice(above, below, initialMiddle, numberOfStates); + auto lattice = storm::analysis::Lattice(&above, &below, &initialMiddle, numberOfStates); lattice.add(2); lattice.add(3); // Build map From f6da9644b011198ee54da1ee7c353c919cd976b3 Mon Sep 17 00:00:00 2001 From: Jip Spel Date: Tue, 5 Feb 2019 11:29:12 +0100 Subject: [PATCH 140/178] Improve efficiency --- src/storm-pars/analysis/Lattice.cpp | 109 +++++++++++++----- src/storm-pars/analysis/Lattice.h | 9 ++ .../analysis/MonotonicityChecker.cpp | 3 +- 3 files changed, 93 insertions(+), 28 deletions(-) diff --git a/src/storm-pars/analysis/Lattice.cpp b/src/storm-pars/analysis/Lattice.cpp index edead7737..c677bcd12 100644 --- a/src/storm-pars/analysis/Lattice.cpp +++ b/src/storm-pars/analysis/Lattice.cpp @@ -17,15 +17,21 @@ namespace storm { assert((*topStates & *bottomStates).getNumberOfSetBits() == 0); nodes = std::vector(numberOfStates); + this->numberOfStates = numberOfStates; + this->addedStates = new storm::storage::BitVector(numberOfStates); + this->doneBuilding = false; + top = new Node(); top->states = *topStates; for (auto const& i : *topStates) { + addedStates->set(i); nodes[i] = top; } bottom = new Node(); bottom->states = *bottomStates; for (auto const& i : *bottomStates) { + addedStates->set(i); nodes[i] = bottom; } @@ -36,10 +42,6 @@ namespace storm { // bottom->statesBelow = storm::storage::BitVector(numberOfStates); // setStatesAbove(bottom, topStates, false); - this->numberOfStates = numberOfStates; - this->addedStates = new storm::storage::BitVector(numberOfStates); - *addedStates |= *(topStates); - *addedStates |= *(bottomStates); for (auto const &state : *initialMiddleStates) { add(state); @@ -51,6 +53,7 @@ namespace storm { numberOfStates = lattice->getAddedStates()->size(); nodes = std::vector(numberOfStates); addedStates = new storm::storage::BitVector(numberOfStates); + this->doneBuilding = lattice->getDoneBuilding(); auto oldNodes = lattice->getNodes(); // Create nodes @@ -103,7 +106,8 @@ namespace storm { newNode->states = storm::storage::BitVector(numberOfStates); newNode->states.set(state); newNode->statesAbove = above->states | above->statesAbove; - below->statesAbove |= newNode->states; + below->statesAbove.set(state); +// comparisons[state] = comparisons[above->states.getNextSetIndex(0)]; // setStatesAbove(newNode, above->statesAbove | above->states, false); // setStatesBelow(newNode, below->statesBelow | below->states, false); // setStatesBelow(above, state, true); @@ -126,6 +130,7 @@ namespace storm { node->states.set(state); nodes[state] = node; addedStates->set(state); +// comparisons[state] = comparisons[node->states.getNextSetIndex(0)]; // for (auto i = node->statesBelow.getNextSetIndex(0); i < node->statesBelow.size(); i = node->statesBelow.getNextSetIndex(i + 1)) { // setStatesAbove(getNode(i), state, true); @@ -148,6 +153,7 @@ namespace storm { // setStatesBelow(above, below->states | below->statesBelow, true); // setStatesAbove(below, above->states | above->statesAbove, true); below->statesAbove |= above->states | above->statesAbove; + // TODO: comparisons // for (auto i = below->statesBelow.getNextSetIndex(0); i < below->statesBelow.size(); i = below->statesBelow.getNextSetIndex(i + 1)) { // setStatesAbove(getNode(i), above->states | above->statesAbove, true); @@ -169,12 +175,24 @@ namespace storm { return SAME; } +// auto state1 = node1->states.getNextSetIndex(0); +// auto state2 = node2->states.getNextSetIndex(0); +// +// auto mapEntry = comparisons[state1]; +// if (mapEntry.find(state2) != mapEntry.end()) { +// return mapEntry[state2]; +// } + if (above(node1, node2)) { assert(!above(node2, node1)); +// comparisons[state1][state2] = ABOVE; +// comparisons[state2][state1] = BELOW; return ABOVE; } if (above(node2, node1)) { +// comparisons[state1][state2] = BELOW; +// comparisons[state2][state1] = ABOVE; return BELOW; } } @@ -201,16 +219,25 @@ namespace storm { return addedStates; } + bool Lattice::getDoneBuilding() { + return doneBuilding; + } + + void Lattice::setDoneBuilding(bool done) { + doneBuilding = done; + } + std::vector Lattice::sortStates(storm::storage::BitVector* states) { - auto result = std::vector(states->getNumberOfSetBits(), -1); + auto numberOfSetBits = states->getNumberOfSetBits(); + auto result = std::vector(numberOfSetBits, -1); for (auto state : *states) { if (result[0] == -1) { result[0] = state; } else { - for (auto i = 0; i < states->getNumberOfSetBits() && result[i] != -1; i++) { + for (auto i = 0; i < numberOfSetBits && result[i] != -1; i++) { auto compareRes = compare(state, result[i]); if (compareRes == Lattice::ABOVE) { - for (auto j = i; j < states->getNumberOfSetBits() -1 && result[j+1] != -1; j++) { + for (auto j = i; j < numberOfSetBits -1 && result[j+1] != -1; j++) { auto temp = result[j]; result[j] = state; result[j+1] = temp; @@ -218,7 +245,7 @@ namespace storm { } else if (compareRes == Lattice::UNKNOWN) { break; } else if (compareRes == Lattice::SAME) { - for (auto j = i+1; j < states->getNumberOfSetBits() -1 && result[j+1] != -1; j++) { + for (auto j = i+1; j < numberOfSetBits -1 && result[j+1] != -1; j++) { auto temp = result[j]; result[j] = state; result[j+1] = temp; @@ -359,15 +386,31 @@ namespace storm { bool Lattice::above(Node *node1, Node *node2) { // ligt node 1 boven node 2 ? // oftewel is er een state in node2.above die met een state in node1 matched - bool found = (node2->statesAbove & node1->states).getNumberOfSetBits() != 0; - storm::storage::BitVector statesSeen(node2->statesAbove); - for (auto const& i: node2->statesAbove) { - auto nodeI = getNode(i); + bool found = false; + for (auto const& state : node1->states) { + found = node2->statesAbove[state]; + if (found) { + break; + } + } + + if (!found && !doneBuilding) { + storm::storage::BitVector statesSeen(node2->statesAbove); + for (auto const &i: node2->statesAbove) { + auto nodeI = getNode(i); + // deze kost veel tijd + // wat wil ik doen? + // ik wil kijken of t nut heeft om de node uberhaupt in te gaan if ((nodeI->statesAbove & statesSeen) != nodeI->statesAbove) { found = above(node1, nodeI, node2, &statesSeen); } - if (found) { - break; + if (found) { + for (auto const& state:node1->states) { + node2->statesAbove.set(state); + } + + break; + } } } return found; @@ -375,20 +418,34 @@ namespace storm { bool Lattice::above(storm::analysis::Lattice::Node *node1, storm::analysis::Lattice::Node *node2, storm::analysis::Lattice::Node *nodePrev, storm::storage::BitVector *statesSeen) { - bool found = (node2->statesAbove & node1->states).getNumberOfSetBits() != 0; - // TODO: kan dit niet anders? - statesSeen->operator|=(node2->statesAbove); - nodePrev->statesAbove |= node2->statesAbove; +// bool found = (node2->statesAbove & node1->states).getNumberOfSetBits() != 0; + bool found = false; + for (auto const& state : node1->states) { + found = node2->statesAbove[state]; + if (found) { + break; + } + } +// bool found = !(node2->statesAbove & node1->states).empty(); + if (!found) { + // TODO: kan dit niet anders? + nodePrev->statesAbove |= node2->statesAbove; + auto complement = (statesSeen->operator~()); - storm::storage::BitVector states = storm::storage::BitVector((node2->statesAbove & (statesSeen->operator~()))); - for (auto const& i: states) { + storm::storage::BitVector states = storm::storage::BitVector( + (node2->statesAbove & complement)); + statesSeen->operator|=(node2->statesAbove); + + for (auto const &i: states) { // assert (!statesSeen[i]); - auto nodeI = getNode(i); - if ((nodeI->statesAbove & *statesSeen) != nodeI->statesAbove) { + auto nodeI = getNode(i); + if (!(nodeI->statesAbove & complement).empty()) { found = above(node1, nodeI, node2, statesSeen); } - if (found) { - break; + if (found) { + break; + } + } } return found; @@ -451,7 +508,7 @@ namespace storm { // add states of node 2 to node 1 node1->states|= node2->states; - for(auto i = node2->states.getNextSetIndex(0); i < node2->states.size(); i = node2->states.getNextSetIndex(i+1)) { + for(auto const& i : node2->states) { nodes[i] = node1; } diff --git a/src/storm-pars/analysis/Lattice.h b/src/storm-pars/analysis/Lattice.h index d47d76bf9..638877729 100644 --- a/src/storm-pars/analysis/Lattice.h +++ b/src/storm-pars/analysis/Lattice.h @@ -8,6 +8,8 @@ #include #include #include +#include + #include "storm/storage/BitVector.h" @@ -119,6 +121,8 @@ namespace storm { */ storm::storage::BitVector* getAddedStates(); + bool getDoneBuilding(); + std::vector sortStates(storm::storage::BitVector* states); // /*! @@ -152,6 +156,7 @@ namespace storm { // * @return The set with all nodes which are below the node. // */ // std::set getBelow(Lattice::Node* node); + void setDoneBuilding(bool done); /*! * Prints a string representation of the lattice to the output stream. @@ -201,6 +206,10 @@ namespace storm { int compare(Node* node1, Node* node2); + std::unordered_map> comparisons; + + bool doneBuilding; + // void setStatesAbove(Node* node, uint_fast64_t state, bool alreadyInitialized); // void setStatesBelow(Node* node, uint_fast64_t state, bool alreadyInitialized); diff --git a/src/storm-pars/analysis/MonotonicityChecker.cpp b/src/storm-pars/analysis/MonotonicityChecker.cpp index 8c5214ca0..1cc60279d 100644 --- a/src/storm-pars/analysis/MonotonicityChecker.cpp +++ b/src/storm-pars/analysis/MonotonicityChecker.cpp @@ -404,8 +404,7 @@ namespace storm { template std::map> MonotonicityChecker::analyseMonotonicity(uint_fast64_t j, storm::analysis::Lattice* lattice, storm::storage::SparseMatrix matrix) { // storm::utility::Stopwatch analyseWatch(true); - - std::cout << "Analyzing monotonicity" << std::endl; + lattice->setDoneBuilding(true); std::map> varsMonotone; for (uint_fast64_t i = 0; i < matrix.getColumnCount(); ++i) { From 46aa007f33171245a406b43fb9fa72aee794609c Mon Sep 17 00:00:00 2001 From: Jip Spel Date: Tue, 5 Feb 2019 11:57:43 +0100 Subject: [PATCH 141/178] Use flat_set --- src/storm-pars/analysis/Lattice.cpp | 135 ++++++++++---------- src/storm-pars/analysis/Lattice.h | 4 +- src/storm-pars/analysis/LatticeExtender.cpp | 5 +- 3 files changed, 76 insertions(+), 68 deletions(-) diff --git a/src/storm-pars/analysis/Lattice.cpp b/src/storm-pars/analysis/Lattice.cpp index c677bcd12..88fa59201 100644 --- a/src/storm-pars/analysis/Lattice.cpp +++ b/src/storm-pars/analysis/Lattice.cpp @@ -12,9 +12,9 @@ namespace storm { storm::storage::BitVector* bottomStates, storm::storage::BitVector* initialMiddleStates, uint_fast64_t numberOfStates) { - assert(topStates->getNumberOfSetBits() != 0); - assert(bottomStates->getNumberOfSetBits() != 0); - assert((*topStates & *bottomStates).getNumberOfSetBits() == 0); +// assert(topStates->getNumberOfSetBits() != 0); +// assert(bottomStates->getNumberOfSetBits() != 0); +// assert((*topStates & *bottomStates).getNumberOfSetBits() == 0); nodes = std::vector(numberOfStates); this->numberOfStates = numberOfStates; @@ -22,21 +22,26 @@ namespace storm { this->doneBuilding = false; top = new Node(); - top->states = *topStates; + bottom = new Node(); + + top->statesAbove = storm::storage::BitVector(numberOfStates); + bottom->statesAbove = storm::storage::BitVector(numberOfStates); + + for (auto const& i : *topStates) { addedStates->set(i); + bottom->statesAbove.set(i); + top->states.insert(i); nodes[i] = top; } - bottom = new Node(); - bottom->states = *bottomStates; for (auto const& i : *bottomStates) { addedStates->set(i); + bottom->states.insert(i); nodes[i] = bottom; } - top->statesAbove = storm::storage::BitVector(numberOfStates); - bottom->statesAbove = *topStates; + // setStatesBelow(top, bottomStates, false); // bottom->statesBelow = storm::storage::BitVector(numberOfStates); @@ -61,9 +66,9 @@ namespace storm { Node *oldNode = (*itr); if (oldNode != nullptr) { Node *newNode = new Node(); - newNode->states = storm::storage::BitVector(oldNode->states); - for (auto i = newNode->states.getNextSetIndex(0); - i < newNode->states.size(); i = newNode->states.getNextSetIndex(i + 1)) { + // TODO: gaat dit goed of moet er een constructor om + newNode->states = oldNode->states; + for (auto const& i : newNode->states) { addedStates->set(i); nodes[i] = newNode; } @@ -81,7 +86,7 @@ namespace storm { for (auto itr = oldNodes.begin(); itr != oldNodes.end(); ++itr) { Node *oldNode = (*itr); if (oldNode != nullptr && oldNode != lattice->getTop() && oldNode != lattice->getBottom()) { - Node *newNode = getNode(oldNode->states.getNextSetIndex(0)); + Node *newNode = getNode(*(oldNode->states.begin())); newNode->statesAbove = storm::storage::BitVector(oldNode->statesAbove); // setStatesAbove(newNode, oldNode->statesAbove, false); // setStatesBelow(newNode, oldNode->statesBelow, false); @@ -103,9 +108,12 @@ namespace storm { Node *newNode = new Node(); nodes[state] = newNode; - newNode->states = storm::storage::BitVector(numberOfStates); - newNode->states.set(state); - newNode->statesAbove = above->states | above->statesAbove; +// newNode->states = storm::storage::BitVector(numberOfStates); + newNode->states.insert(state); + newNode->statesAbove = above->statesAbove; + for (auto const& state : above->states) { + newNode->statesAbove.set(state); + } below->statesAbove.set(state); // comparisons[state] = comparisons[above->states.getNextSetIndex(0)]; // setStatesAbove(newNode, above->statesAbove | above->states, false); @@ -127,7 +135,7 @@ namespace storm { void Lattice::addToNode(uint_fast64_t state, Node *node) { assert(!(*addedStates)[state]); - node->states.set(state); + node->states.insert(state); nodes[state] = node; addedStates->set(state); // comparisons[state] = comparisons[node->states.getNextSetIndex(0)]; @@ -152,7 +160,10 @@ namespace storm { // assert ((above->statesAbove & below->statesBelow).getNumberOfSetBits() == 0); // setStatesBelow(above, below->states | below->statesBelow, true); // setStatesAbove(below, above->states | above->statesAbove, true); - below->statesAbove |= above->states | above->statesAbove; + for (auto const& state : above->states) { + below->statesAbove.set(state); + } + below->statesAbove |= above->statesAbove; // TODO: comparisons // for (auto i = below->statesBelow.getNextSetIndex(0); i < below->statesBelow.size(); i = below->statesBelow.getNextSetIndex(i + 1)) { @@ -283,42 +294,42 @@ namespace storm { // } void Lattice::toString(std::ostream &out) { - assert (false); - std::vector printedNodes = std::vector({}); - for (auto itr = nodes.begin(); itr != nodes.end(); ++itr) { - - if ((*itr) != nullptr && std::find(printedNodes.begin(), printedNodes.end(), (*itr)) == printedNodes.end()) { - Node *node = *itr; - printedNodes.push_back(*itr); - out << "Node: {"; - uint_fast64_t index = node->states.getNextSetIndex(0); - while (index < node->states.size()) { - out << index; - index = node->states.getNextSetIndex(index + 1); - if (index < node->states.size()) { - out << ", "; - } - } - out << "}" << "\n"; - out << " Address: " << node << "\n"; - out << " Above: {"; - - auto statesAbove = node->statesAbove; - for (auto above : statesAbove) { - Node* nodeAbove = getNode(above); - index = nodeAbove->states.getNextSetIndex(0); - out << "{"; - while (index < nodeAbove->states.size()) { - out << index; - index = nodeAbove->states.getNextSetIndex(index + 1); - if (index < nodeAbove->states.size()) { - out << ", "; - } - } - - out << "}"; - } - out << "}" << "\n"; +// assert (false); +// std::vector printedNodes = std::vector({}); +// for (auto itr = nodes.begin(); itr != nodes.end(); ++itr) { +// +// if ((*itr) != nullptr && std::find(printedNodes.begin(), printedNodes.end(), (*itr)) == printedNodes.end()) { +// Node *node = *itr; +// printedNodes.push_back(*itr); +// out << "Node: {"; +// uint_fast64_t index = node->states.getNextSetIndex(0); +// while (index < node->states.size()) { +// out << index; +// index = node->states.getNextSetIndex(index + 1); +// if (index < node->states.size()) { +// out << ", "; +// } +// } +// out << "}" << "\n"; +// out << " Address: " << node << "\n"; +// out << " Above: {"; +// +// auto statesAbove = node->statesAbove; +// for (auto above : statesAbove) { +// Node* nodeAbove = getNode(above); +// index = nodeAbove->states.getNextSetIndex(0); +// out << "{"; +// while (index < nodeAbove->states.size()) { +// out << index; +// index = nodeAbove->states.getNextSetIndex(index + 1); +// if (index < nodeAbove->states.size()) { +// out << ", "; +// } +// } +// +// out << "}"; +// } +// out << "}" << "\n"; // out << " Below: {"; @@ -337,9 +348,9 @@ namespace storm { // // out << "}"; // } - out << "}" << "\n"; - } - } +// out << "}" << "\n"; +// } +// } } void Lattice::toDotFile(std::ostream &out) { @@ -398,17 +409,13 @@ namespace storm { storm::storage::BitVector statesSeen(node2->statesAbove); for (auto const &i: node2->statesAbove) { auto nodeI = getNode(i); - // deze kost veel tijd - // wat wil ik doen? - // ik wil kijken of t nut heeft om de node uberhaupt in te gaan - if ((nodeI->statesAbove & statesSeen) != nodeI->statesAbove) { - found = above(node1, nodeI, node2, &statesSeen); - } + if ((nodeI->statesAbove & statesSeen) != nodeI->statesAbove) { + found = above(node1, nodeI, node2, &statesSeen); + } if (found) { for (auto const& state:node1->states) { node2->statesAbove.set(state); } - break; } } @@ -507,7 +514,7 @@ namespace storm { // node1->statesBelow |= node2->statesBelow; // add states of node 2 to node 1 - node1->states|= node2->states; + node1->states.insert(node2->states.begin(), node2->states.end()); for(auto const& i : node2->states) { nodes[i] = node1; } diff --git a/src/storm-pars/analysis/Lattice.h b/src/storm-pars/analysis/Lattice.h index 638877729..64989cb6d 100644 --- a/src/storm-pars/analysis/Lattice.h +++ b/src/storm-pars/analysis/Lattice.h @@ -9,7 +9,7 @@ #include #include #include - +#include #include "storm/storage/BitVector.h" @@ -19,7 +19,7 @@ namespace storm { public: struct Node { - storm::storage::BitVector states; + boost::container::flat_set states; storm::storage::BitVector statesAbove; // storm::storage::BitVector statesBelow; }; diff --git a/src/storm-pars/analysis/LatticeExtender.cpp b/src/storm-pars/analysis/LatticeExtender.cpp index 045fa6c9c..4549dfe1c 100644 --- a/src/storm-pars/analysis/LatticeExtender.cpp +++ b/src/storm-pars/analysis/LatticeExtender.cpp @@ -18,8 +18,9 @@ #include "storm/exceptions/NotSupportedException.h" #include -#include -#include +#include +#include "storm/storage/StronglyConnectedComponentDecomposition.h" +#include "storm/storage/StronglyConnectedComponent.h" #include "storm/storage/BitVector.h" #include "storm/utility/macros.h" From ed0768cf60de894b605ec2f585d7afb32142b40b Mon Sep 17 00:00:00 2001 From: Jip Spel Date: Wed, 6 Feb 2019 18:39:41 +0100 Subject: [PATCH 142/178] Update implementation --- src/storm-pars/analysis/Lattice.cpp | 171 ++++++++++-------- src/storm-pars/analysis/Lattice.h | 4 +- src/storm-pars/analysis/LatticeExtender.cpp | 4 +- .../analysis/MonotonicityChecker.cpp | 9 +- 4 files changed, 106 insertions(+), 82 deletions(-) diff --git a/src/storm-pars/analysis/Lattice.cpp b/src/storm-pars/analysis/Lattice.cpp index 88fa59201..7c54a4a85 100644 --- a/src/storm-pars/analysis/Lattice.cpp +++ b/src/storm-pars/analysis/Lattice.cpp @@ -87,11 +87,11 @@ namespace storm { Node *oldNode = (*itr); if (oldNode != nullptr && oldNode != lattice->getTop() && oldNode != lattice->getBottom()) { Node *newNode = getNode(*(oldNode->states.begin())); - newNode->statesAbove = storm::storage::BitVector(oldNode->statesAbove); + newNode->statesAbove = storm::storage::BitVector((oldNode->statesAbove)); // setStatesAbove(newNode, oldNode->statesAbove, false); // setStatesBelow(newNode, oldNode->statesBelow, false); } else if (oldNode != nullptr && oldNode == lattice->getBottom()) { - bottom->statesAbove = storm::storage::BitVector(oldNode->statesAbove); + bottom->statesAbove = storm::storage::BitVector((oldNode->statesAbove)); // setStatesAbove(bottom, lattice->getBottom()->statesAbove, false); // bottom->statesBelow = storm::storage::BitVector(numberOfStates); // } else if (oldNode != nullptr && oldNode == lattice->getTop()) { @@ -110,11 +110,13 @@ namespace storm { // newNode->states = storm::storage::BitVector(numberOfStates); newNode->states.insert(state); - newNode->statesAbove = above->statesAbove; + newNode->statesAbove = storm::storage::BitVector((above->statesAbove)); for (auto const& state : above->states) { newNode->statesAbove.set(state); } below->statesAbove.set(state); + addedStates->set(state); + // comparisons[state] = comparisons[above->states.getNextSetIndex(0)]; // setStatesAbove(newNode, above->statesAbove | above->states, false); // setStatesBelow(newNode, below->statesBelow | below->states, false); @@ -129,7 +131,6 @@ namespace storm { // setStatesBelow(getNode(i), state, true); // } - addedStates->set(state); } @@ -163,7 +164,7 @@ namespace storm { for (auto const& state : above->states) { below->statesAbove.set(state); } - below->statesAbove |= above->statesAbove; + below->statesAbove|=((above->statesAbove)); // TODO: comparisons // for (auto i = below->statesBelow.getNextSetIndex(0); i < below->statesBelow.size(); i = below->statesBelow.getNextSetIndex(i + 1)) { @@ -206,6 +207,20 @@ namespace storm { // comparisons[state2][state1] = ABOVE; return BELOW; } + + // tweak for cyclic pmcs + if (doneBuilding) { + doneBuilding = false; + if (above(node1, node2)) { + assert(!above(node2, node1)); + doneBuilding = true; + return ABOVE; + } + if (above(node2, node1)) { + doneBuilding = true; + return BELOW; + } + } } return UNKNOWN; } @@ -240,29 +255,48 @@ namespace storm { std::vector Lattice::sortStates(storm::storage::BitVector* states) { auto numberOfSetBits = states->getNumberOfSetBits(); - auto result = std::vector(numberOfSetBits, -1); + auto stateSize = states->size(); + auto result = std::vector(numberOfSetBits, stateSize); for (auto state : *states) { - if (result[0] == -1) { + if (result[0] == stateSize) { result[0] = state; } else { - for (auto i = 0; i < numberOfSetBits && result[i] != -1; i++) { - auto compareRes = compare(state, result[i]); - if (compareRes == Lattice::ABOVE) { - for (auto j = i; j < numberOfSetBits -1 && result[j+1] != -1; j++) { - auto temp = result[j]; - result[j] = state; - result[j+1] = temp; - } - } else if (compareRes == Lattice::UNKNOWN) { - break; - } else if (compareRes == Lattice::SAME) { - for (auto j = i+1; j < numberOfSetBits -1 && result[j+1] != -1; j++) { - auto temp = result[j]; - result[j] = state; - result[j+1] = temp; + auto i = 0; + bool added = false; + while (i < numberOfSetBits && !added) { + if (result[i] == stateSize) { + result[i] = state; + added = true; + } else { + auto compareRes = compare(state, result[i]); + if (compareRes == Lattice::ABOVE) { + auto temp = result[i]; + result[i] = state; + for (auto j = i + 1; j < numberOfSetBits && result[j + 1] != stateSize; j++) { + auto temp2 = result[j]; + result[j] = temp; + temp = temp2; + } + added = true; + } else if (compareRes == Lattice::UNKNOWN) { + break; + } else if (compareRes == Lattice::SAME) { + ++i; + auto temp = result[i]; + result[i] = state; + for (auto j = i + 1; j < numberOfSetBits && result[j + 1] != stateSize; j++) { + auto temp2 = result[j]; + result[j] = temp; + temp = temp2; + } + added = true; } } + ++i; } +// if (i < numberOfSetBits && result[i] == stateSize) { +// result[i] = state; +// } } } @@ -294,42 +328,26 @@ namespace storm { // } void Lattice::toString(std::ostream &out) { -// assert (false); -// std::vector printedNodes = std::vector({}); -// for (auto itr = nodes.begin(); itr != nodes.end(); ++itr) { -// -// if ((*itr) != nullptr && std::find(printedNodes.begin(), printedNodes.end(), (*itr)) == printedNodes.end()) { -// Node *node = *itr; -// printedNodes.push_back(*itr); -// out << "Node: {"; -// uint_fast64_t index = node->states.getNextSetIndex(0); -// while (index < node->states.size()) { -// out << index; -// index = node->states.getNextSetIndex(index + 1); -// if (index < node->states.size()) { -// out << ", "; -// } -// } -// out << "}" << "\n"; -// out << " Address: " << node << "\n"; -// out << " Above: {"; -// -// auto statesAbove = node->statesAbove; -// for (auto above : statesAbove) { -// Node* nodeAbove = getNode(above); -// index = nodeAbove->states.getNextSetIndex(0); -// out << "{"; -// while (index < nodeAbove->states.size()) { -// out << index; -// index = nodeAbove->states.getNextSetIndex(index + 1); -// if (index < nodeAbove->states.size()) { -// out << ", "; -// } -// } -// -// out << "}"; -// } -// out << "}" << "\n"; + std::vector printedNodes = std::vector({}); + for (auto itr = nodes.begin(); itr != nodes.end(); ++itr) { + + if ((*itr) != nullptr && std::find(printedNodes.begin(), printedNodes.end(), (*itr)) == printedNodes.end()) { + Node *node = *itr; + printedNodes.push_back(*itr); + out << "Node: {"; + for (auto const & state:node->states) { + out << state << "; "; + + } + out << "}" << "\n"; + out << " Address: " << node << "\n"; + out << " Above: {"; + + auto statesAbove = node->statesAbove; + for (auto const & state:(node->statesAbove)) { + out << state << "; "; + } + out << "}" << "\n"; // out << " Below: {"; @@ -349,8 +367,8 @@ namespace storm { // out << "}"; // } // out << "}" << "\n"; -// } -// } + } + } } void Lattice::toDotFile(std::ostream &out) { @@ -399,17 +417,17 @@ namespace storm { // oftewel is er een state in node2.above die met een state in node1 matched bool found = false; for (auto const& state : node1->states) { - found = node2->statesAbove[state]; + found = ((node2->statesAbove))[state]; if (found) { break; } } if (!found && !doneBuilding) { - storm::storage::BitVector statesSeen(node2->statesAbove); - for (auto const &i: node2->statesAbove) { + storm::storage::BitVector statesSeen((node2->statesAbove)); + for (auto const &i: (node2->statesAbove)) { auto nodeI = getNode(i); - if ((nodeI->statesAbove & statesSeen) != nodeI->statesAbove) { + if (((nodeI->statesAbove) & statesSeen) != (nodeI->statesAbove)) { found = above(node1, nodeI, node2, &statesSeen); } if (found) { @@ -428,7 +446,7 @@ namespace storm { // bool found = (node2->statesAbove & node1->states).getNumberOfSetBits() != 0; bool found = false; for (auto const& state : node1->states) { - found = node2->statesAbove[state]; + found = ((node2->statesAbove))[state]; if (found) { break; } @@ -436,19 +454,20 @@ namespace storm { // bool found = !(node2->statesAbove & node1->states).empty(); if (!found) { // TODO: kan dit niet anders? - nodePrev->statesAbove |= node2->statesAbove; - auto complement = (statesSeen->operator~()); + nodePrev->statesAbove|=((node2->statesAbove)); +// auto complement = storm::storage::BitVector(statesSeen->operator~()); - storm::storage::BitVector states = storm::storage::BitVector( - (node2->statesAbove & complement)); - statesSeen->operator|=(node2->statesAbove); +// storm::storage::BitVector states = storm::storage::BitVector(node2->statesAbove & complement); + statesSeen->operator|=(((node2->statesAbove))); - for (auto const &i: states) { + for (auto const &i: node2->statesAbove) { // assert (!statesSeen[i]); - auto nodeI = getNode(i); - if (!(nodeI->statesAbove & complement).empty()) { - found = above(node1, nodeI, node2, statesSeen); - } + if (!(*statesSeen)[i]) { + auto nodeI = getNode(i); + if (((nodeI->statesAbove) & *statesSeen) != (nodeI->statesAbove)) { + found = above(node1, nodeI, node2, statesSeen); + } + } if (found) { break; } @@ -509,7 +528,7 @@ namespace storm { // assert (false); // Merges node2 into node 1 // everything above n2 also above n1 - node1->statesAbove |= node2->statesAbove; + node1->statesAbove|=((node2->statesAbove)); // everything below node 2 also below node 1 // node1->statesBelow |= node2->statesBelow; diff --git a/src/storm-pars/analysis/Lattice.h b/src/storm-pars/analysis/Lattice.h index 64989cb6d..8b66c30db 100644 --- a/src/storm-pars/analysis/Lattice.h +++ b/src/storm-pars/analysis/Lattice.h @@ -123,6 +123,9 @@ namespace storm { bool getDoneBuilding(); + int compare(Node* node1, Node* node2); + + std::vector sortStates(storm::storage::BitVector* states); // /*! @@ -204,7 +207,6 @@ namespace storm { bool above(Node * node1, Node * node2, storm::analysis::Lattice::Node *nodePrev, storm::storage::BitVector *statesSeen); - int compare(Node* node1, Node* node2); std::unordered_map> comparisons; diff --git a/src/storm-pars/analysis/LatticeExtender.cpp b/src/storm-pars/analysis/LatticeExtender.cpp index 4549dfe1c..e1f280a0a 100644 --- a/src/storm-pars/analysis/LatticeExtender.cpp +++ b/src/storm-pars/analysis/LatticeExtender.cpp @@ -367,7 +367,8 @@ namespace storm { } addedStates = lattice->getAddedStates(); - for (auto stateNumber : *addedStates) { + auto notAddedStates = addedStates->operator~(); + for (auto stateNumber : notAddedStates) { // Iterate over all not yet added states storm::storage::BitVector* successors = stateMap[stateNumber]; @@ -392,6 +393,7 @@ namespace storm { } } assert (lattice->getAddedStates()->getNumberOfSetBits() == numberOfStates); + lattice->setDoneBuilding(true); return std::make_tuple(lattice, numberOfStates, numberOfStates); } template class LatticeExtender; diff --git a/src/storm-pars/analysis/MonotonicityChecker.cpp b/src/storm-pars/analysis/MonotonicityChecker.cpp index 1cc60279d..67dbac498 100644 --- a/src/storm-pars/analysis/MonotonicityChecker.cpp +++ b/src/storm-pars/analysis/MonotonicityChecker.cpp @@ -404,7 +404,6 @@ namespace storm { template std::map> MonotonicityChecker::analyseMonotonicity(uint_fast64_t j, storm::analysis::Lattice* lattice, storm::storage::SparseMatrix matrix) { // storm::utility::Stopwatch analyseWatch(true); - lattice->setDoneBuilding(true); std::map> varsMonotone; for (uint_fast64_t i = 0; i < matrix.getColumnCount(); ++i) { @@ -430,10 +429,12 @@ namespace storm { auto sortedStates = lattice->sortStates(states); + assert(sortedStates[sortedStates.size() - 1] != matrix.getColumnCount()); + assert (sortedStates.size() >=2); assert (sortedStates.size() == states->getNumberOfSetBits()); - if (sortedStates[sortedStates.size() - 1] == -1) { + if (sortedStates[sortedStates.size() - 1] == matrix.getColumnCount()) { // auto val = first.getValue(); // auto vars = val.gatherVariables(); for (auto itr = vars.begin(); itr != vars.end(); ++itr) { @@ -498,7 +499,7 @@ namespace storm { } } } else { - bool change = false; + for (auto var : vars) { // if (resultCheckOnSamples.find(*itr) != resultCheckOnSamples.end() && // (!resultCheckOnSamples[*itr].first && !resultCheckOnSamples[*itr].second)) { @@ -512,7 +513,7 @@ namespace storm { varsMonotone[var].second = true; } std::pair *value = &varsMonotone.find(var)->second; - + bool change = false; for (auto const &i : sortedStates) { // auto res = checkDerivative(transitions[i].derivative(var)); auto res = checkDerivative(getDerivative(transitions[i], var)); From b13dbd11f3e9413a3dd7ac4e1897e13aa413d2a5 Mon Sep 17 00:00:00 2001 From: Jip Spel Date: Wed, 6 Feb 2019 20:25:42 +0100 Subject: [PATCH 143/178] Fix for monotonicitychecker --- src/storm-pars/api/region.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/storm-pars/api/region.h b/src/storm-pars/api/region.h index 282c52649..f0315f45d 100644 --- a/src/storm-pars/api/region.h +++ b/src/storm-pars/api/region.h @@ -122,7 +122,7 @@ namespace storm { if (consideredModel->isOfType(storm::models::ModelType::Ctmc) || consideredModel->isOfType(storm::models::ModelType::MarkovAutomaton)) { STORM_LOG_WARN("Parameter lifting not supported for continuous time models. Transforming continuous model to discrete model..."); std::vector> taskFormulaAsVector { task.getFormula().asSharedPointer() }; - consideredModel = storm::api::transformContinuousToDiscreteTimeSparseModel(consideredModel, taskFormulaAsVector); + consideredModel = storm::api::transformContinuousToDiscreteTimeSparseModel(consideredModel, taskFormulaAsVector).first; STORM_LOG_THROW(consideredModel->isOfType(storm::models::ModelType::Dtmc) || consideredModel->isOfType(storm::models::ModelType::Mdp), storm::exceptions::UnexpectedException, "Transformation to discrete time model has failed."); } From ed4f61d3ee4d92d6d32ddc4ea92ea44b18ce50b2 Mon Sep 17 00:00:00 2001 From: Jip Spel Date: Thu, 7 Feb 2019 16:44:00 +0100 Subject: [PATCH 144/178] BIsmulation simplification bisimulation + fix lattice --- src/storm-pars-cli/storm-pars.cpp | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/src/storm-pars-cli/storm-pars.cpp b/src/storm-pars-cli/storm-pars.cpp index 626a27a3c..0aa12c3e0 100644 --- a/src/storm-pars-cli/storm-pars.cpp +++ b/src/storm-pars-cli/storm-pars.cpp @@ -568,6 +568,28 @@ namespace storm { STORM_LOG_THROW(model || input.properties.empty(), storm::exceptions::InvalidSettingsException, "No input model."); + + + if (model) { + auto preprocessingResult = storm::pars::preprocessModel(model, input); + if (preprocessingResult.changed) { + model = preprocessingResult.model; + + if (preprocessingResult.formulas) { + std::vector newProperties; + for (size_t i = 0; i < preprocessingResult.formulas.get().size(); ++i) { + auto formula = preprocessingResult.formulas.get().at(i); + STORM_LOG_ASSERT(i < input.properties.size(), "Index " << i << " greater than number of properties."); + storm::jani::Property property = input.properties.at(i); + newProperties.push_back(storm::jani::Property(property.getName(), formula, property.getUndefinedConstants(), property.getComment())); + } + input.properties = newProperties; + } + + model->printModelInformationToStream(std::cout); + } + } + if (parSettings.isMonotonicityAnalysisSet()) { std::cout << "Hello, Jip1" << std::endl; // Simplify the model @@ -612,7 +634,7 @@ namespace storm { std::cout << "Bye, Jip1" << std::endl; } - if (model) { + if (parSettings.isMonotonicityAnalysisSet() && model) { auto preprocessingResult = storm::pars::preprocessModel(model, input); if (preprocessingResult.changed) { model = preprocessingResult.model; @@ -632,6 +654,7 @@ namespace storm { } } + if (parSettings.isSccEliminationSet()) { storm::utility::Stopwatch eliminationWatch(true); // TODO: check for correct Model type From 0cc82e840aa606fe198c0d22eadc26232e32fa93 Mon Sep 17 00:00:00 2001 From: Jip Spel Date: Fri, 1 Mar 2019 11:00:49 +0100 Subject: [PATCH 145/178] clean up --- src/storm-pars/analysis/Lattice.cpp | 197 +----------------- src/storm-pars/analysis/LatticeExtender.cpp | 25 ++- .../analysis/MonotonicityChecker.cpp | 13 +- 3 files changed, 30 insertions(+), 205 deletions(-) diff --git a/src/storm-pars/analysis/Lattice.cpp b/src/storm-pars/analysis/Lattice.cpp index 7c54a4a85..8c14afe49 100644 --- a/src/storm-pars/analysis/Lattice.cpp +++ b/src/storm-pars/analysis/Lattice.cpp @@ -12,9 +12,6 @@ namespace storm { storm::storage::BitVector* bottomStates, storm::storage::BitVector* initialMiddleStates, uint_fast64_t numberOfStates) { -// assert(topStates->getNumberOfSetBits() != 0); -// assert(bottomStates->getNumberOfSetBits() != 0); -// assert((*topStates & *bottomStates).getNumberOfSetBits() == 0); nodes = std::vector(numberOfStates); this->numberOfStates = numberOfStates; @@ -41,20 +38,12 @@ namespace storm { nodes[i] = bottom; } - -// setStatesBelow(top, bottomStates, false); - -// bottom->statesBelow = storm::storage::BitVector(numberOfStates); -// setStatesAbove(bottom, topStates, false); - - for (auto const &state : *initialMiddleStates) { add(state); } } Lattice::Lattice(Lattice* lattice) { -// assert (false); numberOfStates = lattice->getAddedStates()->size(); nodes = std::vector(numberOfStates); addedStates = new storm::storage::BitVector(numberOfStates); @@ -66,7 +55,6 @@ namespace storm { Node *oldNode = (*itr); if (oldNode != nullptr) { Node *newNode = new Node(); - // TODO: gaat dit goed of moet er een constructor om newNode->states = oldNode->states; for (auto const& i : newNode->states) { addedStates->set(i); @@ -79,36 +67,26 @@ namespace storm { } } } - - assert(addedStates == lattice->getAddedStates()); + assert(*addedStates == *(lattice->getAddedStates())); // set all states above and below for (auto itr = oldNodes.begin(); itr != oldNodes.end(); ++itr) { Node *oldNode = (*itr); - if (oldNode != nullptr && oldNode != lattice->getTop() && oldNode != lattice->getBottom()) { + if (oldNode != nullptr) { Node *newNode = getNode(*(oldNode->states.begin())); newNode->statesAbove = storm::storage::BitVector((oldNode->statesAbove)); -// setStatesAbove(newNode, oldNode->statesAbove, false); -// setStatesBelow(newNode, oldNode->statesBelow, false); - } else if (oldNode != nullptr && oldNode == lattice->getBottom()) { - bottom->statesAbove = storm::storage::BitVector((oldNode->statesAbove)); -// setStatesAbove(bottom, lattice->getBottom()->statesAbove, false); -// bottom->statesBelow = storm::storage::BitVector(numberOfStates); -// } else if (oldNode != nullptr && oldNode == lattice->getTop()) { -// top->statesAbove = storm::storage::BitVector(numberOfStates); -// setStatesBelow(top, lattice->getTop()->statesBelow, false); } } } void Lattice::addBetween(uint_fast64_t state, Node *above, Node *below) { +// std::cout << "Adding " << state << " between " << *(above->states.begin()) << " and " << *(below->states.begin()) << std::endl; assert(!(*addedStates)[state]); assert(compare(above, below) == ABOVE); Node *newNode = new Node(); nodes[state] = newNode; -// newNode->states = storm::storage::BitVector(numberOfStates); newNode->states.insert(state); newNode->statesAbove = storm::storage::BitVector((above->statesAbove)); for (auto const& state : above->states) { @@ -116,38 +94,14 @@ namespace storm { } below->statesAbove.set(state); addedStates->set(state); - -// comparisons[state] = comparisons[above->states.getNextSetIndex(0)]; -// setStatesAbove(newNode, above->statesAbove | above->states, false); -// setStatesBelow(newNode, below->statesBelow | below->states, false); -// setStatesBelow(above, state, true); -// setStatesAbove(below, state, true); - -// for (auto i = below->statesBelow.getNextSetIndex(0); i < below->statesBelow.size(); i = below->statesBelow.getNextSetIndex(i + 1)) { -// setStatesAbove(getNode(i), state, true); -// } -// -// for (auto i = above->statesAbove.getNextSetIndex(0); i < above->statesAbove.size(); i = above->statesAbove.getNextSetIndex(i + 1)) { -// setStatesBelow(getNode(i), state, true); -// } - - } void Lattice::addToNode(uint_fast64_t state, Node *node) { +// std::cout << "Adding " << state << " to " << *(node->states.begin()) << std::endl; assert(!(*addedStates)[state]); node->states.insert(state); nodes[state] = node; addedStates->set(state); -// comparisons[state] = comparisons[node->states.getNextSetIndex(0)]; - -// for (auto i = node->statesBelow.getNextSetIndex(0); i < node->statesBelow.size(); i = node->statesBelow.getNextSetIndex(i + 1)) { -// setStatesAbove(getNode(i), state, true); -// } -// -// for (auto i = node->statesAbove.getNextSetIndex(0); i < node->statesAbove.size(); i = node->statesAbove.getNextSetIndex(i + 1)) { -// setStatesBelow(getNode(i), state, true); -// } } void Lattice::add(uint_fast64_t state) { @@ -157,24 +111,11 @@ namespace storm { void Lattice::addRelationNodes(Lattice::Node *above, Lattice::Node * below) { assert (compare(above, below) == UNKNOWN); - // TODO: welke assert -// assert ((above->statesAbove & below->statesBelow).getNumberOfSetBits() == 0); -// setStatesBelow(above, below->states | below->statesBelow, true); -// setStatesAbove(below, above->states | above->statesAbove, true); for (auto const& state : above->states) { below->statesAbove.set(state); } below->statesAbove|=((above->statesAbove)); - // TODO: comparisons - -// for (auto i = below->statesBelow.getNextSetIndex(0); i < below->statesBelow.size(); i = below->statesBelow.getNextSetIndex(i + 1)) { -// setStatesAbove(getNode(i), above->states | above->statesAbove, true); -// } -// -// for (auto i = above->statesAbove.getNextSetIndex(0); i < above->statesAbove.size(); i = above->statesAbove.getNextSetIndex(i + 1)) { -// setStatesBelow(getNode(i), below->states | below->statesBelow, true); -// } - + assert (compare(above, below) == ABOVE); } int Lattice::compare(uint_fast64_t state1, uint_fast64_t state2) { @@ -187,24 +128,12 @@ namespace storm { return SAME; } -// auto state1 = node1->states.getNextSetIndex(0); -// auto state2 = node2->states.getNextSetIndex(0); -// -// auto mapEntry = comparisons[state1]; -// if (mapEntry.find(state2) != mapEntry.end()) { -// return mapEntry[state2]; -// } - if (above(node1, node2)) { assert(!above(node2, node1)); -// comparisons[state1][state2] = ABOVE; -// comparisons[state2][state1] = BELOW; return ABOVE; } if (above(node2, node1)) { -// comparisons[state1][state2] = BELOW; -// comparisons[state2][state1] = ABOVE; return BELOW; } @@ -254,6 +183,7 @@ namespace storm { } std::vector Lattice::sortStates(storm::storage::BitVector* states) { + // TODO improve auto numberOfSetBits = states->getNumberOfSetBits(); auto stateSize = states->size(); auto result = std::vector(numberOfSetBits, stateSize); @@ -294,39 +224,12 @@ namespace storm { } ++i; } -// if (i < numberOfSetBits && result[i] == stateSize) { -// result[i] = state; -// } } } return result; } -// std::set Lattice::getAbove(uint_fast64_t state) { -// return getAbove(getNode(state)); -// } -// -// std::set Lattice::getBelow(uint_fast64_t state) { -// return getBelow(getNode(state)); -// } -// -// std::set Lattice::getAbove(Lattice::Node* node) { -// std::set result({}); -// for (auto i = node->statesAbove.getNextSetIndex(0); i < node->statesAbove.size(); i = node->statesAbove.getNextSetIndex(i + 1)) { -// result.insert(getNode(i)); -// } -// return result; -// } -// -// std::set Lattice::getBelow(Lattice::Node* node) { -// std::set result({}); -// for (auto i = node->statesBelow.getNextSetIndex(0); i < node->statesBelow.size(); i = node->statesBelow.getNextSetIndex(i + 1)) { -// result.insert(getNode(i)); -// } -// return result; -// } - void Lattice::toString(std::ostream &out) { std::vector printedNodes = std::vector({}); for (auto itr = nodes.begin(); itr != nodes.end(); ++itr) { @@ -348,25 +251,6 @@ namespace storm { out << state << "; "; } out << "}" << "\n"; - - -// out << " Below: {"; -// auto statesBelow = getBelow(node); -// for (auto itr2 = statesBelow.begin(); itr2 != statesBelow.end(); ++itr2) { -// Node *below = *itr2; -// out << "{"; -// index = below->states.getNextSetIndex(0); -// while (index < below->states.size()) { -// out << index; -// index = below->states.getNextSetIndex(index + 1); -// if (index < below->states.size()) { -// out << ", "; -// } -// } -// -// out << "}"; -// } -// out << "}" << "\n"; } } } @@ -413,8 +297,6 @@ namespace storm { bool Lattice::above(Node *node1, Node *node2) { - // ligt node 1 boven node 2 ? - // oftewel is er een state in node2.above die met een state in node1 matched bool found = false; for (auto const& state : node1->states) { found = ((node2->statesAbove))[state]; @@ -443,7 +325,6 @@ namespace storm { bool Lattice::above(storm::analysis::Lattice::Node *node1, storm::analysis::Lattice::Node *node2, storm::analysis::Lattice::Node *nodePrev, storm::storage::BitVector *statesSeen) { -// bool found = (node2->statesAbove & node1->states).getNumberOfSetBits() != 0; bool found = false; for (auto const& state : node1->states) { found = ((node2->statesAbove))[state]; @@ -451,17 +332,12 @@ namespace storm { break; } } -// bool found = !(node2->statesAbove & node1->states).empty(); if (!found) { // TODO: kan dit niet anders? nodePrev->statesAbove|=((node2->statesAbove)); -// auto complement = storm::storage::BitVector(statesSeen->operator~()); - -// storm::storage::BitVector states = storm::storage::BitVector(node2->statesAbove & complement); statesSeen->operator|=(((node2->statesAbove))); for (auto const &i: node2->statesAbove) { -// assert (!statesSeen[i]); if (!(*statesSeen)[i]) { auto nodeI = getNode(i); if (((nodeI->statesAbove) & *statesSeen) != (nodeI->statesAbove)) { @@ -476,78 +352,19 @@ namespace storm { } return found; } -// -// void Lattice::setStatesAbove(Lattice::Node *node, uint_fast64_t state, bool alreadyInitialized) { -// assert (!node->states[state]); -// -// if (!alreadyInitialized) { -// node->statesAbove = storm::storage::BitVector(numberOfStates); -// } -// -// assert (!node->statesBelow[state]); -// node->statesAbove.set(state); -// } -// -// void Lattice::setStatesBelow(Lattice::Node *node, uint_fast64_t state, bool alreadyInitialized) { -// assert (!node->states.get(state)); -// -// if (!alreadyInitialized) { -// node->statesBelow = storm::storage::BitVector(numberOfStates); -// } -// assert (!node->statesAbove[state]); -// node->statesBelow.set(state); -// } -// -// void Lattice::setStatesAbove(Lattice::Node *node, storm::storage::BitVector states, bool alreadyInitialized) { -// assert((states.getNumberOfSetBits() - (node->states & states).getNumberOfSetBits()) != 0); -// // the states to add to the above state of the current node shouldnt occur in either statesbelow or states of ndoe -// -// assert ((node->states & states).getNumberOfSetBits() ==0); -// if (alreadyInitialized) { -// assert ((node->statesBelow & states).getNumberOfSetBits() == 0); -// -// node->statesAbove |= (states); -// } else { -// node->statesAbove = (storm::storage::BitVector(states)); -// } -// } -// -// void Lattice::setStatesBelow(Lattice::Node *node, storm::storage::BitVector states, bool alreadyInitialized) { -// assert((states.getNumberOfSetBits() - (node->states & states).getNumberOfSetBits()) != 0); -// -// assert ((node->states & states).getNumberOfSetBits() ==0); -// if (alreadyInitialized) { -// assert ((node->statesAbove & states).getNumberOfSetBits() == 0); -// node->statesBelow |= (states); -// } else { -// node->statesBelow = (storm::storage::BitVector(states)); -// } -// } void Lattice::mergeNodes(storm::analysis::Lattice::Node *node1, storm::analysis::Lattice::Node *node2) { -// assert (false); // Merges node2 into node 1 // everything above n2 also above n1 node1->statesAbove|=((node2->statesAbove)); // everything below node 2 also below node 1 -// node1->statesBelow |= node2->statesBelow; // add states of node 2 to node 1 node1->states.insert(node2->states.begin(), node2->states.end()); + for(auto const& i : node2->states) { nodes[i] = node1; } - -// // Add all states of combined node to states Above of all states Below of node1 -// for (auto i = node1->statesBelow.getNextSetIndex(0); i < node1->statesBelow.size(); i= node1->statesBelow.getNextSetIndex(i+1)) { -// getNode(i)->statesAbove |= node1->states | node1->statesAbove; -// } - - // Add all states of combined node to states Below of all states Above of node1 -// for (auto i = node1->statesAbove.getNextSetIndex(0); i < node1->statesAbove.size(); i= node1->statesAbove.getNextSetIndex(i+1)) { -// getNode(i)->statesBelow |= node1->states | node1->statesBelow; -// } - } } } diff --git a/src/storm-pars/analysis/LatticeExtender.cpp b/src/storm-pars/analysis/LatticeExtender.cpp index e1f280a0a..0e48ac600 100644 --- a/src/storm-pars/analysis/LatticeExtender.cpp +++ b/src/storm-pars/analysis/LatticeExtender.cpp @@ -241,6 +241,7 @@ namespace storm { std::tuple LatticeExtender::extendLattice(Lattice* lattice, std::shared_ptr assumption) { auto numberOfStates = this->model->getNumberOfStates(); + if (assumption != nullptr) { handleAssumption(lattice, assumption); } @@ -337,7 +338,14 @@ namespace storm { auto succ2 = successors->getNextSetIndex(succ1 + 1); assert ((*addedStates)[stateNumber]); - if (successors->getNumberOfSetBits() == 2 + if (successors->getNumberOfSetBits() == 1) { + if (!(*addedStates)[succ1]) { + lattice->addToNode(succ1, lattice->getNode(stateNumber)); + statesToHandle->set(succ1, true); + } + statesToHandle->set(stateNumber, false); + stateNumber = statesToHandle->getNextSetIndex(0); + } else if (successors->getNumberOfSetBits() == 2 && (((*(addedStates))[succ1] && !(*(addedStates))[succ2]) || (!(*(addedStates))[succ1] && (*(addedStates))[succ2]))) { @@ -348,19 +356,24 @@ namespace storm { auto compare = lattice->compare(stateNumber, succ1); if (compare == Lattice::ABOVE) { lattice->addBetween(succ2, lattice->getTop(), lattice->getNode(stateNumber)); + statesToHandle->set(succ2); + statesToHandle->set(stateNumber, false); + stateNumber = statesToHandle->getNextSetIndex(0); } else if (compare == Lattice::BELOW) { lattice->addBetween(succ2, lattice->getNode(stateNumber), lattice->getBottom()); + statesToHandle->set(succ2); + statesToHandle->set(stateNumber, false); + stateNumber = statesToHandle->getNextSetIndex(0); } else { - assert(false); + // We don't know positions, so we set the current state number to false + statesToHandle->set(stateNumber, false); + stateNumber = statesToHandle->getNextSetIndex(0); } - statesToHandle->set(succ2); - statesToHandle->set(stateNumber, false); - stateNumber = statesToHandle->getNextSetIndex(0); + } else if (!(((*(addedStates))[succ1] && !(*(addedStates))[succ2]) || (!(*(addedStates))[succ1] && (*(addedStates))[succ2]))) { stateNumber = statesToHandle->getNextSetIndex(stateNumber + 1); } else { - assert (successors->getNumberOfSetBits() == 2); statesToHandle->set(stateNumber, false); stateNumber = statesToHandle->getNextSetIndex(0); } diff --git a/src/storm-pars/analysis/MonotonicityChecker.cpp b/src/storm-pars/analysis/MonotonicityChecker.cpp index 67dbac498..55568ab45 100644 --- a/src/storm-pars/analysis/MonotonicityChecker.cpp +++ b/src/storm-pars/analysis/MonotonicityChecker.cpp @@ -429,14 +429,8 @@ namespace storm { auto sortedStates = lattice->sortStates(states); - assert(sortedStates[sortedStates.size() - 1] != matrix.getColumnCount()); - - assert (sortedStates.size() >=2); - - assert (sortedStates.size() == states->getNumberOfSetBits()); - if (sortedStates[sortedStates.size() - 1] == matrix.getColumnCount()) { -// auto val = first.getValue(); -// auto vars = val.gatherVariables(); + if (sortedStates[sortedStates.size() - 1] == matrix.getColumnCount()) {\ + // states are not properly sorted for (auto itr = vars.begin(); itr != vars.end(); ++itr) { // if (resultCheckOnSamples.find(*itr) != resultCheckOnSamples.end() && // (!resultCheckOnSamples[*itr].first && !resultCheckOnSamples[*itr].second)) { @@ -453,7 +447,7 @@ namespace storm { std::pair old = *value; - // states are not properly sorted + for (auto itr2 = transitions.begin(); itr2 != transitions.end(); ++itr2) { for (auto itr3 = transitions.begin(); itr3 != transitions.end(); ++itr3) { if (itr2->first < itr3->first) { @@ -486,6 +480,7 @@ namespace storm { value->first &= mon3.first; value->second &= mon3.second; } else if (compare == storm::analysis::Lattice::SAME) { + assert (false); // TODO: klopt dit // Behaviour doesn't matter, as the states are at the same level. } else { From a35cb2643a8e094bf64b4e9fb4a2d44805131e69 Mon Sep 17 00:00:00 2001 From: Jip Spel Date: Tue, 9 Apr 2019 15:07:16 +0200 Subject: [PATCH 146/178] Extend error message --- src/storm/generator/PrismNextStateGenerator.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/storm/generator/PrismNextStateGenerator.cpp b/src/storm/generator/PrismNextStateGenerator.cpp index 8a7030b17..c368a976d 100644 --- a/src/storm/generator/PrismNextStateGenerator.cpp +++ b/src/storm/generator/PrismNextStateGenerator.cpp @@ -107,7 +107,8 @@ namespace storm { #ifdef STORM_HAVE_CARL else if (std::is_same::value && !program.undefinedConstantsAreGraphPreserving()) { - STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "The program contains undefined constants that appear in some places other than update probabilities and reward value expressions, which is not admitted."); + auto undef = program.getUndefinedConstantsAsString(); + STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "The program contains undefined constants that appear in some places other than update probabilities and reward value expressions, which is not admitted. Undefined constants are: " << undef); } #endif } From f6ea4d38bbf5d16e38c75e596454e166811102d1 Mon Sep 17 00:00:00 2001 From: Jip Spel Date: Thu, 2 May 2019 12:37:36 +0200 Subject: [PATCH 147/178] Fix assumption making and checking and testing --- resources/examples/testfiles/pdtmc/simple1.pm | 17 + resources/examples/testfiles/pdtmc/simple2.pm | 17 + resources/examples/testfiles/pdtmc/simple3.pm | 18 + src/storm-pars-cli/storm-pars.cpp | 12 +- src/storm-pars/analysis/AssumptionChecker.cpp | 355 ++++++++---------- src/storm-pars/analysis/AssumptionChecker.h | 51 +-- src/storm-pars/analysis/AssumptionMaker.cpp | 28 +- src/storm-pars/analysis/AssumptionMaker.h | 7 +- src/storm-pars/analysis/Lattice.cpp | 10 +- src/storm-pars/analysis/Lattice.h | 55 +-- src/storm-pars/analysis/LatticeExtender.cpp | 68 +++- .../analysis/MonotonicityChecker.cpp | 291 ++++++++------ src/storm-pars/analysis/MonotonicityChecker.h | 71 +++- .../RationalFunctionToExpression.cpp | 2 +- .../analysis/AssumptionCheckerTest.cpp | 194 +++++++++- .../analysis/AssumptionMakerTest.cpp | 197 ++++++++-- 16 files changed, 911 insertions(+), 482 deletions(-) create mode 100644 resources/examples/testfiles/pdtmc/simple1.pm create mode 100644 resources/examples/testfiles/pdtmc/simple2.pm create mode 100644 resources/examples/testfiles/pdtmc/simple3.pm diff --git a/resources/examples/testfiles/pdtmc/simple1.pm b/resources/examples/testfiles/pdtmc/simple1.pm new file mode 100644 index 000000000..597da690d --- /dev/null +++ b/resources/examples/testfiles/pdtmc/simple1.pm @@ -0,0 +1,17 @@ +dtmc + +const double p; + +module test + + // local state + s : [0..4] init 0; + + [] s=0 -> p : (s'=1) + (1-p) : (s'=2); + [] s=1 -> p : (s'=3) + (1-p) : (s'=4); + [] s=2 -> p : (s'=4) + (1-p) : (s'=3); + [] s=3 -> 1 : (s'=3); + [] s=4 -> 1 : (s'=4); + +endmodule + diff --git a/resources/examples/testfiles/pdtmc/simple2.pm b/resources/examples/testfiles/pdtmc/simple2.pm new file mode 100644 index 000000000..33002c6ce --- /dev/null +++ b/resources/examples/testfiles/pdtmc/simple2.pm @@ -0,0 +1,17 @@ +dtmc + +const double p; + +module test + + // local state + s : [0..4] init 0; + + [] s=0 -> p : (s'=1) + (1-p) : (s'=2); + [] s=1 -> p : (s'=3) + (1-p) : (s'=4); + [] s=2 -> 0.5*p : (s'=3) + (1-0.5*p) : (s'=4); + [] s=3 -> 1 : (s'=3); + [] s=4 -> 1 : (s'=4); + +endmodule + diff --git a/resources/examples/testfiles/pdtmc/simple3.pm b/resources/examples/testfiles/pdtmc/simple3.pm new file mode 100644 index 000000000..18f515800 --- /dev/null +++ b/resources/examples/testfiles/pdtmc/simple3.pm @@ -0,0 +1,18 @@ +dtmc + +const double p; + +module test + + // local state + s : [0..5] init 0; + + [] s=0 -> 0.4*p : (s'=1) + (1-p) : (s'=2) + 0.6*p : (s'=3); + [] s=1 -> 0.5*p : (s'=4) + 0.5*p : (s'=3) + (1-p) : (s'=5); + [] s=2 -> 0.3*p : (s'=4) + (1-0.3*p) : (s'=5); + [] s=3 -> 0.7*p : (s'=4) + (1-0.7*p) : (s'=5); + [] s=4 -> 1 : (s'=4); + [] s=5 -> 1 : (s'=5); + +endmodule + diff --git a/src/storm-pars-cli/storm-pars.cpp b/src/storm-pars-cli/storm-pars.cpp index 5cd1801a3..01fa208e2 100644 --- a/src/storm-pars-cli/storm-pars.cpp +++ b/src/storm-pars-cli/storm-pars.cpp @@ -596,14 +596,12 @@ namespace storm { } if (parSettings.isMonotonicityAnalysisSet()) { - std::cout << "Hello, Jip1" << std::endl; // Simplify the model storm::utility::Stopwatch simplifyingWatch(true); std::ofstream outfile; outfile.open("results.txt", std::ios_base::app); outfile << ioSettings.getPrismInputFilename() << ", "; - if (model->isOfType(storm::models::ModelType::Dtmc)) { auto consideredModel = (model->as>()); auto simplifier = storm::transformer::SparseParametricDtmcSimplifier>(*consideredModel); @@ -635,8 +633,6 @@ namespace storm { model->printModelInformationToStream(std::cout); outfile << simplifyingWatch << ", "; outfile.close(); - - std::cout << "Bye, Jip1" << std::endl; } if (parSettings.isMonotonicityAnalysisSet() && model) { @@ -668,7 +664,8 @@ namespace storm { auto matrix = sparseModel->getTransitionMatrix(); auto backwardsTransitionMatrix = matrix.transpose(); - auto decomposition = storm::storage::StronglyConnectedComponentDecomposition(matrix, false, false); + storm::storage::StronglyConnectedComponentDecompositionOptions const options; + auto decomposition = storm::storage::StronglyConnectedComponentDecomposition(matrix, options); storm::storage::BitVector selectedStates(matrix.getRowCount()); storm::storage::BitVector selfLoopStates(matrix.getRowCount()); @@ -724,8 +721,6 @@ namespace storm { } if (parSettings.isMonotonicityAnalysisSet()) { - std::cout << "Hello, Jip2" << std::endl; - std::vector> formulas = storm::api::extractFormulasFromProperties(input.properties); // Monotonicity @@ -740,9 +735,6 @@ namespace storm { outfile << monotonicityWatch << std::endl; outfile.close(); - std::cout << "Bye, Jip2" << std::endl; - - return; } std::vector> regions = parseRegions(model); diff --git a/src/storm-pars/analysis/AssumptionChecker.cpp b/src/storm-pars/analysis/AssumptionChecker.cpp index e27cd2610..fb7a8b9a8 100644 --- a/src/storm-pars/analysis/AssumptionChecker.cpp +++ b/src/storm-pars/analysis/AssumptionChecker.cpp @@ -5,6 +5,7 @@ #include "AssumptionChecker.h" #include "storm-pars/utility/ModelInstantiator.h" +#include "storm-pars/analysis/MonotonicityChecker.h" #include "storm/environment/Environment.h" #include "storm/exceptions/NotSupportedException.h" @@ -16,8 +17,8 @@ #include "storm/storage/expressions/SimpleValuation.h" #include "storm/storage/expressions/ExpressionManager.h" #include "storm/storage/expressions/VariableExpression.h" -#include "storm/utility/constants.h" #include "storm/storage/expressions/RationalFunctionToExpression.h" +#include "storm/utility/constants.h" namespace storm { namespace analysis { @@ -30,6 +31,8 @@ namespace storm { auto instantiator = storm::utility::ModelInstantiator, storm::models::sparse::Dtmc>(*model); auto matrix = model->getTransitionMatrix(); std::set variables = storm::models::sparse::getProbabilityParameters(*model); + + // TODO: sampling part also done in MonotonicityChecker, would be better to use this one instead of creating it again for (auto i = 0; i < numberOfSamples; ++i) { auto valuation = storm::utility::parametric::Valuation(); for (auto itr = variables.begin(); itr != variables.end(); ++itr) { @@ -57,7 +60,7 @@ namespace storm { } auto quantitativeResult = checkResult->asExplicitQuantitativeCheckResult(); std::vector values = quantitativeResult.getValueVector(); - results.push_back(values); + samples.push_back(values); } } @@ -70,6 +73,8 @@ namespace storm { auto instantiator = storm::utility::ModelInstantiator, storm::models::sparse::Mdp>(*model); auto matrix = model->getTransitionMatrix(); std::set variables = storm::models::sparse::getProbabilityParameters(*model); + + // TODO: sampling part also done in MonotonicityChecker, would be better to use this one instead of creating it again for (auto i = 0; i < numberOfSamples; ++i) { auto valuation = storm::utility::parametric::Valuation(); for (auto itr = variables.begin(); itr != variables.end(); ++itr) { @@ -96,48 +101,62 @@ namespace storm { } auto quantitativeResult = checkResult->asExplicitQuantitativeCheckResult(); std::vector values = quantitativeResult.getValueVector(); - results.push_back(values); + samples.push_back(values); } } template - bool AssumptionChecker::checkOnSamples(std::shared_ptr assumption) { - bool result = true; + AssumptionStatus AssumptionChecker::checkOnSamples(std::shared_ptr assumption) { + auto result = AssumptionStatus::UNKNOWN; std::set vars = std::set({}); assumption->gatherVariables(vars); - for (auto itr = results.begin(); result && itr != results.end(); ++itr) { + for (auto itr = samples.begin(); result == AssumptionStatus::UNKNOWN && itr != samples.end(); ++itr) { std::shared_ptr manager = assumption->getManager().getSharedPointer(); auto valuation = storm::expressions::SimpleValuation(manager); auto values = (*itr); - for (auto var = vars.begin(); result && var != vars.end(); ++var) { + for (auto var = vars.begin(); result == AssumptionStatus::UNKNOWN && var != vars.end(); ++var) { storm::expressions::Variable par = *var; auto index = std::stoi(par.getName()); valuation.setRationalValue(par, values[index]); } assert(assumption->hasBooleanType()); - result &= assumption->evaluateAsBool(&valuation); + if (!assumption->evaluateAsBool(&valuation)) { + result = AssumptionStatus::INVALID; + } } return result; } template - bool AssumptionChecker::validateAssumption(std::shared_ptr assumption, storm::analysis::Lattice* lattice) { - bool result = validated(assumption); - if (!result) { + AssumptionStatus AssumptionChecker::validateAssumption(std::shared_ptr assumption, storm::analysis::Lattice* lattice) { + // First check if based on sample points the assumption can be discharged + auto result = checkOnSamples(assumption); + assert (result != storm::analysis::AssumptionStatus::VALID); + + if (result == storm::analysis::AssumptionStatus::UNKNOWN) { + // If result from sample checking was unknown, the assumption might hold, so we continue, + // otherwise we return INVALID std::set vars = std::set({}); assumption->gatherVariables(vars); STORM_LOG_THROW(assumption->getRelationType() == - storm::expressions::BinaryRelationExpression::RelationType::Greater ||assumption->getRelationType() == - storm::expressions::BinaryRelationExpression::RelationType::Equal, + storm::expressions::BinaryRelationExpression::RelationType::Greater || + assumption->getRelationType() == + storm::expressions::BinaryRelationExpression::RelationType::Equal, storm::exceptions::NotSupportedException, "Only Greater Or Equal assumptions supported"); - // TODO: implement validation of equal/greater equations - auto row1 = matrix.getRow(std::stoi(assumption->getFirstOperand()->asVariableExpression().getVariableName())); - auto row2 = matrix.getRow(std::stoi(assumption->getSecondOperand()->asVariableExpression().getVariableName())); + // Row with successors of the first state + auto row1 = matrix.getRow( + std::stoi(assumption->getFirstOperand()->asVariableExpression().getVariableName())); + // Row with successors of the second state + auto row2 = matrix.getRow( + std::stoi(assumption->getSecondOperand()->asVariableExpression().getVariableName())); if (row1.getNumberOfEntries() == 2 && row2.getNumberOfEntries() == 2) { + // If the states have the same successors for which we know the position in the lattice + // We can check with a function if the assumption holds + auto state1succ1 = row1.begin(); auto state1succ2 = (++row1.begin()); auto state2succ1 = row2.begin(); @@ -149,63 +168,33 @@ namespace storm { } if (state1succ1->getColumn() == state2succ1->getColumn() && state1succ2->getColumn() == state2succ2->getColumn()) { - auto comp = lattice->compare(state1succ1->getColumn(), state1succ2->getColumn()); - if (comp != storm::analysis::Lattice::UNKNOWN) { + if (assumption->getRelationType() == storm::expressions::BinaryRelationExpression::RelationType::Greater + && lattice->compare(state1succ1->getColumn(), state1succ2->getColumn()) != storm::analysis::Lattice::UNKNOWN) { + // The assumption should be the greater assumption + // If the result is unknown, we cannot compare, also SMTSolver will not help result = validateAssumptionFunction(lattice, state1succ1, state1succ2, state2succ1, state2succ2); - - if (!result) { - result = validateAssumptionSMTSolver(lattice, state1succ1, state1succ2, state2succ1, - state2succ2); - } - - validatedAssumptions.insert(assumption); - if (result) { - validAssumptions.insert(assumption); + } else if (assumption->getRelationType() == storm::expressions::BinaryRelationExpression::RelationType::Equal) { + // The assumption is equal, the successors are the same, + // so if the probability of reaching the successors is the same, we have a valid assumption + if (state1succ1->getValue() == state2succ1->getValue()) { + result = AssumptionStatus::VALID; } + } else { + result = AssumptionStatus::UNKNOWN; } + } else { + result = validateAssumptionSMTSolver(lattice, assumption); } } else { - bool subset = true; - - if (row1.getNumberOfEntries() > row2.getNumberOfEntries()) { - std::swap(row1, row2); - } - storm::storage::BitVector stateNumbers(matrix.getColumnCount()); - for (auto itr1 = row1.begin(); subset && itr1 != row1.end(); ++itr1) { - bool found = false; - stateNumbers.set(itr1->getColumn()); - for (auto itr2 = row2.begin(); !found && itr2 != row2.end(); ++itr2) { - found = itr1->getColumn() == itr2->getColumn(); - } - subset &= found; - } - - if (subset) { - // Check if they all are in the lattice - bool allInLattice = true; - for (auto i = stateNumbers.getNextSetIndex(0); allInLattice && i < stateNumbers.size(); i = stateNumbers.getNextSetIndex(i+1)) { - for (auto j = stateNumbers.getNextSetIndex(i+1); allInLattice && j < stateNumbers.size(); j = stateNumbers.getNextSetIndex(j+1)) { - auto comp = lattice->compare(i,j); - allInLattice &= comp == storm::analysis::Lattice::ABOVE || comp == storm::analysis::Lattice::BELOW || comp == storm::analysis::Lattice::SAME; - } - } - - if (allInLattice) { - result = validateAssumptionSMTSolver(lattice, assumption); - validatedAssumptions.insert(assumption); - if (result) { - validAssumptions.insert(assumption); - } - } - } + result = validateAssumptionSMTSolver(lattice, assumption); } } return result; } template - bool AssumptionChecker::validateAssumptionFunction(storm::analysis::Lattice* lattice, + AssumptionStatus AssumptionChecker::validateAssumptionFunction(storm::analysis::Lattice* lattice, typename storm::storage::SparseMatrix::iterator state1succ1, typename storm::storage::SparseMatrix::iterator state1succ2, typename storm::storage::SparseMatrix::iterator state2succ1, @@ -215,8 +204,9 @@ namespace storm { || (state1succ1->getColumn() == state2succ2->getColumn() && state1succ2->getColumn() == state2succ1->getColumn())); - bool result = true; + AssumptionStatus result; + // Calculate the difference in probability for the "highest" successor state ValueType prob; auto comp = lattice->compare(state1succ1->getColumn(), state1succ2->getColumn()); assert (comp == storm::analysis::Lattice::ABOVE || comp == storm::analysis::Lattice::BELOW); @@ -227,187 +217,136 @@ namespace storm { } auto vars = prob.gatherVariables(); - + + // If the result in monotone increasing (decreasing), then choose 0 (1) for the substitutions + // This will give the smallest result // TODO: Type std::map substitutions; for (auto var : vars) { - auto derivative = prob.derivative(var); - if(derivative.isConstant()) { - if (derivative.constantPart() >= 0) { - substitutions[var] = 0; - } else if (derivative.constantPart() <= 0) { - substitutions[var] = 1; - } + auto monotonicity = MonotonicityChecker::checkDerivative(prob.derivative(var)); + if (monotonicity.first) { + // monotone increasing + substitutions[var] = 0; + } else if (monotonicity.second) { + // monotone increasing + substitutions[var] = 1; } else { - result = false; + result = AssumptionStatus::UNKNOWN; } } -// return result && prob.evaluate(substitutions) >= 0; -//TODO check for > and = - return false; - } - template - bool AssumptionChecker::validateAssumptionSMTSolver(storm::analysis::Lattice* lattice, - typename storm::storage::SparseMatrix::iterator state1succ1, - typename storm::storage::SparseMatrix::iterator state1succ2, - typename storm::storage::SparseMatrix::iterator state2succ1, - typename storm::storage::SparseMatrix::iterator state2succ2) { - assert((state1succ1->getColumn() == state2succ1->getColumn() - && state1succ2->getColumn() == state2succ2->getColumn()) - || (state1succ1->getColumn() == state2succ2->getColumn() - && state1succ2->getColumn() == state2succ1->getColumn())); - std::shared_ptr smtSolverFactory = std::make_shared(); - std::shared_ptr manager( - new storm::expressions::ExpressionManager()); - - storm::solver::Z3SmtSolver s(*manager); - storm::solver::SmtSolver::CheckResult smtResult = storm::solver::SmtSolver::CheckResult::Unknown; - - storm::expressions::Variable succ1 = manager->declareRationalVariable(std::to_string(state1succ1->getColumn())); - storm::expressions::Variable succ2 = manager->declareRationalVariable(std::to_string(state1succ2->getColumn())); - auto comp = lattice->compare(state1succ1->getColumn(), state1succ2->getColumn()); - - storm::expressions::Expression exprGiven; - if (comp == storm::analysis::Lattice::ABOVE) { - exprGiven = succ1 >= succ2; - } else if (comp == storm::analysis::Lattice::BELOW) { - exprGiven = succ1 <= succ2; - } else { - assert (comp != storm::analysis::Lattice::UNKNOWN); - exprGiven = succ1 = succ2; + if (prob.evaluate(substitutions) >= 0) { + result = AssumptionStatus::VALID; } - - auto valueTypeToExpression = storm::expressions::RationalFunctionToExpression(manager); - storm::expressions::Expression exprToCheck = - (valueTypeToExpression.toExpression(state1succ1->getValue())*succ1 - + valueTypeToExpression.toExpression(state1succ2->getValue())*succ2 - >= valueTypeToExpression.toExpression(state2succ1->getValue())*succ1 - + valueTypeToExpression.toExpression(state2succ2->getValue())*succ2); - - storm::expressions::Expression exprBounds = manager->boolean(true); - auto variables = manager->getVariables(); - for (auto var : variables) { - if (var != succ1 && var != succ2) { - // ensure graph-preserving - exprBounds = exprBounds && manager->rational(0) <= var && manager->rational(1) >= var; - } else { - exprBounds = exprBounds && var >= manager->rational(0) && var <= manager->rational(1); - } - } - - s.add(exprGiven); - s.add(exprToCheck); - s.add(exprBounds); - smtResult = s.check(); - -// return smtResult == storm::solver::SmtSolver::CheckResult::Sat; -//TODO check for > and = - return false; + return result; } - template - bool AssumptionChecker::validateAssumptionSMTSolver(storm::analysis::Lattice* lattice, std::shared_ptr assumption) { - assert (!validated(assumption)); + template + AssumptionStatus AssumptionChecker::validateAssumptionSMTSolver(storm::analysis::Lattice* lattice, std::shared_ptr assumption) { std::shared_ptr smtSolverFactory = std::make_shared(); std::shared_ptr manager(new storm::expressions::ExpressionManager()); - bool result = true; - auto row1 = matrix.getRow(std::stoi(assumption->getFirstOperand()->asVariableExpression().getVariableName())); - auto row2 = matrix.getRow(std::stoi(assumption->getSecondOperand()->asVariableExpression().getVariableName())); + AssumptionStatus result; + auto var1 = assumption->getFirstOperand()->asVariableExpression().getVariableName(); + auto var2 = assumption->getSecondOperand()->asVariableExpression().getVariableName(); + auto row1 = matrix.getRow(std::stoi(var1)); + auto row2 = matrix.getRow(std::stoi(var2)); - storm::solver::Z3SmtSolver s(*manager); + bool orderKnown = true; + // Check if the order between the different successors is known + // Also start creating expression for order of states + storm::expressions::Expression exprOrderSucc = manager->boolean(true); std::set stateVariables; - if (row1.getNumberOfEntries() >= row2.getNumberOfEntries()) { - for (auto itr = row1.begin(); itr != row1.end(); ++itr) { - stateVariables.insert(manager->declareRationalVariable(std::to_string(itr->getColumn()))); + for (auto itr1 = row1.begin(); orderKnown && itr1 != row1.end(); ++itr1) { + auto varname1 = "s" + std::to_string(itr1->getColumn()); + if (!manager->hasVariable(varname1)) { + stateVariables.insert(manager->declareRationalVariable(varname1)); } - } else { - for (auto itr = row2.begin(); itr != row2.end(); ++itr) { - stateVariables.insert(manager->declareRationalVariable(std::to_string(itr->getColumn()))); - } - } - - storm::expressions::Expression exprGiven = manager->boolean(true); - - for (auto itr1 = row1.begin(); result && itr1 != row1.end(); ++itr1) { - for (auto itr2 = row1.begin(); result && itr2 != row1.end(); ++itr2) { + for (auto itr2 = row2.begin(); orderKnown && itr2 != row2.end(); ++itr2) { if (itr1->getColumn() != itr2->getColumn()) { + auto varname2 = "s" + std::to_string(itr2->getColumn()); + if (!manager->hasVariable(varname2)) { + stateVariables.insert(manager->declareRationalVariable(varname2)); + } auto comp = lattice->compare(itr1->getColumn(), itr2->getColumn()); - if (comp == storm::analysis::Lattice::ABOVE) { - exprGiven = exprGiven && (manager->getVariable(std::to_string(itr1->getColumn())) >= - manager->getVariable(std::to_string(itr2->getColumn()))); + exprOrderSucc = exprOrderSucc && !(manager->getVariable(varname1) <= + manager->getVariable(varname2)); } else if (comp == storm::analysis::Lattice::BELOW) { - exprGiven = exprGiven && (manager->getVariable(std::to_string(itr1->getColumn())) <= - manager->getVariable(std::to_string(itr2->getColumn()))); + exprOrderSucc = exprOrderSucc && !(manager->getVariable(varname1) >= + manager->getVariable(varname2)); + } else if (comp == storm::analysis::Lattice::SAME) { + exprOrderSucc = exprOrderSucc && + (manager->getVariable(varname1) = manager->getVariable(varname2)); } else { - assert (comp != storm::analysis::Lattice::UNKNOWN); - exprGiven = exprGiven && - (manager->getVariable(std::to_string(itr1->getColumn())) = manager->getVariable( - std::to_string(itr2->getColumn()))); + orderKnown = false; } } } } - auto valueTypeToExpression = storm::expressions::RationalFunctionToExpression(manager); - storm::expressions::Expression expr1 = manager->rational(0); - for (auto itr1 = row1.begin(); result && itr1 != row1.end(); ++itr1) { - expr1 = expr1 + (valueTypeToExpression.toExpression(itr1->getValue()) * manager->getVariable(std::to_string(itr1->getColumn()))); - } - - storm::expressions::Expression expr2 = manager->rational(0); - for (auto itr2 = row2.begin(); result && itr2 != row2.end(); ++itr2) { - expr2 = expr2 + (valueTypeToExpression.toExpression(itr2->getValue()) * manager->getVariable(std::to_string(itr2->getColumn()))); - } - storm::expressions::Expression exprToCheck = expr1 >= expr2; + if (orderKnown) { + storm::solver::Z3SmtSolver s(*manager); + auto valueTypeToExpression = storm::expressions::RationalFunctionToExpression(manager); + storm::expressions::Expression expr1 = manager->rational(0); + for (auto itr1 = row1.begin(); itr1 != row1.end(); ++itr1) { + expr1 = expr1 + (valueTypeToExpression.toExpression(itr1->getValue()) * manager->getVariable("s" + std::to_string(itr1->getColumn()))); + } - storm::expressions::Expression exprProb1 = manager->rational(0); - for (auto itr1 = row1.begin(); result && itr1 != row1.end(); ++itr1) { - exprProb1 = exprProb1 + (valueTypeToExpression.toExpression(itr1->getValue())); - } + storm::expressions::Expression expr2 = manager->rational(0); + for (auto itr2 = row2.begin(); itr2 != row2.end(); ++itr2) { + expr2 = expr2 + (valueTypeToExpression.toExpression(itr2->getValue()) * manager->getVariable("s" + std::to_string(itr2->getColumn()))); + } - storm::expressions::Expression exprProb2 = manager->rational(0); - for (auto itr2 = row2.begin(); result && itr2 != row2.end(); ++itr2) { - exprProb2 = exprProb2 + (valueTypeToExpression.toExpression(itr2->getValue())); - } + // Create expression for the assumption based on the relation to successors + // It is the negation of actual assumption + // TODO: use same manager s.t. assumption can be used directly ? + storm::expressions::Expression exprToCheck ; + if (assumption->getRelationType() == + storm::expressions::BinaryRelationExpression::RelationType::Greater) { + exprToCheck = expr1 <= expr2; + } else { + assert (assumption->getRelationType() == + storm::expressions::BinaryRelationExpression::RelationType::Equal); + exprToCheck = expr1 > expr2; + } - storm::expressions::Expression exprBounds = exprProb1 >= manager->rational(0) - && exprProb1 <= manager->rational(1) - && exprProb2 >= manager->rational(0) - && exprProb2 <= manager->rational(1); + auto variables = manager->getVariables(); + // Bounds for the state probabilities and parameters + storm::expressions::Expression exprBounds = manager->boolean(true); + for (auto var : variables) { + if (find(stateVariables.begin(), stateVariables.end(), var) != stateVariables.end()) { + // the var is a state + exprBounds = exprBounds && manager->rational(0) <= var && var <= manager->rational(1); + } else { + // the var is a parameter + // TODO: graph-preserving + exprBounds = exprBounds && manager->rational(0) < var && var < manager->rational(1); + } + } - auto variables = manager->getVariables(); - for (auto var : variables) { - if (find(stateVariables.begin(), stateVariables.end(), var) != stateVariables.end()) { - // ensure graph-preserving - exprBounds = exprBounds && manager->rational(0) <= var && manager->rational(1) >= var; + s.add(exprOrderSucc); + s.add(exprBounds); + // assert that sorting of successors in the lattice and the bounds on the expression are at least satisfiable + assert (s.check() == storm::solver::SmtSolver::CheckResult::Sat); + // TODO: kijken of t SAT moet zijn? + s.add(exprToCheck); + auto smtRes = s.check(); + if (smtRes == storm::solver::SmtSolver::CheckResult::Unsat) { + // If there is no thing satisfying the negation we are safe. + result = AssumptionStatus::VALID; + } else if (smtRes == storm::solver::SmtSolver::CheckResult::Sat) { + assert (smtRes == storm::solver::SmtSolver::CheckResult::Sat); + result = AssumptionStatus::INVALID; } else { - exprBounds = exprBounds && var >= manager->rational(0) && var <= manager->rational(1); + result = AssumptionStatus::UNKNOWN; } + } else { + result = AssumptionStatus::UNKNOWN; } - s.add(exprGiven); - s.add(exprBounds); - assert(s.check() == storm::solver::SmtSolver::CheckResult::Sat); - s.add(exprToCheck); - auto smtRes = s.check(); - //TODO check for > and = - result = result && smtRes == storm::solver::SmtSolver::CheckResult::Sat; - return false; - } - - template - bool AssumptionChecker::validated(std::shared_ptr assumption) { - return find(validatedAssumptions.begin(), validatedAssumptions.end(), assumption) != validatedAssumptions.end(); - } - - template - bool AssumptionChecker::valid(std::shared_ptr assumption) { - assert(find(validatedAssumptions.begin(), validatedAssumptions.end(), assumption) != validatedAssumptions.end()); - return find(validAssumptions.begin(), validAssumptions.end(), assumption) != validAssumptions.end(); + return result; } template class AssumptionChecker; diff --git a/src/storm-pars/analysis/AssumptionChecker.h b/src/storm-pars/analysis/AssumptionChecker.h index 9ad2aee08..5cde2df72 100644 --- a/src/storm-pars/analysis/AssumptionChecker.h +++ b/src/storm-pars/analysis/AssumptionChecker.h @@ -14,9 +14,19 @@ namespace storm { namespace analysis { + enum AssumptionStatus { + VALID, + INVALID, + UNKNOWN, + }; template class AssumptionChecker { public: + /*! + * Constants for status of assumption + */ + + /*! * Constructs an AssumptionChecker based on the number of samples, for the given formula and model. * @@ -39,60 +49,37 @@ namespace storm { * Checks if the assumption holds at the sample points of the AssumptionChecker. * * @param assumption The assumption to check. - * @return true if the assumption holds at the sample points + * @return AssumptionStatus::UNKNOWN or AssumptionStatus::INVALID */ - bool checkOnSamples(std::shared_ptr assumption); + AssumptionStatus checkOnSamples(std::shared_ptr assumption); /*! * Tries to validate an assumption based on the lattice and underlying transition matrix. * * @param assumption The assumption to validate. * @param lattice The lattice. - * @return true if the assumption can be validated and holds, false otherwise - */ - bool validateAssumption(std::shared_ptr assumption, storm::analysis::Lattice* lattice); - - /*! - * Looks up if assumption has been validated. - * - * @param assumption The assumption. - * @return true if the assumption has been validated. + * @return AssumptionStatus::VALID, or AssumptionStatus::UNKNOWN, or AssumptionStatus::INVALID */ - bool validated(std::shared_ptr assumption); + AssumptionStatus validateAssumption(std::shared_ptr assumption, storm::analysis::Lattice* lattice); - /*! - * Looks up if assumption is valid. Requires the function to be validated. - * - * @param assumption The assumption. - * @return true if the assumption is valid. - */ - bool valid(std::shared_ptr assumption); + AssumptionStatus validateAssumptionSMTSolver(storm::analysis::Lattice* lattice, + std::shared_ptr assumption); private: std::shared_ptr formula; storm::storage::SparseMatrix matrix; - std::vector> results; - - std::set> validatedAssumptions; - - std::set> validAssumptions; + std::vector> samples; - bool validateAssumptionFunction(storm::analysis::Lattice* lattice, - typename storm::storage::SparseMatrix::iterator state1succ1, - typename storm::storage::SparseMatrix::iterator state1succ2, - typename storm::storage::SparseMatrix::iterator state2succ1, - typename storm::storage::SparseMatrix::iterator state2succ2); + void createSamples(); - bool validateAssumptionSMTSolver(storm::analysis::Lattice* lattice, + AssumptionStatus validateAssumptionFunction(storm::analysis::Lattice* lattice, typename storm::storage::SparseMatrix::iterator state1succ1, typename storm::storage::SparseMatrix::iterator state1succ2, typename storm::storage::SparseMatrix::iterator state2succ1, typename storm::storage::SparseMatrix::iterator state2succ2); - bool validateAssumptionSMTSolver(storm::analysis::Lattice* lattice, - std::shared_ptr assumption); }; } } diff --git a/src/storm-pars/analysis/AssumptionMaker.cpp b/src/storm-pars/analysis/AssumptionMaker.cpp index 0a5ab376e..e2828db50 100644 --- a/src/storm-pars/analysis/AssumptionMaker.cpp +++ b/src/storm-pars/analysis/AssumptionMaker.cpp @@ -6,6 +6,7 @@ namespace storm { namespace analysis { + typedef std::shared_ptr AssumptionType; template AssumptionMaker::AssumptionMaker(storm::analysis::AssumptionChecker* assumptionChecker, uint_fast64_t numberOfStates, bool validate) { this->numberOfStates = numberOfStates; @@ -13,51 +14,44 @@ namespace storm { this->validate = validate; this->expressionManager = std::make_shared(storm::expressions::ExpressionManager()); for (uint_fast64_t i = 0; i < this->numberOfStates; ++i) { + // TODO: expressenmanager pointer maken die oorspronkelijk in monotonicity checker zit expressionManager->declareRationalVariable(std::to_string(i)); } } + template - std::map, bool> AssumptionMaker::createAndCheckAssumption(uint_fast64_t val1, uint_fast64_t val2, storm::analysis::Lattice* lattice) { - std::map, bool> result; + std::map, AssumptionStatus> AssumptionMaker::createAndCheckAssumption(uint_fast64_t val1, uint_fast64_t val2, storm::analysis::Lattice* lattice) { + std::map, AssumptionStatus> result; + // TODO: alleen maar als validate true is results genereren storm::expressions::Variable var1 = expressionManager->getVariable(std::to_string(val1)); storm::expressions::Variable var2 = expressionManager->getVariable(std::to_string(val2)); - std::shared_ptr assumption1 = std::make_shared(storm::expressions::BinaryRelationExpression(*expressionManager, expressionManager->getBooleanType(), var1.getExpression().getBaseExpressionPointer(), var2.getExpression().getBaseExpressionPointer(), - storm::expressions::BinaryRelationExpression::RelationType::Greater)); - bool result1 = (validate && assumptionChecker->validateAssumption(assumption1, lattice) && assumptionChecker->valid(assumption1)); + storm::expressions::BinaryRelationExpression::RelationType::Greater)); + // TODO: dischargen gebasseerd op monotonicity + auto result1 = assumptionChecker->validateAssumption(assumption1, lattice); result[assumption1] = result1; std::shared_ptr assumption2 = std::make_shared(storm::expressions::BinaryRelationExpression(*expressionManager, expressionManager->getBooleanType(), var2.getExpression().getBaseExpressionPointer(), var1.getExpression().getBaseExpressionPointer(), storm::expressions::BinaryRelationExpression::RelationType::Greater)); - bool result2 = (validate && assumptionChecker->validateAssumption(assumption2, lattice) && assumptionChecker->valid(assumption2)); + auto result2 = assumptionChecker->validateAssumption(assumption2, lattice); result[assumption2] = result2; std::shared_ptr assumption3 = std::make_shared(storm::expressions::BinaryRelationExpression(*expressionManager, expressionManager->getBooleanType(), var2.getExpression().getBaseExpressionPointer(), var1.getExpression().getBaseExpressionPointer(), storm::expressions::BinaryRelationExpression::RelationType::Equal)); - bool result3 = (validate && assumptionChecker->validateAssumption(assumption3, lattice) && assumptionChecker->valid(assumption3)); + auto result3 = assumptionChecker->validateAssumption(assumption3, lattice); result[assumption3] = result3; return result; } - template - std::shared_ptr AssumptionMaker::createEqualAssumption(uint_fast64_t val1, uint_fast64_t val2) { - storm::expressions::Variable var1 = expressionManager->getVariable(std::to_string(val1)); - storm::expressions::Variable var2 = expressionManager->getVariable(std::to_string(val2)); - return std::make_shared(storm::expressions::BinaryRelationExpression(*expressionManager, expressionManager->getBooleanType(), - var1.getExpression().getBaseExpressionPointer(), var2.getExpression().getBaseExpressionPointer(), - storm::expressions::BinaryRelationExpression::RelationType::Equal)); - } - - template class AssumptionMaker; } } diff --git a/src/storm-pars/analysis/AssumptionMaker.h b/src/storm-pars/analysis/AssumptionMaker.h index 190559a72..72d0255dc 100644 --- a/src/storm-pars/analysis/AssumptionMaker.h +++ b/src/storm-pars/analysis/AssumptionMaker.h @@ -17,6 +17,7 @@ namespace storm { template class AssumptionMaker { + typedef std::shared_ptr AssumptionType; public: /*! * Constructs AssumptionMaker based on the lattice extender, the assumption checker and number of states of the model. @@ -27,9 +28,7 @@ namespace storm { */ AssumptionMaker( storm::analysis::AssumptionChecker* checker, uint_fast64_t numberOfStates, bool validate); - std::map, bool> createAndCheckAssumption(uint_fast64_t val1, uint_fast64_t val2, storm::analysis::Lattice* lattice); - - std::shared_ptr createEqualAssumption(uint_fast64_t val1, uint_fast64_t val2); + std::map, AssumptionStatus> createAndCheckAssumption(uint_fast64_t val1, uint_fast64_t val2, storm::analysis::Lattice* lattice); private: storm::analysis::AssumptionChecker* assumptionChecker; @@ -39,8 +38,6 @@ namespace storm { uint_fast64_t numberOfStates; bool validate; - - }; } } diff --git a/src/storm-pars/analysis/Lattice.cpp b/src/storm-pars/analysis/Lattice.cpp index 8c14afe49..665d39537 100644 --- a/src/storm-pars/analysis/Lattice.cpp +++ b/src/storm-pars/analysis/Lattice.cpp @@ -80,7 +80,6 @@ namespace storm { } void Lattice::addBetween(uint_fast64_t state, Node *above, Node *below) { -// std::cout << "Adding " << state << " between " << *(above->states.begin()) << " and " << *(below->states.begin()) << std::endl; assert(!(*addedStates)[state]); assert(compare(above, below) == ABOVE); @@ -97,7 +96,6 @@ namespace storm { } void Lattice::addToNode(uint_fast64_t state, Node *node) { -// std::cout << "Adding " << state << " to " << *(node->states.begin()) << std::endl; assert(!(*addedStates)[state]); node->states.insert(state); nodes[state] = node; @@ -118,6 +116,10 @@ namespace storm { assert (compare(above, below) == ABOVE); } + void Lattice::addRelation(uint_fast64_t above, uint_fast64_t below) { + addRelationNodes(getNode(above), getNode(below)); + } + int Lattice::compare(uint_fast64_t state1, uint_fast64_t state2) { return compare(getNode(state1), getNode(state2)); } @@ -366,5 +368,9 @@ namespace storm { nodes[i] = node1; } } + + void Lattice::merge(uint_fast64_t var1, uint_fast64_t var2) { + mergeNodes(getNode(var1), getNode(var2)); + } } } diff --git a/src/storm-pars/analysis/Lattice.h b/src/storm-pars/analysis/Lattice.h index 8b66c30db..0e1790fc3 100644 --- a/src/storm-pars/analysis/Lattice.h +++ b/src/storm-pars/analysis/Lattice.h @@ -21,7 +21,6 @@ namespace storm { struct Node { boost::container::flat_set states; storm::storage::BitVector statesAbove; -// storm::storage::BitVector statesBelow; }; /*! @@ -70,6 +69,13 @@ namespace storm { */ void addRelationNodes(storm::analysis::Lattice::Node *above, storm::analysis::Lattice::Node * below); + /*! + * Adds a new relation between two nodes to the lattice + * @param above The node closest to the top Node of the Lattice. + * @param below The node closest to the bottom Node of the Lattice. + */ + void addRelation(uint_fast64_t above, uint_fast64_t below); + /*! * Compares the level of the nodes of the states. * Behaviour unknown when one or more of the states doesnot occur at any Node in the Lattice. @@ -128,37 +134,6 @@ namespace storm { std::vector sortStates(storm::storage::BitVector* states); -// /*! -// * Returns a set with the nodes which are above the state. -// * -// * @param state The state number. -// * @return The set with all nodes which are above the state. -// */ -// std::set getAbove(uint_fast64_t state); -// -// /*! -// * Returns a set with the nodes which are below the state. -// * -// * @param state The state number. -// * @return The set with all nodes which are below the state. -// */ -// std::set getBelow(uint_fast64_t state); -// -// /*! -// * Returns a set with the nodes which are above the node. -// * -// * @param node The node. -// * @return The set with all nodes which are above the node. -// */ -// std::set getAbove(Lattice::Node* node); -// -// /*! -// * Returns a set with the nodes which are below the node. -// * -// * @param node The node. -// * @return The set with all nodes which are below the node. -// */ -// std::set getBelow(Lattice::Node* node); void setDoneBuilding(bool done); /*! @@ -181,6 +156,13 @@ namespace storm { * @param node2 */ void mergeNodes(Node* node1, Node* node2); + /*! + * Merges node of var2 into node of var1 + * @param var1 + * @param var2 + */ + void merge(uint_fast64_t var1, uint_fast64_t var2); + /*! * Constants for comparison of nodes/states @@ -207,18 +189,9 @@ namespace storm { bool above(Node * node1, Node * node2, storm::analysis::Lattice::Node *nodePrev, storm::storage::BitVector *statesSeen); - std::unordered_map> comparisons; bool doneBuilding; - -// void setStatesAbove(Node* node, uint_fast64_t state, bool alreadyInitialized); - -// void setStatesBelow(Node* node, uint_fast64_t state, bool alreadyInitialized); - -// void setStatesAbove(storm::analysis::Lattice::Node *node, storm::storage::BitVector states, bool alreadyInitialized); - -// void setStatesBelow(storm::analysis::Lattice::Node *node, storm::storage::BitVector states, bool alreadyInitialized); }; } } diff --git a/src/storm-pars/analysis/LatticeExtender.cpp b/src/storm-pars/analysis/LatticeExtender.cpp index 0e48ac600..4135e4ded 100644 --- a/src/storm-pars/analysis/LatticeExtender.cpp +++ b/src/storm-pars/analysis/LatticeExtender.cpp @@ -72,7 +72,8 @@ namespace storm { auto initialMiddleStates = storm::storage::BitVector(numberOfStates); // Check if MC contains cycles // TODO maybe move to other place? - auto decomposition = storm::storage::StronglyConnectedComponentDecomposition(model->getTransitionMatrix(), false, false); + storm::storage::StronglyConnectedComponentDecompositionOptions const options; + auto decomposition = storm::storage::StronglyConnectedComponentDecomposition(model->getTransitionMatrix(), options); acyclic = true; for (auto i = 0; acyclic && i < decomposition.size(); ++i) { acyclic &= decomposition.getBlock(i).size() <= 1; @@ -80,6 +81,7 @@ namespace storm { if (acyclic) { statesSorted = storm::utility::graph::getTopologicalSort(matrix); } else { + statesSorted = storm::utility::graph::getTopologicalSort(matrix); for (uint_fast64_t i = 0; i < numberOfStates; ++i) { stateMap[i] = new storm::storage::BitVector(numberOfStates, false); @@ -241,7 +243,6 @@ namespace storm { std::tuple LatticeExtender::extendLattice(Lattice* lattice, std::shared_ptr assumption) { auto numberOfStates = this->model->getNumberOfStates(); - if (assumption != nullptr) { handleAssumption(lattice, assumption); } @@ -328,6 +329,7 @@ namespace storm { auto addedStates = lattice->getAddedStates(); if (assumptionSeen) { statesToHandle = addedStates; + // TODO: statesSorted = } auto stateNumber = statesToHandle->getNextSetIndex(0); while (stateNumber != numberOfStates) { @@ -342,6 +344,7 @@ namespace storm { if (!(*addedStates)[succ1]) { lattice->addToNode(succ1, lattice->getNode(stateNumber)); statesToHandle->set(succ1, true); + statesSorted.erase(std::find(statesSorted.begin(), statesSorted.end(), succ1)); } statesToHandle->set(stateNumber, false); stateNumber = statesToHandle->getNextSetIndex(0); @@ -355,11 +358,13 @@ namespace storm { auto compare = lattice->compare(stateNumber, succ1); if (compare == Lattice::ABOVE) { + statesSorted.erase(std::find(statesSorted.begin(), statesSorted.end(), succ2)); lattice->addBetween(succ2, lattice->getTop(), lattice->getNode(stateNumber)); statesToHandle->set(succ2); statesToHandle->set(stateNumber, false); stateNumber = statesToHandle->getNextSetIndex(0); } else if (compare == Lattice::BELOW) { + statesSorted.erase(std::find(statesSorted.begin(), statesSorted.end(), succ2)); lattice->addBetween(succ2, lattice->getNode(stateNumber), lattice->getBottom()); statesToHandle->set(succ2); statesToHandle->set(stateNumber, false); @@ -379,27 +384,58 @@ namespace storm { } } - addedStates = lattice->getAddedStates(); - auto notAddedStates = addedStates->operator~(); - for (auto stateNumber : notAddedStates) { - // Iterate over all not yet added states - storm::storage::BitVector* successors = stateMap[stateNumber]; +// addedStates = lattice->getAddedStates(); +// auto notAddedStates = addedStates->operator~(); + if (!assumptionSeen) { + stateNumber = *(statesSorted.begin()); + while (stateNumber != numberOfStates && (*(lattice->getAddedStates()))[stateNumber]) { + statesSorted.erase(statesSorted.begin()); + stateNumber = *(statesSorted.begin()); + } - // Check if current state has not been added yet, and all successors have, ignore selfloop in this - successors->set(stateNumber, false); - if ((*successors & *addedStates) == *successors) { - auto result = extendAllSuccAdded(lattice, stateNumber, successors); - if (std::get<1>(result) != successors->size()) { - return result; + if (stateNumber == numberOfStates) { + assert(false); + } + storm::storage::BitVector* successors = stateMap[stateNumber]; + + // Check if current state has not been added yet, and all successors have, ignore selfloop in this + successors->set(stateNumber, false); + if ((*successors & *addedStates) == *successors) { + auto result = extendAllSuccAdded(lattice, stateNumber, successors); + if (std::get<1>(result) != successors->size()) { + return result; + } + statesToHandle->set(stateNumber); + } + } else { + addedStates = lattice->getAddedStates(); + auto notAddedStates = addedStates->operator~(); + for (auto stateNumber : notAddedStates) { + // Iterate over all not yet added states + storm::storage::BitVector* successors = stateMap[stateNumber]; + + // Check if current state has not been added yet, and all successors have, ignore selfloop in this + successors->set(stateNumber, false); + if ((*successors & *addedStates) == *successors) { + auto result = extendAllSuccAdded(lattice, stateNumber, successors); + if (std::get<1>(result) != successors->size()) { + return result; + } + statesToHandle->set(stateNumber); + } } - statesToHandle->set(stateNumber); } - } // if nothing changed and there are states left, then add a state between top and bottom if (oldNumberSet == lattice->getAddedStates()->getNumberOfSetBits() && oldNumberSet != numberOfStates) { - auto stateNumber = lattice->getAddedStates()->getNextUnsetIndex(0); + if (assumptionSeen) { + stateNumber = lattice->getAddedStates()->getNextUnsetIndex(0); + } else { + stateNumber = *(statesSorted.begin());//lattice->getAddedStates()->getNextUnsetIndex(0); + } + + statesSorted.erase(statesSorted.begin()); lattice->add(stateNumber); statesToHandle->set(stateNumber); } diff --git a/src/storm-pars/analysis/MonotonicityChecker.cpp b/src/storm-pars/analysis/MonotonicityChecker.cpp index 55568ab45..d96c358de 100644 --- a/src/storm-pars/analysis/MonotonicityChecker.cpp +++ b/src/storm-pars/analysis/MonotonicityChecker.cpp @@ -22,11 +22,7 @@ #include "storm/modelchecker/results/ExplicitQuantitativeCheckResult.h" #include "storm-pars/modelchecker/region/SparseDtmcParameterLiftingModelChecker.h" -#include "storm/solver/Z3SmtSolver.h" -#include "storm/storage/expressions/ExpressionManager.h" -#include "storm/storage/expressions/RationalFunctionToExpression.h" -#include "storm/utility/constants.h" namespace storm { namespace analysis { @@ -37,6 +33,7 @@ namespace storm { this->formulas = formulas; this->validate = validate; this->resultCheckOnSamples = std::map>(); + // TODO initialiseren van sample check if (model != nullptr) { std::shared_ptr> sparseModel = model->as>(); this->extender = new storm::analysis::LatticeExtender(sparseModel); @@ -204,12 +201,12 @@ namespace storm { } else if (validSomewhere) { auto itr2 = varsMonotone.begin(); while (itr2 != varsMonotone.end()) { -// if (resultCheckOnSamples.find(itr2->first) != resultCheckOnSamples.end() && -// (!resultCheckOnSamples[itr2->first].first && -// !resultCheckOnSamples[itr2->first].second)) { -// // STORM_PRINT(" - Not monotone in: " << itr2->first << std::endl); -// outfile << "X " << itr2->first; -// } else { + if (resultCheckOnSamples.find(itr2->first) != resultCheckOnSamples.end() && + (!resultCheckOnSamples[itr2->first].first && + !resultCheckOnSamples[itr2->first].second)) { + // STORM_PRINT(" - Not monotone in: " << itr2->first << std::endl); + outfile << "X " << itr2->first; + } else { if (itr2->second.first && itr2->second.second) { // STORM_PRINT(" - Constant in" << itr2->first << std::endl); outfile << "C " << itr2->first; @@ -224,7 +221,7 @@ namespace storm { // STORM_PRINT(" - Do not know if monotone incr/decreasing in: " << itr2->first << std::endl); outfile << "? " << itr2->first; } -// } + } ++itr2; if (itr2 != varsMonotone.end()) { outfile << " "; @@ -313,44 +310,81 @@ namespace storm { ++itr; auto assumption3 = *itr; - if (!assumption1.second && !assumption2.second && !assumption3.second) { - // Both assumption cannot be validated, so we need to keep them both - // TODO: hier niet verder gaan als je iets gevonden hebt? - auto assumptionsCopy = std::vector>( - assumptions); - auto assumptionsCopy2 = std::vector>( - assumptions); - auto latticeCopy = new storm::analysis::Lattice(lattice); - auto latticeCopy2 = new storm::analysis::Lattice(lattice); - assumptions.push_back(assumption1.first); - assumptionsCopy.push_back(assumption2.first); - assumptionsCopy2.push_back(assumption2.first); - - auto criticalTuple = extender->extendLattice(lattice, assumption1.first); - if (somewhereMonotonicity(std::get<0>(criticalTuple))) { - auto map = extendLatticeWithAssumptions(std::get<0>(criticalTuple), assumptionMaker, - std::get<1>(criticalTuple), std::get<2>(criticalTuple), - assumptions); - result.insert(map.begin(), map.end()); - } + auto assumptionsCopy = std::vector>( + assumptions); + auto assumptionsCopy2 = std::vector>( + assumptions); - criticalTuple = extender->extendLattice(latticeCopy, assumption2.first); - if (somewhereMonotonicity(std::get<0>(criticalTuple))) { - auto map = extendLatticeWithAssumptions(std::get<0>(criticalTuple), assumptionMaker, - std::get<1>(criticalTuple), std::get<2>(criticalTuple), - assumptionsCopy); - result.insert(map.begin(), map.end()); - } - criticalTuple = extender->extendLattice(latticeCopy2, assumption3.first); - if (somewhereMonotonicity(std::get<0>(criticalTuple))) { - auto map = extendLatticeWithAssumptions(std::get<0>(criticalTuple), assumptionMaker, - std::get<1>(criticalTuple), std::get<2>(criticalTuple), - assumptionsCopy2); - result.insert(map.begin(), map.end()); - } + auto latticeCopy = new storm::analysis::Lattice(lattice); + auto latticeCopy2 = new storm::analysis::Lattice(lattice); + + assumptions.push_back(assumption1.first); + assumptionsCopy.push_back(assumption2.first); + assumptionsCopy2.push_back(assumption3.first); + + auto criticalTuple = extender->extendLattice(lattice, assumption1.first); + if (assumption1.second != AssumptionStatus::INVALID && somewhereMonotonicity(std::get<0>(criticalTuple))) { + auto map = extendLatticeWithAssumptions(std::get<0>(criticalTuple), assumptionMaker, + std::get<1>(criticalTuple), std::get<2>(criticalTuple), + assumptions); + result.insert(map.begin(), map.end()); + } + + // TODO: checkend at ie niet invalid is + criticalTuple = extender->extendLattice(latticeCopy, assumption2.first); + if (somewhereMonotonicity(std::get<0>(criticalTuple))) { + auto map = extendLatticeWithAssumptions(std::get<0>(criticalTuple), assumptionMaker, + std::get<1>(criticalTuple), std::get<2>(criticalTuple), + assumptionsCopy); + result.insert(map.begin(), map.end()); + } + criticalTuple = extender->extendLattice(latticeCopy2, assumption3.first); + if (somewhereMonotonicity(std::get<0>(criticalTuple))) { + auto map = extendLatticeWithAssumptions(std::get<0>(criticalTuple), assumptionMaker, + std::get<1>(criticalTuple), std::get<2>(criticalTuple), + assumptionsCopy2); + result.insert(map.begin(), map.end()); } -// } else if (assumption1.second && assumption2.second) { -// assert (false); + + +// if (!assumption1.second && !assumption2.second && !assumption3.second) { +// // Both assumption cannot be validated, so we need to keep them both +// // TODO: hier niet verder gaan als je iets gevonden hebt? +// auto assumptionsCopy = std::vector>( +// assumptions); +// auto assumptionsCopy2 = std::vector>( +// assumptions); +// auto latticeCopy = new storm::analysis::Lattice(lattice); +// auto latticeCopy2 = new storm::analysis::Lattice(lattice); +// assumptions.push_back(assumption1.first); +// assumptionsCopy.push_back(assumption2.first); +// assumptionsCopy2.push_back(assumption3.first); +// +// auto criticalTuple = extender->extendLattice(lattice, assumption1.first); +// if (somewhereMonotonicity(std::get<0>(criticalTuple))) { +// auto map = extendLatticeWithAssumptions(std::get<0>(criticalTuple), assumptionMaker, +// std::get<1>(criticalTuple), std::get<2>(criticalTuple), +// assumptions); +// result.insert(map.begin(), map.end()); +// } +// +// criticalTuple = extender->extendLattice(latticeCopy, assumption2.first); +// if (somewhereMonotonicity(std::get<0>(criticalTuple))) { +// auto map = extendLatticeWithAssumptions(std::get<0>(criticalTuple), assumptionMaker, +// std::get<1>(criticalTuple), std::get<2>(criticalTuple), +// assumptionsCopy); +// result.insert(map.begin(), map.end()); +// } +// criticalTuple = extender->extendLattice(latticeCopy2, assumption3.first); +// if (somewhereMonotonicity(std::get<0>(criticalTuple))) { +// auto map = extendLatticeWithAssumptions(std::get<0>(criticalTuple), assumptionMaker, +// std::get<1>(criticalTuple), std::get<2>(criticalTuple), +// assumptionsCopy2); +// result.insert(map.begin(), map.end()); +// } +//// } +// } else if (!assumption3.second && assumption1.second && assumption2.second) { +//// assert (false); // //TODO Both assumptions hold --> should not happen if we change it to < instead of <= // auto assumption = assumptionMaker->createEqualAssumption(val1, val2); // if (!validate) { @@ -361,9 +395,9 @@ namespace storm { // if (somewhereMonotonicity(std::get<0>(criticalTuple))) { // result = extendLatticeWithAssumptions(std::get<0>(criticalTuple), assumptionMaker, std::get<1>(criticalTuple), std::get<2>(criticalTuple), assumptions); // } -// } else if (assumption1.second) { +// } else if (!assumption3.second && !assumption2.second && assumption1.second) { // if (!validate) { -// assert(false); +//// assert(false); // assumptions.push_back(assumption1.first); // } // // if validate is true and both hold, then they must be valid, so no need to add to assumptions @@ -374,8 +408,8 @@ namespace storm { // result = extendLatticeWithAssumptions(std::get<0>(criticalTuple), assumptionMaker, std::get<1>(criticalTuple), std::get<2>(criticalTuple), assumptions); // } // -// } else { -// assert (assumption2.second); +// } else if (!assumption3.second && !assumption1.second && assumption2.second){ +//// assert (assumption2.second); // if (!validate) { // assumptions.push_back(assumption2.first); // } @@ -384,6 +418,43 @@ namespace storm { // if (somewhereMonotonicity(std::get<0>(criticalTuple))) { // result = extendLatticeWithAssumptions(std::get<0>(criticalTuple), assumptionMaker, std::get<1>(criticalTuple), std::get<2>(criticalTuple), assumptions); // } +// } else { +// // TODO: should not happen +// STORM_LOG_WARN("All assumptions are true");// {" << *(assumption1.first) <<", " << *(assumption2.first) << ", " << *(assumption3.first) << "}" << std::endl); +// // Both assumption cannot be validated, so we need to keep them both +// // TODO: hier niet verder gaan als je iets gevonden hebt? +// auto assumptionsCopy = std::vector>( +// assumptions); +// auto assumptionsCopy2 = std::vector>( +// assumptions); +// auto latticeCopy = new storm::analysis::Lattice(lattice); +// auto latticeCopy2 = new storm::analysis::Lattice(lattice); +// assumptions.push_back(assumption1.first); +// assumptionsCopy.push_back(assumption2.first); +// assumptionsCopy2.push_back(assumption2.first); +// +// auto criticalTuple = extender->extendLattice(lattice, assumption1.first); +// if (somewhereMonotonicity(std::get<0>(criticalTuple))) { +// auto map = extendLatticeWithAssumptions(std::get<0>(criticalTuple), assumptionMaker, +// std::get<1>(criticalTuple), std::get<2>(criticalTuple), +// assumptions); +// result.insert(map.begin(), map.end()); +// } +// +// criticalTuple = extender->extendLattice(latticeCopy, assumption2.first); +// if (somewhereMonotonicity(std::get<0>(criticalTuple))) { +// auto map = extendLatticeWithAssumptions(std::get<0>(criticalTuple), assumptionMaker, +// std::get<1>(criticalTuple), std::get<2>(criticalTuple), +// assumptionsCopy); +// result.insert(map.begin(), map.end()); +// } +// criticalTuple = extender->extendLattice(latticeCopy2, assumption3.first); +// if (somewhereMonotonicity(std::get<0>(criticalTuple))) { +// auto map = extendLatticeWithAssumptions(std::get<0>(criticalTuple), assumptionMaker, +// std::get<1>(criticalTuple), std::get<2>(criticalTuple), +// assumptionsCopy2); +// result.insert(map.begin(), map.end()); +// } // } } return result; @@ -538,65 +609,65 @@ namespace storm { return varsMonotone; } - template - std::pair MonotonicityChecker::checkDerivative(ValueType derivative) { - bool monIncr = false; - bool monDecr = false; - - if (derivative.isZero()) { - monIncr = true; - monDecr = true; - } else if (derivative.isConstant()) { - monIncr = derivative.constantPart() >= 0; - monDecr = derivative.constantPart() <= 0; - } else { - - std::shared_ptr smtSolverFactory = std::make_shared(); - std::shared_ptr manager( - new storm::expressions::ExpressionManager()); - - storm::solver::Z3SmtSolver s(*manager); - storm::solver::SmtSolver::CheckResult smtResult = storm::solver::SmtSolver::CheckResult::Unknown; - - std::set variables = derivative.gatherVariables(); - - - for (auto variable : variables) { - manager->declareRationalVariable(variable.name()); - - } - storm::expressions::Expression exprBounds = manager->boolean(true); - auto managervars = manager->getVariables(); - for (auto var : managervars) { - exprBounds = exprBounds && manager->rational(0) < var && var < manager->rational(1); - } - - auto converter = storm::expressions::RationalFunctionToExpression(manager); - - storm::expressions::Expression exprToCheck1 = - converter.toExpression(derivative) >= manager->rational(0); - s.add(exprBounds); - s.add(exprToCheck1); - smtResult = s.check(); - monIncr = smtResult == storm::solver::SmtSolver::CheckResult::Sat; - - storm::expressions::Expression exprToCheck2 = - converter.toExpression(derivative) <= manager->rational(0); - s.reset(); - smtResult = storm::solver::SmtSolver::CheckResult::Unknown; - s.add(exprBounds); - s.add(exprToCheck2); - smtResult = s.check(); - monDecr = smtResult == storm::solver::SmtSolver::CheckResult::Sat; - if (monIncr && monDecr) { - monIncr = false; - monDecr = false; - } - } - assert (!(monIncr && monDecr) || derivative.isZero()); - - return std::pair(monIncr, monDecr); - } +// template +// std::pair MonotonicityChecker::checkDerivative(ValueType derivative) { +// bool monIncr = false; +// bool monDecr = false; +// +// if (derivative.isZero()) { +// monIncr = true; +// monDecr = true; +// } else if (derivative.isConstant()) { +// monIncr = derivative.constantPart() >= 0; +// monDecr = derivative.constantPart() <= 0; +// } else { +// +// std::shared_ptr smtSolverFactory = std::make_shared(); +// std::shared_ptr manager( +// new storm::expressions::ExpressionManager()); +// +// storm::solver::Z3SmtSolver s(*manager); +// storm::solver::SmtSolver::CheckResult smtResult = storm::solver::SmtSolver::CheckResult::Unknown; +// +// std::set variables = derivative.gatherVariables(); +// +// +// for (auto variable : variables) { +// manager->declareRationalVariable(variable.name()); +// +// } +// storm::expressions::Expression exprBounds = manager->boolean(true); +// auto managervars = manager->getVariables(); +// for (auto var : managervars) { +// exprBounds = exprBounds && manager->rational(0) < var && var < manager->rational(1); +// } +// +// auto converter = storm::expressions::RationalFunctionToExpression(manager); +// +// storm::expressions::Expression exprToCheck1 = +// converter.toExpression(derivative) >= manager->rational(0); +// s.add(exprBounds); +// s.add(exprToCheck1); +// smtResult = s.check(); +// monIncr = smtResult == storm::solver::SmtSolver::CheckResult::Sat; +// +// storm::expressions::Expression exprToCheck2 = +// converter.toExpression(derivative) <= manager->rational(0); +// s.reset(); +// smtResult = storm::solver::SmtSolver::CheckResult::Unknown; +// s.add(exprBounds); +// s.add(exprToCheck2); +// smtResult = s.check(); +// monDecr = smtResult == storm::solver::SmtSolver::CheckResult::Sat; +// if (monIncr && monDecr) { +// monIncr = false; +// monDecr = false; +// } +// } +// assert (!(monIncr && monDecr) || derivative.isZero()); +// +// return std::pair(monIncr, monDecr); +// } template diff --git a/src/storm-pars/analysis/MonotonicityChecker.h b/src/storm-pars/analysis/MonotonicityChecker.h index 94cb39ff3..957827f73 100644 --- a/src/storm-pars/analysis/MonotonicityChecker.h +++ b/src/storm-pars/analysis/MonotonicityChecker.h @@ -10,7 +10,10 @@ #include "LatticeExtender.h" #include "AssumptionMaker.h" #include "storm/storage/expressions/BinaryRelationExpression.h" +#include "storm/storage/expressions/ExpressionManager.h" +#include "storm/storage/expressions/RationalFunctionToExpression.h" +#include "storm/utility/constants.h" #include "carl/core/Variable.h" #include "storm/models/ModelBase.h" #include "storm/models/sparse/Dtmc.h" @@ -18,6 +21,8 @@ #include "storm/logic/Formula.h" #include "storm/storage/SparseMatrix.h" #include "storm-pars/api/region.h" +#include "storm/solver/Z3SmtSolver.h" + namespace storm { namespace analysis { @@ -50,6 +55,70 @@ namespace storm { */ bool somewhereMonotonicity(storm::analysis::Lattice* lattice) ; + /*! + * Checks if a derivative >=0 or/and <=0 + * @param derivative The derivative you want to check + * @return pair of bools, >= 0 and <= 0 + */ + static std::pair checkDerivative(ValueType derivative) { + bool monIncr = false; + bool monDecr = false; + + if (derivative.isZero()) { + monIncr = true; + monDecr = true; + } else if (derivative.isConstant()) { + monIncr = derivative.constantPart() >= 0; + monDecr = derivative.constantPart() <= 0; + } else { + + std::shared_ptr smtSolverFactory = std::make_shared(); + std::shared_ptr manager( + new storm::expressions::ExpressionManager()); + + storm::solver::Z3SmtSolver s(*manager); + storm::solver::SmtSolver::CheckResult smtResult = storm::solver::SmtSolver::CheckResult::Unknown; + + std::set variables = derivative.gatherVariables(); + + + for (auto variable : variables) { + manager->declareRationalVariable(variable.name()); + + } + storm::expressions::Expression exprBounds = manager->boolean(true); + auto managervars = manager->getVariables(); + for (auto var : managervars) { + exprBounds = exprBounds && manager->rational(0) < var && var < manager->rational(1); + } + + auto converter = storm::expressions::RationalFunctionToExpression(manager); + + storm::expressions::Expression exprToCheck1 = + converter.toExpression(derivative) >= manager->rational(0); + s.add(exprBounds); + s.add(exprToCheck1); + smtResult = s.check(); + monIncr = smtResult == storm::solver::SmtSolver::CheckResult::Sat; + + storm::expressions::Expression exprToCheck2 = + converter.toExpression(derivative) <= manager->rational(0); + s.reset(); + smtResult = storm::solver::SmtSolver::CheckResult::Unknown; + s.add(exprBounds); + s.add(exprToCheck2); + smtResult = s.check(); + monDecr = smtResult == storm::solver::SmtSolver::CheckResult::Sat; + if (monIncr && monDecr) { + monIncr = false; + monDecr = false; + } + } + assert (!(monIncr && monDecr) || derivative.isZero()); + + return std::pair(monIncr, monDecr); + } + private: //TODO: variabele type std::map> analyseMonotonicity(uint_fast64_t i, storm::analysis::Lattice* lattice, storm::storage::SparseMatrix matrix) ; @@ -60,8 +129,6 @@ namespace storm { std::map> checkOnSamples(std::shared_ptr> model, uint_fast64_t numberOfSamples); - std::pair checkDerivative(ValueType derivative); - std::unordered_map> derivatives; ValueType getDerivative(ValueType function, carl::Variable var); diff --git a/src/storm/storage/expressions/RationalFunctionToExpression.cpp b/src/storm/storage/expressions/RationalFunctionToExpression.cpp index 81abc8f36..0bbd08038 100644 --- a/src/storm/storage/expressions/RationalFunctionToExpression.cpp +++ b/src/storm/storage/expressions/RationalFunctionToExpression.cpp @@ -28,7 +28,7 @@ namespace storm { return val.getName() == var.name(); }) != varsManager.end(); if (!found) { - manager->declareIntegerVariable(var.name()); + manager->declareRationalVariable(var.name()); } } diff --git a/src/test/storm-pars/analysis/AssumptionCheckerTest.cpp b/src/test/storm-pars/analysis/AssumptionCheckerTest.cpp index ab0b25d18..e6b515987 100644 --- a/src/test/storm-pars/analysis/AssumptionCheckerTest.cpp +++ b/src/test/storm-pars/analysis/AssumptionCheckerTest.cpp @@ -27,7 +27,6 @@ #include "storm-parsers/api/storm-parsers.h" -// TODO: extend for cases in which checkOnSamples and validateAssumption return true TEST(AssumptionCheckerTest, Brp_no_bisimulation) { std::string programFile = STORM_TEST_RESOURCES_DIR "/pdtmc/brp16_2.pm"; std::string formulaAsString = "P=? [F s=4 & i=N ]"; @@ -59,22 +58,24 @@ TEST(AssumptionCheckerTest, Brp_no_bisimulation) { storm::expressions::BinaryRelationExpression(*expressionManager, expressionManager->getBooleanType(), expressionManager->getVariable("7").getExpression().getBaseExpressionPointer(), expressionManager->getVariable("5").getExpression().getBaseExpressionPointer(), - storm::expressions::BinaryRelationExpression::RelationType::GreaterOrEqual)); - EXPECT_TRUE(checker.checkOnSamples(assumption)); + storm::expressions::BinaryRelationExpression::RelationType::Greater)); + EXPECT_EQ(storm::analysis::AssumptionStatus::UNKNOWN, checker.checkOnSamples(assumption)); assumption = std::make_shared( storm::expressions::BinaryRelationExpression(*expressionManager, expressionManager->getBooleanType(), - expressionManager->getVariable("7").getExpression().getBaseExpressionPointer(), expressionManager->getVariable("5").getExpression().getBaseExpressionPointer(), + expressionManager->getVariable("7").getExpression().getBaseExpressionPointer(), storm::expressions::BinaryRelationExpression::RelationType::Greater)); - EXPECT_TRUE(checker.checkOnSamples(assumption)); + EXPECT_EQ(storm::analysis::AssumptionStatus::INVALID, checker.checkOnSamples(assumption)); + assumption = std::make_shared( storm::expressions::BinaryRelationExpression(*expressionManager, expressionManager->getBooleanType(), expressionManager->getVariable("7").getExpression().getBaseExpressionPointer(), expressionManager->getVariable("5").getExpression().getBaseExpressionPointer(), storm::expressions::BinaryRelationExpression::RelationType::Equal)); - EXPECT_FALSE(checker.checkOnSamples(assumption)); + EXPECT_EQ(storm::analysis::AssumptionStatus::INVALID, checker.checkOnSamples(assumption)); + storm::storage::BitVector above(8); above.set(0); @@ -84,8 +85,8 @@ TEST(AssumptionCheckerTest, Brp_no_bisimulation) { auto dummyLattice = new storm::analysis::Lattice(&above, &below, &initialMiddle, 8); // Validate assumption - EXPECT_FALSE(checker.validateAssumption(assumption, dummyLattice)); - EXPECT_FALSE(checker.validated(assumption)); + EXPECT_EQ(storm::analysis::AssumptionStatus::INVALID, checker.validateAssumption(assumption, dummyLattice)); +// EXPECT_FALSE(checker.validated(assumption)); expressionManager->declareRationalVariable("6"); expressionManager->declareRationalVariable("8"); @@ -100,12 +101,181 @@ TEST(AssumptionCheckerTest, Brp_no_bisimulation) { below.set(9); initialMiddle = storm::storage::BitVector(13); dummyLattice = new storm::analysis::Lattice(&above, &below, &initialMiddle, 13); - EXPECT_FALSE(checker.checkOnSamples(assumption)); - EXPECT_FALSE(checker.validateAssumption(assumption, dummyLattice)); - EXPECT_TRUE(checker.validated(assumption)); - EXPECT_FALSE(checker.valid(assumption)); + EXPECT_EQ(storm::analysis::AssumptionStatus::INVALID, checker.checkOnSamples(assumption)); + EXPECT_EQ(storm::analysis::AssumptionStatus::INVALID, checker.validateAssumption(assumption, dummyLattice)); +// EXPECT_EQ(checker.validated(assumption)); +// EXPECT_FALSE(checker.valid(assumption)); } +TEST(AssumptionCheckerTest, Simple1) { + std::string programFile = STORM_TEST_RESOURCES_DIR "/pdtmc/simple1.pm"; + std::string formulaAsString = "P=? [F s=3]"; + std::string constantsAsString = ""; //e.g. pL=0.9,TOACK=0.5 + + // Program and formula + storm::prism::Program program = storm::api::parseProgram(programFile); + program = storm::utility::prism::preprocess(program, constantsAsString); + std::vector> formulas = storm::api::extractFormulasFromProperties(storm::api::parsePropertiesForPrismProgram(formulaAsString, program)); + std::shared_ptr> model = storm::api::buildSparseModel(program, formulas)->as>(); + std::shared_ptr> dtmc = model->as>(); + auto simplifier = storm::transformer::SparseParametricDtmcSimplifier>(*dtmc); + ASSERT_TRUE(simplifier.simplify(*(formulas[0]))); + model = simplifier.getSimplifiedModel(); + dtmc = model->as>(); + + ASSERT_EQ(dtmc->getNumberOfStates(), 5); + ASSERT_EQ(dtmc->getNumberOfTransitions(), 8); + + auto checker = storm::analysis::AssumptionChecker(formulas[0], dtmc, 3); + + auto expressionManager = std::make_shared(storm::expressions::ExpressionManager()); + expressionManager->declareRationalVariable("1"); + expressionManager->declareRationalVariable("2"); + + // Checking on samples + auto assumption = std::make_shared( + storm::expressions::BinaryRelationExpression(*expressionManager, expressionManager->getBooleanType(), + expressionManager->getVariable("1").getExpression().getBaseExpressionPointer(), + expressionManager->getVariable("2").getExpression().getBaseExpressionPointer(), + storm::expressions::BinaryRelationExpression::RelationType::Greater)); + EXPECT_EQ(storm::analysis::AssumptionStatus::INVALID, checker.checkOnSamples(assumption)); + + assumption = std::make_shared( + storm::expressions::BinaryRelationExpression(*expressionManager, expressionManager->getBooleanType(), + expressionManager->getVariable("2").getExpression().getBaseExpressionPointer(), + expressionManager->getVariable("1").getExpression().getBaseExpressionPointer(), + storm::expressions::BinaryRelationExpression::RelationType::Greater)); + EXPECT_EQ(storm::analysis::AssumptionStatus::INVALID, checker.checkOnSamples(assumption)); + + assumption = std::make_shared( + storm::expressions::BinaryRelationExpression(*expressionManager, expressionManager->getBooleanType(), + expressionManager->getVariable("1").getExpression().getBaseExpressionPointer(), + expressionManager->getVariable("2").getExpression().getBaseExpressionPointer(), + storm::expressions::BinaryRelationExpression::RelationType::Equal)); + EXPECT_EQ(storm::analysis::AssumptionStatus::INVALID, checker.checkOnSamples(assumption)); +} + +TEST(AssumptionCheckerTest, Simple2) { + std::string programFile = STORM_TEST_RESOURCES_DIR "/pdtmc/simple2.pm"; + std::string formulaAsString = "P=? [F s=3]"; + std::string constantsAsString = ""; //e.g. pL=0.9,TOACK=0.5 + + // Program and formula + storm::prism::Program program = storm::api::parseProgram(programFile); + program = storm::utility::prism::preprocess(program, constantsAsString); + std::vector> formulas = storm::api::extractFormulasFromProperties(storm::api::parsePropertiesForPrismProgram(formulaAsString, program)); + std::shared_ptr> model = storm::api::buildSparseModel(program, formulas)->as>(); + std::shared_ptr> dtmc = model->as>(); + auto simplifier = storm::transformer::SparseParametricDtmcSimplifier>(*dtmc); + ASSERT_TRUE(simplifier.simplify(*(formulas[0]))); + model = simplifier.getSimplifiedModel(); + dtmc = model->as>(); + + ASSERT_EQ(dtmc->getNumberOfStates(), 5); + ASSERT_EQ(dtmc->getNumberOfTransitions(), 8); + + auto checker = storm::analysis::AssumptionChecker(formulas[0], dtmc, 3); + auto expressionManager = std::make_shared(storm::expressions::ExpressionManager()); + expressionManager->declareRationalVariable("1"); + expressionManager->declareRationalVariable("2"); + + storm::storage::BitVector above(5); + above.set(3); + storm::storage::BitVector below(5); + below.set(4); + storm::storage::BitVector initialMiddle(5); + + auto lattice = new storm::analysis::Lattice(&above, &below, &initialMiddle, 5); + + // Checking on samples and validate + auto assumption = std::make_shared( + storm::expressions::BinaryRelationExpression(*expressionManager, expressionManager->getBooleanType(), + expressionManager->getVariable("1").getExpression().getBaseExpressionPointer(), + expressionManager->getVariable("2").getExpression().getBaseExpressionPointer(), + storm::expressions::BinaryRelationExpression::RelationType::Greater)); + EXPECT_EQ(storm::analysis::AssumptionStatus::UNKNOWN, checker.checkOnSamples(assumption)); + EXPECT_EQ(storm::analysis::AssumptionStatus::VALID, checker.validateAssumption(assumption, lattice)); + + assumption = std::make_shared( + storm::expressions::BinaryRelationExpression(*expressionManager, expressionManager->getBooleanType(), + expressionManager->getVariable("2").getExpression().getBaseExpressionPointer(), + expressionManager->getVariable("1").getExpression().getBaseExpressionPointer(), + storm::expressions::BinaryRelationExpression::RelationType::Greater)); + EXPECT_EQ(storm::analysis::AssumptionStatus::INVALID, checker.checkOnSamples(assumption)); + EXPECT_EQ(storm::analysis::AssumptionStatus::INVALID, checker.validateAssumption(assumption, lattice)); + + + assumption = std::make_shared( + storm::expressions::BinaryRelationExpression(*expressionManager, expressionManager->getBooleanType(), + expressionManager->getVariable("1").getExpression().getBaseExpressionPointer(), + expressionManager->getVariable("2").getExpression().getBaseExpressionPointer(), + storm::expressions::BinaryRelationExpression::RelationType::Equal)); + EXPECT_EQ(storm::analysis::AssumptionStatus::INVALID, checker.checkOnSamples(assumption)); + EXPECT_EQ(storm::analysis::AssumptionStatus::INVALID, checker.validateAssumption(assumption, lattice)); +} + +TEST(AssumptionCheckerTest, Simple3) { + std::string programFile = STORM_TEST_RESOURCES_DIR "/pdtmc/simple3.pm"; + std::string formulaAsString = "P=? [F s=4]"; + std::string constantsAsString = ""; //e.g. pL=0.9,TOACK=0.5 + + // Program and formula + storm::prism::Program program = storm::api::parseProgram(programFile); + program = storm::utility::prism::preprocess(program, constantsAsString); + std::vector> formulas = storm::api::extractFormulasFromProperties(storm::api::parsePropertiesForPrismProgram(formulaAsString, program)); + std::shared_ptr> model = storm::api::buildSparseModel(program, formulas)->as>(); + std::shared_ptr> dtmc = model->as>(); + auto simplifier = storm::transformer::SparseParametricDtmcSimplifier>(*dtmc); + ASSERT_TRUE(simplifier.simplify(*(formulas[0]))); + model = simplifier.getSimplifiedModel(); + dtmc = model->as>(); + + ASSERT_EQ(6, dtmc->getNumberOfStates()); + ASSERT_EQ(12, dtmc->getNumberOfTransitions()); + + auto checker = storm::analysis::AssumptionChecker(formulas[0], dtmc, 3); + + auto expressionManager = std::make_shared(storm::expressions::ExpressionManager()); + expressionManager->declareRationalVariable("1"); + expressionManager->declareRationalVariable("2"); + + storm::storage::BitVector above(6); + above.set(4); + storm::storage::BitVector below(6); + below.set(5); + storm::storage::BitVector initialMiddle(6); + + auto lattice = new storm::analysis::Lattice(&above, &below, &initialMiddle, 6); + lattice->add(3); + + // Checking on samples and validate + auto assumption = std::make_shared( + storm::expressions::BinaryRelationExpression(*expressionManager, expressionManager->getBooleanType(), + expressionManager->getVariable("1").getExpression().getBaseExpressionPointer(), + expressionManager->getVariable("2").getExpression().getBaseExpressionPointer(), + storm::expressions::BinaryRelationExpression::RelationType::Greater)); + EXPECT_EQ(storm::analysis::AssumptionStatus::UNKNOWN, checker.checkOnSamples(assumption)); + EXPECT_EQ(storm::analysis::AssumptionStatus::VALID, checker.validateAssumption(assumption, lattice)); + EXPECT_EQ(storm::analysis::AssumptionStatus::VALID, checker.validateAssumptionSMTSolver(lattice,assumption)); + + assumption = std::make_shared( + storm::expressions::BinaryRelationExpression(*expressionManager, expressionManager->getBooleanType(), + expressionManager->getVariable("2").getExpression().getBaseExpressionPointer(), + expressionManager->getVariable("1").getExpression().getBaseExpressionPointer(), + storm::expressions::BinaryRelationExpression::RelationType::Greater)); + EXPECT_EQ(storm::analysis::AssumptionStatus::INVALID, checker.checkOnSamples(assumption)); + EXPECT_EQ(storm::analysis::AssumptionStatus::INVALID, checker.validateAssumption(assumption, lattice)); + EXPECT_EQ(storm::analysis::AssumptionStatus::INVALID, checker.validateAssumptionSMTSolver(lattice, assumption)); + + assumption = std::make_shared( + storm::expressions::BinaryRelationExpression(*expressionManager, expressionManager->getBooleanType(), + expressionManager->getVariable("1").getExpression().getBaseExpressionPointer(), + expressionManager->getVariable("2").getExpression().getBaseExpressionPointer(), + storm::expressions::BinaryRelationExpression::RelationType::Equal)); + EXPECT_EQ(storm::analysis::AssumptionStatus::INVALID, checker.checkOnSamples(assumption)); + EXPECT_EQ(storm::analysis::AssumptionStatus::INVALID, checker.validateAssumption(assumption, lattice)); + EXPECT_EQ(storm::analysis::AssumptionStatus::INVALID, checker.validateAssumptionSMTSolver(lattice,assumption)); +} diff --git a/src/test/storm-pars/analysis/AssumptionMakerTest.cpp b/src/test/storm-pars/analysis/AssumptionMakerTest.cpp index af6f0213d..a7603ca09 100644 --- a/src/test/storm-pars/analysis/AssumptionMakerTest.cpp +++ b/src/test/storm-pars/analysis/AssumptionMakerTest.cpp @@ -56,34 +56,179 @@ TEST(AssumptionMakerTest, Brp_without_bisimulation) { auto assumptionMaker = storm::analysis::AssumptionMaker(&assumptionChecker, dtmc->getNumberOfStates(), true); auto result = assumptionMaker.createAndCheckAssumption(std::get<1>(criticalTuple), std::get<2>(criticalTuple), std::get<0>(criticalTuple)); - auto itr = result.begin(); + EXPECT_EQ(3, result.size()); + + bool foundFirst = false; + bool foundSecond = false; + bool foundThird = false; + for (auto itr = result.begin(); itr != result.end(); ++itr) { + if (!foundFirst && itr->first->getFirstOperand()->asVariableExpression().getVariable().getName() == "183") { + EXPECT_EQ(storm::analysis::AssumptionStatus::INVALID, itr->second); + EXPECT_EQ(true, itr->first->getFirstOperand()->isVariable()); + EXPECT_EQ(true, itr->first->getSecondOperand()->isVariable()); + EXPECT_EQ("186", itr->first->getSecondOperand()->asVariableExpression().getVariable().getName()); + EXPECT_EQ(storm::expressions::BinaryRelationExpression::RelationType::Greater, itr->first->getRelationType()); + foundFirst = true; + } else if (!foundSecond && itr->first->getRelationType() == storm::expressions::BinaryRelationExpression::RelationType::Greater) { + EXPECT_EQ(storm::analysis::AssumptionStatus::UNKNOWN, itr->second); + EXPECT_EQ(true, itr->first->getFirstOperand()->isVariable()); + EXPECT_EQ(true, itr->first->getSecondOperand()->isVariable()); + EXPECT_EQ("186", itr->first->getFirstOperand()->asVariableExpression().getVariable().getName()); + EXPECT_EQ("183", itr->first->getSecondOperand()->asVariableExpression().getVariable().getName()); + EXPECT_EQ(storm::expressions::BinaryRelationExpression::RelationType::Greater, itr->first->getRelationType()); + foundSecond = true; + } else if (!foundThird && itr->first->getRelationType() == storm::expressions::BinaryRelationExpression::RelationType::Equal) { + EXPECT_EQ(storm::analysis::AssumptionStatus::INVALID, itr->second); + EXPECT_EQ(true, itr->first->getFirstOperand()->isVariable()); + EXPECT_EQ(true, itr->first->getSecondOperand()->isVariable()); + EXPECT_EQ("186", itr->first->getFirstOperand()->asVariableExpression().getVariable().getName()); + EXPECT_EQ("183", itr->first->getSecondOperand()->asVariableExpression().getVariable().getName()); + EXPECT_EQ(storm::expressions::BinaryRelationExpression::RelationType::Equal, itr->first->getRelationType()); + foundThird = true; + } else { + EXPECT_TRUE(false); + } + } + EXPECT_TRUE(foundFirst); + EXPECT_TRUE(foundSecond); + EXPECT_TRUE(foundThird); +} + +TEST(AssumptionMakerTest, Simple1) { + std::string programFile = STORM_TEST_RESOURCES_DIR "/pdtmc/simple1.pm"; + std::string formulaAsString = "P=? [F s=3]"; + std::string constantsAsString = ""; //e.g. pL=0.9,TOACK=0.5 + + storm::prism::Program program = storm::api::parseProgram(programFile); + program = storm::utility::prism::preprocess(program, constantsAsString); + std::vector> formulas = storm::api::extractFormulasFromProperties(storm::api::parsePropertiesForPrismProgram(formulaAsString, program)); + std::shared_ptr> model = storm::api::buildSparseModel(program, formulas)->as>(); + std::shared_ptr> dtmc = model->as>(); + auto simplifier = storm::transformer::SparseParametricDtmcSimplifier>(*dtmc); + ASSERT_TRUE(simplifier.simplify(*(formulas[0]))); + model = simplifier.getSimplifiedModel(); + dtmc = model->as>(); + + ASSERT_EQ(dtmc->getNumberOfStates(), 5); + ASSERT_EQ(dtmc->getNumberOfTransitions(), 8); + + storm::storage::BitVector above(5); + above.set(3); + storm::storage::BitVector below(5); + below.set(4); + storm::storage::BitVector initialMiddle(5); + + auto lattice = new storm::analysis::Lattice(&above, &below, &initialMiddle, 5); + + auto assumptionChecker = storm::analysis::AssumptionChecker(formulas[0], dtmc, 3); + auto assumptionMaker = storm::analysis::AssumptionMaker(&assumptionChecker, dtmc->getNumberOfStates(), true); + auto result = assumptionMaker.createAndCheckAssumption(1, 2, lattice); + + EXPECT_EQ(3, result.size()); + + bool foundFirst = false; + bool foundSecond = false; + bool foundThird = false; + for (auto itr = result.begin(); itr != result.end(); ++itr) { + if (!foundFirst && itr->first->getFirstOperand()->asVariableExpression().getVariable().getName() == "1") { + EXPECT_EQ(storm::analysis::AssumptionStatus::INVALID, itr->second); + EXPECT_EQ(true, itr->first->getFirstOperand()->isVariable()); + EXPECT_EQ(true, itr->first->getSecondOperand()->isVariable()); + EXPECT_EQ("2", itr->first->getSecondOperand()->asVariableExpression().getVariable().getName()); + EXPECT_EQ(storm::expressions::BinaryRelationExpression::RelationType::Greater, itr->first->getRelationType()); + foundFirst = true; + } else if (!foundSecond && itr->first->getRelationType() == storm::expressions::BinaryRelationExpression::RelationType::Greater) { + EXPECT_EQ(storm::analysis::AssumptionStatus::INVALID, itr->second); + EXPECT_EQ(true, itr->first->getFirstOperand()->isVariable()); + EXPECT_EQ(true, itr->first->getSecondOperand()->isVariable()); + EXPECT_EQ("2", itr->first->getFirstOperand()->asVariableExpression().getVariable().getName()); + EXPECT_EQ("1", itr->first->getSecondOperand()->asVariableExpression().getVariable().getName()); + EXPECT_EQ(storm::expressions::BinaryRelationExpression::RelationType::Greater, itr->first->getRelationType()); + foundSecond = true; + } else if (!foundThird && itr->first->getRelationType() == storm::expressions::BinaryRelationExpression::RelationType::Equal) { + EXPECT_EQ(storm::analysis::AssumptionStatus::INVALID, itr->second); + EXPECT_EQ(true, itr->first->getFirstOperand()->isVariable()); + EXPECT_EQ(true, itr->first->getSecondOperand()->isVariable()); + EXPECT_EQ("2", itr->first->getFirstOperand()->asVariableExpression().getVariable().getName()); + EXPECT_EQ("1", itr->first->getSecondOperand()->asVariableExpression().getVariable().getName()); + EXPECT_EQ(storm::expressions::BinaryRelationExpression::RelationType::Equal, itr->first->getRelationType()); + foundThird = true; + } else { + EXPECT_TRUE(false); + } + } + EXPECT_TRUE(foundFirst); + EXPECT_TRUE(foundSecond); + EXPECT_TRUE(foundThird); +} - auto var1 = itr->first->getManager().getVariable("183"); - auto var2 = itr->first->getManager().getVariable("186"); +TEST(AssumptionMakerTest, Simple2) { + std::string programFile = STORM_TEST_RESOURCES_DIR "/pdtmc/simple2.pm"; + std::string formulaAsString = "P=? [F s=3]"; + std::string constantsAsString = ""; //e.g. pL=0.9,TOACK=0.5 + + storm::prism::Program program = storm::api::parseProgram(programFile); + program = storm::utility::prism::preprocess(program, constantsAsString); + std::vector> formulas = storm::api::extractFormulasFromProperties(storm::api::parsePropertiesForPrismProgram(formulaAsString, program)); + std::shared_ptr> model = storm::api::buildSparseModel(program, formulas)->as>(); + std::shared_ptr> dtmc = model->as>(); + auto simplifier = storm::transformer::SparseParametricDtmcSimplifier>(*dtmc); + ASSERT_TRUE(simplifier.simplify(*(formulas[0]))); + model = simplifier.getSimplifiedModel(); + dtmc = model->as>(); + + ASSERT_EQ(dtmc->getNumberOfStates(), 5); + ASSERT_EQ(dtmc->getNumberOfTransitions(), 8); + + storm::storage::BitVector above(5); + above.set(3); + storm::storage::BitVector below(5); + below.set(4); + storm::storage::BitVector initialMiddle(5); + + auto lattice = new storm::analysis::Lattice(&above, &below, &initialMiddle, 5); + + auto assumptionChecker = storm::analysis::AssumptionChecker(formulas[0], dtmc, 3); + auto assumptionMaker = storm::analysis::AssumptionMaker(&assumptionChecker, dtmc->getNumberOfStates(), true); + auto result = assumptionMaker.createAndCheckAssumption(1, 2, lattice); + + auto itr = result.begin(); EXPECT_EQ(3, result.size()); - EXPECT_EQ(false, itr->second); - EXPECT_EQ(true, itr->first->getFirstOperand()->isVariable()); - EXPECT_EQ(true, itr->first->getSecondOperand()->isVariable()); - EXPECT_EQ(var1, itr->first->getFirstOperand()->asVariableExpression().getVariable()); - EXPECT_EQ(var2, itr->first->getSecondOperand()->asVariableExpression().getVariable()); - EXPECT_EQ(storm::expressions::BinaryRelationExpression::RelationType::Greater, itr->first->getRelationType()); - - ++itr; - EXPECT_EQ(false, itr->second); - EXPECT_EQ(true, itr->first->getFirstOperand()->isVariable()); - EXPECT_EQ(true, itr->first->getSecondOperand()->isVariable()); - EXPECT_EQ(var2, itr->first->getFirstOperand()->asVariableExpression().getVariable()); - EXPECT_EQ(var1, itr->first->getSecondOperand()->asVariableExpression().getVariable()); - EXPECT_EQ(storm::expressions::BinaryRelationExpression::RelationType::Greater, itr->first->getRelationType()); - - ++itr; - EXPECT_EQ(false, itr->second); - EXPECT_EQ(true, itr->first->getFirstOperand()->isVariable()); - EXPECT_EQ(true, itr->first->getSecondOperand()->isVariable()); - EXPECT_EQ(var2, itr->first->getFirstOperand()->asVariableExpression().getVariable()); - EXPECT_EQ(var1, itr->first->getSecondOperand()->asVariableExpression().getVariable()); - EXPECT_EQ(storm::expressions::BinaryRelationExpression::RelationType::Equal, itr->first->getRelationType()); - // TODO: createEqualsAssumption checken + bool foundFirst = false; + bool foundSecond = false; + bool foundThird = false; + for (auto itr = result.begin(); itr != result.end(); ++itr) { + if (!foundFirst && itr->first->getFirstOperand()->asVariableExpression().getVariable().getName() == "1") { + EXPECT_EQ(storm::analysis::AssumptionStatus::VALID, itr->second); + EXPECT_EQ(true, itr->first->getFirstOperand()->isVariable()); + EXPECT_EQ(true, itr->first->getSecondOperand()->isVariable()); + EXPECT_EQ("2", itr->first->getSecondOperand()->asVariableExpression().getVariable().getName()); + EXPECT_EQ(storm::expressions::BinaryRelationExpression::RelationType::Greater, itr->first->getRelationType()); + foundFirst = true; + } else if (!foundSecond && itr->first->getRelationType() == storm::expressions::BinaryRelationExpression::RelationType::Greater) { + EXPECT_EQ(storm::analysis::AssumptionStatus::INVALID, itr->second); + EXPECT_EQ(true, itr->first->getFirstOperand()->isVariable()); + EXPECT_EQ(true, itr->first->getSecondOperand()->isVariable()); + EXPECT_EQ("2", itr->first->getFirstOperand()->asVariableExpression().getVariable().getName()); + EXPECT_EQ("1", itr->first->getSecondOperand()->asVariableExpression().getVariable().getName()); + EXPECT_EQ(storm::expressions::BinaryRelationExpression::RelationType::Greater, itr->first->getRelationType()); + foundSecond = true; + } else if (!foundThird && itr->first->getRelationType() == storm::expressions::BinaryRelationExpression::RelationType::Equal) { + EXPECT_EQ(storm::analysis::AssumptionStatus::INVALID, itr->second); + EXPECT_EQ(true, itr->first->getFirstOperand()->isVariable()); + EXPECT_EQ(true, itr->first->getSecondOperand()->isVariable()); + EXPECT_EQ("2", itr->first->getFirstOperand()->asVariableExpression().getVariable().getName()); + EXPECT_EQ("1", itr->first->getSecondOperand()->asVariableExpression().getVariable().getName()); + EXPECT_EQ(storm::expressions::BinaryRelationExpression::RelationType::Equal, itr->first->getRelationType()); + foundThird = true; + } else { + EXPECT_TRUE(false); + } + } + EXPECT_TRUE(foundFirst); + EXPECT_TRUE(foundSecond); + EXPECT_TRUE(foundThird); } + From 74598000020c16d068466b3521167aa45b5b94b2 Mon Sep 17 00:00:00 2001 From: Jip Spel Date: Thu, 2 May 2019 15:16:05 +0200 Subject: [PATCH 148/178] Improve derivative check --- src/storm-pars/analysis/MonotonicityChecker.h | 34 ++++++------ .../analysis/MonotonicityCheckerTest.cpp | 53 +++++++++++++++++++ 2 files changed, 71 insertions(+), 16 deletions(-) diff --git a/src/storm-pars/analysis/MonotonicityChecker.h b/src/storm-pars/analysis/MonotonicityChecker.h index 957827f73..a183edf14 100644 --- a/src/storm-pars/analysis/MonotonicityChecker.h +++ b/src/storm-pars/analysis/MonotonicityChecker.h @@ -77,7 +77,6 @@ namespace storm { new storm::expressions::ExpressionManager()); storm::solver::Z3SmtSolver s(*manager); - storm::solver::SmtSolver::CheckResult smtResult = storm::solver::SmtSolver::CheckResult::Unknown; std::set variables = derivative.gatherVariables(); @@ -91,28 +90,31 @@ namespace storm { for (auto var : managervars) { exprBounds = exprBounds && manager->rational(0) < var && var < manager->rational(1); } + assert (s.check() == storm::solver::SmtSolver::CheckResult::Sat); auto converter = storm::expressions::RationalFunctionToExpression(manager); - storm::expressions::Expression exprToCheck1 = - converter.toExpression(derivative) >= manager->rational(0); + // < 0 so not monotone increasing + storm::expressions::Expression exprToCheck = + converter.toExpression(derivative) < manager->rational(0); s.add(exprBounds); - s.add(exprToCheck1); - smtResult = s.check(); - monIncr = smtResult == storm::solver::SmtSolver::CheckResult::Sat; + s.add(exprToCheck); + // If it is unsatisfiable then it should be monotone increasing + monIncr = s.check() == storm::solver::SmtSolver::CheckResult::Unsat; + + // > 0 so not monotone decreasing + exprToCheck = + converter.toExpression(derivative) > manager->rational(0); - storm::expressions::Expression exprToCheck2 = - converter.toExpression(derivative) <= manager->rational(0); s.reset(); - smtResult = storm::solver::SmtSolver::CheckResult::Unknown; s.add(exprBounds); - s.add(exprToCheck2); - smtResult = s.check(); - monDecr = smtResult == storm::solver::SmtSolver::CheckResult::Sat; - if (monIncr && monDecr) { - monIncr = false; - monDecr = false; - } + assert (s.check() == storm::solver::SmtSolver::CheckResult::Sat); + s.add(exprToCheck); + monDecr = s.check() == storm::solver::SmtSolver::CheckResult::Unsat; +// if (monIncr && monDecr) { +// monIncr = false; +// monDecr = false; +// } } assert (!(monIncr && monDecr) || derivative.isZero()); diff --git a/src/test/storm-pars/analysis/MonotonicityCheckerTest.cpp b/src/test/storm-pars/analysis/MonotonicityCheckerTest.cpp index 3367f3d09..bb2d7008e 100644 --- a/src/test/storm-pars/analysis/MonotonicityCheckerTest.cpp +++ b/src/test/storm-pars/analysis/MonotonicityCheckerTest.cpp @@ -26,6 +26,59 @@ #include "storm/api/storm.h" #include "storm-parsers/api/storm-parsers.h" +TEST(MonotonicityCheckerTest, Derivative_checker) { + // Derivative 0 + auto constFunction = storm::RationalFunction(0); + auto constFunctionRes = storm::analysis::MonotonicityChecker::checkDerivative(constFunction); + EXPECT_TRUE(constFunctionRes.first); + EXPECT_TRUE(constFunctionRes.second); + + // Derivative 5 + constFunction = storm::RationalFunction(5); + constFunctionRes = storm::analysis::MonotonicityChecker::checkDerivative(constFunction); + EXPECT_TRUE(constFunctionRes.first); + EXPECT_FALSE(constFunctionRes.second); + + // Derivative -4 + constFunction = storm::RationalFunction(storm::RationalFunction(1)-constFunction); + constFunctionRes = storm::analysis::MonotonicityChecker::checkDerivative(constFunction); + EXPECT_FALSE(constFunctionRes.first); + EXPECT_TRUE(constFunctionRes.second); + + std::shared_ptr cache = std::make_shared(); + carl::StringParser parser; + parser.setVariables({"p", "q"}); + // Derivative p + auto function = storm::RationalFunction(storm::Polynomial(parser.template parseMultivariatePolynomial("p"), cache)); + auto functionRes = storm::analysis::MonotonicityChecker::checkDerivative(function); + EXPECT_TRUE(functionRes.first); + EXPECT_FALSE(functionRes.second); + + // Derivative 1-p + auto functionDecr = storm::RationalFunction(storm::RationalFunction(1)-function); + auto functionDecrRes = storm::analysis::MonotonicityChecker::checkDerivative(functionDecr); + EXPECT_TRUE(functionDecrRes.first); + EXPECT_FALSE(functionDecrRes.second); + + // Derivative 1-2p + auto functionNonMonotonic = storm::RationalFunction(storm::RationalFunction(1)-storm::RationalFunction(2)*function); + auto functionNonMonotonicRes = storm::analysis::MonotonicityChecker::checkDerivative(functionNonMonotonic); + EXPECT_FALSE(functionNonMonotonicRes.first); + EXPECT_FALSE(functionNonMonotonicRes.second); + + // Derivative -p + functionDecr = storm::RationalFunction(storm::RationalFunction(0)-function); + functionDecrRes = storm::analysis::MonotonicityChecker::checkDerivative(functionDecr); + EXPECT_FALSE(functionDecrRes.first); + EXPECT_TRUE(functionDecrRes.second); + + // Derivative p*q + function = storm::RationalFunction(storm::Polynomial(parser.template parseMultivariatePolynomial("p"), cache)) + * storm::RationalFunction(storm::Polynomial(parser.template parseMultivariatePolynomial("q"), cache)) ; + functionRes = storm::analysis::MonotonicityChecker::checkDerivative(function); + EXPECT_TRUE(functionRes.first); + EXPECT_FALSE(functionRes.second); +} TEST(MonotonicityCheckerTest, Monotone_no_model) { std::shared_ptr model; From 73a514a9c7d315de5acd18e4c5747086beeb03cb Mon Sep 17 00:00:00 2001 From: Jip Spel Date: Fri, 10 May 2019 14:16:22 +0200 Subject: [PATCH 149/178] Fix validation of assumptions/use it --- src/storm-pars/analysis/AssumptionMaker.cpp | 27 ++++++-- src/storm-pars/analysis/AssumptionMaker.h | 6 +- .../analysis/MonotonicityChecker.cpp | 4 +- .../analysis/AssumptionMakerTest.cpp | 68 +++++++++++++++++++ 4 files changed, 95 insertions(+), 10 deletions(-) diff --git a/src/storm-pars/analysis/AssumptionMaker.cpp b/src/storm-pars/analysis/AssumptionMaker.cpp index e2828db50..bdac30bb2 100644 --- a/src/storm-pars/analysis/AssumptionMaker.cpp +++ b/src/storm-pars/analysis/AssumptionMaker.cpp @@ -8,7 +8,7 @@ namespace storm { namespace analysis { typedef std::shared_ptr AssumptionType; template - AssumptionMaker::AssumptionMaker(storm::analysis::AssumptionChecker* assumptionChecker, uint_fast64_t numberOfStates, bool validate) { + AssumptionMaker::AssumptionMaker(AssumptionChecker* assumptionChecker, uint_fast64_t numberOfStates, bool validate) { this->numberOfStates = numberOfStates; this->assumptionChecker = assumptionChecker; this->validate = validate; @@ -21,7 +21,7 @@ namespace storm { template - std::map, AssumptionStatus> AssumptionMaker::createAndCheckAssumption(uint_fast64_t val1, uint_fast64_t val2, storm::analysis::Lattice* lattice) { + std::map, AssumptionStatus> AssumptionMaker::createAndCheckAssumption(uint_fast64_t val1, uint_fast64_t val2, Lattice* lattice) { std::map, AssumptionStatus> result; // TODO: alleen maar als validate true is results genereren @@ -32,21 +32,38 @@ namespace storm { var1.getExpression().getBaseExpressionPointer(), var2.getExpression().getBaseExpressionPointer(), storm::expressions::BinaryRelationExpression::RelationType::Greater)); // TODO: dischargen gebasseerd op monotonicity - auto result1 = assumptionChecker->validateAssumption(assumption1, lattice); + AssumptionStatus result1; + AssumptionStatus result2; + AssumptionStatus result3; + if (validate) { + result1 = assumptionChecker->validateAssumption(assumption1, lattice); + } else { + result1 = AssumptionStatus::UNKNOWN; + } result[assumption1] = result1; + std::shared_ptr assumption2 = std::make_shared(storm::expressions::BinaryRelationExpression(*expressionManager, expressionManager->getBooleanType(), var2.getExpression().getBaseExpressionPointer(), var1.getExpression().getBaseExpressionPointer(), storm::expressions::BinaryRelationExpression::RelationType::Greater)); - auto result2 = assumptionChecker->validateAssumption(assumption2, lattice); + + if (validate) { + result2 = assumptionChecker->validateAssumption(assumption2, lattice); + } else { + result2 = AssumptionStatus::UNKNOWN; + } result[assumption2] = result2; std::shared_ptr assumption3 = std::make_shared(storm::expressions::BinaryRelationExpression(*expressionManager, expressionManager->getBooleanType(), var2.getExpression().getBaseExpressionPointer(), var1.getExpression().getBaseExpressionPointer(), storm::expressions::BinaryRelationExpression::RelationType::Equal)); - auto result3 = assumptionChecker->validateAssumption(assumption3, lattice); + if (validate) { + result3 = assumptionChecker->validateAssumption(assumption3, lattice); + } else { + result3 = AssumptionStatus::UNKNOWN; + } result[assumption3] = result3; return result; diff --git a/src/storm-pars/analysis/AssumptionMaker.h b/src/storm-pars/analysis/AssumptionMaker.h index 72d0255dc..2f52b85de 100644 --- a/src/storm-pars/analysis/AssumptionMaker.h +++ b/src/storm-pars/analysis/AssumptionMaker.h @@ -26,12 +26,12 @@ namespace storm { * @param checker The AssumptionChecker which checks the assumptions at sample points. * @param numberOfStates The number of states of the model. */ - AssumptionMaker( storm::analysis::AssumptionChecker* checker, uint_fast64_t numberOfStates, bool validate); + AssumptionMaker( AssumptionChecker* checker, uint_fast64_t numberOfStates, bool validate); - std::map, AssumptionStatus> createAndCheckAssumption(uint_fast64_t val1, uint_fast64_t val2, storm::analysis::Lattice* lattice); + std::map, AssumptionStatus> createAndCheckAssumption(uint_fast64_t val1, uint_fast64_t val2, Lattice* lattice); private: - storm::analysis::AssumptionChecker* assumptionChecker; + AssumptionChecker* assumptionChecker; std::shared_ptr expressionManager; diff --git a/src/storm-pars/analysis/MonotonicityChecker.cpp b/src/storm-pars/analysis/MonotonicityChecker.cpp index d96c358de..64543de48 100644 --- a/src/storm-pars/analysis/MonotonicityChecker.cpp +++ b/src/storm-pars/analysis/MonotonicityChecker.cpp @@ -332,14 +332,14 @@ namespace storm { // TODO: checkend at ie niet invalid is criticalTuple = extender->extendLattice(latticeCopy, assumption2.first); - if (somewhereMonotonicity(std::get<0>(criticalTuple))) { + if (assumption2.second != AssumptionStatus::INVALID && somewhereMonotonicity(std::get<0>(criticalTuple))) { auto map = extendLatticeWithAssumptions(std::get<0>(criticalTuple), assumptionMaker, std::get<1>(criticalTuple), std::get<2>(criticalTuple), assumptionsCopy); result.insert(map.begin(), map.end()); } criticalTuple = extender->extendLattice(latticeCopy2, assumption3.first); - if (somewhereMonotonicity(std::get<0>(criticalTuple))) { + if (assumption3.second != AssumptionStatus::INVALID && somewhereMonotonicity(std::get<0>(criticalTuple))) { auto map = extendLatticeWithAssumptions(std::get<0>(criticalTuple), assumptionMaker, std::get<1>(criticalTuple), std::get<2>(criticalTuple), assumptionsCopy2); diff --git a/src/test/storm-pars/analysis/AssumptionMakerTest.cpp b/src/test/storm-pars/analysis/AssumptionMakerTest.cpp index a7603ca09..bcdac1227 100644 --- a/src/test/storm-pars/analysis/AssumptionMakerTest.cpp +++ b/src/test/storm-pars/analysis/AssumptionMakerTest.cpp @@ -28,6 +28,7 @@ #include "storm-parsers/api/storm-parsers.h" +//TODO: voor als validate uit staat TEST(AssumptionMakerTest, Brp_without_bisimulation) { std::string programFile = STORM_TEST_RESOURCES_DIR "/pdtmc/brp16_2.pm"; std::string formulaAsString = "P=? [F s=4 & i=N ]"; @@ -94,6 +95,73 @@ TEST(AssumptionMakerTest, Brp_without_bisimulation) { EXPECT_TRUE(foundThird); } +TEST(AssumptionMakerTest, Brp_without_bisimulation_no_validation) { + std::string programFile = STORM_TEST_RESOURCES_DIR "/pdtmc/brp16_2.pm"; + std::string formulaAsString = "P=? [F s=4 & i=N ]"; + std::string constantsAsString = ""; //e.g. pL=0.9,TOACK=0.5 + + // Program and formula + storm::prism::Program program = storm::api::parseProgram(programFile); + program = storm::utility::prism::preprocess(program, constantsAsString); + std::vector> formulas = storm::api::extractFormulasFromProperties(storm::api::parsePropertiesForPrismProgram(formulaAsString, program)); + std::shared_ptr> model = storm::api::buildSparseModel(program, formulas)->as>(); + std::shared_ptr> dtmc = model->as>(); + auto simplifier = storm::transformer::SparseParametricDtmcSimplifier>(*dtmc); + ASSERT_TRUE(simplifier.simplify(*(formulas[0]))); + model = simplifier.getSimplifiedModel(); + dtmc = model->as>(); + + ASSERT_EQ(dtmc->getNumberOfStates(), 193ull); + ASSERT_EQ(dtmc->getNumberOfTransitions(), 383ull); + + auto *extender = new storm::analysis::LatticeExtender(dtmc); + auto criticalTuple = extender->toLattice(formulas); + ASSERT_EQ(183, std::get<1>(criticalTuple)); + ASSERT_EQ(186, std::get<2>(criticalTuple)); + + auto assumptionChecker = storm::analysis::AssumptionChecker(formulas[0], dtmc, 3); + // This one does not validate the assumptions! + auto assumptionMaker = storm::analysis::AssumptionMaker(&assumptionChecker, dtmc->getNumberOfStates(), false); + auto result = assumptionMaker.createAndCheckAssumption(std::get<1>(criticalTuple), std::get<2>(criticalTuple), std::get<0>(criticalTuple)); + + EXPECT_EQ(3, result.size()); + + bool foundFirst = false; + bool foundSecond = false; + bool foundThird = false; + for (auto itr = result.begin(); itr != result.end(); ++itr) { + if (!foundFirst && itr->first->getFirstOperand()->asVariableExpression().getVariable().getName() == "183") { + EXPECT_EQ(storm::analysis::AssumptionStatus::UNKNOWN, itr->second); + EXPECT_EQ(true, itr->first->getFirstOperand()->isVariable()); + EXPECT_EQ(true, itr->first->getSecondOperand()->isVariable()); + EXPECT_EQ("186", itr->first->getSecondOperand()->asVariableExpression().getVariable().getName()); + EXPECT_EQ(storm::expressions::BinaryRelationExpression::RelationType::Greater, itr->first->getRelationType()); + foundFirst = true; + } else if (!foundSecond && itr->first->getRelationType() == storm::expressions::BinaryRelationExpression::RelationType::Greater) { + EXPECT_EQ(storm::analysis::AssumptionStatus::UNKNOWN, itr->second); + EXPECT_EQ(true, itr->first->getFirstOperand()->isVariable()); + EXPECT_EQ(true, itr->first->getSecondOperand()->isVariable()); + EXPECT_EQ("186", itr->first->getFirstOperand()->asVariableExpression().getVariable().getName()); + EXPECT_EQ("183", itr->first->getSecondOperand()->asVariableExpression().getVariable().getName()); + EXPECT_EQ(storm::expressions::BinaryRelationExpression::RelationType::Greater, itr->first->getRelationType()); + foundSecond = true; + } else if (!foundThird && itr->first->getRelationType() == storm::expressions::BinaryRelationExpression::RelationType::Equal) { + EXPECT_EQ(storm::analysis::AssumptionStatus::UNKNOWN, itr->second); + EXPECT_EQ(true, itr->first->getFirstOperand()->isVariable()); + EXPECT_EQ(true, itr->first->getSecondOperand()->isVariable()); + EXPECT_EQ("186", itr->first->getFirstOperand()->asVariableExpression().getVariable().getName()); + EXPECT_EQ("183", itr->first->getSecondOperand()->asVariableExpression().getVariable().getName()); + EXPECT_EQ(storm::expressions::BinaryRelationExpression::RelationType::Equal, itr->first->getRelationType()); + foundThird = true; + } else { + EXPECT_TRUE(false); + } + } + EXPECT_TRUE(foundFirst); + EXPECT_TRUE(foundSecond); + EXPECT_TRUE(foundThird); +} + TEST(AssumptionMakerTest, Simple1) { std::string programFile = STORM_TEST_RESOURCES_DIR "/pdtmc/simple1.pm"; std::string formulaAsString = "P=? [F s=3]"; From 77a70179d3e69c5c915cda02425bd672e21d4d35 Mon Sep 17 00:00:00 2001 From: Jip Spel Date: Tue, 14 May 2019 15:05:47 +0200 Subject: [PATCH 150/178] Update MonotonicityChecker --- .../analysis/MonotonicityChecker.cpp | 618 +++++------------- src/storm-pars/analysis/MonotonicityChecker.h | 18 +- .../analysis/MonotonicityCheckerTest.cpp | 89 +-- 3 files changed, 185 insertions(+), 540 deletions(-) diff --git a/src/storm-pars/analysis/MonotonicityChecker.cpp b/src/storm-pars/analysis/MonotonicityChecker.cpp index 64543de48..a2f3693c0 100644 --- a/src/storm-pars/analysis/MonotonicityChecker.cpp +++ b/src/storm-pars/analysis/MonotonicityChecker.cpp @@ -27,112 +27,35 @@ namespace storm { namespace analysis { template - MonotonicityChecker::MonotonicityChecker(std::shared_ptr model, std::vector> formulas, bool validate) { + MonotonicityChecker::MonotonicityChecker(std::shared_ptr model, std::vector> formulas, bool validate, uint_fast64_t numberOfSamples) { outfile.open(filename, std::ios_base::app); + assert (model != nullptr); this->model = model; this->formulas = formulas; this->validate = validate; - this->resultCheckOnSamples = std::map>(); - // TODO initialiseren van sample check - if (model != nullptr) { - std::shared_ptr> sparseModel = model->as>(); - this->extender = new storm::analysis::LatticeExtender(sparseModel); - outfile << model->getNumberOfStates() << ", " << model->getNumberOfTransitions() << ", "; + + // sampling + if ( model->isOfType(storm::models::ModelType::Dtmc)) { + this->resultCheckOnSamples = std::map>(checkOnSamples(model->as>(), numberOfSamples)); + } else if (model->isOfType(storm::models::ModelType::Mdp)){ + this->resultCheckOnSamples = std::map>(checkOnSamples(model->as>(), numberOfSamples)); + } + + std::shared_ptr> sparseModel = model->as>(); + this->extender = new storm::analysis::LatticeExtender(sparseModel); + outfile << model->getNumberOfStates() << ", " << model->getNumberOfTransitions() << ", "; outfile.close(); - totalWatch = storm::utility::Stopwatch(true); } template std::map>> MonotonicityChecker::checkMonotonicity() { - // TODO: check on samples or not? - totalWatch = storm::utility::Stopwatch(true); - auto latticeWatch = storm::utility::Stopwatch(true); auto map = createLattice(); - // STORM_PRINT(std::endl << "Time for creating lattice: " << latticeWatch << "." << std::endl << std::endl); std::shared_ptr> sparseModel = model->as>(); auto matrix = sparseModel->getTransitionMatrix(); return checkMonotonicity(map, matrix); } - template - std::vector> MonotonicityChecker::checkAssumptionsOnRegion(std::vector> assumptions) { - assert (formulas[0]->isProbabilityOperatorFormula()); - assert (formulas[0]->asProbabilityOperatorFormula().getSubformula().isUntilFormula() || formulas[0]->asProbabilityOperatorFormula().getSubformula().isEventuallyFormula()); - Environment env = Environment(); - std::shared_ptr> sparseModel = model->as>(); - bool generateSplitEstimates = false; - bool allowModelSimplification = false; - auto task = storm::api::createTask(formulas[0], true); - // TODO: storm::RationalNumber or double? - - // TODO: Also allow different models - STORM_LOG_THROW (sparseModel->isOfType(storm::models::ModelType::Dtmc), storm::exceptions::NotImplementedException, - "Checking assumptions on a region not implemented for this type of model"); - auto modelChecker = storm::api::initializeParameterLiftingDtmcModelChecker(env, sparseModel, task, generateSplitEstimates, allowModelSimplification); - - std::stack, int>> regions; - std::vector> satRegions; - std::string regionText = ""; - auto parameters = storm::models::sparse::getProbabilityParameters(*sparseModel); - for (auto itr = parameters.begin(); itr != parameters.end(); ++itr) { - if (regionText != "") { - regionText += ","; - } - // TODO: region bounds - regionText += "0.1 <= " + itr->name() + " <= 0.9"; - } - - auto initialRegion = storm::api::parseRegion(regionText, parameters); - regions.push(std::pair, int>(initialRegion,0)); - while (!regions.empty()) { - auto lastElement = regions.top(); - regions.pop(); - storm::storage::ParameterRegion currentRegion = lastElement.first; - - // TODO: depth - if (lastElement.second < 5) { - auto upperBound = modelChecker->getBound(env, currentRegion, storm::solver::OptimizationDirection::Maximize); - auto lowerBound = modelChecker->getBound(env, currentRegion, storm::solver::OptimizationDirection::Minimize); - std::vector valuesUpper = upperBound->template asExplicitQuantitativeCheckResult().getValueVector(); - std::vector valuesLower = lowerBound->template asExplicitQuantitativeCheckResult().getValueVector(); - bool assumptionsHold = true; - for (auto itr = assumptions.begin(); assumptionsHold && itr != assumptions.end(); ++itr) { - auto assumption = *itr; - if (assumption->getRelationType() == storm::expressions::BinaryRelationExpression::RelationType::Greater) { - auto state1 = std::stoi( - assumption->getFirstOperand()->asVariableExpression().getVariableName()); - auto state2 = std::stoi( - assumption->getSecondOperand()->asVariableExpression().getVariableName()); - assumptionsHold &= valuesLower[state1] >= valuesUpper[state2]; - } else if (assumption->getRelationType() == storm::expressions::BinaryRelationExpression::RelationType::Equal) { - auto state1 = std::stoi( - assumption->getFirstOperand()->asVariableExpression().getVariableName()); - auto state2 = std::stoi( - assumption->getSecondOperand()->asVariableExpression().getVariableName()); - assumptionsHold &= valuesLower[state1] == valuesUpper[state2]; - } else { - assert(false); - } - } - if (!assumptionsHold) { - std::vector> newRegions; - currentRegion.split(currentRegion.getCenterPoint(), newRegions); - for (auto itr = newRegions.begin(); itr != newRegions.end(); ++itr) { - regions.push(std::pair, int>(*itr, - lastElement.second + - 1)); - } - } else { - satRegions.push_back(currentRegion); - } - } - } - return satRegions; - } - - - template std::map>> MonotonicityChecker::checkMonotonicity(std::map>> map, storm::storage::SparseMatrix matrix) { storm::utility::Stopwatch monotonicityCheckWatch(true); @@ -142,8 +65,26 @@ namespace storm { if (map.size() == 0) { // Nothing is known - outfile << " No assumptions; ?"; - // STORM_PRINT(std::endl << "Do not know about monotonicity" << std::endl); + outfile << " No assumptions -"; + STORM_PRINT("No valid assumptions, couldn't build a sufficient lattice"); + if (resultCheckOnSamples.size() != 0) { + STORM_PRINT("\n" << "Based results on samples"); + } else { + outfile << " ?"; + } + + for (auto entry : resultCheckOnSamples) { + if (!entry.second.first && ! entry.second.second) { + outfile << " SX " << entry.first << " "; + } else if (entry.second.first && ! entry.second.second) { + outfile << " SI " << entry.first << " "; + } else if (entry.second.first && entry.second.second) { + outfile << " SC " << entry.first << " "; + } else { + outfile << " SD " << entry.first << " "; + } + } + } else { auto i = 0; for (auto itr = map.begin(); i < map.size() && itr != map.end(); ++itr) { @@ -160,43 +101,21 @@ namespace storm { validSomewhere = itr2->second.first || itr2->second.second; } if (assumptions.size() > 0) { -// auto regions = checkAssumptionsOnRegion(assumptions); -// if (regions.size() > 0) { -// // STORM_PRINT("For regions: " << std::endl); -// bool first = true; -// for (auto itr2 = regions.begin(); itr2 != regions.end(); ++itr2) { -// if (first) { -// // STORM_PRINT(" "); -// first = false; -// } -// // STORM_PRINT(*itr2); -// outfile << (*itr2); -// } -// // STORM_PRINT(std::endl); -// outfile << ", "; -// } else { - // STORM_PRINT("Assumption(s): "); - bool first = true; - for (auto itr2 = assumptions.begin(); itr2 != assumptions.end(); ++itr2) { - if (!first) { - // STORM_PRINT(" ^ "); - outfile << (" ^ "); - } else { - first = false; - } - // STORM_PRINT(*(*itr2)); - outfile << (*(*itr2)); + bool first = true; + for (auto itr2 = assumptions.begin(); itr2 != assumptions.end(); ++itr2) { + if (!first) { + outfile << (" ^ "); + } else { + first = false; } - // STORM_PRINT(std::endl); - outfile << " - "; -// } + outfile << (*(*itr2)); + } + outfile << " - "; } else if (assumptions.size() == 0) { outfile << "No assumptions - "; } - if (validSomewhere && varsMonotone.size() == 0) { - // STORM_PRINT("Result is constant" << std::endl); outfile << "No params"; } else if (validSomewhere) { auto itr2 = varsMonotone.begin(); @@ -204,21 +123,15 @@ namespace storm { if (resultCheckOnSamples.find(itr2->first) != resultCheckOnSamples.end() && (!resultCheckOnSamples[itr2->first].first && !resultCheckOnSamples[itr2->first].second)) { - // STORM_PRINT(" - Not monotone in: " << itr2->first << std::endl); outfile << "X " << itr2->first; } else { if (itr2->second.first && itr2->second.second) { - // STORM_PRINT(" - Constant in" << itr2->first << std::endl); outfile << "C " << itr2->first; } else if (itr2->second.first) { - // STORM_PRINT(" - Monotone increasing in: " << itr2->first << std::endl); outfile << "I " << itr2->first; } else if (itr2->second.second) { - // STORM_PRINT(" - Monotone decreasing in: " << itr2->first << std::endl); outfile << "D " << itr2->first; } else { - - // STORM_PRINT(" - Do not know if monotone incr/decreasing in: " << itr2->first << std::endl); outfile << "? " << itr2->first; } } @@ -244,7 +157,6 @@ namespace storm { monotonicityCheckWatch.stop(); outfile << monotonicityCheckWatch << ", "; - // STORM_PRINT(std::endl << "Time for monotonicity check on lattice: " << monotonicityCheckWatch << "." << std::endl << std::endl); outfile.close(); return result; } @@ -283,7 +195,6 @@ namespace storm { assert(false); } latticeWatch.stop(); - // STORM_PRINT(std::endl << "Total time for lattice creation: " << latticeWatch << "." << std::endl << std::endl); outfile.open(filename, std::ios_base::app); outfile << latticeWatch << ", "; outfile.close(); @@ -300,7 +211,7 @@ namespace storm { assert (lattice->getAddedStates()->size() == lattice->getAddedStates()->getNumberOfSetBits()); result.insert(std::pair>>(lattice, assumptions)); } else { - + // Make the three assumptions auto assumptionTriple = assumptionMaker->createAndCheckAssumption(val1, val2, lattice); assert (assumptionTriple.size() == 3); auto itr = assumptionTriple.begin(); @@ -310,152 +221,55 @@ namespace storm { ++itr; auto assumption3 = *itr; - auto assumptionsCopy = std::vector>( - assumptions); - auto assumptionsCopy2 = std::vector>( - assumptions); + if (assumption1.second != AssumptionStatus::INVALID) { + auto latticeCopy = new Lattice(lattice); + auto assumptionsCopy = std::vector>(assumptions); - auto latticeCopy = new storm::analysis::Lattice(lattice); - auto latticeCopy2 = new storm::analysis::Lattice(lattice); - - assumptions.push_back(assumption1.first); - assumptionsCopy.push_back(assumption2.first); - assumptionsCopy2.push_back(assumption3.first); + if (assumption1.second == AssumptionStatus::UNKNOWN) { + // only add assumption to the set of assumptions if it is unknown if it is valid + assumptionsCopy.push_back(assumption1.first); + } - auto criticalTuple = extender->extendLattice(lattice, assumption1.first); - if (assumption1.second != AssumptionStatus::INVALID && somewhereMonotonicity(std::get<0>(criticalTuple))) { - auto map = extendLatticeWithAssumptions(std::get<0>(criticalTuple), assumptionMaker, - std::get<1>(criticalTuple), std::get<2>(criticalTuple), - assumptions); - result.insert(map.begin(), map.end()); + auto criticalTuple = extender->extendLattice(latticeCopy, assumption1.first); + if (somewhereMonotonicity(std::get<0>(criticalTuple))) { + auto map = extendLatticeWithAssumptions(std::get<0>(criticalTuple), assumptionMaker, + std::get<1>(criticalTuple), std::get<2>(criticalTuple), + assumptionsCopy); + result.insert(map.begin(), map.end()); + } } - // TODO: checkend at ie niet invalid is - criticalTuple = extender->extendLattice(latticeCopy, assumption2.first); - if (assumption2.second != AssumptionStatus::INVALID && somewhereMonotonicity(std::get<0>(criticalTuple))) { - auto map = extendLatticeWithAssumptions(std::get<0>(criticalTuple), assumptionMaker, - std::get<1>(criticalTuple), std::get<2>(criticalTuple), - assumptionsCopy); - result.insert(map.begin(), map.end()); - } - criticalTuple = extender->extendLattice(latticeCopy2, assumption3.first); - if (assumption3.second != AssumptionStatus::INVALID && somewhereMonotonicity(std::get<0>(criticalTuple))) { - auto map = extendLatticeWithAssumptions(std::get<0>(criticalTuple), assumptionMaker, - std::get<1>(criticalTuple), std::get<2>(criticalTuple), - assumptionsCopy2); - result.insert(map.begin(), map.end()); + if (assumption2.second != AssumptionStatus::INVALID) { + auto latticeCopy = new Lattice(lattice); + auto assumptionsCopy = std::vector>(assumptions); + + if (assumption2.second == AssumptionStatus::UNKNOWN) { + assumptionsCopy.push_back(assumption2.first); + } + + auto criticalTuple = extender->extendLattice(latticeCopy, assumption2.first); + if (somewhereMonotonicity(std::get<0>(criticalTuple))) { + auto map = extendLatticeWithAssumptions(std::get<0>(criticalTuple), assumptionMaker, + std::get<1>(criticalTuple), std::get<2>(criticalTuple), + assumptionsCopy); + result.insert(map.begin(), map.end()); + } } + if (assumption3.second != AssumptionStatus::INVALID) { + // Here we can use the original lattice and assumptions set + if (assumption3.second == AssumptionStatus::UNKNOWN) { + assumptions.push_back(assumption3.first); + } -// if (!assumption1.second && !assumption2.second && !assumption3.second) { -// // Both assumption cannot be validated, so we need to keep them both -// // TODO: hier niet verder gaan als je iets gevonden hebt? -// auto assumptionsCopy = std::vector>( -// assumptions); -// auto assumptionsCopy2 = std::vector>( -// assumptions); -// auto latticeCopy = new storm::analysis::Lattice(lattice); -// auto latticeCopy2 = new storm::analysis::Lattice(lattice); -// assumptions.push_back(assumption1.first); -// assumptionsCopy.push_back(assumption2.first); -// assumptionsCopy2.push_back(assumption3.first); -// -// auto criticalTuple = extender->extendLattice(lattice, assumption1.first); -// if (somewhereMonotonicity(std::get<0>(criticalTuple))) { -// auto map = extendLatticeWithAssumptions(std::get<0>(criticalTuple), assumptionMaker, -// std::get<1>(criticalTuple), std::get<2>(criticalTuple), -// assumptions); -// result.insert(map.begin(), map.end()); -// } -// -// criticalTuple = extender->extendLattice(latticeCopy, assumption2.first); -// if (somewhereMonotonicity(std::get<0>(criticalTuple))) { -// auto map = extendLatticeWithAssumptions(std::get<0>(criticalTuple), assumptionMaker, -// std::get<1>(criticalTuple), std::get<2>(criticalTuple), -// assumptionsCopy); -// result.insert(map.begin(), map.end()); -// } -// criticalTuple = extender->extendLattice(latticeCopy2, assumption3.first); -// if (somewhereMonotonicity(std::get<0>(criticalTuple))) { -// auto map = extendLatticeWithAssumptions(std::get<0>(criticalTuple), assumptionMaker, -// std::get<1>(criticalTuple), std::get<2>(criticalTuple), -// assumptionsCopy2); -// result.insert(map.begin(), map.end()); -// } -//// } -// } else if (!assumption3.second && assumption1.second && assumption2.second) { -//// assert (false); -// //TODO Both assumptions hold --> should not happen if we change it to < instead of <= -// auto assumption = assumptionMaker->createEqualAssumption(val1, val2); -// if (!validate) { -// assumptions.push_back(assumption); -// } -// // if validate is true and both hold, then they must be valid, so no need to add to assumptions -// auto criticalTuple = extender->extendLattice(lattice, assumption); -// if (somewhereMonotonicity(std::get<0>(criticalTuple))) { -// result = extendLatticeWithAssumptions(std::get<0>(criticalTuple), assumptionMaker, std::get<1>(criticalTuple), std::get<2>(criticalTuple), assumptions); -// } -// } else if (!assumption3.second && !assumption2.second && assumption1.second) { -// if (!validate) { -//// assert(false); -// assumptions.push_back(assumption1.first); -// } -// // if validate is true and both hold, then they must be valid, so no need to add to assumptions -// -// auto criticalTuple = extender->extendLattice(lattice, assumption1.first); -// -// if (somewhereMonotonicity(std::get<0>(criticalTuple))) { -// result = extendLatticeWithAssumptions(std::get<0>(criticalTuple), assumptionMaker, std::get<1>(criticalTuple), std::get<2>(criticalTuple), assumptions); -// } -// -// } else if (!assumption3.second && !assumption1.second && assumption2.second){ -//// assert (assumption2.second); -// if (!validate) { -// assumptions.push_back(assumption2.first); -// } -// // if validate is true and both hold, then they must be valid, so no need to add to assumptions -// auto criticalTuple = extender->extendLattice(lattice, assumption2.first); -// if (somewhereMonotonicity(std::get<0>(criticalTuple))) { -// result = extendLatticeWithAssumptions(std::get<0>(criticalTuple), assumptionMaker, std::get<1>(criticalTuple), std::get<2>(criticalTuple), assumptions); -// } -// } else { -// // TODO: should not happen -// STORM_LOG_WARN("All assumptions are true");// {" << *(assumption1.first) <<", " << *(assumption2.first) << ", " << *(assumption3.first) << "}" << std::endl); -// // Both assumption cannot be validated, so we need to keep them both -// // TODO: hier niet verder gaan als je iets gevonden hebt? -// auto assumptionsCopy = std::vector>( -// assumptions); -// auto assumptionsCopy2 = std::vector>( -// assumptions); -// auto latticeCopy = new storm::analysis::Lattice(lattice); -// auto latticeCopy2 = new storm::analysis::Lattice(lattice); -// assumptions.push_back(assumption1.first); -// assumptionsCopy.push_back(assumption2.first); -// assumptionsCopy2.push_back(assumption2.first); -// -// auto criticalTuple = extender->extendLattice(lattice, assumption1.first); -// if (somewhereMonotonicity(std::get<0>(criticalTuple))) { -// auto map = extendLatticeWithAssumptions(std::get<0>(criticalTuple), assumptionMaker, -// std::get<1>(criticalTuple), std::get<2>(criticalTuple), -// assumptions); -// result.insert(map.begin(), map.end()); -// } -// -// criticalTuple = extender->extendLattice(latticeCopy, assumption2.first); -// if (somewhereMonotonicity(std::get<0>(criticalTuple))) { -// auto map = extendLatticeWithAssumptions(std::get<0>(criticalTuple), assumptionMaker, -// std::get<1>(criticalTuple), std::get<2>(criticalTuple), -// assumptionsCopy); -// result.insert(map.begin(), map.end()); -// } -// criticalTuple = extender->extendLattice(latticeCopy2, assumption3.first); -// if (somewhereMonotonicity(std::get<0>(criticalTuple))) { -// auto map = extendLatticeWithAssumptions(std::get<0>(criticalTuple), assumptionMaker, -// std::get<1>(criticalTuple), std::get<2>(criticalTuple), -// assumptionsCopy2); -// result.insert(map.begin(), map.end()); -// } -// } + auto criticalTuple = extender->extendLattice(lattice, assumption3.first); + if (somewhereMonotonicity(std::get<0>(criticalTuple))) { + auto map = extendLatticeWithAssumptions(std::get<0>(criticalTuple), assumptionMaker, + std::get<1>(criticalTuple), std::get<2>(criticalTuple), + assumptions); + result.insert(map.begin(), map.end()); + } + } } return result; } @@ -474,17 +288,17 @@ namespace storm { template std::map> MonotonicityChecker::analyseMonotonicity(uint_fast64_t j, storm::analysis::Lattice* lattice, storm::storage::SparseMatrix matrix) { -// storm::utility::Stopwatch analyseWatch(true); std::map> varsMonotone; + // go over all rows, check for each row local monotonicity for (uint_fast64_t i = 0; i < matrix.getColumnCount(); ++i) { - // go over all rows auto row = matrix.getRow(i); // only enter if you are in a state with at least two successors (so there must be successors, - // and first prob shouldnt be 1) + // and first prob shouldn't be 1) if (row.begin() != row.end() && !row.begin()->getValue().isOne()) { std::map transitions; + // Gather all states which are reached with a non constant probability auto states = new storm::storage::BitVector(matrix.getColumnCount()); std::set vars; for (auto const& entry : row) { @@ -498,94 +312,79 @@ namespace storm { } } - auto sortedStates = lattice->sortStates(states); - - if (sortedStates[sortedStates.size() - 1] == matrix.getColumnCount()) {\ - // states are not properly sorted - for (auto itr = vars.begin(); itr != vars.end(); ++itr) { -// if (resultCheckOnSamples.find(*itr) != resultCheckOnSamples.end() && -// (!resultCheckOnSamples[*itr].first && !resultCheckOnSamples[*itr].second)) { -// if (varsMonotone.find(*itr) == varsMonotone.end()) { -// varsMonotone[*itr].first = false; -// varsMonotone[*itr].second = false; -// } -// } else { - if (varsMonotone.find(*itr) == varsMonotone.end()) { - varsMonotone[*itr].first = true; - varsMonotone[*itr].second = true; - } - std::pair *value = &varsMonotone.find(*itr)->second; - std::pair old = *value; - + // Copy info from checkOnSamples + for (auto itr = vars.begin(); itr != vars.end(); ++itr) { + assert (resultCheckOnSamples.find(*itr) != resultCheckOnSamples.end()); + if (varsMonotone.find(*itr) == varsMonotone.end()) { + varsMonotone[*itr].first = resultCheckOnSamples[*itr].first; + varsMonotone[*itr].second = resultCheckOnSamples[*itr].second; + } else { + varsMonotone[*itr].first &= resultCheckOnSamples[*itr].first; + varsMonotone[*itr].second &= resultCheckOnSamples[*itr].second; + } + } + // Sort the states based on the lattice + auto sortedStates = lattice->sortStates(states); + if (sortedStates[sortedStates.size() - 1] == matrix.getColumnCount()) { + // If the states are not all sorted, we still might obtain some monotonicity + for (auto var: vars) { + // current value of monotonicity + std::pair *value = &varsMonotone.find(var)->second; - for (auto itr2 = transitions.begin(); itr2 != transitions.end(); ++itr2) { - for (auto itr3 = transitions.begin(); itr3 != transitions.end(); ++itr3) { + // Go over all transitions to successor states, compare all of them + for (auto itr2 = transitions.begin(); (value->first || value->second) + && itr2 != transitions.end(); ++itr2) { + for (auto itr3 = transitions.begin(); (value->first || value->second) + && itr3 != transitions.end(); ++itr3) { if (itr2->first < itr3->first) { - auto derivative2 = getDerivative(itr2->second, *itr); - auto derivative3 = getDerivative(itr3->second, *itr); + auto derivative2 = getDerivative(itr2->second, var); + auto derivative3 = getDerivative(itr3->second, var); auto compare = lattice->compare(itr2->first, itr3->first); - if (compare == storm::analysis::Lattice::ABOVE) { - // As the first state (itr2) is above the second state (itr3) it is sufficient to look at the derivative of itr2. + if (compare == Lattice::ABOVE) { + // As the first state (itr2) is above the second state (itr3) it + // is sufficient to look at the derivative of itr2. std::pair mon2; - if (derivative2.isConstant()) { - mon2 = std::pair(derivative2.constantPart() >= 0, - derivative2.constantPart() <= 0); - } else { - mon2 = checkDerivative(derivative2); - } + mon2 = checkDerivative(derivative2); value->first &= mon2.first; value->second &= mon2.second; - } else if (compare == storm::analysis::Lattice::BELOW) { - // As the second state (itr3) is above the first state (itr2) it is sufficient to look at the derivative of itr3. + } else if (compare == Lattice::BELOW) { + // As the second state (itr3) is above the first state (itr2) it + // is sufficient to look at the derivative of itr3. std::pair mon3; - if (derivative2.isConstant()) { - mon3 = std::pair(derivative3.constantPart() >= 0, - derivative3.constantPart() <= 0); - } else { - mon3 = checkDerivative(derivative3); - } + + mon3 = checkDerivative(derivative3); value->first &= mon3.first; value->second &= mon3.second; - } else if (compare == storm::analysis::Lattice::SAME) { - assert (false); - // TODO: klopt dit + } else if (compare == Lattice::SAME) { // Behaviour doesn't matter, as the states are at the same level. } else { - // As the relation between the states is unknown, we can't claim anything about the monotonicity. - value->first = false; - value->second = false; + // only if derivatives are the same we can continue + if (derivative2 != derivative3) { + // As the relation between the states is unknown, we can't claim + // anything about the monotonicity. + value->first = false; + value->second = false; + } + } } -// } } } } } else { - + // The states are all sorted for (auto var : vars) { -// if (resultCheckOnSamples.find(*itr) != resultCheckOnSamples.end() && -// (!resultCheckOnSamples[*itr].first && !resultCheckOnSamples[*itr].second)) { -// if (varsMonotone.find(*itr) == varsMonotone.end()) { -// varsMonotone[*itr].first = false; -// varsMonotone[*itr].second = false; -// } -// } else { - if (varsMonotone.find(var) == varsMonotone.end()) { - varsMonotone[var].first = true; - varsMonotone[var].second = true; - } std::pair *value = &varsMonotone.find(var)->second; bool change = false; for (auto const &i : sortedStates) { -// auto res = checkDerivative(transitions[i].derivative(var)); auto res = checkDerivative(getDerivative(transitions[i], var)); change = change || (!(value->first && value->second) // they do not hold both - && ((value->first && !res.first) - || (value->second && !res.second))); + && ((value->first && !res.first) + || (value->second && !res.second))); if (change) { value->first &= res.second; @@ -598,84 +397,19 @@ namespace storm { break; } } + } } } } - -// analyseWatch.stop(); - // STORM_PRINT(std::endl << "Time to check monotonicity based on the lattice: " << analyseWatch << "." << std::endl << std::endl); -// outfile << analyseWatch << "; "; return varsMonotone; } -// template -// std::pair MonotonicityChecker::checkDerivative(ValueType derivative) { -// bool monIncr = false; -// bool monDecr = false; -// -// if (derivative.isZero()) { -// monIncr = true; -// monDecr = true; -// } else if (derivative.isConstant()) { -// monIncr = derivative.constantPart() >= 0; -// monDecr = derivative.constantPart() <= 0; -// } else { -// -// std::shared_ptr smtSolverFactory = std::make_shared(); -// std::shared_ptr manager( -// new storm::expressions::ExpressionManager()); -// -// storm::solver::Z3SmtSolver s(*manager); -// storm::solver::SmtSolver::CheckResult smtResult = storm::solver::SmtSolver::CheckResult::Unknown; -// -// std::set variables = derivative.gatherVariables(); -// -// -// for (auto variable : variables) { -// manager->declareRationalVariable(variable.name()); -// -// } -// storm::expressions::Expression exprBounds = manager->boolean(true); -// auto managervars = manager->getVariables(); -// for (auto var : managervars) { -// exprBounds = exprBounds && manager->rational(0) < var && var < manager->rational(1); -// } -// -// auto converter = storm::expressions::RationalFunctionToExpression(manager); -// -// storm::expressions::Expression exprToCheck1 = -// converter.toExpression(derivative) >= manager->rational(0); -// s.add(exprBounds); -// s.add(exprToCheck1); -// smtResult = s.check(); -// monIncr = smtResult == storm::solver::SmtSolver::CheckResult::Sat; -// -// storm::expressions::Expression exprToCheck2 = -// converter.toExpression(derivative) <= manager->rational(0); -// s.reset(); -// smtResult = storm::solver::SmtSolver::CheckResult::Unknown; -// s.add(exprBounds); -// s.add(exprToCheck2); -// smtResult = s.check(); -// monDecr = smtResult == storm::solver::SmtSolver::CheckResult::Sat; -// if (monIncr && monDecr) { -// monIncr = false; -// monDecr = false; -// } -// } -// assert (!(monIncr && monDecr) || derivative.isZero()); -// -// return std::pair(monIncr, monDecr); -// } - - template - bool MonotonicityChecker::somewhereMonotonicity(storm::analysis::Lattice* lattice) { + bool MonotonicityChecker::somewhereMonotonicity(Lattice* lattice) { std::shared_ptr> sparseModel = model->as>(); auto matrix = sparseModel->getTransitionMatrix(); - // TODO: tussenresultaten hergebruiken std::map> varsMonotone; for (uint_fast64_t i = 0; i < matrix.getColumnCount(); ++i) { @@ -691,46 +425,54 @@ namespace storm { auto val = first.getValue(); auto vars = val.gatherVariables(); + // Copy info from checkOnSamples for (auto itr = vars.begin(); itr != vars.end(); ++itr) { + assert (resultCheckOnSamples.find(*itr) != resultCheckOnSamples.end()); if (varsMonotone.find(*itr) == varsMonotone.end()) { - varsMonotone[*itr].first = true; - varsMonotone[*itr].second = true; + varsMonotone[*itr].first = resultCheckOnSamples[*itr].first; + varsMonotone[*itr].second = resultCheckOnSamples[*itr].second; + } else { + varsMonotone[*itr].first &= resultCheckOnSamples[*itr].first; + varsMonotone[*itr].second &= resultCheckOnSamples[*itr].second; } - std::pair *value = &varsMonotone.find(*itr)->second; - std::pair old = *value; -// TODO deze ook aanpassen aan deel met smt solver - for (auto itr2 = transitions.begin(); itr2 != transitions.end(); ++itr2) { - for (auto itr3 = transitions.begin(); itr3 != transitions.end(); ++itr3) { - auto derivative2 = itr2->second.derivative(*itr); - auto derivative3 = itr3->second.derivative(*itr); - - auto compare = lattice->compare(itr2->first, itr3->first); - - if (compare == storm::analysis::Lattice::ABOVE) { - // As the first state (itr2) is above the second state (itr3) it is sufficient to look at the derivative of itr2. - std::pair mon2; - if (derivative2.isConstant()) { - mon2 = std::pair(derivative2.constantPart() >= 0, derivative2.constantPart() <=0); - } else { + } + + for (auto var: vars) { + // current value of monotonicity + std::pair *value = &varsMonotone.find(var)->second; + + // Go over all transitions to successor states, compare all of them + for (auto itr2 = transitions.begin(); (value->first || value->second) + && itr2 != transitions.end(); ++itr2) { + for (auto itr3 = transitions.begin(); (value->first || value->second) + && itr3 != transitions.end(); ++itr3) { + if (itr2->first < itr3->first) { + + auto derivative2 = getDerivative(itr2->second, var); + auto derivative3 = getDerivative(itr3->second, var); + + auto compare = lattice->compare(itr2->first, itr3->first); + + if (compare == Lattice::ABOVE) { + // As the first state (itr2) is above the second state (itr3) it + // is sufficient to look at the derivative of itr2. + std::pair mon2; mon2 = checkDerivative(derivative2); - } - value->first &= mon2.first; - value->second &= mon2.second; - } else if (compare == storm::analysis::Lattice::BELOW) { - // As the second state (itr3) is above the first state (itr2) it is sufficient to look at the derivative of itr3. - std::pair mon3; - if (derivative2.isConstant()) { - mon3 = std::pair(derivative3.constantPart() >= 0, derivative3.constantPart() <=0); - } else { + value->first &= mon2.first; + value->second &= mon2.second; + } else if (compare == Lattice::BELOW) { + // As the second state (itr3) is above the first state (itr2) it + // is sufficient to look at the derivative of itr3. + std::pair mon3; + mon3 = checkDerivative(derivative3); + value->first &= mon3.first; + value->second &= mon3.second; + } else if (compare == Lattice::SAME) { + // Behaviour doesn't matter, as the states are at the same level. + } else { + // As the relation between the states is unknown, we don't do anything } - value->first &= mon3.first; - value->second &= mon3.second; - } else if (compare == storm::analysis::Lattice::SAME) { - // TODO: klopt dit - // Behaviour doesn't matter, as the states are at the same level. - } else { - // As the relation between the states is unknown, we don't do anything } } } @@ -804,7 +546,7 @@ namespace storm { initial += values[i]; } float diff = previous - initial; - // TODO: define precission + // TODO: define precision if (previous != -1 && diff > 0.000005 && diff < -0.000005) { monDecr &= previous >= initial; monIncr &= previous <= initial; @@ -815,7 +557,6 @@ namespace storm { } samplesWatch.stop(); - // STORM_PRINT(std::endl << "Time to check monotonicity on samples: " << samplesWatch << "." << std::endl << std::endl); resultCheckOnSamples = result; return result; } @@ -886,7 +627,6 @@ namespace storm { } samplesWatch.stop(); - // STORM_PRINT(std::endl << "Time to check monotonicity on samples: " << samplesWatch << "." << std::endl << std::endl); resultCheckOnSamples = result; return result; } diff --git a/src/storm-pars/analysis/MonotonicityChecker.h b/src/storm-pars/analysis/MonotonicityChecker.h index a183edf14..47e189ad4 100644 --- a/src/storm-pars/analysis/MonotonicityChecker.h +++ b/src/storm-pars/analysis/MonotonicityChecker.h @@ -31,7 +31,7 @@ namespace storm { class MonotonicityChecker { public: - MonotonicityChecker(std::shared_ptr model, std::vector> formulas, bool validate); + MonotonicityChecker(std::shared_ptr model, std::vector> formulas, bool validate, uint_fast64_t numberOfSamples = 100); /*! * Checks for all lattices in the map if they are monotone increasing or monotone decreasing. * @@ -111,10 +111,6 @@ namespace storm { assert (s.check() == storm::solver::SmtSolver::CheckResult::Sat); s.add(exprToCheck); monDecr = s.check() == storm::solver::SmtSolver::CheckResult::Unsat; -// if (monIncr && monDecr) { -// monIncr = false; -// monDecr = false; -// } } assert (!(monIncr && monDecr) || derivative.isZero()); @@ -123,9 +119,9 @@ namespace storm { private: //TODO: variabele type - std::map> analyseMonotonicity(uint_fast64_t i, storm::analysis::Lattice* lattice, storm::storage::SparseMatrix matrix) ; + std::map> analyseMonotonicity(uint_fast64_t i, Lattice* lattice, storm::storage::SparseMatrix matrix) ; - std::map>> createLattice(); + std::map>> createLattice(); std::map> checkOnSamples(std::shared_ptr> model, uint_fast64_t numberOfSamples); @@ -135,9 +131,7 @@ namespace storm { ValueType getDerivative(ValueType function, carl::Variable var); - std::vector> checkAssumptionsOnRegion(std::vector> assumptions); - - std::map>> extendLatticeWithAssumptions(storm::analysis::Lattice* lattice, storm::analysis::AssumptionMaker* assumptionMaker, uint_fast64_t val1, uint_fast64_t val2, std::vector> assumptions); + std::map>> extendLatticeWithAssumptions(Lattice* lattice, AssumptionMaker* assumptionMaker, uint_fast64_t val1, uint_fast64_t val2, std::vector> assumptions); std::shared_ptr model; @@ -147,13 +141,11 @@ namespace storm { std::map> resultCheckOnSamples; - storm::analysis::LatticeExtender *extender; + LatticeExtender *extender; std::ofstream outfile; std::string filename = "results.txt"; - - storm::utility::Stopwatch totalWatch; }; } } diff --git a/src/test/storm-pars/analysis/MonotonicityCheckerTest.cpp b/src/test/storm-pars/analysis/MonotonicityCheckerTest.cpp index bb2d7008e..5b9a4ebfb 100644 --- a/src/test/storm-pars/analysis/MonotonicityCheckerTest.cpp +++ b/src/test/storm-pars/analysis/MonotonicityCheckerTest.cpp @@ -80,93 +80,6 @@ TEST(MonotonicityCheckerTest, Derivative_checker) { EXPECT_FALSE(functionRes.second); } -TEST(MonotonicityCheckerTest, Monotone_no_model) { - std::shared_ptr model; - std::vector> formulas; - auto checker = storm::analysis::MonotonicityChecker(model, formulas, false); - // Build lattice - auto numberOfStates = 4; - auto above = storm::storage::BitVector(numberOfStates); - above.set(1); - auto below = storm::storage::BitVector(numberOfStates); - below.set(0); - auto initialMiddle = storm::storage::BitVector(numberOfStates); - auto lattice = storm::analysis::Lattice(&above, &below, &initialMiddle, numberOfStates); - lattice.add(2); - lattice.add(3); - // Build map - std::vector> assumptions; - std::map>> map; - map.insert(std::pair>>(&lattice, assumptions)); - - // Build matrix - auto builder = storm::storage::SparseMatrixBuilder(numberOfStates, numberOfStates, 4); - std::shared_ptr cache = std::make_shared(); - carl::StringParser parser; - parser.setVariables({"p", "q"}); - auto func = storm::RationalFunction(storm::Polynomial(parser.template parseMultivariatePolynomial("p"), cache)); - auto funcMin = storm::RationalFunction(storm::RationalFunction(1)-func); - builder.addNextValue(2, 1, func); - builder.addNextValue(2, 0, funcMin); - func = storm::RationalFunction(storm::Polynomial(parser.template parseMultivariatePolynomial("q"), cache)); - funcMin = storm::RationalFunction(storm::RationalFunction(1)-func); - builder.addNextValue(3, 1, funcMin); - builder.addNextValue(3, 0, func); - storm::storage::SparseMatrix matrix = builder.build(); - - std::map>> result = checker.checkMonotonicity(map, matrix); - ASSERT_EQ(1, result.size()); - ASSERT_EQ(2, result.begin()->second.size()); - auto entry1 = result.begin()->second.begin(); - auto entry2 = ++ (result.begin()->second.begin()); - ASSERT_EQ("p", entry1->first.name()); - EXPECT_TRUE(entry1->second.first); - EXPECT_FALSE(entry1->second.second); - EXPECT_FALSE(entry2->second.first); - EXPECT_TRUE(entry2->second.second); -} - -TEST(MonotonicityCheckerTest, Not_monotone_no_model) { - std::shared_ptr model; - std::vector> formulas; - auto checker = storm::analysis::MonotonicityChecker(model, formulas, false); - // Build lattice - auto numberOfStates = 4; - auto above = storm::storage::BitVector(numberOfStates); - above.set(1); - auto below = storm::storage::BitVector(numberOfStates); - below.set(0); - auto initialMiddle = storm::storage::BitVector(numberOfStates); - auto lattice = storm::analysis::Lattice(&above, &below, &initialMiddle, numberOfStates); - lattice.add(2); - lattice.add(3); - // Build map - std::vector> assumptions; - std::map>> map; - map.insert(std::pair>>(&lattice, assumptions)); - - // Build matrix - auto builder = storm::storage::SparseMatrixBuilder(numberOfStates, numberOfStates, 4); - std::shared_ptr cache = std::make_shared(); - carl::StringParser parser; - parser.setVariables({"p", "q"}); - auto func = storm::RationalFunction(storm::Polynomial(parser.template parseMultivariatePolynomial("p"), cache)); - auto funcMin = storm::RationalFunction(storm::RationalFunction(1)-func); - builder.addNextValue(2, 1, func); - builder.addNextValue(2, 0, funcMin); - builder.addNextValue(3, 1, funcMin); - builder.addNextValue(3, 0, func); - auto matrix = builder.build(); - - auto result = checker.checkMonotonicity(map, matrix); - ASSERT_EQ(1, result.size()); - ASSERT_EQ(1, result.begin()->second.size()); - auto entry1 = result.begin()->second.begin(); - ASSERT_EQ("p", entry1->first.name()); - EXPECT_FALSE(entry1->second.first); - EXPECT_FALSE(entry1->second.second); -} - TEST(MonotonicityCheckerTest, Brp_with_bisimulation) { std::string programFile = STORM_TEST_RESOURCES_DIR "/pdtmc/brp16_2.pm"; std::string formulaAsString = "P=? [F s=4 & i=N ]"; @@ -200,4 +113,4 @@ TEST(MonotonicityCheckerTest, Brp_with_bisimulation) { auto monotone = result.begin()->second.begin(); EXPECT_EQ(monotone->second.first, true); EXPECT_EQ(monotone->second.second, false); -} \ No newline at end of file +} From 0d1ddb623270cc2c52d3fc78ae0a95e83edb448c Mon Sep 17 00:00:00 2001 From: Jip Spel Date: Tue, 14 May 2019 16:25:21 +0200 Subject: [PATCH 151/178] Make sampling in monotonicity-analysis optional --- src/storm-pars-cli/storm-pars.cpp | 3 +- .../analysis/MonotonicityChecker.cpp | 92 +++++++++++-------- src/storm-pars/analysis/MonotonicityChecker.h | 28 +++--- .../settings/modules/ParametricSettings.cpp | 14 ++- .../settings/modules/ParametricSettings.h | 19 +++- .../analysis/MonotonicityCheckerTest.cpp | 41 ++++++++- 6 files changed, 134 insertions(+), 63 deletions(-) diff --git a/src/storm-pars-cli/storm-pars.cpp b/src/storm-pars-cli/storm-pars.cpp index 01fa208e2..0105e55ef 100644 --- a/src/storm-pars-cli/storm-pars.cpp +++ b/src/storm-pars-cli/storm-pars.cpp @@ -727,7 +727,8 @@ namespace storm { std::ofstream outfile; outfile.open("results.txt", std::ios_base::app); storm::utility::Stopwatch monotonicityWatch(true); - auto monotonicityChecker = storm::analysis::MonotonicityChecker(model, formulas, parSettings.isValidateAssumptionsSet()); + auto numberOfSamples = parSettings.getNumberOfSamples(); + auto monotonicityChecker = storm::analysis::MonotonicityChecker(model, formulas, parSettings.isValidateAssumptionsSet(), numberOfSamples); monotonicityChecker.checkMonotonicity(); monotonicityWatch.stop(); STORM_PRINT(std::endl << "Total time for monotonicity checking: " << monotonicityWatch << "." << std::endl diff --git a/src/storm-pars/analysis/MonotonicityChecker.cpp b/src/storm-pars/analysis/MonotonicityChecker.cpp index a2f3693c0..092a3ffbf 100644 --- a/src/storm-pars/analysis/MonotonicityChecker.cpp +++ b/src/storm-pars/analysis/MonotonicityChecker.cpp @@ -28,24 +28,28 @@ namespace storm { namespace analysis { template MonotonicityChecker::MonotonicityChecker(std::shared_ptr model, std::vector> formulas, bool validate, uint_fast64_t numberOfSamples) { - outfile.open(filename, std::ios_base::app); assert (model != nullptr); this->model = model; this->formulas = formulas; this->validate = validate; - // sampling - if ( model->isOfType(storm::models::ModelType::Dtmc)) { - this->resultCheckOnSamples = std::map>(checkOnSamples(model->as>(), numberOfSamples)); - } else if (model->isOfType(storm::models::ModelType::Mdp)){ - this->resultCheckOnSamples = std::map>(checkOnSamples(model->as>(), numberOfSamples)); + if (numberOfSamples > 0) { + // sampling + if (model->isOfType(storm::models::ModelType::Dtmc)) { + this->resultCheckOnSamples = std::map>( + checkOnSamples(model->as>(), numberOfSamples)); + } else if (model->isOfType(storm::models::ModelType::Mdp)) { + this->resultCheckOnSamples = std::map>( + checkOnSamples(model->as>(), numberOfSamples)); + } + checkSamples= true; + } else { + checkSamples= false; } std::shared_ptr> sparseModel = model->as>(); this->extender = new storm::analysis::LatticeExtender(sparseModel); - outfile << model->getNumberOfStates() << ", " << model->getNumberOfTransitions() << ", "; - outfile.close(); } template @@ -96,10 +100,6 @@ namespace storm { matrix); auto assumptions = itr->second; - bool validSomewhere = false; - for (auto itr2 = varsMonotone.begin(); !validSomewhere && itr2 != varsMonotone.end(); ++itr2) { - validSomewhere = itr2->second.first || itr2->second.second; - } if (assumptions.size() > 0) { bool first = true; for (auto itr2 = assumptions.begin(); itr2 != assumptions.end(); ++itr2) { @@ -115,12 +115,13 @@ namespace storm { outfile << "No assumptions - "; } - if (validSomewhere && varsMonotone.size() == 0) { + if (varsMonotone.size() == 0) { outfile << "No params"; - } else if (validSomewhere) { + } else { auto itr2 = varsMonotone.begin(); while (itr2 != varsMonotone.end()) { - if (resultCheckOnSamples.find(itr2->first) != resultCheckOnSamples.end() && + if (checkSamples && + resultCheckOnSamples.find(itr2->first) != resultCheckOnSamples.end() && (!resultCheckOnSamples[itr2->first].first && !resultCheckOnSamples[itr2->first].second)) { outfile << "X " << itr2->first; @@ -143,11 +144,6 @@ namespace storm { result.insert( std::pair>>( lattice, varsMonotone)); - } else { - result.insert( - std::pair>>( - lattice, varsMonotone)); - outfile << "no monotonicity found"; } ++i; outfile << ";"; @@ -156,7 +152,6 @@ namespace storm { outfile << ", "; monotonicityCheckWatch.stop(); - outfile << monotonicityCheckWatch << ", "; outfile.close(); return result; } @@ -195,9 +190,6 @@ namespace storm { assert(false); } latticeWatch.stop(); - outfile.open(filename, std::ios_base::app); - outfile << latticeWatch << ", "; - outfile.close(); return result; } @@ -313,17 +305,28 @@ namespace storm { } // Copy info from checkOnSamples - for (auto itr = vars.begin(); itr != vars.end(); ++itr) { - assert (resultCheckOnSamples.find(*itr) != resultCheckOnSamples.end()); - if (varsMonotone.find(*itr) == varsMonotone.end()) { - varsMonotone[*itr].first = resultCheckOnSamples[*itr].first; - varsMonotone[*itr].second = resultCheckOnSamples[*itr].second; - } else { - varsMonotone[*itr].first &= resultCheckOnSamples[*itr].first; - varsMonotone[*itr].second &= resultCheckOnSamples[*itr].second; + if (checkSamples) { + for (auto var : vars) { + assert (resultCheckOnSamples.find(var) != resultCheckOnSamples.end()); + if (varsMonotone.find(var) == varsMonotone.end()) { + varsMonotone[var].first = resultCheckOnSamples[var].first; + varsMonotone[var].second = resultCheckOnSamples[var].second; + } else { + varsMonotone[var].first &= resultCheckOnSamples[var].first; + varsMonotone[var].second &= resultCheckOnSamples[var].second; + } + } + } else { + for (auto var : vars) { + if (varsMonotone.find(var) == varsMonotone.end()) { + varsMonotone[var].first = true; + varsMonotone[var].second = true; + } } } + + // Sort the states based on the lattice auto sortedStates = lattice->sortStates(states); if (sortedStates[sortedStates.size() - 1] == matrix.getColumnCount()) { @@ -426,14 +429,23 @@ namespace storm { auto val = first.getValue(); auto vars = val.gatherVariables(); // Copy info from checkOnSamples - for (auto itr = vars.begin(); itr != vars.end(); ++itr) { - assert (resultCheckOnSamples.find(*itr) != resultCheckOnSamples.end()); - if (varsMonotone.find(*itr) == varsMonotone.end()) { - varsMonotone[*itr].first = resultCheckOnSamples[*itr].first; - varsMonotone[*itr].second = resultCheckOnSamples[*itr].second; - } else { - varsMonotone[*itr].first &= resultCheckOnSamples[*itr].first; - varsMonotone[*itr].second &= resultCheckOnSamples[*itr].second; + if (checkSamples) { + for (auto var : vars) { + assert (resultCheckOnSamples.find(var) != resultCheckOnSamples.end()); + if (varsMonotone.find(var) == varsMonotone.end()) { + varsMonotone[var].first = resultCheckOnSamples[var].first; + varsMonotone[var].second = resultCheckOnSamples[var].second; + } else { + varsMonotone[var].first &= resultCheckOnSamples[var].first; + varsMonotone[var].second &= resultCheckOnSamples[var].second; + } + } + } else { + for (auto var : vars) { + if (varsMonotone.find(var) == varsMonotone.end()) { + varsMonotone[var].first = true; + varsMonotone[var].second = true; + } } } diff --git a/src/storm-pars/analysis/MonotonicityChecker.h b/src/storm-pars/analysis/MonotonicityChecker.h index 47e189ad4..81bd6801a 100644 --- a/src/storm-pars/analysis/MonotonicityChecker.h +++ b/src/storm-pars/analysis/MonotonicityChecker.h @@ -31,27 +31,23 @@ namespace storm { class MonotonicityChecker { public: - MonotonicityChecker(std::shared_ptr model, std::vector> formulas, bool validate, uint_fast64_t numberOfSamples = 100); /*! - * Checks for all lattices in the map if they are monotone increasing or monotone decreasing. - * - * @param map The map with lattices and the assumptions made to create the lattices. - * @param matrix The transition matrix. - * @return TODO + * Constructor of MonotonicityChecker + * @param model the model considered + * @param formula the formula considered + * @param validate whether or not assumptions are to be validated + * @param numberOfSamples number of samples taken for monotonicity checking, default 0, + * if 0then no check on samples is executed */ - std::map>> checkMonotonicity(std::map>> map, storm::storage::SparseMatrix matrix); + MonotonicityChecker(std::shared_ptr model, std::vector> formulas, bool validate, uint_fast64_t numberOfSamples=0); /*! - * TODO - * @return + * Checks for model and formula as provided in constructor for monotonicity */ std::map>> checkMonotonicity(); /*! - * TODO - * @param lattice - * @param matrix - * @return + * Checks if monotonicity can be found in this lattice. Unordered states are not checked */ bool somewhereMonotonicity(storm::analysis::Lattice* lattice) ; @@ -118,6 +114,8 @@ namespace storm { } private: + std::map>> checkMonotonicity(std::map>> map, storm::storage::SparseMatrix matrix); + //TODO: variabele type std::map> analyseMonotonicity(uint_fast64_t i, Lattice* lattice, storm::storage::SparseMatrix matrix) ; @@ -139,13 +137,15 @@ namespace storm { bool validate; + bool checkSamples; + std::map> resultCheckOnSamples; LatticeExtender *extender; std::ofstream outfile; - std::string filename = "results.txt"; + std::string filename = "monotonicity.txt"; }; } } diff --git a/src/storm-pars/settings/modules/ParametricSettings.cpp b/src/storm-pars/settings/modules/ParametricSettings.cpp index 967d83ef8..e0c8c3bee 100644 --- a/src/storm-pars/settings/modules/ParametricSettings.cpp +++ b/src/storm-pars/settings/modules/ParametricSettings.cpp @@ -22,8 +22,9 @@ namespace storm { const std::string ParametricSettings::samplesGraphPreservingOptionName = "samples-graph-preserving"; const std::string ParametricSettings::sampleExactOptionName = "sample-exact"; const std::string ParametricSettings::monotonicityAnalysis = "monotonicity-analysis"; - const std::string ParametricSettings::sccElimination = "elim-scc"; - const std::string ParametricSettings::validateAssumptions = "validate-assumptions"; + const std::string ParametricSettings::sccElimination = "mon-elim-scc"; + const std::string ParametricSettings::validateAssumptions = "mon-validate-assumptions"; + const std::string ParametricSettings::samplesMonotonicityAnalysis = "mon-samples"; ParametricSettings::ParametricSettings() : ModuleSettings(moduleName) { this->addOption(storm::settings::OptionBuilder(moduleName, exportResultOptionName, false, "A path to a file where the parametric result should be saved.") @@ -36,8 +37,11 @@ namespace storm { this->addOption(storm::settings::OptionBuilder(moduleName, samplesGraphPreservingOptionName, false, "Sets whether it can be assumed that the samples are graph-preserving.").build()); this->addOption(storm::settings::OptionBuilder(moduleName, sampleExactOptionName, false, "Sets whether to sample using exact arithmetic.").build()); this->addOption(storm::settings::OptionBuilder(moduleName, monotonicityAnalysis, false, "Sets whether monotonicity analysis is done").build()); - this->addOption(storm::settings::OptionBuilder(moduleName, sccElimination, false, "Sets whether SCCs should be eliminated").build()); + this->addOption(storm::settings::OptionBuilder(moduleName, sccElimination, false, "Sets whether SCCs should be eliminated in the monotonicity analysis").build()); this->addOption(storm::settings::OptionBuilder(moduleName, validateAssumptions, false, "Sets whether assumptions made in monotonicity analysis are validated").build()); + this->addOption(storm::settings::OptionBuilder(moduleName, samplesMonotonicityAnalysis, false, "Sets whether monotonicity should be checked on samples") + .addArgument(storm::settings::ArgumentBuilder::createUnsignedIntegerArgument("mon-samples", "The number of samples taken in monotonicity-analysis can be given, default is 0, no samples").setDefaultValueUnsignedInteger(0).build()).build()); + } bool ParametricSettings::exportResultToFile() const { @@ -83,6 +87,10 @@ namespace storm { bool ParametricSettings::isValidateAssumptionsSet() const { return this->getOption(validateAssumptions).getHasOptionBeenSet(); } + + uint_fast64_t ParametricSettings::getNumberOfSamples() const { + return this->getOption(samplesMonotonicityAnalysis).getArgumentByName("mon-samples").getValueAsUnsignedInteger(); + } } // namespace modules } // namespace settings } // namespace storm diff --git a/src/storm-pars/settings/modules/ParametricSettings.h b/src/storm-pars/settings/modules/ParametricSettings.h index 29cbb81bf..cbb740ec6 100644 --- a/src/storm-pars/settings/modules/ParametricSettings.h +++ b/src/storm-pars/settings/modules/ParametricSettings.h @@ -42,7 +42,7 @@ namespace storm { */ bool transformContinuousModel() const; - /* + /*! * Retrieves whether instead of model checking, only the wellformedness constraints should be obtained. */ bool onlyObtainConstraints() const; @@ -64,12 +64,26 @@ namespace storm { */ bool isSampleExactSet() const; + /*! + * Retrieves whether monotonicity analysis should be applied. + */ bool isMonotonicityAnalysisSet() const; - // TODO: maybe move to other place + + /*! + * Retrieves whether SCCs in the monotonicity analysis should be eliminated. + */ bool isSccEliminationSet() const; + /*! + * Retrieves whether assumptions in monotonicity analysis should be validated + */ bool isValidateAssumptionsSet() const; + /*! + * Retrieves the number of samples used for sampling in the monotonicity analysis + */ + uint_fast64_t getNumberOfSamples() const; + const static std::string moduleName; private: @@ -84,6 +98,7 @@ namespace storm { const static std::string monotonicityAnalysis; const static std::string sccElimination; const static std::string validateAssumptions; + const static std::string samplesMonotonicityAnalysis; }; } // namespace modules diff --git a/src/test/storm-pars/analysis/MonotonicityCheckerTest.cpp b/src/test/storm-pars/analysis/MonotonicityCheckerTest.cpp index 5b9a4ebfb..27ba61483 100644 --- a/src/test/storm-pars/analysis/MonotonicityCheckerTest.cpp +++ b/src/test/storm-pars/analysis/MonotonicityCheckerTest.cpp @@ -80,7 +80,7 @@ TEST(MonotonicityCheckerTest, Derivative_checker) { EXPECT_FALSE(functionRes.second); } -TEST(MonotonicityCheckerTest, Brp_with_bisimulation) { +TEST(MonotonicityCheckerTest, Brp_with_bisimulation_no_samples) { std::string programFile = STORM_TEST_RESOURCES_DIR "/pdtmc/brp16_2.pm"; std::string formulaAsString = "P=? [F s=4 & i=N ]"; std::string constantsAsString = ""; //e.g. pL=0.9,TOACK=0.5 @@ -111,6 +111,41 @@ TEST(MonotonicityCheckerTest, Brp_with_bisimulation) { EXPECT_EQ(1, result.size()); EXPECT_EQ(2, result.begin()->second.size()); auto monotone = result.begin()->second.begin(); - EXPECT_EQ(monotone->second.first, true); - EXPECT_EQ(monotone->second.second, false); + EXPECT_EQ(true, monotone->second.first); + EXPECT_EQ(false, monotone->second.second); +} + +TEST(MonotonicityCheckerTest, Brp_with_bisimulation_samples) { + std::string programFile = STORM_TEST_RESOURCES_DIR "/pdtmc/brp16_2.pm"; + std::string formulaAsString = "P=? [F s=4 & i=N ]"; + std::string constantsAsString = ""; //e.g. pL=0.9,TOACK=0.5 + + // Program and formula + storm::prism::Program program = storm::api::parseProgram(programFile); + program = storm::utility::prism::preprocess(program, constantsAsString); + std::vector> formulas = storm::api::extractFormulasFromProperties(storm::api::parsePropertiesForPrismProgram(formulaAsString, program)); + std::shared_ptr> model = storm::api::buildSparseModel(program, formulas)->as>(); + std::shared_ptr> dtmc = model->as>(); + auto simplifier = storm::transformer::SparseParametricDtmcSimplifier>(*dtmc); + ASSERT_TRUE(simplifier.simplify(*(formulas[0]))); + model = simplifier.getSimplifiedModel(); + + // Apply bisimulation + storm::storage::BisimulationType bisimType = storm::storage::BisimulationType::Strong; + if (storm::settings::getModule().isWeakBisimulationSet()) { + bisimType = storm::storage::BisimulationType::Weak; + } + + dtmc = storm::api::performBisimulationMinimization(model, formulas, bisimType)->as>(); + + ASSERT_EQ(dtmc->getNumberOfStates(), 99ull); + ASSERT_EQ(dtmc->getNumberOfTransitions(), 195ull); + + storm::analysis::MonotonicityChecker monotonicityChecker = storm::analysis::MonotonicityChecker(dtmc, formulas, true, 50); + auto result = monotonicityChecker.checkMonotonicity(); + EXPECT_EQ(1, result.size()); + EXPECT_EQ(2, result.begin()->second.size()); + auto monotone = result.begin()->second.begin(); + EXPECT_EQ(true, monotone->second.first); + EXPECT_EQ(false, monotone->second.second); } From 3ebd5f0bf60a36e8a8b47119332312db2f5b90ab Mon Sep 17 00:00:00 2001 From: Jip Spel Date: Wed, 15 May 2019 09:58:16 +0200 Subject: [PATCH 152/178] Clean up assumption checker --- src/storm-pars/analysis/AssumptionChecker.cpp | 147 +++++++++--------- src/storm-pars/analysis/AssumptionChecker.h | 39 +++-- 2 files changed, 92 insertions(+), 94 deletions(-) diff --git a/src/storm-pars/analysis/AssumptionChecker.cpp b/src/storm-pars/analysis/AssumptionChecker.cpp index fb7a8b9a8..747b85874 100644 --- a/src/storm-pars/analysis/AssumptionChecker.cpp +++ b/src/storm-pars/analysis/AssumptionChecker.cpp @@ -23,39 +23,37 @@ namespace storm { namespace analysis { template - AssumptionChecker::AssumptionChecker(std::shared_ptr formula, std::shared_ptr> model, uint_fast64_t numberOfSamples) { + AssumptionChecker::AssumptionChecker(std::shared_ptr formula, std::shared_ptr> model, uint_fast64_t numberOfSamples) { this->formula = formula; this->matrix = model->getTransitionMatrix(); // Create sample points - auto instantiator = storm::utility::ModelInstantiator, storm::models::sparse::Dtmc>(*model); + auto instantiator = utility::ModelInstantiator, models::sparse::Dtmc>(*model); auto matrix = model->getTransitionMatrix(); - std::set variables = storm::models::sparse::getProbabilityParameters(*model); + std::set::type> variables = models::sparse::getProbabilityParameters(*model); - // TODO: sampling part also done in MonotonicityChecker, would be better to use this one instead of creating it again for (auto i = 0; i < numberOfSamples; ++i) { - auto valuation = storm::utility::parametric::Valuation(); + auto valuation = utility::parametric::Valuation(); for (auto itr = variables.begin(); itr != variables.end(); ++itr) { - // TODO: Type // Creates samples between 0 and 1, 1/(#samples+2), 2/(#samples+2), ..., (#samples+1)/(#samples+2) - auto val = std::pair((*itr), storm::utility::convertNumber(boost::lexical_cast((i+1)/(double (numberOfSamples + 2))))); + auto val = std::pair::type, typename utility::parametric::CoefficientType::type>((*itr), utility::convertNumber::type>(boost::lexical_cast((i+1)/(double (numberOfSamples + 2))))); valuation.insert(val); } - storm::models::sparse::Dtmc sampleModel = instantiator.instantiate(valuation); - auto checker = storm::modelchecker::SparseDtmcPrctlModelChecker>(sampleModel); - std::unique_ptr checkResult; + models::sparse::Dtmc sampleModel = instantiator.instantiate(valuation); + auto checker = modelchecker::SparseDtmcPrctlModelChecker>(sampleModel); + std::unique_ptr checkResult; if (formula->isProbabilityOperatorFormula() && formula->asProbabilityOperatorFormula().getSubformula().isUntilFormula()) { - const storm::modelchecker::CheckTask checkTask = storm::modelchecker::CheckTask( + const modelchecker::CheckTask checkTask = modelchecker::CheckTask( (*formula).asProbabilityOperatorFormula().getSubformula().asUntilFormula()); checkResult = checker.computeUntilProbabilities(Environment(), checkTask); } else if (formula->isProbabilityOperatorFormula() && formula->asProbabilityOperatorFormula().getSubformula().isEventuallyFormula()) { - const storm::modelchecker::CheckTask checkTask = storm::modelchecker::CheckTask( + const modelchecker::CheckTask checkTask = modelchecker::CheckTask( (*formula).asProbabilityOperatorFormula().getSubformula().asEventuallyFormula()); checkResult = checker.computeReachabilityProbabilities(Environment(), checkTask); } else { - STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, + STORM_LOG_THROW(false, exceptions::NotSupportedException, "Expecting until or eventually formula"); } auto quantitativeResult = checkResult->asExplicitQuantitativeCheckResult(); @@ -65,38 +63,37 @@ namespace storm { } template - AssumptionChecker::AssumptionChecker(std::shared_ptr formula, std::shared_ptr> model, uint_fast64_t numberOfSamples) { + AssumptionChecker::AssumptionChecker(std::shared_ptr formula, std::shared_ptr> model, uint_fast64_t numberOfSamples) { this->formula = formula; this->matrix = model->getTransitionMatrix(); // Create sample points - auto instantiator = storm::utility::ModelInstantiator, storm::models::sparse::Mdp>(*model); + auto instantiator = utility::ModelInstantiator, models::sparse::Mdp>(*model); auto matrix = model->getTransitionMatrix(); - std::set variables = storm::models::sparse::getProbabilityParameters(*model); + std::set::type> variables = models::sparse::getProbabilityParameters(*model); - // TODO: sampling part also done in MonotonicityChecker, would be better to use this one instead of creating it again for (auto i = 0; i < numberOfSamples; ++i) { - auto valuation = storm::utility::parametric::Valuation(); + auto valuation = utility::parametric::Valuation(); for (auto itr = variables.begin(); itr != variables.end(); ++itr) { - // TODO: Type - auto val = std::pair((*itr), storm::utility::convertNumber(boost::lexical_cast((i+1)/(double (numberOfSamples + 1))))); + auto val = std::pair::type, + typename utility::parametric::CoefficientType::type>((*itr), utility::convertNumber::type>(boost::lexical_cast((i+1)/(double (numberOfSamples + 1))))); valuation.insert(val); } - storm::models::sparse::Mdp sampleModel = instantiator.instantiate(valuation); - auto checker = storm::modelchecker::SparseMdpPrctlModelChecker>(sampleModel); - std::unique_ptr checkResult; + models::sparse::Mdp sampleModel = instantiator.instantiate(valuation); + auto checker = modelchecker::SparseMdpPrctlModelChecker>(sampleModel); + std::unique_ptr checkResult; if (formula->isProbabilityOperatorFormula() && formula->asProbabilityOperatorFormula().getSubformula().isUntilFormula()) { - const storm::modelchecker::CheckTask checkTask = storm::modelchecker::CheckTask( + const modelchecker::CheckTask checkTask = modelchecker::CheckTask( (*formula).asProbabilityOperatorFormula().getSubformula().asUntilFormula()); checkResult = checker.computeUntilProbabilities(Environment(), checkTask); } else if (formula->isProbabilityOperatorFormula() && formula->asProbabilityOperatorFormula().getSubformula().isEventuallyFormula()) { - const storm::modelchecker::CheckTask checkTask = storm::modelchecker::CheckTask( + const modelchecker::CheckTask checkTask = modelchecker::CheckTask( (*formula).asProbabilityOperatorFormula().getSubformula().asEventuallyFormula()); checkResult = checker.computeReachabilityProbabilities(Environment(), checkTask); } else { - STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, + STORM_LOG_THROW(false, exceptions::NotSupportedException, "Expecting until or eventually formula"); } auto quantitativeResult = checkResult->asExplicitQuantitativeCheckResult(); @@ -106,16 +103,16 @@ namespace storm { } template - AssumptionStatus AssumptionChecker::checkOnSamples(std::shared_ptr assumption) { + AssumptionStatus AssumptionChecker::checkOnSamples(std::shared_ptr assumption) { auto result = AssumptionStatus::UNKNOWN; - std::set vars = std::set({}); + std::set vars = std::set({}); assumption->gatherVariables(vars); for (auto itr = samples.begin(); result == AssumptionStatus::UNKNOWN && itr != samples.end(); ++itr) { - std::shared_ptr manager = assumption->getManager().getSharedPointer(); - auto valuation = storm::expressions::SimpleValuation(manager); + std::shared_ptr manager = assumption->getManager().getSharedPointer(); + auto valuation = expressions::SimpleValuation(manager); auto values = (*itr); for (auto var = vars.begin(); result == AssumptionStatus::UNKNOWN && var != vars.end(); ++var) { - storm::expressions::Variable par = *var; + expressions::Variable par = *var; auto index = std::stoi(par.getName()); valuation.setRationalValue(par, values[index]); } @@ -128,22 +125,22 @@ namespace storm { } template - AssumptionStatus AssumptionChecker::validateAssumption(std::shared_ptr assumption, storm::analysis::Lattice* lattice) { + AssumptionStatus AssumptionChecker::validateAssumption(std::shared_ptr assumption, Lattice* lattice) { // First check if based on sample points the assumption can be discharged auto result = checkOnSamples(assumption); - assert (result != storm::analysis::AssumptionStatus::VALID); + assert (result != AssumptionStatus::VALID); - if (result == storm::analysis::AssumptionStatus::UNKNOWN) { + if (result == AssumptionStatus::UNKNOWN) { // If result from sample checking was unknown, the assumption might hold, so we continue, // otherwise we return INVALID - std::set vars = std::set({}); + std::set vars = std::set({}); assumption->gatherVariables(vars); STORM_LOG_THROW(assumption->getRelationType() == - storm::expressions::BinaryRelationExpression::RelationType::Greater || + expressions::BinaryRelationExpression::RelationType::Greater || assumption->getRelationType() == - storm::expressions::BinaryRelationExpression::RelationType::Equal, - storm::exceptions::NotSupportedException, + expressions::BinaryRelationExpression::RelationType::Equal, + exceptions::NotSupportedException, "Only Greater Or Equal assumptions supported"); // Row with successors of the first state @@ -168,13 +165,13 @@ namespace storm { } if (state1succ1->getColumn() == state2succ1->getColumn() && state1succ2->getColumn() == state2succ2->getColumn()) { - if (assumption->getRelationType() == storm::expressions::BinaryRelationExpression::RelationType::Greater - && lattice->compare(state1succ1->getColumn(), state1succ2->getColumn()) != storm::analysis::Lattice::UNKNOWN) { + if (assumption->getRelationType() == expressions::BinaryRelationExpression::RelationType::Greater + && lattice->compare(state1succ1->getColumn(), state1succ2->getColumn()) != Lattice::UNKNOWN) { // The assumption should be the greater assumption // If the result is unknown, we cannot compare, also SMTSolver will not help result = validateAssumptionFunction(lattice, state1succ1, state1succ2, state2succ1, state2succ2); - } else if (assumption->getRelationType() == storm::expressions::BinaryRelationExpression::RelationType::Equal) { + } else if (assumption->getRelationType() == expressions::BinaryRelationExpression::RelationType::Equal) { // The assumption is equal, the successors are the same, // so if the probability of reaching the successors is the same, we have a valid assumption if (state1succ1->getValue() == state2succ1->getValue()) { @@ -184,21 +181,21 @@ namespace storm { result = AssumptionStatus::UNKNOWN; } } else { - result = validateAssumptionSMTSolver(lattice, assumption); + result = validateAssumptionSMTSolver(assumption, lattice); } } else { - result = validateAssumptionSMTSolver(lattice, assumption); + result = validateAssumptionSMTSolver(assumption, lattice); } } return result; } template - AssumptionStatus AssumptionChecker::validateAssumptionFunction(storm::analysis::Lattice* lattice, - typename storm::storage::SparseMatrix::iterator state1succ1, - typename storm::storage::SparseMatrix::iterator state1succ2, - typename storm::storage::SparseMatrix::iterator state2succ1, - typename storm::storage::SparseMatrix::iterator state2succ2) { + AssumptionStatus AssumptionChecker::validateAssumptionFunction(Lattice* lattice, + typename storage::SparseMatrix::iterator state1succ1, + typename storage::SparseMatrix::iterator state1succ2, + typename storage::SparseMatrix::iterator state2succ1, + typename storage::SparseMatrix::iterator state2succ2) { assert((state1succ1->getColumn() == state2succ1->getColumn() && state1succ2->getColumn() == state2succ2->getColumn()) || (state1succ1->getColumn() == state2succ2->getColumn() @@ -209,10 +206,10 @@ namespace storm { // Calculate the difference in probability for the "highest" successor state ValueType prob; auto comp = lattice->compare(state1succ1->getColumn(), state1succ2->getColumn()); - assert (comp == storm::analysis::Lattice::ABOVE || comp == storm::analysis::Lattice::BELOW); - if (comp == storm::analysis::Lattice::ABOVE) { + assert (comp == Lattice::ABOVE || comp == Lattice::BELOW); + if (comp == Lattice::ABOVE) { prob = state1succ1->getValue() - state2succ1->getValue(); - } else if (comp == storm::analysis::Lattice::BELOW) { + } else if (comp == Lattice::BELOW) { prob = state1succ2->getValue() - state2succ2->getValue(); } @@ -220,8 +217,7 @@ namespace storm { // If the result in monotone increasing (decreasing), then choose 0 (1) for the substitutions // This will give the smallest result - // TODO: Type - std::map substitutions; + std::map::type, typename utility::parametric::CoefficientType::type> substitutions; for (auto var : vars) { auto monotonicity = MonotonicityChecker::checkDerivative(prob.derivative(var)); if (monotonicity.first) { @@ -243,9 +239,9 @@ namespace storm { template - AssumptionStatus AssumptionChecker::validateAssumptionSMTSolver(storm::analysis::Lattice* lattice, std::shared_ptr assumption) { - std::shared_ptr smtSolverFactory = std::make_shared(); - std::shared_ptr manager(new storm::expressions::ExpressionManager()); + AssumptionStatus AssumptionChecker::validateAssumptionSMTSolver(std::shared_ptr assumption, Lattice* lattice) { + std::shared_ptr smtSolverFactory = std::make_shared(); + std::shared_ptr manager(new expressions::ExpressionManager()); AssumptionStatus result; auto var1 = assumption->getFirstOperand()->asVariableExpression().getVariableName(); @@ -256,8 +252,8 @@ namespace storm { bool orderKnown = true; // Check if the order between the different successors is known // Also start creating expression for order of states - storm::expressions::Expression exprOrderSucc = manager->boolean(true); - std::set stateVariables; + expressions::Expression exprOrderSucc = manager->boolean(true); + std::set stateVariables; for (auto itr1 = row1.begin(); orderKnown && itr1 != row1.end(); ++itr1) { auto varname1 = "s" + std::to_string(itr1->getColumn()); if (!manager->hasVariable(varname1)) { @@ -270,13 +266,13 @@ namespace storm { stateVariables.insert(manager->declareRationalVariable(varname2)); } auto comp = lattice->compare(itr1->getColumn(), itr2->getColumn()); - if (comp == storm::analysis::Lattice::ABOVE) { + if (comp == Lattice::ABOVE) { exprOrderSucc = exprOrderSucc && !(manager->getVariable(varname1) <= manager->getVariable(varname2)); - } else if (comp == storm::analysis::Lattice::BELOW) { + } else if (comp == Lattice::BELOW) { exprOrderSucc = exprOrderSucc && !(manager->getVariable(varname1) >= manager->getVariable(varname2)); - } else if (comp == storm::analysis::Lattice::SAME) { + } else if (comp == Lattice::SAME) { exprOrderSucc = exprOrderSucc && (manager->getVariable(varname1) = manager->getVariable(varname2)); } else { @@ -287,41 +283,39 @@ namespace storm { } if (orderKnown) { - storm::solver::Z3SmtSolver s(*manager); - auto valueTypeToExpression = storm::expressions::RationalFunctionToExpression(manager); - storm::expressions::Expression expr1 = manager->rational(0); + solver::Z3SmtSolver s(*manager); + auto valueTypeToExpression = expressions::RationalFunctionToExpression(manager); + expressions::Expression expr1 = manager->rational(0); for (auto itr1 = row1.begin(); itr1 != row1.end(); ++itr1) { expr1 = expr1 + (valueTypeToExpression.toExpression(itr1->getValue()) * manager->getVariable("s" + std::to_string(itr1->getColumn()))); } - storm::expressions::Expression expr2 = manager->rational(0); + expressions::Expression expr2 = manager->rational(0); for (auto itr2 = row2.begin(); itr2 != row2.end(); ++itr2) { expr2 = expr2 + (valueTypeToExpression.toExpression(itr2->getValue()) * manager->getVariable("s" + std::to_string(itr2->getColumn()))); } // Create expression for the assumption based on the relation to successors // It is the negation of actual assumption - // TODO: use same manager s.t. assumption can be used directly ? - storm::expressions::Expression exprToCheck ; + expressions::Expression exprToCheck ; if (assumption->getRelationType() == - storm::expressions::BinaryRelationExpression::RelationType::Greater) { + expressions::BinaryRelationExpression::RelationType::Greater) { exprToCheck = expr1 <= expr2; } else { assert (assumption->getRelationType() == - storm::expressions::BinaryRelationExpression::RelationType::Equal); + expressions::BinaryRelationExpression::RelationType::Equal); exprToCheck = expr1 > expr2; } auto variables = manager->getVariables(); // Bounds for the state probabilities and parameters - storm::expressions::Expression exprBounds = manager->boolean(true); + expressions::Expression exprBounds = manager->boolean(true); for (auto var : variables) { if (find(stateVariables.begin(), stateVariables.end(), var) != stateVariables.end()) { // the var is a state exprBounds = exprBounds && manager->rational(0) <= var && var <= manager->rational(1); } else { // the var is a parameter - // TODO: graph-preserving exprBounds = exprBounds && manager->rational(0) < var && var < manager->rational(1); } } @@ -329,15 +323,14 @@ namespace storm { s.add(exprOrderSucc); s.add(exprBounds); // assert that sorting of successors in the lattice and the bounds on the expression are at least satisfiable - assert (s.check() == storm::solver::SmtSolver::CheckResult::Sat); - // TODO: kijken of t SAT moet zijn? + assert (s.check() == solver::SmtSolver::CheckResult::Sat); s.add(exprToCheck); auto smtRes = s.check(); - if (smtRes == storm::solver::SmtSolver::CheckResult::Unsat) { + if (smtRes == solver::SmtSolver::CheckResult::Unsat) { // If there is no thing satisfying the negation we are safe. result = AssumptionStatus::VALID; - } else if (smtRes == storm::solver::SmtSolver::CheckResult::Sat) { - assert (smtRes == storm::solver::SmtSolver::CheckResult::Sat); + } else if (smtRes == solver::SmtSolver::CheckResult::Sat) { + assert (smtRes == solver::SmtSolver::CheckResult::Sat); result = AssumptionStatus::INVALID; } else { result = AssumptionStatus::UNKNOWN; @@ -349,6 +342,6 @@ namespace storm { return result; } - template class AssumptionChecker; + template class AssumptionChecker; } } diff --git a/src/storm-pars/analysis/AssumptionChecker.h b/src/storm-pars/analysis/AssumptionChecker.h index 5cde2df72..b7746000f 100644 --- a/src/storm-pars/analysis/AssumptionChecker.h +++ b/src/storm-pars/analysis/AssumptionChecker.h @@ -14,6 +14,9 @@ namespace storm { namespace analysis { + /*! + * Constants for status of assumption + */ enum AssumptionStatus { VALID, INVALID, @@ -22,10 +25,6 @@ namespace storm { template class AssumptionChecker { public: - /*! - * Constants for status of assumption - */ - /*! * Constructs an AssumptionChecker based on the number of samples, for the given formula and model. @@ -34,7 +33,7 @@ namespace storm { * @param model The dtmc model to check the formula on. * @param numberOfSamples Number of sample points. */ - AssumptionChecker(std::shared_ptr formula, std::shared_ptr> model, uint_fast64_t numberOfSamples); + AssumptionChecker(std::shared_ptr formula, std::shared_ptr> model, uint_fast64_t numberOfSamples); /*! * Constructs an AssumptionChecker based on the number of samples, for the given formula and model. @@ -43,7 +42,7 @@ namespace storm { * @param model The mdp model to check the formula on. * @param numberOfSamples Number of sample points. */ - AssumptionChecker(std::shared_ptr formula, std::shared_ptr> model, uint_fast64_t numberOfSamples); + AssumptionChecker(std::shared_ptr formula, std::shared_ptr> model, uint_fast64_t numberOfSamples); /*! * Checks if the assumption holds at the sample points of the AssumptionChecker. @@ -51,7 +50,7 @@ namespace storm { * @param assumption The assumption to check. * @return AssumptionStatus::UNKNOWN or AssumptionStatus::INVALID */ - AssumptionStatus checkOnSamples(std::shared_ptr assumption); + AssumptionStatus checkOnSamples(std::shared_ptr assumption); /*! * Tries to validate an assumption based on the lattice and underlying transition matrix. @@ -60,25 +59,31 @@ namespace storm { * @param lattice The lattice. * @return AssumptionStatus::VALID, or AssumptionStatus::UNKNOWN, or AssumptionStatus::INVALID */ - AssumptionStatus validateAssumption(std::shared_ptr assumption, storm::analysis::Lattice* lattice); + AssumptionStatus validateAssumption(std::shared_ptr assumption, Lattice* lattice); - AssumptionStatus validateAssumptionSMTSolver(storm::analysis::Lattice* lattice, - std::shared_ptr assumption); + /*! + * Tries to validate an assumption based on the lattice, and SMT solving techniques + * + * @param assumption The assumption to validate. + * @param lattice The lattice. + * @return AssumptionStatus::VALID, or AssumptionStatus::UNKNOWN, or AssumptionStatus::INVALID + */ + AssumptionStatus validateAssumptionSMTSolver(std::shared_ptr assumption, Lattice* lattice); private: - std::shared_ptr formula; + std::shared_ptr formula; - storm::storage::SparseMatrix matrix; + storage::SparseMatrix matrix; std::vector> samples; void createSamples(); - AssumptionStatus validateAssumptionFunction(storm::analysis::Lattice* lattice, - typename storm::storage::SparseMatrix::iterator state1succ1, - typename storm::storage::SparseMatrix::iterator state1succ2, - typename storm::storage::SparseMatrix::iterator state2succ1, - typename storm::storage::SparseMatrix::iterator state2succ2); + AssumptionStatus validateAssumptionFunction(Lattice* lattice, + typename storage::SparseMatrix::iterator state1succ1, + typename storage::SparseMatrix::iterator state1succ2, + typename storage::SparseMatrix::iterator state2succ1, + typename storage::SparseMatrix::iterator state2succ2); }; } From ee0813964198b7ed48a1cd0d2d6ddf71ca5af647 Mon Sep 17 00:00:00 2001 From: Jip Spel Date: Wed, 15 May 2019 10:06:08 +0200 Subject: [PATCH 153/178] Fix test --- src/test/storm-pars/analysis/AssumptionCheckerTest.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/test/storm-pars/analysis/AssumptionCheckerTest.cpp b/src/test/storm-pars/analysis/AssumptionCheckerTest.cpp index e6b515987..93fc5955b 100644 --- a/src/test/storm-pars/analysis/AssumptionCheckerTest.cpp +++ b/src/test/storm-pars/analysis/AssumptionCheckerTest.cpp @@ -257,7 +257,7 @@ TEST(AssumptionCheckerTest, Simple3) { storm::expressions::BinaryRelationExpression::RelationType::Greater)); EXPECT_EQ(storm::analysis::AssumptionStatus::UNKNOWN, checker.checkOnSamples(assumption)); EXPECT_EQ(storm::analysis::AssumptionStatus::VALID, checker.validateAssumption(assumption, lattice)); - EXPECT_EQ(storm::analysis::AssumptionStatus::VALID, checker.validateAssumptionSMTSolver(lattice,assumption)); + EXPECT_EQ(storm::analysis::AssumptionStatus::VALID, checker.validateAssumptionSMTSolver(assumption, lattice)); assumption = std::make_shared( storm::expressions::BinaryRelationExpression(*expressionManager, expressionManager->getBooleanType(), @@ -266,7 +266,7 @@ TEST(AssumptionCheckerTest, Simple3) { storm::expressions::BinaryRelationExpression::RelationType::Greater)); EXPECT_EQ(storm::analysis::AssumptionStatus::INVALID, checker.checkOnSamples(assumption)); EXPECT_EQ(storm::analysis::AssumptionStatus::INVALID, checker.validateAssumption(assumption, lattice)); - EXPECT_EQ(storm::analysis::AssumptionStatus::INVALID, checker.validateAssumptionSMTSolver(lattice, assumption)); + EXPECT_EQ(storm::analysis::AssumptionStatus::INVALID, checker.validateAssumptionSMTSolver(assumption, lattice)); assumption = std::make_shared( storm::expressions::BinaryRelationExpression(*expressionManager, expressionManager->getBooleanType(), @@ -275,7 +275,7 @@ TEST(AssumptionCheckerTest, Simple3) { storm::expressions::BinaryRelationExpression::RelationType::Equal)); EXPECT_EQ(storm::analysis::AssumptionStatus::INVALID, checker.checkOnSamples(assumption)); EXPECT_EQ(storm::analysis::AssumptionStatus::INVALID, checker.validateAssumption(assumption, lattice)); - EXPECT_EQ(storm::analysis::AssumptionStatus::INVALID, checker.validateAssumptionSMTSolver(lattice,assumption)); + EXPECT_EQ(storm::analysis::AssumptionStatus::INVALID, checker.validateAssumptionSMTSolver(assumption, lattice)); } From fa97e0138f16378892467f7806fbde689f1014d6 Mon Sep 17 00:00:00 2001 From: Jip Spel Date: Wed, 15 May 2019 10:08:00 +0200 Subject: [PATCH 154/178] Clean up assumption maker --- src/storm-pars/analysis/AssumptionMaker.cpp | 39 +++++++++------------ src/storm-pars/analysis/AssumptionMaker.h | 26 ++++++++------ 2 files changed, 32 insertions(+), 33 deletions(-) diff --git a/src/storm-pars/analysis/AssumptionMaker.cpp b/src/storm-pars/analysis/AssumptionMaker.cpp index bdac30bb2..78cebe88e 100644 --- a/src/storm-pars/analysis/AssumptionMaker.cpp +++ b/src/storm-pars/analysis/AssumptionMaker.cpp @@ -1,37 +1,30 @@ -// -// Created by Jip Spel on 03.09.18. -// - #include "AssumptionMaker.h" namespace storm { namespace analysis { - typedef std::shared_ptr AssumptionType; + typedef std::shared_ptr AssumptionType; template AssumptionMaker::AssumptionMaker(AssumptionChecker* assumptionChecker, uint_fast64_t numberOfStates, bool validate) { this->numberOfStates = numberOfStates; this->assumptionChecker = assumptionChecker; this->validate = validate; - this->expressionManager = std::make_shared(storm::expressions::ExpressionManager()); + this->expressionManager = std::make_shared(expressions::ExpressionManager()); for (uint_fast64_t i = 0; i < this->numberOfStates; ++i) { - // TODO: expressenmanager pointer maken die oorspronkelijk in monotonicity checker zit expressionManager->declareRationalVariable(std::to_string(i)); } } template - std::map, AssumptionStatus> AssumptionMaker::createAndCheckAssumption(uint_fast64_t val1, uint_fast64_t val2, Lattice* lattice) { - std::map, AssumptionStatus> result; + std::map, AssumptionStatus> AssumptionMaker::createAndCheckAssumption(uint_fast64_t val1, uint_fast64_t val2, Lattice* lattice) { + std::map, AssumptionStatus> result; - // TODO: alleen maar als validate true is results genereren - storm::expressions::Variable var1 = expressionManager->getVariable(std::to_string(val1)); - storm::expressions::Variable var2 = expressionManager->getVariable(std::to_string(val2)); - std::shared_ptr assumption1 - = std::make_shared(storm::expressions::BinaryRelationExpression(*expressionManager, expressionManager->getBooleanType(), + expressions::Variable var1 = expressionManager->getVariable(std::to_string(val1)); + expressions::Variable var2 = expressionManager->getVariable(std::to_string(val2)); + std::shared_ptr assumption1 + = std::make_shared(expressions::BinaryRelationExpression(*expressionManager, expressionManager->getBooleanType(), var1.getExpression().getBaseExpressionPointer(), var2.getExpression().getBaseExpressionPointer(), - storm::expressions::BinaryRelationExpression::RelationType::Greater)); - // TODO: dischargen gebasseerd op monotonicity + expressions::BinaryRelationExpression::RelationType::Greater)); AssumptionStatus result1; AssumptionStatus result2; AssumptionStatus result3; @@ -43,10 +36,10 @@ namespace storm { result[assumption1] = result1; - std::shared_ptr assumption2 - = std::make_shared(storm::expressions::BinaryRelationExpression(*expressionManager, expressionManager->getBooleanType(), + std::shared_ptr assumption2 + = std::make_shared(expressions::BinaryRelationExpression(*expressionManager, expressionManager->getBooleanType(), var2.getExpression().getBaseExpressionPointer(), var1.getExpression().getBaseExpressionPointer(), - storm::expressions::BinaryRelationExpression::RelationType::Greater)); + expressions::BinaryRelationExpression::RelationType::Greater)); if (validate) { result2 = assumptionChecker->validateAssumption(assumption2, lattice); @@ -55,10 +48,10 @@ namespace storm { } result[assumption2] = result2; - std::shared_ptr assumption3 - = std::make_shared(storm::expressions::BinaryRelationExpression(*expressionManager, expressionManager->getBooleanType(), + std::shared_ptr assumption3 + = std::make_shared(expressions::BinaryRelationExpression(*expressionManager, expressionManager->getBooleanType(), var2.getExpression().getBaseExpressionPointer(), var1.getExpression().getBaseExpressionPointer(), - storm::expressions::BinaryRelationExpression::RelationType::Equal)); + expressions::BinaryRelationExpression::RelationType::Equal)); if (validate) { result3 = assumptionChecker->validateAssumption(assumption3, lattice); } else { @@ -69,6 +62,6 @@ namespace storm { return result; } - template class AssumptionMaker; + template class AssumptionMaker; } } diff --git a/src/storm-pars/analysis/AssumptionMaker.h b/src/storm-pars/analysis/AssumptionMaker.h index 2f52b85de..42710fcc6 100644 --- a/src/storm-pars/analysis/AssumptionMaker.h +++ b/src/storm-pars/analysis/AssumptionMaker.h @@ -1,7 +1,3 @@ -// -// Created by Jip Spel on 03.09.18. -// - #ifndef STORM_ASSUMPTIONMAKER_H #define STORM_ASSUMPTIONMAKER_H @@ -17,23 +13,33 @@ namespace storm { template class AssumptionMaker { - typedef std::shared_ptr AssumptionType; + typedef std::shared_ptr AssumptionType; public: /*! - * Constructs AssumptionMaker based on the lattice extender, the assumption checker and number of states of the model. - * TODO + * Constructs AssumptionMaker based on the lattice extender, the assumption checker and number of states of the mode + * * @param latticeExtender The LatticeExtender which needs the assumptions made by the AssumptionMaker. * @param checker The AssumptionChecker which checks the assumptions at sample points. * @param numberOfStates The number of states of the model. */ - AssumptionMaker( AssumptionChecker* checker, uint_fast64_t numberOfStates, bool validate); + AssumptionMaker(AssumptionChecker* checker, uint_fast64_t numberOfStates, bool validate); - std::map, AssumptionStatus> createAndCheckAssumption(uint_fast64_t val1, uint_fast64_t val2, Lattice* lattice); + /*! + * Creates assumptions, and checks them if validate in constructor is true. + * Possible results: AssumptionStatus::VALID, AssumptionStatus::INVALID, AssumptionStatus::UNKNOWN + * If validate is false result is always AssumptionStatus::UNKNOWN + * + * @param val1 First state number + * @param val2 Second state number + * @param lattice The lattice on which the assumptions are checked + * @return Map with three assumptions, and the validation + */ + std::map, AssumptionStatus> createAndCheckAssumption(uint_fast64_t val1, uint_fast64_t val2, Lattice* lattice); private: AssumptionChecker* assumptionChecker; - std::shared_ptr expressionManager; + std::shared_ptr expressionManager; uint_fast64_t numberOfStates; From c0aa6eefa38f97f99899e76b47f83ecad8270214 Mon Sep 17 00:00:00 2001 From: Jip Spel Date: Wed, 15 May 2019 12:02:21 +0200 Subject: [PATCH 155/178] Clean up Lattice --- src/storm-pars/analysis/AssumptionChecker.cpp | 17 +- src/storm-pars/analysis/AssumptionChecker.h | 4 - src/storm-pars/analysis/Lattice.cpp | 62 +----- src/storm-pars/analysis/Lattice.h | 82 ++++--- .../analysis/LatticeExtenderTest.cpp | 15 +- src/test/storm-pars/analysis/LatticeTest.cpp | 201 +++++++++--------- 6 files changed, 155 insertions(+), 226 deletions(-) diff --git a/src/storm-pars/analysis/AssumptionChecker.cpp b/src/storm-pars/analysis/AssumptionChecker.cpp index 747b85874..3aca39f31 100644 --- a/src/storm-pars/analysis/AssumptionChecker.cpp +++ b/src/storm-pars/analysis/AssumptionChecker.cpp @@ -1,6 +1,3 @@ -// -// Created by Jip Spel on 12.09.18. -// #include #include "AssumptionChecker.h" @@ -166,7 +163,7 @@ namespace storm { if (state1succ1->getColumn() == state2succ1->getColumn() && state1succ2->getColumn() == state2succ2->getColumn()) { if (assumption->getRelationType() == expressions::BinaryRelationExpression::RelationType::Greater - && lattice->compare(state1succ1->getColumn(), state1succ2->getColumn()) != Lattice::UNKNOWN) { + && lattice->compare(state1succ1->getColumn(), state1succ2->getColumn()) != Lattice::NodeComparison::UNKNOWN) { // The assumption should be the greater assumption // If the result is unknown, we cannot compare, also SMTSolver will not help result = validateAssumptionFunction(lattice, state1succ1, state1succ2, state2succ1, @@ -206,10 +203,10 @@ namespace storm { // Calculate the difference in probability for the "highest" successor state ValueType prob; auto comp = lattice->compare(state1succ1->getColumn(), state1succ2->getColumn()); - assert (comp == Lattice::ABOVE || comp == Lattice::BELOW); - if (comp == Lattice::ABOVE) { + assert (comp == Lattice::NodeComparison::ABOVE || comp == Lattice::NodeComparison::BELOW); + if (comp == Lattice::NodeComparison::ABOVE) { prob = state1succ1->getValue() - state2succ1->getValue(); - } else if (comp == Lattice::BELOW) { + } else if (comp == Lattice::NodeComparison::BELOW) { prob = state1succ2->getValue() - state2succ2->getValue(); } @@ -266,13 +263,13 @@ namespace storm { stateVariables.insert(manager->declareRationalVariable(varname2)); } auto comp = lattice->compare(itr1->getColumn(), itr2->getColumn()); - if (comp == Lattice::ABOVE) { + if (comp == Lattice::NodeComparison::ABOVE) { exprOrderSucc = exprOrderSucc && !(manager->getVariable(varname1) <= manager->getVariable(varname2)); - } else if (comp == Lattice::BELOW) { + } else if (comp == Lattice::NodeComparison::BELOW) { exprOrderSucc = exprOrderSucc && !(manager->getVariable(varname1) >= manager->getVariable(varname2)); - } else if (comp == Lattice::SAME) { + } else if (comp == Lattice::NodeComparison::SAME) { exprOrderSucc = exprOrderSucc && (manager->getVariable(varname1) = manager->getVariable(varname2)); } else { diff --git a/src/storm-pars/analysis/AssumptionChecker.h b/src/storm-pars/analysis/AssumptionChecker.h index b7746000f..3f98189ae 100644 --- a/src/storm-pars/analysis/AssumptionChecker.h +++ b/src/storm-pars/analysis/AssumptionChecker.h @@ -1,7 +1,3 @@ -// -// Created by Jip Spel on 12.09.18. -// - #ifndef STORM_ASSUMPTIONCHECKER_H #define STORM_ASSUMPTIONCHECKER_H diff --git a/src/storm-pars/analysis/Lattice.cpp b/src/storm-pars/analysis/Lattice.cpp index 665d39537..c585bb000 100644 --- a/src/storm-pars/analysis/Lattice.cpp +++ b/src/storm-pars/analysis/Lattice.cpp @@ -1,7 +1,3 @@ -// -// Created by Jip Spel on 24.07.18. -// - #include #include #include "Lattice.h" @@ -24,7 +20,6 @@ namespace storm { top->statesAbove = storm::storage::BitVector(numberOfStates); bottom->statesAbove = storm::storage::BitVector(numberOfStates); - for (auto const& i : *topStates) { addedStates->set(i); bottom->statesAbove.set(i); @@ -116,15 +111,11 @@ namespace storm { assert (compare(above, below) == ABOVE); } - void Lattice::addRelation(uint_fast64_t above, uint_fast64_t below) { - addRelationNodes(getNode(above), getNode(below)); - } - - int Lattice::compare(uint_fast64_t state1, uint_fast64_t state2) { + Lattice::NodeComparison Lattice::compare(uint_fast64_t state1, uint_fast64_t state2) { return compare(getNode(state1), getNode(state2)); } - int Lattice::compare(Node* node1, Node* node2) { + Lattice::NodeComparison Lattice::compare(Node* node1, Node* node2) { if (node1 != nullptr && node2 != nullptr) { if (node1 == node2) { return SAME; @@ -185,7 +176,6 @@ namespace storm { } std::vector Lattice::sortStates(storm::storage::BitVector* states) { - // TODO improve auto numberOfSetBits = states->getNumberOfSetBits(); auto stateSize = states->size(); auto result = std::vector(numberOfSetBits, stateSize); @@ -201,7 +191,7 @@ namespace storm { added = true; } else { auto compareRes = compare(state, result[i]); - if (compareRes == Lattice::ABOVE) { + if (compareRes == ABOVE) { auto temp = result[i]; result[i] = state; for (auto j = i + 1; j < numberOfSetBits && result[j + 1] != stateSize; j++) { @@ -210,9 +200,9 @@ namespace storm { temp = temp2; } added = true; - } else if (compareRes == Lattice::UNKNOWN) { + } else if (compareRes == UNKNOWN) { break; - } else if (compareRes == Lattice::SAME) { + } else if (compareRes == SAME) { ++i; auto temp = result[i]; result[i] = state; @@ -257,47 +247,6 @@ namespace storm { } } - void Lattice::toDotFile(std::ostream &out) { - assert (false); -// out << "digraph \"Lattice\" {" << std::endl; -// -// // print all nodes -// std::vector printed; -// out << "\t" << "node [shape=ellipse]" << std::endl; -// for (auto itr = nodes.begin(); itr != nodes.end(); ++itr) { -// -// if ((*itr) != nullptr && find(printed.begin(), printed.end(), (*itr)) == printed.end()) { -// out << "\t\"" << (*itr) << "\" [label = \""; -// uint_fast64_t index = (*itr)->states.getNextSetIndex(0); -// while (index < (*itr)->states.size()) { -// out << index; -// index = (*itr)->states.getNextSetIndex(index + 1); -// if (index < (*itr)->states.size()) { -// out << ", "; -// } -// } -// -// out << "\"]" << std::endl; -// printed.push_back(*itr); -// } -// } -// -// // print arcs -// printed.clear(); -// for (auto itr = nodes.begin(); itr != nodes.end(); ++itr) { -// if ((*itr) != nullptr && find(printed.begin(), printed.end(), (*itr)) == printed.end()) { -// auto below = getBelow(*itr); -// for (auto itr2 = below.begin(); itr2 != below.end(); ++itr2) { -// out << "\t\"" << (*itr) << "\" -> \"" << (*itr2) << "\";" << std::endl; -// } -// printed.push_back(*itr); -// } -// } -// -// out << "}" << std::endl; - } - - bool Lattice::above(Node *node1, Node *node2) { bool found = false; for (auto const& state : node1->states) { @@ -335,7 +284,6 @@ namespace storm { } } if (!found) { - // TODO: kan dit niet anders? nodePrev->statesAbove|=((node2->statesAbove)); statesSeen->operator|=(((node2->statesAbove))); diff --git a/src/storm-pars/analysis/Lattice.h b/src/storm-pars/analysis/Lattice.h index 0e1790fc3..e0aef5acd 100644 --- a/src/storm-pars/analysis/Lattice.h +++ b/src/storm-pars/analysis/Lattice.h @@ -1,7 +1,3 @@ -// -// Created by Jip Spel on 24.07.18. -// - #ifndef LATTICE_LATTICE_H #define LATTICE_LATTICE_H @@ -15,9 +11,19 @@ namespace storm { namespace analysis { + class Lattice { public: + /*! + * Constants for comparison of nodes/states + */ + enum NodeComparison { + UNKNOWN, + BELOW, + ABOVE, + SAME, + }; struct Node { boost::container::flat_set states; storm::storage::BitVector statesAbove; @@ -63,30 +69,23 @@ namespace storm { void add(uint_fast64_t state); /*! - * Adds a new relation between two nodes to the lattice - * @param above The node closest to the top Node of the Lattice. - * @param below The node closest to the bottom Node of the Lattice. - */ + * Adds a new relation between two nodes to the lattice + * @param above The node closest to the top Node of the Lattice. + * @param below The node closest to the bottom Node of the Lattice. + */ void addRelationNodes(storm::analysis::Lattice::Node *above, storm::analysis::Lattice::Node * below); - /*! - * Adds a new relation between two nodes to the lattice - * @param above The node closest to the top Node of the Lattice. - * @param below The node closest to the bottom Node of the Lattice. - */ - void addRelation(uint_fast64_t above, uint_fast64_t below); - /*! * Compares the level of the nodes of the states. * Behaviour unknown when one or more of the states doesnot occur at any Node in the Lattice. * @param state1 The first state. * @param state2 The second state. - * @return 0 if the nodes are on the same level; - * 1 if the node of the first state is closer to top then the node of the second state; - * 2 if the node of the second state is closer to top then the node of the first state; - * -1 if it is unclear from the structure of the lattice how the nodes relate. + * @return SAME if the nodes are on the same level; + * ABOVE if the node of the first state is closer to top then the node of the second state; + * BELOW if the node of the second state is closer to top then the node of the first state; + * UNKNOWN if it is unclear from the structure of the lattice how the nodes relate. */ - int compare(uint_fast64_t state1, uint_fast64_t state2); + Lattice::NodeComparison compare(uint_fast64_t state1, uint_fast64_t state2); /*! * Retrieves the pointer to a Node at which the state occurs. @@ -127,13 +126,32 @@ namespace storm { */ storm::storage::BitVector* getAddedStates(); + /*! + * Returns true if done building the lattice. + * @return + */ bool getDoneBuilding(); - int compare(Node* node1, Node* node2); - + /*! + * Compares two nodes in the lattice + * @param node1 + * @param node2 + * @return BELOW, ABOVE, SAME or UNKNOWN + */ + NodeComparison compare(Node* node1, Node* node2); + /*! + * Sorts the given stats if possible. + * + * @param states Bitvector of the states to sort + * @return Vector with states sorted, length equals number of states to sort. + * If states cannot be sorted, last state of the vector will always equal the length of the BitVector + */ std::vector sortStates(storm::storage::BitVector* states); + /*! + * If the lattice is fully build, this can be set to true. + */ void setDoneBuilding(bool done); /*! @@ -143,13 +161,6 @@ namespace storm { */ void toString(std::ostream &out); - /*! - * Prints a dot representation of the lattice to the output stream. - * - * @param out The stream to output to. - */ - void toDotFile(std::ostream &out); - /*! * Merges node2 into node1 * @param node1 @@ -163,17 +174,6 @@ namespace storm { */ void merge(uint_fast64_t var1, uint_fast64_t var2); - - /*! - * Constants for comparison of nodes/states - */ - enum { - UNKNOWN = -1, - BELOW = 2, - ABOVE = 1, - SAME = 0, - }; - private: std::vector nodes; @@ -189,8 +189,6 @@ namespace storm { bool above(Node * node1, Node * node2, storm::analysis::Lattice::Node *nodePrev, storm::storage::BitVector *statesSeen); - std::unordered_map> comparisons; - bool doneBuilding; }; } diff --git a/src/test/storm-pars/analysis/LatticeExtenderTest.cpp b/src/test/storm-pars/analysis/LatticeExtenderTest.cpp index b174d3873..cda1d7233 100644 --- a/src/test/storm-pars/analysis/LatticeExtenderTest.cpp +++ b/src/test/storm-pars/analysis/LatticeExtenderTest.cpp @@ -1,8 +1,3 @@ -// -// Created by Jip Spel on 20.09.18. -// - -// TODO: cleanup includes #include "gtest/gtest.h" #include "storm-config.h" #include "test/storm_gtest.h" @@ -63,11 +58,11 @@ TEST(LatticeExtenderTest, Brp_with_bisimulation) { } // Check on some nodes - EXPECT_EQ(storm::analysis::Lattice::ABOVE, lattice->compare(1,0)); - EXPECT_EQ(storm::analysis::Lattice::ABOVE, lattice->compare(1,5)); - EXPECT_EQ(storm::analysis::Lattice::ABOVE, lattice->compare(5,0)); - EXPECT_EQ(storm::analysis::Lattice::ABOVE, lattice->compare(94,5)); - EXPECT_EQ(storm::analysis::Lattice::UNKNOWN, lattice->compare(7,13)); + EXPECT_EQ(storm::analysis::Lattice::NodeComparison::ABOVE, lattice->compare(1,0)); + EXPECT_EQ(storm::analysis::Lattice::NodeComparison::ABOVE, lattice->compare(1,5)); + EXPECT_EQ(storm::analysis::Lattice::NodeComparison::ABOVE, lattice->compare(5,0)); + EXPECT_EQ(storm::analysis::Lattice::NodeComparison::ABOVE, lattice->compare(94,5)); + EXPECT_EQ(storm::analysis::Lattice::NodeComparison::UNKNOWN, lattice->compare(7,13)); } TEST(LatticeExtenderTest, Brp_without_bisimulation) { diff --git a/src/test/storm-pars/analysis/LatticeTest.cpp b/src/test/storm-pars/analysis/LatticeTest.cpp index 27806bc50..dbb590c41 100644 --- a/src/test/storm-pars/analysis/LatticeTest.cpp +++ b/src/test/storm-pars/analysis/LatticeTest.cpp @@ -1,8 +1,3 @@ -// -// Created by Jip Spel on 20.09.18. -// - -// TODO: cleanup includes #include "gtest/gtest.h" #include "storm-config.h" #include "test/storm_gtest.h" @@ -18,60 +13,60 @@ TEST(LatticeTest, Simple) { auto initialMiddle = storm::storage::BitVector(numberOfStates); auto lattice = storm::analysis::Lattice(&above, &below, &initialMiddle, numberOfStates); - EXPECT_EQ(storm::analysis::Lattice::ABOVE, lattice.compare(0,1)); - EXPECT_EQ(storm::analysis::Lattice::BELOW, lattice.compare(1,0)); + EXPECT_EQ(storm::analysis::Lattice::NodeComparison::ABOVE, lattice.compare(0,1)); + EXPECT_EQ(storm::analysis::Lattice::NodeComparison::BELOW, lattice.compare(1,0)); EXPECT_EQ(nullptr, lattice.getNode(2)); lattice.add(2); - EXPECT_EQ(storm::analysis::Lattice::ABOVE, lattice.compare(0,2)); - EXPECT_EQ(storm::analysis::Lattice::BELOW, lattice.compare(2,0)); - EXPECT_EQ(storm::analysis::Lattice::ABOVE, lattice.compare(2,1)); - EXPECT_EQ(storm::analysis::Lattice::BELOW, lattice.compare(1,2)); + EXPECT_EQ(storm::analysis::Lattice::NodeComparison::ABOVE, lattice.compare(0,2)); + EXPECT_EQ(storm::analysis::Lattice::NodeComparison::BELOW, lattice.compare(2,0)); + EXPECT_EQ(storm::analysis::Lattice::NodeComparison::ABOVE, lattice.compare(2,1)); + EXPECT_EQ(storm::analysis::Lattice::NodeComparison::BELOW, lattice.compare(1,2)); lattice.add(3); - EXPECT_EQ(storm::analysis::Lattice::UNKNOWN, lattice.compare(2,3)); - EXPECT_EQ(storm::analysis::Lattice::UNKNOWN, lattice.compare(3,2)); + EXPECT_EQ(storm::analysis::Lattice::NodeComparison::UNKNOWN, lattice.compare(2,3)); + EXPECT_EQ(storm::analysis::Lattice::NodeComparison::UNKNOWN, lattice.compare(3,2)); lattice.addToNode(4, lattice.getNode(2)); - EXPECT_EQ(storm::analysis::Lattice::SAME, lattice.compare(2,4)); - EXPECT_EQ(storm::analysis::Lattice::SAME, lattice.compare(4,2)); - EXPECT_EQ(storm::analysis::Lattice::ABOVE, lattice.compare(0,4)); - EXPECT_EQ(storm::analysis::Lattice::BELOW, lattice.compare(4,0)); - EXPECT_EQ(storm::analysis::Lattice::ABOVE, lattice.compare(4,1)); - EXPECT_EQ(storm::analysis::Lattice::BELOW, lattice.compare(1,4)); - EXPECT_EQ(storm::analysis::Lattice::UNKNOWN, lattice.compare(4,3)); - EXPECT_EQ(storm::analysis::Lattice::UNKNOWN, lattice.compare(3,4)); + EXPECT_EQ(storm::analysis::Lattice::NodeComparison::SAME, lattice.compare(2,4)); + EXPECT_EQ(storm::analysis::Lattice::NodeComparison::SAME, lattice.compare(4,2)); + EXPECT_EQ(storm::analysis::Lattice::NodeComparison::ABOVE, lattice.compare(0,4)); + EXPECT_EQ(storm::analysis::Lattice::NodeComparison::BELOW, lattice.compare(4,0)); + EXPECT_EQ(storm::analysis::Lattice::NodeComparison::ABOVE, lattice.compare(4,1)); + EXPECT_EQ(storm::analysis::Lattice::NodeComparison::BELOW, lattice.compare(1,4)); + EXPECT_EQ(storm::analysis::Lattice::NodeComparison::UNKNOWN, lattice.compare(4,3)); + EXPECT_EQ(storm::analysis::Lattice::NodeComparison::UNKNOWN, lattice.compare(3,4)); lattice.addBetween(5, lattice.getNode(0), lattice.getNode(3)); - EXPECT_EQ(storm::analysis::Lattice::BELOW, lattice.compare(5,0)); - EXPECT_EQ(storm::analysis::Lattice::ABOVE, lattice.compare(0,5)); - EXPECT_EQ(storm::analysis::Lattice::ABOVE, lattice.compare(5,3)); - EXPECT_EQ(storm::analysis::Lattice::BELOW, lattice.compare(3,5)); - EXPECT_EQ(storm::analysis::Lattice::ABOVE, lattice.compare(5,1)); - EXPECT_EQ(storm::analysis::Lattice::BELOW, lattice.compare(1,5)); - EXPECT_EQ(storm::analysis::Lattice::UNKNOWN, lattice.compare(5,2)); - EXPECT_EQ(storm::analysis::Lattice::UNKNOWN, lattice.compare(2,5)); - EXPECT_EQ(storm::analysis::Lattice::UNKNOWN, lattice.compare(5,4)); - EXPECT_EQ(storm::analysis::Lattice::UNKNOWN, lattice.compare(4,5)); + EXPECT_EQ(storm::analysis::Lattice::NodeComparison::BELOW, lattice.compare(5,0)); + EXPECT_EQ(storm::analysis::Lattice::NodeComparison::ABOVE, lattice.compare(0,5)); + EXPECT_EQ(storm::analysis::Lattice::NodeComparison::ABOVE, lattice.compare(5,3)); + EXPECT_EQ(storm::analysis::Lattice::NodeComparison::BELOW, lattice.compare(3,5)); + EXPECT_EQ(storm::analysis::Lattice::NodeComparison::ABOVE, lattice.compare(5,1)); + EXPECT_EQ(storm::analysis::Lattice::NodeComparison::BELOW, lattice.compare(1,5)); + EXPECT_EQ(storm::analysis::Lattice::NodeComparison::UNKNOWN, lattice.compare(5,2)); + EXPECT_EQ(storm::analysis::Lattice::NodeComparison::UNKNOWN, lattice.compare(2,5)); + EXPECT_EQ(storm::analysis::Lattice::NodeComparison::UNKNOWN, lattice.compare(5,4)); + EXPECT_EQ(storm::analysis::Lattice::NodeComparison::UNKNOWN, lattice.compare(4,5)); lattice.addBetween(6, lattice.getNode(5), lattice.getNode(3)); - EXPECT_EQ(storm::analysis::Lattice::BELOW, lattice.compare(6,0)); - EXPECT_EQ(storm::analysis::Lattice::ABOVE, lattice.compare(0,6)); - EXPECT_EQ(storm::analysis::Lattice::ABOVE, lattice.compare(6,1)); - EXPECT_EQ(storm::analysis::Lattice::BELOW, lattice.compare(1,6)); - EXPECT_EQ(storm::analysis::Lattice::UNKNOWN, lattice.compare(6,2)); - EXPECT_EQ(storm::analysis::Lattice::UNKNOWN, lattice.compare(2,6)); - EXPECT_EQ(storm::analysis::Lattice::ABOVE, lattice.compare(6,3)); - EXPECT_EQ(storm::analysis::Lattice::BELOW, lattice.compare(3,6)); - EXPECT_EQ(storm::analysis::Lattice::UNKNOWN, lattice.compare(6,4)); - EXPECT_EQ(storm::analysis::Lattice::UNKNOWN, lattice.compare(6,4)); - EXPECT_EQ(storm::analysis::Lattice::BELOW, lattice.compare(6,5)); - EXPECT_EQ(storm::analysis::Lattice::ABOVE, lattice.compare(5,6)); + EXPECT_EQ(storm::analysis::Lattice::NodeComparison::BELOW, lattice.compare(6,0)); + EXPECT_EQ(storm::analysis::Lattice::NodeComparison::ABOVE, lattice.compare(0,6)); + EXPECT_EQ(storm::analysis::Lattice::NodeComparison::ABOVE, lattice.compare(6,1)); + EXPECT_EQ(storm::analysis::Lattice::NodeComparison::BELOW, lattice.compare(1,6)); + EXPECT_EQ(storm::analysis::Lattice::NodeComparison::UNKNOWN, lattice.compare(6,2)); + EXPECT_EQ(storm::analysis::Lattice::NodeComparison::UNKNOWN, lattice.compare(2,6)); + EXPECT_EQ(storm::analysis::Lattice::NodeComparison::ABOVE, lattice.compare(6,3)); + EXPECT_EQ(storm::analysis::Lattice::NodeComparison::BELOW, lattice.compare(3,6)); + EXPECT_EQ(storm::analysis::Lattice::NodeComparison::UNKNOWN, lattice.compare(6,4)); + EXPECT_EQ(storm::analysis::Lattice::NodeComparison::UNKNOWN, lattice.compare(6,4)); + EXPECT_EQ(storm::analysis::Lattice::NodeComparison::BELOW, lattice.compare(6,5)); + EXPECT_EQ(storm::analysis::Lattice::NodeComparison::ABOVE, lattice.compare(5,6)); lattice.addRelationNodes(lattice.getNode(6), lattice.getNode(4)); - EXPECT_EQ(storm::analysis::Lattice::ABOVE, lattice.compare(6,4)); - EXPECT_EQ(storm::analysis::Lattice::BELOW, lattice.compare(4,6)); + EXPECT_EQ(storm::analysis::Lattice::NodeComparison::ABOVE, lattice.compare(6,4)); + EXPECT_EQ(storm::analysis::Lattice::NodeComparison::BELOW, lattice.compare(4,6)); } @@ -93,51 +88,51 @@ TEST(LatticeTest, copy_lattice) { auto latticeCopy = storm::analysis::Lattice(lattice); - EXPECT_EQ(storm::analysis::Lattice::ABOVE, latticeCopy.compare(0,1)); - EXPECT_EQ(storm::analysis::Lattice::BELOW, latticeCopy.compare(1,0)); - - EXPECT_EQ(storm::analysis::Lattice::ABOVE, latticeCopy.compare(0,2)); - EXPECT_EQ(storm::analysis::Lattice::BELOW, latticeCopy.compare(2,0)); - EXPECT_EQ(storm::analysis::Lattice::ABOVE, latticeCopy.compare(2,1)); - EXPECT_EQ(storm::analysis::Lattice::BELOW, latticeCopy.compare(1,2)); - - EXPECT_EQ(storm::analysis::Lattice::UNKNOWN, latticeCopy.compare(2,3)); - EXPECT_EQ(storm::analysis::Lattice::UNKNOWN, latticeCopy.compare(3,2)); - - EXPECT_EQ(storm::analysis::Lattice::SAME, latticeCopy.compare(2,4)); - EXPECT_EQ(storm::analysis::Lattice::SAME, latticeCopy.compare(4,2)); - EXPECT_EQ(storm::analysis::Lattice::ABOVE, latticeCopy.compare(0,4)); - EXPECT_EQ(storm::analysis::Lattice::BELOW, latticeCopy.compare(4,0)); - EXPECT_EQ(storm::analysis::Lattice::ABOVE, latticeCopy.compare(4,1)); - EXPECT_EQ(storm::analysis::Lattice::BELOW, latticeCopy.compare(1,4)); - EXPECT_EQ(storm::analysis::Lattice::UNKNOWN, latticeCopy.compare(4,3)); - EXPECT_EQ(storm::analysis::Lattice::UNKNOWN, latticeCopy.compare(3,4)); - - EXPECT_EQ(storm::analysis::Lattice::BELOW, latticeCopy.compare(5,0)); - EXPECT_EQ(storm::analysis::Lattice::ABOVE, latticeCopy.compare(0,5)); - EXPECT_EQ(storm::analysis::Lattice::ABOVE, latticeCopy.compare(5,3)); - EXPECT_EQ(storm::analysis::Lattice::BELOW, latticeCopy.compare(3,5)); - EXPECT_EQ(storm::analysis::Lattice::ABOVE, latticeCopy.compare(5,1)); - EXPECT_EQ(storm::analysis::Lattice::BELOW, latticeCopy.compare(1,5)); - EXPECT_EQ(storm::analysis::Lattice::UNKNOWN, latticeCopy.compare(5,2)); - EXPECT_EQ(storm::analysis::Lattice::UNKNOWN, latticeCopy.compare(5,2)); - EXPECT_EQ(storm::analysis::Lattice::UNKNOWN, latticeCopy.compare(5,4)); - EXPECT_EQ(storm::analysis::Lattice::UNKNOWN, latticeCopy.compare(5,4)); + EXPECT_EQ(storm::analysis::Lattice::NodeComparison::ABOVE, latticeCopy.compare(0,1)); + EXPECT_EQ(storm::analysis::Lattice::NodeComparison::BELOW, latticeCopy.compare(1,0)); + + EXPECT_EQ(storm::analysis::Lattice::NodeComparison::ABOVE, latticeCopy.compare(0,2)); + EXPECT_EQ(storm::analysis::Lattice::NodeComparison::BELOW, latticeCopy.compare(2,0)); + EXPECT_EQ(storm::analysis::Lattice::NodeComparison::ABOVE, latticeCopy.compare(2,1)); + EXPECT_EQ(storm::analysis::Lattice::NodeComparison::BELOW, latticeCopy.compare(1,2)); + + EXPECT_EQ(storm::analysis::Lattice::NodeComparison::UNKNOWN, latticeCopy.compare(2,3)); + EXPECT_EQ(storm::analysis::Lattice::NodeComparison::UNKNOWN, latticeCopy.compare(3,2)); + + EXPECT_EQ(storm::analysis::Lattice::NodeComparison::SAME, latticeCopy.compare(2,4)); + EXPECT_EQ(storm::analysis::Lattice::NodeComparison::SAME, latticeCopy.compare(4,2)); + EXPECT_EQ(storm::analysis::Lattice::NodeComparison::ABOVE, latticeCopy.compare(0,4)); + EXPECT_EQ(storm::analysis::Lattice::NodeComparison::BELOW, latticeCopy.compare(4,0)); + EXPECT_EQ(storm::analysis::Lattice::NodeComparison::ABOVE, latticeCopy.compare(4,1)); + EXPECT_EQ(storm::analysis::Lattice::NodeComparison::BELOW, latticeCopy.compare(1,4)); + EXPECT_EQ(storm::analysis::Lattice::NodeComparison::UNKNOWN, latticeCopy.compare(4,3)); + EXPECT_EQ(storm::analysis::Lattice::NodeComparison::UNKNOWN, latticeCopy.compare(3,4)); + + EXPECT_EQ(storm::analysis::Lattice::NodeComparison::BELOW, latticeCopy.compare(5,0)); + EXPECT_EQ(storm::analysis::Lattice::NodeComparison::ABOVE, latticeCopy.compare(0,5)); + EXPECT_EQ(storm::analysis::Lattice::NodeComparison::ABOVE, latticeCopy.compare(5,3)); + EXPECT_EQ(storm::analysis::Lattice::NodeComparison::BELOW, latticeCopy.compare(3,5)); + EXPECT_EQ(storm::analysis::Lattice::NodeComparison::ABOVE, latticeCopy.compare(5,1)); + EXPECT_EQ(storm::analysis::Lattice::NodeComparison::BELOW, latticeCopy.compare(1,5)); + EXPECT_EQ(storm::analysis::Lattice::NodeComparison::UNKNOWN, latticeCopy.compare(5,2)); + EXPECT_EQ(storm::analysis::Lattice::NodeComparison::UNKNOWN, latticeCopy.compare(5,2)); + EXPECT_EQ(storm::analysis::Lattice::NodeComparison::UNKNOWN, latticeCopy.compare(5,4)); + EXPECT_EQ(storm::analysis::Lattice::NodeComparison::UNKNOWN, latticeCopy.compare(5,4)); lattice.addRelationNodes(lattice.getNode(6), lattice.getNode(4)); latticeCopy = storm::analysis::Lattice(lattice); - EXPECT_EQ(storm::analysis::Lattice::BELOW, latticeCopy.compare(6,0)); - EXPECT_EQ(storm::analysis::Lattice::ABOVE, latticeCopy.compare(0,6)); - EXPECT_EQ(storm::analysis::Lattice::ABOVE, latticeCopy.compare(6,1)); - EXPECT_EQ(storm::analysis::Lattice::BELOW, latticeCopy.compare(1,6)); - EXPECT_EQ(storm::analysis::Lattice::ABOVE, latticeCopy.compare(6,2)); - EXPECT_EQ(storm::analysis::Lattice::BELOW, latticeCopy.compare(2,6)); - EXPECT_EQ(storm::analysis::Lattice::ABOVE, latticeCopy.compare(6,3)); - EXPECT_EQ(storm::analysis::Lattice::BELOW, latticeCopy.compare(3,6)); - EXPECT_EQ(storm::analysis::Lattice::ABOVE, latticeCopy.compare(6,4)); - EXPECT_EQ(storm::analysis::Lattice::BELOW, latticeCopy.compare(4,6)); - EXPECT_EQ(storm::analysis::Lattice::BELOW, latticeCopy.compare(6,5)); - EXPECT_EQ(storm::analysis::Lattice::ABOVE, latticeCopy.compare(5,6)); + EXPECT_EQ(storm::analysis::Lattice::NodeComparison::BELOW, latticeCopy.compare(6,0)); + EXPECT_EQ(storm::analysis::Lattice::NodeComparison::ABOVE, latticeCopy.compare(0,6)); + EXPECT_EQ(storm::analysis::Lattice::NodeComparison::ABOVE, latticeCopy.compare(6,1)); + EXPECT_EQ(storm::analysis::Lattice::NodeComparison::BELOW, latticeCopy.compare(1,6)); + EXPECT_EQ(storm::analysis::Lattice::NodeComparison::ABOVE, latticeCopy.compare(6,2)); + EXPECT_EQ(storm::analysis::Lattice::NodeComparison::BELOW, latticeCopy.compare(2,6)); + EXPECT_EQ(storm::analysis::Lattice::NodeComparison::ABOVE, latticeCopy.compare(6,3)); + EXPECT_EQ(storm::analysis::Lattice::NodeComparison::BELOW, latticeCopy.compare(3,6)); + EXPECT_EQ(storm::analysis::Lattice::NodeComparison::ABOVE, latticeCopy.compare(6,4)); + EXPECT_EQ(storm::analysis::Lattice::NodeComparison::BELOW, latticeCopy.compare(4,6)); + EXPECT_EQ(storm::analysis::Lattice::NodeComparison::BELOW, latticeCopy.compare(6,5)); + EXPECT_EQ(storm::analysis::Lattice::NodeComparison::ABOVE, latticeCopy.compare(5,6)); } TEST(LatticeTest, merge_nodes) { @@ -156,20 +151,20 @@ TEST(LatticeTest, merge_nodes) { lattice.addBetween(6, lattice.getNode(5), lattice.getNode(3)); lattice.mergeNodes(lattice.getNode(4), lattice.getNode(5)); - EXPECT_EQ(storm::analysis::Lattice::SAME, lattice.compare(2,4)); - EXPECT_EQ(storm::analysis::Lattice::SAME, lattice.compare(2,5)); - - EXPECT_EQ(storm::analysis::Lattice::ABOVE, lattice.compare(0,5)); - EXPECT_EQ(storm::analysis::Lattice::ABOVE, lattice.compare(0,2)); - EXPECT_EQ(storm::analysis::Lattice::ABOVE, lattice.compare(0,4)); - - EXPECT_EQ(storm::analysis::Lattice::BELOW, lattice.compare(6,2)); - EXPECT_EQ(storm::analysis::Lattice::BELOW, lattice.compare(6,4)); - EXPECT_EQ(storm::analysis::Lattice::BELOW, lattice.compare(6,5)); - EXPECT_EQ(storm::analysis::Lattice::BELOW, lattice.compare(3,2)); - EXPECT_EQ(storm::analysis::Lattice::BELOW, lattice.compare(3,4)); - EXPECT_EQ(storm::analysis::Lattice::BELOW, lattice.compare(3,5)); - EXPECT_EQ(storm::analysis::Lattice::BELOW, lattice.compare(1,2)); - EXPECT_EQ(storm::analysis::Lattice::BELOW, lattice.compare(1,4)); - EXPECT_EQ(storm::analysis::Lattice::BELOW, lattice.compare(1,5)); + EXPECT_EQ(storm::analysis::Lattice::NodeComparison::SAME, lattice.compare(2,4)); + EXPECT_EQ(storm::analysis::Lattice::NodeComparison::SAME, lattice.compare(2,5)); + + EXPECT_EQ(storm::analysis::Lattice::NodeComparison::ABOVE, lattice.compare(0,5)); + EXPECT_EQ(storm::analysis::Lattice::NodeComparison::ABOVE, lattice.compare(0,2)); + EXPECT_EQ(storm::analysis::Lattice::NodeComparison::ABOVE, lattice.compare(0,4)); + + EXPECT_EQ(storm::analysis::Lattice::NodeComparison::BELOW, lattice.compare(6,2)); + EXPECT_EQ(storm::analysis::Lattice::NodeComparison::BELOW, lattice.compare(6,4)); + EXPECT_EQ(storm::analysis::Lattice::NodeComparison::BELOW, lattice.compare(6,5)); + EXPECT_EQ(storm::analysis::Lattice::NodeComparison::BELOW, lattice.compare(3,2)); + EXPECT_EQ(storm::analysis::Lattice::NodeComparison::BELOW, lattice.compare(3,4)); + EXPECT_EQ(storm::analysis::Lattice::NodeComparison::BELOW, lattice.compare(3,5)); + EXPECT_EQ(storm::analysis::Lattice::NodeComparison::BELOW, lattice.compare(1,2)); + EXPECT_EQ(storm::analysis::Lattice::NodeComparison::BELOW, lattice.compare(1,4)); + EXPECT_EQ(storm::analysis::Lattice::NodeComparison::BELOW, lattice.compare(1,5)); } From 7f5416adb823b8e42794d535636d5121ef02e74b Mon Sep 17 00:00:00 2001 From: Jip Spel Date: Wed, 15 May 2019 14:26:10 +0200 Subject: [PATCH 156/178] Clean up LatticeExtender --- src/storm-pars/analysis/LatticeExtender.cpp | 33 +++++++-------------- src/storm-pars/analysis/LatticeExtender.h | 7 ----- 2 files changed, 11 insertions(+), 29 deletions(-) diff --git a/src/storm-pars/analysis/LatticeExtender.cpp b/src/storm-pars/analysis/LatticeExtender.cpp index 4135e4ded..f2f6c4fa8 100644 --- a/src/storm-pars/analysis/LatticeExtender.cpp +++ b/src/storm-pars/analysis/LatticeExtender.cpp @@ -38,8 +38,6 @@ namespace storm { template std::tuple LatticeExtender::toLattice(std::vector> formulas) { -// storm::utility::Stopwatch latticeWatch(true); - STORM_LOG_THROW((++formulas.begin()) == formulas.end(), storm::exceptions::NotSupportedException, "Only one formula allowed for monotonicity analysis"); STORM_LOG_THROW((*(formulas[0])).isProbabilityOperatorFormula() && ((*(formulas[0])).asProbabilityOperatorFormula().getSubformula().isUntilFormula() @@ -71,7 +69,6 @@ namespace storm { auto initialMiddleStates = storm::storage::BitVector(numberOfStates); // Check if MC contains cycles - // TODO maybe move to other place? storm::storage::StronglyConnectedComponentDecompositionOptions const options; auto decomposition = storm::storage::StronglyConnectedComponentDecomposition(model->getTransitionMatrix(), options); acyclic = true; @@ -119,8 +116,6 @@ namespace storm { // Create the Lattice Lattice *lattice = new Lattice(&topStates, &bottomStates, &initialMiddleStates, numberOfStates); -// latticeWatch.stop(); -// STORM_PRINT(std::endl << "Time for initialization of lattice: " << latticeWatch << "." << std::endl << std::endl); return this->extendLattice(lattice); } @@ -325,11 +320,9 @@ namespace storm { } } else if (!acyclic) { - // TODO: kan dit niet efficienter auto addedStates = lattice->getAddedStates(); if (assumptionSeen) { statesToHandle = addedStates; - // TODO: statesSorted = } auto stateNumber = statesToHandle->getNextSetIndex(0); while (stateNumber != numberOfStates) { @@ -384,8 +377,6 @@ namespace storm { } } -// addedStates = lattice->getAddedStates(); -// auto notAddedStates = addedStates->operator~(); if (!assumptionSeen) { stateNumber = *(statesSorted.begin()); while (stateNumber != numberOfStates && (*(lattice->getAddedStates()))[stateNumber]) { @@ -393,20 +384,17 @@ namespace storm { stateNumber = *(statesSorted.begin()); } - if (stateNumber == numberOfStates) { - assert(false); - } - storm::storage::BitVector* successors = stateMap[stateNumber]; - - // Check if current state has not been added yet, and all successors have, ignore selfloop in this - successors->set(stateNumber, false); - if ((*successors & *addedStates) == *successors) { - auto result = extendAllSuccAdded(lattice, stateNumber, successors); - if (std::get<1>(result) != successors->size()) { - return result; - } - statesToHandle->set(stateNumber); + storm::storage::BitVector* successors = stateMap[stateNumber]; + + // Check if current state has not been added yet, and all successors have, ignore selfloop in this + successors->set(stateNumber, false); + if ((*successors & *addedStates) == *successors) { + auto result = extendAllSuccAdded(lattice, stateNumber, successors); + if (std::get<1>(result) != successors->size()) { + return result; } + statesToHandle->set(stateNumber); + } } else { addedStates = lattice->getAddedStates(); auto notAddedStates = addedStates->operator~(); @@ -445,6 +433,7 @@ namespace storm { lattice->setDoneBuilding(true); return std::make_tuple(lattice, numberOfStates, numberOfStates); } + template class LatticeExtender; } } diff --git a/src/storm-pars/analysis/LatticeExtender.h b/src/storm-pars/analysis/LatticeExtender.h index 63f224792..7497aa594 100644 --- a/src/storm-pars/analysis/LatticeExtender.h +++ b/src/storm-pars/analysis/LatticeExtender.h @@ -1,7 +1,3 @@ -// -// Created by Jip Spel on 28.08.18. -// - #ifndef STORM_LATTICEEXTENDER_H #define STORM_LATTICEEXTENDER_H @@ -10,9 +6,6 @@ #include "storm-pars/analysis/Lattice.h" #include "storm/api/storm.h" - - - namespace storm { namespace analysis { From 8732a7f40dc288f0b88afec5be17f4d2ef557d72 Mon Sep 17 00:00:00 2001 From: Jip Spel Date: Wed, 15 May 2019 14:34:42 +0200 Subject: [PATCH 157/178] Make variabletype depend on value type --- .../analysis/MonotonicityChecker.cpp | 60 +++++++++---------- src/storm-pars/analysis/MonotonicityChecker.h | 23 +++---- 2 files changed, 37 insertions(+), 46 deletions(-) diff --git a/src/storm-pars/analysis/MonotonicityChecker.cpp b/src/storm-pars/analysis/MonotonicityChecker.cpp index 092a3ffbf..972585535 100644 --- a/src/storm-pars/analysis/MonotonicityChecker.cpp +++ b/src/storm-pars/analysis/MonotonicityChecker.cpp @@ -1,7 +1,3 @@ -// -// Created by Jip Spel on 05.09.18. -// - #include "MonotonicityChecker.h" #include "storm-pars/analysis/AssumptionMaker.h" #include "storm-pars/analysis/AssumptionChecker.h" @@ -36,10 +32,10 @@ namespace storm { if (numberOfSamples > 0) { // sampling if (model->isOfType(storm::models::ModelType::Dtmc)) { - this->resultCheckOnSamples = std::map>( + this->resultCheckOnSamples = std::map::type, std::pair>( checkOnSamples(model->as>(), numberOfSamples)); } else if (model->isOfType(storm::models::ModelType::Mdp)) { - this->resultCheckOnSamples = std::map>( + this->resultCheckOnSamples = std::map::type, std::pair>( checkOnSamples(model->as>(), numberOfSamples)); } @@ -53,7 +49,7 @@ namespace storm { } template - std::map>> MonotonicityChecker::checkMonotonicity() { + std::map::type, std::pair>> MonotonicityChecker::checkMonotonicity() { auto map = createLattice(); std::shared_ptr> sparseModel = model->as>(); auto matrix = sparseModel->getTransitionMatrix(); @@ -61,9 +57,9 @@ namespace storm { } template - std::map>> MonotonicityChecker::checkMonotonicity(std::map>> map, storm::storage::SparseMatrix matrix) { + std::map::type, std::pair>> MonotonicityChecker::checkMonotonicity(std::map>> map, storm::storage::SparseMatrix matrix) { storm::utility::Stopwatch monotonicityCheckWatch(true); - std::map>> result; + std::map::type, std::pair>> result; outfile.open(filename, std::ios_base::app); @@ -96,7 +92,7 @@ namespace storm { auto addedStates = lattice->getAddedStates()->getNumberOfSetBits(); assert (addedStates == lattice->getAddedStates()->size()); - std::map> varsMonotone = analyseMonotonicity(i, lattice, + std::map::type, std::pair> varsMonotone = analyseMonotonicity(i, lattice, matrix); auto assumptions = itr->second; @@ -142,7 +138,7 @@ namespace storm { } } result.insert( - std::pair>>( + std::pair::type, std::pair>>( lattice, varsMonotone)); } ++i; @@ -267,7 +263,7 @@ namespace storm { } template - ValueType MonotonicityChecker::getDerivative(ValueType function, carl::Variable var) { + ValueType MonotonicityChecker::getDerivative(ValueType function, typename utility::parametric::VariableType::type var) { if (function.isConstant()) { return storm::utility::zero(); } @@ -279,8 +275,8 @@ namespace storm { } template - std::map> MonotonicityChecker::analyseMonotonicity(uint_fast64_t j, storm::analysis::Lattice* lattice, storm::storage::SparseMatrix matrix) { - std::map> varsMonotone; + std::map::type, std::pair> MonotonicityChecker::analyseMonotonicity(uint_fast64_t j, storm::analysis::Lattice* lattice, storm::storage::SparseMatrix matrix) { + std::map::type, std::pair> varsMonotone; // go over all rows, check for each row local monotonicity for (uint_fast64_t i = 0; i < matrix.getColumnCount(); ++i) { @@ -292,7 +288,7 @@ namespace storm { // Gather all states which are reached with a non constant probability auto states = new storm::storage::BitVector(matrix.getColumnCount()); - std::set vars; + std::set::type> vars; for (auto const& entry : row) { if (!entry.getValue().isConstant()) { // only analyse take non constant transitions @@ -413,7 +409,7 @@ namespace storm { std::shared_ptr> sparseModel = model->as>(); auto matrix = sparseModel->getTransitionMatrix(); - std::map> varsMonotone; + std::map::type, std::pair> varsMonotone; for (uint_fast64_t i = 0; i < matrix.getColumnCount(); ++i) { // go over all rows @@ -502,14 +498,14 @@ namespace storm { template - std::map> MonotonicityChecker::checkOnSamples(std::shared_ptr> model, uint_fast64_t numberOfSamples) { + std::map::type, std::pair> MonotonicityChecker::checkOnSamples(std::shared_ptr> model, uint_fast64_t numberOfSamples) { storm::utility::Stopwatch samplesWatch(true); - std::map> result; + std::map::type, std::pair> result; auto instantiator = storm::utility::ModelInstantiator, storm::models::sparse::Dtmc>(*model); auto matrix = model->getTransitionMatrix(); - std::set variables = storm::models::sparse::getProbabilityParameters(*model); + std::set::type> variables = storm::models::sparse::getProbabilityParameters(*model); for (auto itr = variables.begin(); itr != variables.end(); ++itr) { double previous = -1; @@ -521,13 +517,13 @@ namespace storm { for (auto itr2 = variables.begin(); itr2 != variables.end(); ++itr2) { // Only change value for current variable if ((*itr) == (*itr2)) { - auto val = std::pair( - (*itr2), storm::utility::convertNumber( + auto val = std::pair::type, typename utility::parametric::CoefficientType::type>( + (*itr2), storm::utility::convertNumber::type>( boost::lexical_cast((i + 1) / (double(numberOfSamples + 1))))); valuation.insert(val); } else { - auto val = std::pair( - (*itr2), storm::utility::convertNumber( + auto val = std::pair::type, typename utility::parametric::CoefficientType::type>( + (*itr2), storm::utility::convertNumber::type>( boost::lexical_cast((1) / (double(numberOfSamples + 1))))); valuation.insert(val); } @@ -565,7 +561,7 @@ namespace storm { } previous = initial; } - result.insert(std::pair>(*itr, std::pair(monIncr, monDecr))); + result.insert(std::pair::type, std::pair>(*itr, std::pair(monIncr, monDecr))); } samplesWatch.stop(); @@ -574,14 +570,14 @@ namespace storm { } template - std::map> MonotonicityChecker::checkOnSamples(std::shared_ptr> model, uint_fast64_t numberOfSamples) { + std::map::type, std::pair> MonotonicityChecker::checkOnSamples(std::shared_ptr> model, uint_fast64_t numberOfSamples) { storm::utility::Stopwatch samplesWatch(true); - std::map> result; + std::map::type, std::pair> result; auto instantiator = storm::utility::ModelInstantiator, storm::models::sparse::Mdp>(*model); auto matrix = model->getTransitionMatrix(); - std::set variables = storm::models::sparse::getProbabilityParameters(*model); + std::set::type> variables = storm::models::sparse::getProbabilityParameters(*model); for (auto itr = variables.begin(); itr != variables.end(); ++itr) { double previous = -1; @@ -593,13 +589,13 @@ namespace storm { for (auto itr2 = variables.begin(); itr2 != variables.end(); ++itr2) { // Only change value for current variable if ((*itr) == (*itr2)) { - auto val = std::pair( - (*itr2), storm::utility::convertNumber( + auto val = std::pair::type, typename utility::parametric::CoefficientType::type>( + (*itr2), storm::utility::convertNumber::type>( boost::lexical_cast((i + 1) / (double(numberOfSamples + 1))))); valuation.insert(val); } else { - auto val = std::pair( - (*itr2), storm::utility::convertNumber( + auto val = std::pair::type, typename utility::parametric::CoefficientType::type>( + (*itr2), storm::utility::convertNumber::type>( boost::lexical_cast((1) / (double(numberOfSamples + 1))))); valuation.insert(val); } @@ -635,7 +631,7 @@ namespace storm { } previous = initial; } - result.insert(std::pair>(*itr, std::pair(monIncr, monDecr))); + result.insert(std::pair::type, std::pair>(*itr, std::pair(monIncr, monDecr))); } samplesWatch.stop(); diff --git a/src/storm-pars/analysis/MonotonicityChecker.h b/src/storm-pars/analysis/MonotonicityChecker.h index 81bd6801a..66a2d3869 100644 --- a/src/storm-pars/analysis/MonotonicityChecker.h +++ b/src/storm-pars/analysis/MonotonicityChecker.h @@ -1,7 +1,3 @@ -// -// Created by Jip Spel on 03.09.18. -// - #ifndef STORM_MONOTONICITYCHECKER_H #define STORM_MONOTONICITYCHECKER_H @@ -14,7 +10,6 @@ #include "storm/storage/expressions/RationalFunctionToExpression.h" #include "storm/utility/constants.h" -#include "carl/core/Variable.h" #include "storm/models/ModelBase.h" #include "storm/models/sparse/Dtmc.h" #include "storm/models/sparse/Mdp.h" @@ -44,7 +39,7 @@ namespace storm { /*! * Checks for model and formula as provided in constructor for monotonicity */ - std::map>> checkMonotonicity(); + std::map::type, std::pair>> checkMonotonicity(); /*! * Checks if monotonicity can be found in this lattice. Unordered states are not checked @@ -74,7 +69,7 @@ namespace storm { storm::solver::Z3SmtSolver s(*manager); - std::set variables = derivative.gatherVariables(); + std::set::type> variables = derivative.gatherVariables(); for (auto variable : variables) { @@ -114,20 +109,20 @@ namespace storm { } private: - std::map>> checkMonotonicity(std::map>> map, storm::storage::SparseMatrix matrix); + std::map::type, std::pair>> checkMonotonicity(std::map>> map, storm::storage::SparseMatrix matrix); //TODO: variabele type - std::map> analyseMonotonicity(uint_fast64_t i, Lattice* lattice, storm::storage::SparseMatrix matrix) ; + std::map::type, std::pair> analyseMonotonicity(uint_fast64_t i, Lattice* lattice, storm::storage::SparseMatrix matrix) ; std::map>> createLattice(); - std::map> checkOnSamples(std::shared_ptr> model, uint_fast64_t numberOfSamples); + std::map::type, std::pair> checkOnSamples(std::shared_ptr> model, uint_fast64_t numberOfSamples); - std::map> checkOnSamples(std::shared_ptr> model, uint_fast64_t numberOfSamples); + std::map::type, std::pair> checkOnSamples(std::shared_ptr> model, uint_fast64_t numberOfSamples); - std::unordered_map> derivatives; + std::unordered_map::type, ValueType>> derivatives; - ValueType getDerivative(ValueType function, carl::Variable var); + ValueType getDerivative(ValueType function, typename utility::parametric::VariableType::type var); std::map>> extendLatticeWithAssumptions(Lattice* lattice, AssumptionMaker* assumptionMaker, uint_fast64_t val1, uint_fast64_t val2, std::vector> assumptions); @@ -139,7 +134,7 @@ namespace storm { bool checkSamples; - std::map> resultCheckOnSamples; + std::map::type, std::pair> resultCheckOnSamples; LatticeExtender *extender; From 1557f6d2131e8e77e7c52ffd45bb50347663ede4 Mon Sep 17 00:00:00 2001 From: Jip Spel Date: Wed, 15 May 2019 15:31:00 +0200 Subject: [PATCH 158/178] Use precision in sample checking monotonicity --- src/storm-pars/analysis/MonotonicityChecker.cpp | 14 +++++++------- src/storm-pars/analysis/MonotonicityChecker.h | 5 ++++- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/src/storm-pars/analysis/MonotonicityChecker.cpp b/src/storm-pars/analysis/MonotonicityChecker.cpp index 972585535..f4e6fbde0 100644 --- a/src/storm-pars/analysis/MonotonicityChecker.cpp +++ b/src/storm-pars/analysis/MonotonicityChecker.cpp @@ -23,11 +23,12 @@ namespace storm { namespace analysis { template - MonotonicityChecker::MonotonicityChecker(std::shared_ptr model, std::vector> formulas, bool validate, uint_fast64_t numberOfSamples) { + MonotonicityChecker::MonotonicityChecker(std::shared_ptr model, std::vector> formulas, bool validate, uint_fast64_t numberOfSamples, double const& precision) { assert (model != nullptr); this->model = model; this->formulas = formulas; this->validate = validate; + this->precision = precision; if (numberOfSamples > 0) { // sampling @@ -512,7 +513,7 @@ namespace storm { bool monDecr = true; bool monIncr = true; - for (auto i = 0; i < numberOfSamples; ++i) { + for (auto i = 0; (monDecr || monIncr) && i < numberOfSamples; ++i) { auto valuation = storm::utility::parametric::Valuation(); for (auto itr2 = variables.begin(); itr2 != variables.end(); ++itr2) { // Only change value for current variable @@ -553,11 +554,10 @@ namespace storm { for (auto i = initialStates.getNextSetIndex(0); i < model->getNumberOfStates(); i = initialStates.getNextSetIndex(i+1)) { initial += values[i]; } - float diff = previous - initial; - // TODO: define precision - if (previous != -1 && diff > 0.000005 && diff < -0.000005) { - monDecr &= previous >= initial; - monIncr &= previous <= initial; + double diff = previous - initial; + if (previous != -1 && (diff > precision || diff < -precision)) { + monDecr &= diff > precision; // then previous value is larger than the current value from the initial states + monIncr &= diff < -precision; } previous = initial; } diff --git a/src/storm-pars/analysis/MonotonicityChecker.h b/src/storm-pars/analysis/MonotonicityChecker.h index 66a2d3869..5d6b60ba4 100644 --- a/src/storm-pars/analysis/MonotonicityChecker.h +++ b/src/storm-pars/analysis/MonotonicityChecker.h @@ -33,8 +33,9 @@ namespace storm { * @param validate whether or not assumptions are to be validated * @param numberOfSamples number of samples taken for monotonicity checking, default 0, * if 0then no check on samples is executed + * @param precision precision on which the samples are compared */ - MonotonicityChecker(std::shared_ptr model, std::vector> formulas, bool validate, uint_fast64_t numberOfSamples=0); + MonotonicityChecker(std::shared_ptr model, std::vector> formulas, bool validate, uint_fast64_t numberOfSamples=0, double const& precision=0.000001); /*! * Checks for model and formula as provided in constructor for monotonicity @@ -141,6 +142,8 @@ namespace storm { std::ofstream outfile; std::string filename = "monotonicity.txt"; + + double precision; }; } } From 4825cb254f7926644100756a73136ef7756a2a25 Mon Sep 17 00:00:00 2001 From: Jip Spel Date: Thu, 16 May 2019 16:28:07 +0200 Subject: [PATCH 159/178] Precision as argument --- src/storm-pars-cli/storm-pars.cpp | 17 ++--------------- src/storm-pars/analysis/MonotonicityChecker.cpp | 17 ++++++++++++----- .../settings/modules/ParametricSettings.cpp | 7 +++++++ .../settings/modules/ParametricSettings.h | 6 ++++++ 4 files changed, 27 insertions(+), 20 deletions(-) diff --git a/src/storm-pars-cli/storm-pars.cpp b/src/storm-pars-cli/storm-pars.cpp index 0105e55ef..42415b81a 100644 --- a/src/storm-pars-cli/storm-pars.cpp +++ b/src/storm-pars-cli/storm-pars.cpp @@ -598,10 +598,6 @@ namespace storm { if (parSettings.isMonotonicityAnalysisSet()) { // Simplify the model storm::utility::Stopwatch simplifyingWatch(true); - std::ofstream outfile; - outfile.open("results.txt", std::ios_base::app); - outfile << ioSettings.getPrismInputFilename() << ", "; - if (model->isOfType(storm::models::ModelType::Dtmc)) { auto consideredModel = (model->as>()); auto simplifier = storm::transformer::SparseParametricDtmcSimplifier>(*consideredModel); @@ -631,11 +627,9 @@ namespace storm { simplifyingWatch.stop(); STORM_PRINT(std::endl << "Time for model simplification: " << simplifyingWatch << "." << std::endl << std::endl); model->printModelInformationToStream(std::cout); - outfile << simplifyingWatch << ", "; - outfile.close(); } - if (parSettings.isMonotonicityAnalysisSet() && model) { + if (model) { auto preprocessingResult = storm::pars::preprocessModel(model, input); if (preprocessingResult.changed) { model = preprocessingResult.model; @@ -722,20 +716,13 @@ namespace storm { if (parSettings.isMonotonicityAnalysisSet()) { std::vector> formulas = storm::api::extractFormulasFromProperties(input.properties); - // Monotonicity - std::ofstream outfile; - outfile.open("results.txt", std::ios_base::app); storm::utility::Stopwatch monotonicityWatch(true); - auto numberOfSamples = parSettings.getNumberOfSamples(); - auto monotonicityChecker = storm::analysis::MonotonicityChecker(model, formulas, parSettings.isValidateAssumptionsSet(), numberOfSamples); + auto monotonicityChecker = storm::analysis::MonotonicityChecker(model, formulas, parSettings.isValidateAssumptionsSet(), parSettings.getNumberOfSamples(), parSettings.getMonotonicityAnalysisPrecision()); monotonicityChecker.checkMonotonicity(); monotonicityWatch.stop(); STORM_PRINT(std::endl << "Total time for monotonicity checking: " << monotonicityWatch << "." << std::endl << std::endl); - - outfile << monotonicityWatch << std::endl; - outfile.close(); } std::vector> regions = parseRegions(model); diff --git a/src/storm-pars/analysis/MonotonicityChecker.cpp b/src/storm-pars/analysis/MonotonicityChecker.cpp index f4e6fbde0..33bc02d63 100644 --- a/src/storm-pars/analysis/MonotonicityChecker.cpp +++ b/src/storm-pars/analysis/MonotonicityChecker.cpp @@ -522,11 +522,13 @@ namespace storm { (*itr2), storm::utility::convertNumber::type>( boost::lexical_cast((i + 1) / (double(numberOfSamples + 1))))); valuation.insert(val); + assert (0 < val.second && val.second < 1); } else { auto val = std::pair::type, typename utility::parametric::CoefficientType::type>( (*itr2), storm::utility::convertNumber::type>( boost::lexical_cast((1) / (double(numberOfSamples + 1))))); valuation.insert(val); + assert (0 < val.second && val.second < 1); } } storm::models::sparse::Dtmc sampleModel = instantiator.instantiate(valuation); @@ -551,10 +553,12 @@ namespace storm { std::vector values = quantitativeResult.getValueVector(); auto initialStates = model->getInitialStates(); double initial = 0; - for (auto i = initialStates.getNextSetIndex(0); i < model->getNumberOfStates(); i = initialStates.getNextSetIndex(i+1)) { - initial += values[i]; + for (auto j = initialStates.getNextSetIndex(0); j < model->getNumberOfStates(); j = initialStates.getNextSetIndex(j+1)) { + initial += values[j]; } + assert (initial >= precision && initial <= 1+precision); double diff = previous - initial; + assert (previous == -1 || diff >= -1-precision && diff <= 1 + precision); if (previous != -1 && (diff > precision || diff < -precision)) { monDecr &= diff > precision; // then previous value is larger than the current value from the initial states monIncr &= diff < -precision; @@ -625,9 +629,12 @@ namespace storm { for (auto i = initialStates.getNextSetIndex(0); i < model->getNumberOfStates(); i = initialStates.getNextSetIndex(i+1)) { initial += values[i]; } - if (previous != -1) { - monDecr &= previous >= initial; - monIncr &= previous <= initial; + assert (initial >= precision && initial <= 1+precision); + double diff = previous - initial; + assert (previous == -1 || diff >= -1-precision && diff <= 1 + precision); + if (previous != -1 && (diff > precision || diff < -precision)) { + monDecr &= diff > precision; // then previous value is larger than the current value from the initial states + monIncr &= diff < -precision; } previous = initial; } diff --git a/src/storm-pars/settings/modules/ParametricSettings.cpp b/src/storm-pars/settings/modules/ParametricSettings.cpp index e0c8c3bee..75d31566e 100644 --- a/src/storm-pars/settings/modules/ParametricSettings.cpp +++ b/src/storm-pars/settings/modules/ParametricSettings.cpp @@ -25,6 +25,7 @@ namespace storm { const std::string ParametricSettings::sccElimination = "mon-elim-scc"; const std::string ParametricSettings::validateAssumptions = "mon-validate-assumptions"; const std::string ParametricSettings::samplesMonotonicityAnalysis = "mon-samples"; + const std::string ParametricSettings::precision = "mon-precision"; ParametricSettings::ParametricSettings() : ModuleSettings(moduleName) { this->addOption(storm::settings::OptionBuilder(moduleName, exportResultOptionName, false, "A path to a file where the parametric result should be saved.") @@ -41,6 +42,8 @@ namespace storm { this->addOption(storm::settings::OptionBuilder(moduleName, validateAssumptions, false, "Sets whether assumptions made in monotonicity analysis are validated").build()); this->addOption(storm::settings::OptionBuilder(moduleName, samplesMonotonicityAnalysis, false, "Sets whether monotonicity should be checked on samples") .addArgument(storm::settings::ArgumentBuilder::createUnsignedIntegerArgument("mon-samples", "The number of samples taken in monotonicity-analysis can be given, default is 0, no samples").setDefaultValueUnsignedInteger(0).build()).build()); + this->addOption(storm::settings::OptionBuilder(moduleName, precision, false, "Sets precision of monotonicity checking on samples") + .addArgument(storm::settings::ArgumentBuilder::createDoubleArgument("mon-precision", "The precision of checking monotonicity on samples, default is 1e-6").setDefaultValueDouble(0.000001).build()).build()); } @@ -91,6 +94,10 @@ namespace storm { uint_fast64_t ParametricSettings::getNumberOfSamples() const { return this->getOption(samplesMonotonicityAnalysis).getArgumentByName("mon-samples").getValueAsUnsignedInteger(); } + + double ParametricSettings::getMonotonicityAnalysisPrecision() const { + return this->getOption(precision).getArgumentByName("mon-precision").getValueAsDouble(); + } } // namespace modules } // namespace settings } // namespace storm diff --git a/src/storm-pars/settings/modules/ParametricSettings.h b/src/storm-pars/settings/modules/ParametricSettings.h index cbb740ec6..60e8fe067 100644 --- a/src/storm-pars/settings/modules/ParametricSettings.h +++ b/src/storm-pars/settings/modules/ParametricSettings.h @@ -84,6 +84,11 @@ namespace storm { */ uint_fast64_t getNumberOfSamples() const; + /*! + * Retrieves the precision for the extremal value + */ + double getMonotonicityAnalysisPrecision() const; + const static std::string moduleName; private: @@ -99,6 +104,7 @@ namespace storm { const static std::string sccElimination; const static std::string validateAssumptions; const static std::string samplesMonotonicityAnalysis; + const static std::string precision; }; } // namespace modules From 2883f81be1a87c152cb50af99c98d3f7540c7387 Mon Sep 17 00:00:00 2001 From: Jip Spel Date: Fri, 24 May 2019 13:32:36 +0200 Subject: [PATCH 160/178] Move settings to separate file --- src/storm-pars-cli/storm-pars.cpp | 10 ++-- src/storm-pars/settings/ParsSettings.cpp | 5 +- .../settings/modules/MonotonicitySettings.cpp | 54 +++++++++++++++++ .../settings/modules/MonotonicitySettings.h | 60 +++++++++++++++++++ .../settings/modules/ParametricSettings.cpp | 32 ---------- .../settings/modules/ParametricSettings.h | 30 ---------- 6 files changed, 124 insertions(+), 67 deletions(-) create mode 100644 src/storm-pars/settings/modules/MonotonicitySettings.cpp create mode 100644 src/storm-pars/settings/modules/MonotonicitySettings.h diff --git a/src/storm-pars-cli/storm-pars.cpp b/src/storm-pars-cli/storm-pars.cpp index 42415b81a..59bdc61f0 100644 --- a/src/storm-pars-cli/storm-pars.cpp +++ b/src/storm-pars-cli/storm-pars.cpp @@ -13,6 +13,7 @@ #include "storm-pars/settings/ParsSettings.h" #include "storm-pars/settings/modules/ParametricSettings.h" +#include "storm-pars/settings/modules/MonotonicitySettings.h" #include "storm-pars/settings/modules/RegionSettings.h" #include "storm-pars/transformer/SparseParametricMdpSimplifier.h" @@ -558,6 +559,7 @@ namespace storm { auto buildSettings = storm::settings::getModule(); auto parSettings = storm::settings::getModule(); + auto monSettings = storm::settings::getModule(); auto engine = coreSettings.getEngine(); STORM_LOG_THROW(engine == storm::settings::modules::CoreSettings::Engine::Sparse || engine == storm::settings::modules::CoreSettings::Engine::Hybrid || engine == storm::settings::modules::CoreSettings::Engine::Dd, storm::exceptions::InvalidSettingsException, "The selected engine is not supported for parametric models."); @@ -595,7 +597,7 @@ namespace storm { } } - if (parSettings.isMonotonicityAnalysisSet()) { + if (monSettings.isMonotonicityAnalysisSet()) { // Simplify the model storm::utility::Stopwatch simplifyingWatch(true); if (model->isOfType(storm::models::ModelType::Dtmc)) { @@ -650,7 +652,7 @@ namespace storm { } - if (parSettings.isSccEliminationSet()) { + if (monSettings.isSccEliminationSet()) { storm::utility::Stopwatch eliminationWatch(true); // TODO: check for correct Model type STORM_PRINT("Applying scc elimination" << std::endl); @@ -714,11 +716,11 @@ namespace storm { model->printModelInformationToStream(std::cout); } - if (parSettings.isMonotonicityAnalysisSet()) { + if (monSettings.isMonotonicityAnalysisSet()) { std::vector> formulas = storm::api::extractFormulasFromProperties(input.properties); // Monotonicity storm::utility::Stopwatch monotonicityWatch(true); - auto monotonicityChecker = storm::analysis::MonotonicityChecker(model, formulas, parSettings.isValidateAssumptionsSet(), parSettings.getNumberOfSamples(), parSettings.getMonotonicityAnalysisPrecision()); + auto monotonicityChecker = storm::analysis::MonotonicityChecker(model, formulas, monSettings.isValidateAssumptionsSet(), monSettings.getNumberOfSamples(), monSettings.getMonotonicityAnalysisPrecision()); monotonicityChecker.checkMonotonicity(); monotonicityWatch.stop(); STORM_PRINT(std::endl << "Total time for monotonicity checking: " << monotonicityWatch << "." << std::endl diff --git a/src/storm-pars/settings/ParsSettings.cpp b/src/storm-pars/settings/ParsSettings.cpp index d819f8e24..c7eebd767 100644 --- a/src/storm-pars/settings/ParsSettings.cpp +++ b/src/storm-pars/settings/ParsSettings.cpp @@ -2,6 +2,8 @@ #include "storm-pars/settings/modules/ParametricSettings.h" #include "storm-pars/settings/modules/RegionSettings.h" +#include "storm-pars/settings/modules/MonotonicitySettings.h" + #include "storm/settings/SettingsManager.h" #include "storm/settings/modules/GeneralSettings.h" @@ -28,12 +30,13 @@ namespace storm { namespace settings { void initializeParsSettings(std::string const& name, std::string const& executableName) { storm::settings::mutableManager().setName(name, executableName); - + // Register relevant settings modules. storm::settings::addModule(); storm::settings::addModule(); storm::settings::addModule(); storm::settings::addModule(); + storm::settings::addModule(); storm::settings::addModule(); storm::settings::addModule(); storm::settings::addModule(); diff --git a/src/storm-pars/settings/modules/MonotonicitySettings.cpp b/src/storm-pars/settings/modules/MonotonicitySettings.cpp new file mode 100644 index 000000000..dd7a91b80 --- /dev/null +++ b/src/storm-pars/settings/modules/MonotonicitySettings.cpp @@ -0,0 +1,54 @@ +#include "storm-pars/settings/modules/MonotonicitySettings.h" + +#include "storm/settings/Option.h" +#include "storm/settings/OptionBuilder.h" +#include "storm/settings/ArgumentBuilder.h" +#include "storm/settings/Argument.h" + +#include "storm/utility/macros.h" +#include "storm/exceptions/IllegalArgumentValueException.h" + +namespace storm { + namespace settings { + namespace modules { + + const std::string MonotonicitySettings::moduleName = "monotonicity"; + const std::string MonotonicitySettings::monotonicityAnalysis = "monotonicity-analysis"; + const std::string MonotonicitySettings::sccElimination = "mon-elim-scc"; + const std::string MonotonicitySettings::validateAssumptions = "mon-validate-assumptions"; + const std::string MonotonicitySettings::samplesMonotonicityAnalysis = "mon-samples"; + const std::string MonotonicitySettings::precision = "mon-precision"; + + MonotonicitySettings::MonotonicitySettings() : ModuleSettings(moduleName) { + this->addOption(storm::settings::OptionBuilder(moduleName, monotonicityAnalysis, false, "Sets whether monotonicity analysis is done").setIsAdvanced().build()); + this->addOption(storm::settings::OptionBuilder(moduleName, sccElimination, false, "Sets whether SCCs should be eliminated in the monotonicity analysis").setIsAdvanced().build()); + this->addOption(storm::settings::OptionBuilder(moduleName, validateAssumptions, false, "Sets whether assumptions made in monotonicity analysis are validated").setIsAdvanced().build()); + this->addOption(storm::settings::OptionBuilder(moduleName, samplesMonotonicityAnalysis, false, "Sets whether monotonicity should be checked on samples").setIsAdvanced() + .addArgument(storm::settings::ArgumentBuilder::createUnsignedIntegerArgument("mon-samples", "The number of samples taken in monotonicity-analysis can be given, default is 0, no samples").setDefaultValueUnsignedInteger(0).build()).build()); + this->addOption(storm::settings::OptionBuilder(moduleName, precision, false, "Sets precision of monotonicity checking on samples").setIsAdvanced() + .addArgument(storm::settings::ArgumentBuilder::createDoubleArgument("mon-precision", "The precision of checking monotonicity on samples, default is 1e-6").setDefaultValueDouble(0.000001).build()).build()); + + } + + bool MonotonicitySettings::isMonotonicityAnalysisSet() const { + return this->getOption(monotonicityAnalysis).getHasOptionBeenSet(); + } + + bool MonotonicitySettings::isSccEliminationSet() const { + return this->getOption(sccElimination).getHasOptionBeenSet(); + } + + bool MonotonicitySettings::isValidateAssumptionsSet() const { + return this->getOption(validateAssumptions).getHasOptionBeenSet(); + } + + uint_fast64_t MonotonicitySettings::getNumberOfSamples() const { + return this->getOption(samplesMonotonicityAnalysis).getArgumentByName("mon-samples").getValueAsUnsignedInteger(); + } + + double MonotonicitySettings::getMonotonicityAnalysisPrecision() const { + return this->getOption(precision).getArgumentByName("mon-precision").getValueAsDouble(); + } + } // namespace modules + } // namespace settings +} // namespace storm diff --git a/src/storm-pars/settings/modules/MonotonicitySettings.h b/src/storm-pars/settings/modules/MonotonicitySettings.h new file mode 100644 index 000000000..f420935cd --- /dev/null +++ b/src/storm-pars/settings/modules/MonotonicitySettings.h @@ -0,0 +1,60 @@ +#ifndef STORM_SETTINGS_MODULES_MONOTONICITYSETTINGS_H_ +#define STORM_SETTINGS_MODULES_MONOTONICITYSETTINGS_H_ + +#include "storm/settings/modules/ModuleSettings.h" + +namespace storm { + namespace settings { + namespace modules { + + /*! + * This class represents the settings for monotonicity checking. + */ + class MonotonicitySettings : public ModuleSettings { + public: + + /*! + * Creates a new set of monotonicity checking settings. + */ + MonotonicitySettings(); + + /*! + * Retrieves whether monotonicity analysis should be applied. + */ + bool isMonotonicityAnalysisSet() const; + + /*! + * Retrieves whether SCCs in the monotonicity analysis should be eliminated. + */ + bool isSccEliminationSet() const; + + /*! + * Retrieves whether assumptions in monotonicity analysis should be validated + */ + bool isValidateAssumptionsSet() const; + + /*! + * Retrieves the number of samples used for sampling in the monotonicity analysis + */ + uint_fast64_t getNumberOfSamples() const; + + /*! + * Retrieves the precision for the extremal value + */ + double getMonotonicityAnalysisPrecision() const; + + const static std::string moduleName; + + private: + const static std::string monotonicityAnalysis; + const static std::string sccElimination; + const static std::string validateAssumptions; + const static std::string samplesMonotonicityAnalysis; + const static std::string precision; + }; + + } // namespace modules + } // namespace settings +} // namespace storm + +#endif /* STORM_SETTINGS_MODULES_MONOTONICITYSETTINGS_H_ */ diff --git a/src/storm-pars/settings/modules/ParametricSettings.cpp b/src/storm-pars/settings/modules/ParametricSettings.cpp index 75d31566e..45528844c 100644 --- a/src/storm-pars/settings/modules/ParametricSettings.cpp +++ b/src/storm-pars/settings/modules/ParametricSettings.cpp @@ -21,11 +21,6 @@ namespace storm { const std::string ParametricSettings::samplesOptionName = "samples"; const std::string ParametricSettings::samplesGraphPreservingOptionName = "samples-graph-preserving"; const std::string ParametricSettings::sampleExactOptionName = "sample-exact"; - const std::string ParametricSettings::monotonicityAnalysis = "monotonicity-analysis"; - const std::string ParametricSettings::sccElimination = "mon-elim-scc"; - const std::string ParametricSettings::validateAssumptions = "mon-validate-assumptions"; - const std::string ParametricSettings::samplesMonotonicityAnalysis = "mon-samples"; - const std::string ParametricSettings::precision = "mon-precision"; ParametricSettings::ParametricSettings() : ModuleSettings(moduleName) { this->addOption(storm::settings::OptionBuilder(moduleName, exportResultOptionName, false, "A path to a file where the parametric result should be saved.") @@ -37,14 +32,6 @@ namespace storm { .addArgument(storm::settings::ArgumentBuilder::createStringArgument("samples", "The samples are semicolon-separated entries of the form 'Var1=Val1:Val2:...:Valk,Var2=... that span the sample spaces.").setDefaultValueString("").build()).build()); this->addOption(storm::settings::OptionBuilder(moduleName, samplesGraphPreservingOptionName, false, "Sets whether it can be assumed that the samples are graph-preserving.").build()); this->addOption(storm::settings::OptionBuilder(moduleName, sampleExactOptionName, false, "Sets whether to sample using exact arithmetic.").build()); - this->addOption(storm::settings::OptionBuilder(moduleName, monotonicityAnalysis, false, "Sets whether monotonicity analysis is done").build()); - this->addOption(storm::settings::OptionBuilder(moduleName, sccElimination, false, "Sets whether SCCs should be eliminated in the monotonicity analysis").build()); - this->addOption(storm::settings::OptionBuilder(moduleName, validateAssumptions, false, "Sets whether assumptions made in monotonicity analysis are validated").build()); - this->addOption(storm::settings::OptionBuilder(moduleName, samplesMonotonicityAnalysis, false, "Sets whether monotonicity should be checked on samples") - .addArgument(storm::settings::ArgumentBuilder::createUnsignedIntegerArgument("mon-samples", "The number of samples taken in monotonicity-analysis can be given, default is 0, no samples").setDefaultValueUnsignedInteger(0).build()).build()); - this->addOption(storm::settings::OptionBuilder(moduleName, precision, false, "Sets precision of monotonicity checking on samples") - .addArgument(storm::settings::ArgumentBuilder::createDoubleArgument("mon-precision", "The precision of checking monotonicity on samples, default is 1e-6").setDefaultValueDouble(0.000001).build()).build()); - } bool ParametricSettings::exportResultToFile() const { @@ -79,25 +66,6 @@ namespace storm { return this->getOption(sampleExactOptionName).getHasOptionBeenSet(); } - bool ParametricSettings::isMonotonicityAnalysisSet() const { - return this->getOption(monotonicityAnalysis).getHasOptionBeenSet(); - } - - bool ParametricSettings::isSccEliminationSet() const { - return this->getOption(sccElimination).getHasOptionBeenSet(); - } - - bool ParametricSettings::isValidateAssumptionsSet() const { - return this->getOption(validateAssumptions).getHasOptionBeenSet(); - } - - uint_fast64_t ParametricSettings::getNumberOfSamples() const { - return this->getOption(samplesMonotonicityAnalysis).getArgumentByName("mon-samples").getValueAsUnsignedInteger(); - } - - double ParametricSettings::getMonotonicityAnalysisPrecision() const { - return this->getOption(precision).getArgumentByName("mon-precision").getValueAsDouble(); - } } // namespace modules } // namespace settings } // namespace storm diff --git a/src/storm-pars/settings/modules/ParametricSettings.h b/src/storm-pars/settings/modules/ParametricSettings.h index 60e8fe067..3fe281e4e 100644 --- a/src/storm-pars/settings/modules/ParametricSettings.h +++ b/src/storm-pars/settings/modules/ParametricSettings.h @@ -64,31 +64,6 @@ namespace storm { */ bool isSampleExactSet() const; - /*! - * Retrieves whether monotonicity analysis should be applied. - */ - bool isMonotonicityAnalysisSet() const; - - /*! - * Retrieves whether SCCs in the monotonicity analysis should be eliminated. - */ - bool isSccEliminationSet() const; - - /*! - * Retrieves whether assumptions in monotonicity analysis should be validated - */ - bool isValidateAssumptionsSet() const; - - /*! - * Retrieves the number of samples used for sampling in the monotonicity analysis - */ - uint_fast64_t getNumberOfSamples() const; - - /*! - * Retrieves the precision for the extremal value - */ - double getMonotonicityAnalysisPrecision() const; - const static std::string moduleName; private: @@ -100,11 +75,6 @@ namespace storm { const static std::string samplesOptionName; const static std::string samplesGraphPreservingOptionName; const static std::string sampleExactOptionName; - const static std::string monotonicityAnalysis; - const static std::string sccElimination; - const static std::string validateAssumptions; - const static std::string samplesMonotonicityAnalysis; - const static std::string precision; }; } // namespace modules From 8df0a05ab8f54679fd49b3cb0f259dee4a1c880c Mon Sep 17 00:00:00 2001 From: Jip Spel Date: Fri, 24 May 2019 13:32:55 +0200 Subject: [PATCH 161/178] Fix assertion --- src/storm-pars/analysis/MonotonicityChecker.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/storm-pars/analysis/MonotonicityChecker.cpp b/src/storm-pars/analysis/MonotonicityChecker.cpp index 33bc02d63..93a70c46b 100644 --- a/src/storm-pars/analysis/MonotonicityChecker.cpp +++ b/src/storm-pars/analysis/MonotonicityChecker.cpp @@ -556,7 +556,7 @@ namespace storm { for (auto j = initialStates.getNextSetIndex(0); j < model->getNumberOfStates(); j = initialStates.getNextSetIndex(j+1)) { initial += values[j]; } - assert (initial >= precision && initial <= 1+precision); + assert (initial >= 0-precision && initial <= 1+precision); double diff = previous - initial; assert (previous == -1 || diff >= -1-precision && diff <= 1 + precision); if (previous != -1 && (diff > precision || diff < -precision)) { From 4a1f98a0bae7e13ab190ff7a4d27836472e6942a Mon Sep 17 00:00:00 2001 From: Jip Spel Date: Thu, 13 Jun 2019 12:11:02 +0200 Subject: [PATCH 162/178] Fix segfaults --- src/storm-pars/analysis/LatticeExtender.cpp | 52 ++++++++++++++------- 1 file changed, 36 insertions(+), 16 deletions(-) diff --git a/src/storm-pars/analysis/LatticeExtender.cpp b/src/storm-pars/analysis/LatticeExtender.cpp index f2f6c4fa8..dc0817a8b 100644 --- a/src/storm-pars/analysis/LatticeExtender.cpp +++ b/src/storm-pars/analysis/LatticeExtender.cpp @@ -337,7 +337,10 @@ namespace storm { if (!(*addedStates)[succ1]) { lattice->addToNode(succ1, lattice->getNode(stateNumber)); statesToHandle->set(succ1, true); - statesSorted.erase(std::find(statesSorted.begin(), statesSorted.end(), succ1)); + auto itr = std::find(statesSorted.begin(), statesSorted.end(), succ1); + if (itr != statesSorted.end()) { + statesSorted.erase(itr); + } } statesToHandle->set(stateNumber, false); stateNumber = statesToHandle->getNextSetIndex(0); @@ -351,13 +354,19 @@ namespace storm { auto compare = lattice->compare(stateNumber, succ1); if (compare == Lattice::ABOVE) { - statesSorted.erase(std::find(statesSorted.begin(), statesSorted.end(), succ2)); + auto itr = std::find(statesSorted.begin(), statesSorted.end(), succ2); + if (itr != statesSorted.end()) { + statesSorted.erase(itr); + } lattice->addBetween(succ2, lattice->getTop(), lattice->getNode(stateNumber)); statesToHandle->set(succ2); statesToHandle->set(stateNumber, false); stateNumber = statesToHandle->getNextSetIndex(0); } else if (compare == Lattice::BELOW) { - statesSorted.erase(std::find(statesSorted.begin(), statesSorted.end(), succ2)); + auto itr = std::find(statesSorted.begin(), statesSorted.end(), succ2); + if (itr != statesSorted.end()) { + statesSorted.erase(itr); + } lattice->addBetween(succ2, lattice->getNode(stateNumber), lattice->getBottom()); statesToHandle->set(succ2); statesToHandle->set(stateNumber, false); @@ -378,22 +387,33 @@ namespace storm { } if (!assumptionSeen) { - stateNumber = *(statesSorted.begin()); - while (stateNumber != numberOfStates && (*(lattice->getAddedStates()))[stateNumber]) { - statesSorted.erase(statesSorted.begin()); + if (statesSorted.size() > 0) { stateNumber = *(statesSorted.begin()); + } else { + stateNumber = numberOfStates; + } + while (stateNumber != numberOfStates + && (*(lattice->getAddedStates()))[stateNumber]) { + statesSorted.erase(statesSorted.begin()); + if (statesSorted.size() > 0) { + stateNumber = *(statesSorted.begin()); + } else { + stateNumber = numberOfStates; + } } - storm::storage::BitVector* successors = stateMap[stateNumber]; + if (stateNumber != numberOfStates) { + storm::storage::BitVector *successors = stateMap[stateNumber]; - // Check if current state has not been added yet, and all successors have, ignore selfloop in this - successors->set(stateNumber, false); - if ((*successors & *addedStates) == *successors) { - auto result = extendAllSuccAdded(lattice, stateNumber, successors); - if (std::get<1>(result) != successors->size()) { - return result; + // Check if current state has not been added yet, and all successors have, ignore selfloop in this + successors->set(stateNumber, false); + if ((*successors & *addedStates) == *successors) { + auto result = extendAllSuccAdded(lattice, stateNumber, successors); + if (std::get<1>(result) != successors->size()) { + return result; + } + statesToHandle->set(stateNumber); } - statesToHandle->set(stateNumber); } } else { addedStates = lattice->getAddedStates(); @@ -417,13 +437,13 @@ namespace storm { // if nothing changed and there are states left, then add a state between top and bottom if (oldNumberSet == lattice->getAddedStates()->getNumberOfSetBits() && oldNumberSet != numberOfStates) { - if (assumptionSeen) { + if (assumptionSeen || statesSorted.size() == 0) { stateNumber = lattice->getAddedStates()->getNextUnsetIndex(0); } else { stateNumber = *(statesSorted.begin());//lattice->getAddedStates()->getNextUnsetIndex(0); + statesSorted.erase(statesSorted.begin()); } - statesSorted.erase(statesSorted.begin()); lattice->add(stateNumber); statesToHandle->set(stateNumber); } From 6db964363eec0e97a7f3f72b7d323ed2e63fe89c Mon Sep 17 00:00:00 2001 From: Jip Spel Date: Tue, 18 Jun 2019 11:18:58 +0200 Subject: [PATCH 163/178] Update for artifact evaluation ATVA --- src/storm-pars-cli/storm-pars.cpp | 1 + src/storm-pars/analysis/Lattice.cpp | 23 +---------------------- 2 files changed, 2 insertions(+), 22 deletions(-) diff --git a/src/storm-pars-cli/storm-pars.cpp b/src/storm-pars-cli/storm-pars.cpp index 59bdc61f0..cd6a20712 100644 --- a/src/storm-pars-cli/storm-pars.cpp +++ b/src/storm-pars-cli/storm-pars.cpp @@ -725,6 +725,7 @@ namespace storm { monotonicityWatch.stop(); STORM_PRINT(std::endl << "Total time for monotonicity checking: " << monotonicityWatch << "." << std::endl << std::endl); +return; } std::vector> regions = parseRegions(model); diff --git a/src/storm-pars/analysis/Lattice.cpp b/src/storm-pars/analysis/Lattice.cpp index c585bb000..8c0e04136 100644 --- a/src/storm-pars/analysis/Lattice.cpp +++ b/src/storm-pars/analysis/Lattice.cpp @@ -223,28 +223,7 @@ namespace storm { } void Lattice::toString(std::ostream &out) { - std::vector printedNodes = std::vector({}); - for (auto itr = nodes.begin(); itr != nodes.end(); ++itr) { - - if ((*itr) != nullptr && std::find(printedNodes.begin(), printedNodes.end(), (*itr)) == printedNodes.end()) { - Node *node = *itr; - printedNodes.push_back(*itr); - out << "Node: {"; - for (auto const & state:node->states) { - out << state << "; "; - - } - out << "}" << "\n"; - out << " Address: " << node << "\n"; - out << " Above: {"; - - auto statesAbove = node->statesAbove; - for (auto const & state:(node->statesAbove)) { - out << state << "; "; - } - out << "}" << "\n"; - } - } + } bool Lattice::above(Node *node1, Node *node2) { From 13f44ab7ea3b5ec2adefab3fe7a478fa855a53a1 Mon Sep 17 00:00:00 2001 From: Jip Spel Date: Wed, 10 Jul 2019 17:45:54 +0200 Subject: [PATCH 164/178] Monotonicity Checking on Region --- src/storm-pars-cli/storm-pars.cpp | 9 +- src/storm-pars/analysis/AssumptionChecker.cpp | 30 ++++-- src/storm-pars/analysis/AssumptionChecker.h | 5 +- src/storm-pars/analysis/LatticeExtender.h | 1 + .../analysis/MonotonicityChecker.cpp | 32 ++++-- src/storm-pars/analysis/MonotonicityChecker.h | 14 ++- src/storm-pars/storage/ParameterRegion.cpp | 20 ++++ src/storm-pars/storage/ParameterRegion.h | 2 + .../analysis/AssumptionCheckerTest.cpp | 101 ++++++++++++++++-- .../analysis/AssumptionMakerTest.cpp | 24 ++++- .../analysis/MonotonicityCheckerTest.cpp | 81 +++++++++++--- 11 files changed, 267 insertions(+), 52 deletions(-) diff --git a/src/storm-pars-cli/storm-pars.cpp b/src/storm-pars-cli/storm-pars.cpp index cd6a20712..03665fe25 100644 --- a/src/storm-pars-cli/storm-pars.cpp +++ b/src/storm-pars-cli/storm-pars.cpp @@ -652,7 +652,7 @@ namespace storm { } - if (monSettings.isSccEliminationSet()) { + if (model && monSettings.isSccEliminationSet()) { storm::utility::Stopwatch eliminationWatch(true); // TODO: check for correct Model type STORM_PRINT("Applying scc elimination" << std::endl); @@ -720,12 +720,15 @@ namespace storm { std::vector> formulas = storm::api::extractFormulasFromProperties(input.properties); // Monotonicity storm::utility::Stopwatch monotonicityWatch(true); - auto monotonicityChecker = storm::analysis::MonotonicityChecker(model, formulas, monSettings.isValidateAssumptionsSet(), monSettings.getNumberOfSamples(), monSettings.getMonotonicityAnalysisPrecision()); + std::vector> regions = parseRegions(model); + + STORM_LOG_THROW(regions.size() > 1, storm::exceptions::InvalidArgumentException, "Monotonicity analysis only allowed on single region"); + storm::analysis::MonotonicityChecker monotonicityChecker = storm::analysis::MonotonicityChecker(model, formulas, regions, monSettings.isValidateAssumptionsSet(), monSettings.getNumberOfSamples(), monSettings.getMonotonicityAnalysisPrecision()); monotonicityChecker.checkMonotonicity(); monotonicityWatch.stop(); STORM_PRINT(std::endl << "Total time for monotonicity checking: " << monotonicityWatch << "." << std::endl << std::endl); -return; + return; } std::vector> regions = parseRegions(model); diff --git a/src/storm-pars/analysis/AssumptionChecker.cpp b/src/storm-pars/analysis/AssumptionChecker.cpp index 3aca39f31..5fe86eff5 100644 --- a/src/storm-pars/analysis/AssumptionChecker.cpp +++ b/src/storm-pars/analysis/AssumptionChecker.cpp @@ -20,9 +20,10 @@ namespace storm { namespace analysis { template - AssumptionChecker::AssumptionChecker(std::shared_ptr formula, std::shared_ptr> model, uint_fast64_t numberOfSamples) { + AssumptionChecker::AssumptionChecker(std::shared_ptr formula, std::shared_ptr> model, storm::storage::ParameterRegion region, uint_fast64_t numberOfSamples) { this->formula = formula; this->matrix = model->getTransitionMatrix(); + this->region = region; // Create sample points auto instantiator = utility::ModelInstantiator, models::sparse::Dtmc>(*model); @@ -31,9 +32,15 @@ namespace storm { for (auto i = 0; i < numberOfSamples; ++i) { auto valuation = utility::parametric::Valuation(); - for (auto itr = variables.begin(); itr != variables.end(); ++itr) { - // Creates samples between 0 and 1, 1/(#samples+2), 2/(#samples+2), ..., (#samples+1)/(#samples+2) - auto val = std::pair::type, typename utility::parametric::CoefficientType::type>((*itr), utility::convertNumber::type>(boost::lexical_cast((i+1)/(double (numberOfSamples + 2))))); + // TODO: samplen over de region + for (auto var: variables) { + + auto lb = region.getLowerBoundary(var.name()); + auto ub = region.getUpperBoundary(var.name()); + // Creates samples between lb and ub, that is: lb, lb + (ub-lb)/(#samples -1), lb + 2* (ub-lb)/(#samples -1), ..., ub + auto val = + std::pair::type, typename utility::parametric::CoefficientType::type> + (var,utility::convertNumber::type>(lb + i*(ub-lb)/(numberOfSamples-1))); valuation.insert(val); } models::sparse::Dtmc sampleModel = instantiator.instantiate(valuation); @@ -61,6 +68,7 @@ namespace storm { template AssumptionChecker::AssumptionChecker(std::shared_ptr formula, std::shared_ptr> model, uint_fast64_t numberOfSamples) { + STORM_LOG_THROW(false, exceptions::NotImplementedException, "Assumption checking for mdps not yet implemented"); this->formula = formula; this->matrix = model->getTransitionMatrix(); @@ -166,8 +174,10 @@ namespace storm { && lattice->compare(state1succ1->getColumn(), state1succ2->getColumn()) != Lattice::NodeComparison::UNKNOWN) { // The assumption should be the greater assumption // If the result is unknown, we cannot compare, also SMTSolver will not help - result = validateAssumptionFunction(lattice, state1succ1, state1succ2, state2succ1, - state2succ2); + result = validateAssumptionSMTSolver(assumption, lattice); + +// result = validateAssumptionFunction(lattice, state1succ1, state1succ2, state2succ1, +// state2succ2); } else if (assumption->getRelationType() == expressions::BinaryRelationExpression::RelationType::Equal) { // The assumption is equal, the successors are the same, // so if the probability of reaching the successors is the same, we have a valid assumption @@ -216,7 +226,7 @@ namespace storm { // This will give the smallest result std::map::type, typename utility::parametric::CoefficientType::type> substitutions; for (auto var : vars) { - auto monotonicity = MonotonicityChecker::checkDerivative(prob.derivative(var)); + auto monotonicity = MonotonicityChecker::checkDerivative(prob.derivative(var), region); if (monotonicity.first) { // monotone increasing substitutions[var] = 0; @@ -301,7 +311,7 @@ namespace storm { } else { assert (assumption->getRelationType() == expressions::BinaryRelationExpression::RelationType::Equal); - exprToCheck = expr1 > expr2; + exprToCheck = expr1 != expr2 ; } auto variables = manager->getVariables(); @@ -313,7 +323,9 @@ namespace storm { exprBounds = exprBounds && manager->rational(0) <= var && var <= manager->rational(1); } else { // the var is a parameter - exprBounds = exprBounds && manager->rational(0) < var && var < manager->rational(1); + auto lb = storm::utility::convertNumber(region.getLowerBoundary(var.getName())); + auto ub = storm::utility::convertNumber(region.getUpperBoundary(var.getName())); + exprBounds = exprBounds && manager->rational(lb) < var && var < manager->rational(ub); } } diff --git a/src/storm-pars/analysis/AssumptionChecker.h b/src/storm-pars/analysis/AssumptionChecker.h index 3f98189ae..c1e58dd69 100644 --- a/src/storm-pars/analysis/AssumptionChecker.h +++ b/src/storm-pars/analysis/AssumptionChecker.h @@ -6,6 +6,7 @@ #include "storm/models/sparse/Mdp.h" #include "storm/environment/Environment.h" #include "storm/storage/expressions/BinaryRelationExpression.h" +#include "storm-pars/storage/ParameterRegion.h" #include "Lattice.h" namespace storm { @@ -29,7 +30,7 @@ namespace storm { * @param model The dtmc model to check the formula on. * @param numberOfSamples Number of sample points. */ - AssumptionChecker(std::shared_ptr formula, std::shared_ptr> model, uint_fast64_t numberOfSamples); + AssumptionChecker(std::shared_ptr formula, std::shared_ptr> model, storm::storage::ParameterRegion region, uint_fast64_t numberOfSamples); /*! * Constructs an AssumptionChecker based on the number of samples, for the given formula and model. @@ -81,6 +82,8 @@ namespace storm { typename storage::SparseMatrix::iterator state2succ1, typename storage::SparseMatrix::iterator state2succ2); + storm::storage::ParameterRegion region; + }; } } diff --git a/src/storm-pars/analysis/LatticeExtender.h b/src/storm-pars/analysis/LatticeExtender.h index 7497aa594..4899fdf46 100644 --- a/src/storm-pars/analysis/LatticeExtender.h +++ b/src/storm-pars/analysis/LatticeExtender.h @@ -6,6 +6,7 @@ #include "storm-pars/analysis/Lattice.h" #include "storm/api/storm.h" + namespace storm { namespace analysis { diff --git a/src/storm-pars/analysis/MonotonicityChecker.cpp b/src/storm-pars/analysis/MonotonicityChecker.cpp index 93a70c46b..f451f7df7 100644 --- a/src/storm-pars/analysis/MonotonicityChecker.cpp +++ b/src/storm-pars/analysis/MonotonicityChecker.cpp @@ -23,7 +23,7 @@ namespace storm { namespace analysis { template - MonotonicityChecker::MonotonicityChecker(std::shared_ptr model, std::vector> formulas, bool validate, uint_fast64_t numberOfSamples, double const& precision) { + MonotonicityChecker::MonotonicityChecker(std::shared_ptr model, std::vector> formulas, std::vector> regions, bool validate, uint_fast64_t numberOfSamples, double const& precision) { assert (model != nullptr); this->model = model; this->formulas = formulas; @@ -46,6 +46,24 @@ namespace storm { } std::shared_ptr> sparseModel = model->as>(); + + if (regions.size() == 1) { + region = *(regions.begin()); + } else { + assert (regions.size() == 0); + typename storm::storage::ParameterRegion::Valuation lowerBoundaries; + typename storm::storage::ParameterRegion::Valuation upperBoundaries; + std::set::VariableType> vars; + vars = storm::models::sparse::getProbabilityParameters(*sparseModel); + for (auto var : vars) { + typename storm::storage::ParameterRegion::CoefficientType lb = storm::utility::convertNumber::CoefficientType>(0 + precision); + typename storm::storage::ParameterRegion::CoefficientType ub = storm::utility::convertNumber::CoefficientType>(1 - precision); + lowerBoundaries.insert(std::make_pair(var, lb)); + upperBoundaries.insert(std::make_pair(var, ub)); + } + region = storm::storage::ParameterRegion(std::move(lowerBoundaries), std::move(upperBoundaries)); + } + this->extender = new storm::analysis::LatticeExtender(sparseModel); } @@ -173,7 +191,7 @@ namespace storm { storm::analysis::AssumptionChecker *assumptionChecker; if (model->isOfType(storm::models::ModelType::Dtmc)) { auto dtmc = model->as>(); - assumptionChecker = new storm::analysis::AssumptionChecker(formulas[0], dtmc, 3); + assumptionChecker = new storm::analysis::AssumptionChecker(formulas[0], dtmc, region, 3); } else if (model->isOfType(storm::models::ModelType::Mdp)) { auto mdp = model->as>(); assumptionChecker = new storm::analysis::AssumptionChecker(formulas[0], mdp, 3); @@ -348,7 +366,7 @@ namespace storm { // As the first state (itr2) is above the second state (itr3) it // is sufficient to look at the derivative of itr2. std::pair mon2; - mon2 = checkDerivative(derivative2); + mon2 = checkDerivative(derivative2, region); value->first &= mon2.first; value->second &= mon2.second; } else if (compare == Lattice::BELOW) { @@ -356,7 +374,7 @@ namespace storm { // is sufficient to look at the derivative of itr3. std::pair mon3; - mon3 = checkDerivative(derivative3); + mon3 = checkDerivative(derivative3, region); value->first &= mon3.first; value->second &= mon3.second; } else if (compare == Lattice::SAME) { @@ -381,7 +399,7 @@ namespace storm { std::pair *value = &varsMonotone.find(var)->second; bool change = false; for (auto const &i : sortedStates) { - auto res = checkDerivative(getDerivative(transitions[i], var)); + auto res = checkDerivative(getDerivative(transitions[i], var), region); change = change || (!(value->first && value->second) // they do not hold both && ((value->first && !res.first) || (value->second && !res.second))); @@ -466,7 +484,7 @@ namespace storm { // As the first state (itr2) is above the second state (itr3) it // is sufficient to look at the derivative of itr2. std::pair mon2; - mon2 = checkDerivative(derivative2); + mon2 = checkDerivative(derivative2, region); value->first &= mon2.first; value->second &= mon2.second; } else if (compare == Lattice::BELOW) { @@ -474,7 +492,7 @@ namespace storm { // is sufficient to look at the derivative of itr3. std::pair mon3; - mon3 = checkDerivative(derivative3); + mon3 = checkDerivative(derivative3, region); value->first &= mon3.first; value->second &= mon3.second; } else if (compare == Lattice::SAME) { diff --git a/src/storm-pars/analysis/MonotonicityChecker.h b/src/storm-pars/analysis/MonotonicityChecker.h index 5d6b60ba4..0ef738154 100644 --- a/src/storm-pars/analysis/MonotonicityChecker.h +++ b/src/storm-pars/analysis/MonotonicityChecker.h @@ -30,12 +30,13 @@ namespace storm { * Constructor of MonotonicityChecker * @param model the model considered * @param formula the formula considered + * @param regions the regions to consider * @param validate whether or not assumptions are to be validated * @param numberOfSamples number of samples taken for monotonicity checking, default 0, - * if 0then no check on samples is executed + * if 0 then no check on samples is executed * @param precision precision on which the samples are compared */ - MonotonicityChecker(std::shared_ptr model, std::vector> formulas, bool validate, uint_fast64_t numberOfSamples=0, double const& precision=0.000001); + MonotonicityChecker(std::shared_ptr model, std::vector> formulas, std::vector> regions, bool validate, uint_fast64_t numberOfSamples=0, double const& precision=0.000001); /*! * Checks for model and formula as provided in constructor for monotonicity @@ -52,7 +53,7 @@ namespace storm { * @param derivative The derivative you want to check * @return pair of bools, >= 0 and <= 0 */ - static std::pair checkDerivative(ValueType derivative) { + static std::pair checkDerivative(ValueType derivative, storm::storage::ParameterRegion reg) { bool monIncr = false; bool monDecr = false; @@ -80,7 +81,9 @@ namespace storm { storm::expressions::Expression exprBounds = manager->boolean(true); auto managervars = manager->getVariables(); for (auto var : managervars) { - exprBounds = exprBounds && manager->rational(0) < var && var < manager->rational(1); + auto lb = storm::utility::convertNumber(reg.getLowerBoundary(var.getName())); + auto ub = storm::utility::convertNumber(reg.getUpperBoundary(var.getName())); + exprBounds = exprBounds && manager->rational(lb) < var && var < manager->rational(ub); } assert (s.check() == storm::solver::SmtSolver::CheckResult::Sat); @@ -112,7 +115,6 @@ namespace storm { private: std::map::type, std::pair>> checkMonotonicity(std::map>> map, storm::storage::SparseMatrix matrix); - //TODO: variabele type std::map::type, std::pair> analyseMonotonicity(uint_fast64_t i, Lattice* lattice, storm::storage::SparseMatrix matrix) ; std::map>> createLattice(); @@ -144,6 +146,8 @@ namespace storm { std::string filename = "monotonicity.txt"; double precision; + + storm::storage::ParameterRegion region; }; } } diff --git a/src/storm-pars/storage/ParameterRegion.cpp b/src/storm-pars/storage/ParameterRegion.cpp index 3d9e36c93..68d6e94dc 100644 --- a/src/storm-pars/storage/ParameterRegion.cpp +++ b/src/storm-pars/storage/ParameterRegion.cpp @@ -48,6 +48,16 @@ namespace storm { return (*result).second; } + template + typename ParameterRegion::CoefficientType const& ParameterRegion::getLowerBoundary(const std::string varName) const { + for (auto itr = lowerBoundaries.begin(); itr != lowerBoundaries.end(); ++itr) { + if (itr->first.name().compare(varName) == 0) { + return (*itr).second; + } + } + STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "Tried to find a lower boundary for variableName " << varName << " which is not specified by this region"); + } + template typename ParameterRegion::CoefficientType const& ParameterRegion::getUpperBoundary(VariableType const& variable) const { auto const& result = upperBoundaries.find(variable); @@ -55,6 +65,16 @@ namespace storm { return (*result).second; } + template + typename ParameterRegion::CoefficientType const& ParameterRegion::getUpperBoundary(const std::string varName) const { + for (auto itr = upperBoundaries.begin(); itr != upperBoundaries.end(); ++itr) { + if (itr->first.name().compare(varName) == 0) { + return (*itr).second; + } + } + STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "Tried to find an upper boundary for variableName " << varName << " which is not specified by this region"); + } + template typename ParameterRegion::Valuation const& ParameterRegion::getUpperBoundaries() const { return upperBoundaries; diff --git a/src/storm-pars/storage/ParameterRegion.h b/src/storm-pars/storage/ParameterRegion.h index bcdd86ccb..d4f3ce457 100644 --- a/src/storm-pars/storage/ParameterRegion.h +++ b/src/storm-pars/storage/ParameterRegion.h @@ -24,7 +24,9 @@ namespace storm { std::set const& getVariables() const; CoefficientType const& getLowerBoundary(VariableType const& variable) const; + CoefficientType const& getLowerBoundary(const std::string varName) const; CoefficientType const& getUpperBoundary(VariableType const& variable) const; + CoefficientType const& getUpperBoundary(const std::string varName) const; Valuation const& getLowerBoundaries() const; Valuation const& getUpperBoundaries() const; diff --git a/src/test/storm-pars/analysis/AssumptionCheckerTest.cpp b/src/test/storm-pars/analysis/AssumptionCheckerTest.cpp index 93fc5955b..08e7319a6 100644 --- a/src/test/storm-pars/analysis/AssumptionCheckerTest.cpp +++ b/src/test/storm-pars/analysis/AssumptionCheckerTest.cpp @@ -1,8 +1,3 @@ -// -// Created by Jip Spel on 19.09.18. -// - -// TODO: cleanup includes #include "gtest/gtest.h" #include "storm-config.h" #include "test/storm_gtest.h" @@ -21,12 +16,16 @@ #include "storm-pars/analysis/Lattice.h" #include "storm/storage/expressions/BinaryRelationExpression.h" #include "storm-pars/transformer/SparseParametricDtmcSimplifier.h" +#include "storm-pars/storage/ParameterRegion.h" #include "storm-pars/api/storm-pars.h" #include "storm/api/storm.h" #include "storm-parsers/api/storm-parsers.h" +#include "storm-pars/api/region.h" + + TEST(AssumptionCheckerTest, Brp_no_bisimulation) { std::string programFile = STORM_TEST_RESOURCES_DIR "/pdtmc/brp16_2.pm"; std::string formulaAsString = "P=? [F s=4 & i=N ]"; @@ -47,7 +46,13 @@ TEST(AssumptionCheckerTest, Brp_no_bisimulation) { ASSERT_EQ(dtmc->getNumberOfStates(), 193ull); ASSERT_EQ(dtmc->getNumberOfTransitions(), 383ull); - auto checker = storm::analysis::AssumptionChecker(formulas[0], dtmc, 3); + // Create the region + storm::storage::ParameterRegion::Valuation lowerBoundaries; + storm::storage::ParameterRegion::Valuation upperBoundaries; + auto vars = storm::models::sparse::getProbabilityParameters(*dtmc); + auto region = storm::api::parseRegion("0.00001 <= pK <= 0.00001, 0.00001 <= pL <= 0.99999", vars); + + auto checker = storm::analysis::AssumptionChecker(formulas[0], dtmc, region, 3); // Check on samples auto expressionManager = std::make_shared(storm::expressions::ExpressionManager()); @@ -126,7 +131,11 @@ TEST(AssumptionCheckerTest, Simple1) { ASSERT_EQ(dtmc->getNumberOfStates(), 5); ASSERT_EQ(dtmc->getNumberOfTransitions(), 8); - auto checker = storm::analysis::AssumptionChecker(formulas[0], dtmc, 3); + // Create the region + auto vars = storm::models::sparse::getProbabilityParameters(*dtmc); + auto region = storm::api::parseRegion("0.00001 <= p <= 0.99999", vars); + + auto checker = storm::analysis::AssumptionChecker(formulas[0], dtmc, region, 3); auto expressionManager = std::make_shared(storm::expressions::ExpressionManager()); expressionManager->declareRationalVariable("1"); @@ -174,7 +183,11 @@ TEST(AssumptionCheckerTest, Simple2) { ASSERT_EQ(dtmc->getNumberOfStates(), 5); ASSERT_EQ(dtmc->getNumberOfTransitions(), 8); - auto checker = storm::analysis::AssumptionChecker(formulas[0], dtmc, 3); + // Create the region + auto vars = storm::models::sparse::getProbabilityParameters(*dtmc); + auto region = storm::api::parseRegion("0.00001 <= p <= 0.99999", vars); + + auto checker = storm::analysis::AssumptionChecker(formulas[0], dtmc, region, 3); auto expressionManager = std::make_shared(storm::expressions::ExpressionManager()); expressionManager->declareRationalVariable("1"); @@ -234,7 +247,11 @@ TEST(AssumptionCheckerTest, Simple3) { ASSERT_EQ(6, dtmc->getNumberOfStates()); ASSERT_EQ(12, dtmc->getNumberOfTransitions()); - auto checker = storm::analysis::AssumptionChecker(formulas[0], dtmc, 3); + // Create the region + auto vars = storm::models::sparse::getProbabilityParameters(*dtmc); + auto region = storm::api::parseRegion("0.00001 <= p <= 0.99999", vars); + + auto checker = storm::analysis::AssumptionChecker(formulas[0], dtmc, region, 3); auto expressionManager = std::make_shared(storm::expressions::ExpressionManager()); expressionManager->declareRationalVariable("1"); @@ -278,4 +295,70 @@ TEST(AssumptionCheckerTest, Simple3) { EXPECT_EQ(storm::analysis::AssumptionStatus::INVALID, checker.validateAssumptionSMTSolver(assumption, lattice)); } +TEST(AssumptionCheckerTest, Simple4) { + std::string programFile = STORM_TEST_RESOURCES_DIR "/pdtmc/simple4.pm"; + std::string formulaAsString = "P=? [F s=3]"; + std::string constantsAsString = ""; //e.g. pL=0.9,TOACK=0.5 + // Program and formula + storm::prism::Program program = storm::api::parseProgram(programFile); + program = storm::utility::prism::preprocess(program, constantsAsString); + std::vector> formulas = storm::api::extractFormulasFromProperties(storm::api::parsePropertiesForPrismProgram(formulaAsString, program)); + std::shared_ptr> model = storm::api::buildSparseModel(program, formulas)->as>(); + std::shared_ptr> dtmc = model->as>(); + auto simplifier = storm::transformer::SparseParametricDtmcSimplifier>(*dtmc); + ASSERT_TRUE(simplifier.simplify(*(formulas[0]))); + model = simplifier.getSimplifiedModel(); + dtmc = model->as>(); + + ASSERT_EQ(dtmc->getNumberOfStates(), 5); + ASSERT_EQ(dtmc->getNumberOfTransitions(), 8); + + // Create the region + auto vars = storm::models::sparse::getProbabilityParameters(*dtmc); + auto region = storm::api::parseRegion("0.00001 <= p <= 0.4", vars); + + auto checker = storm::analysis::AssumptionChecker(formulas[0], dtmc, region, 3); + + auto expressionManager = std::make_shared(storm::expressions::ExpressionManager()); + expressionManager->declareRationalVariable("1"); + expressionManager->declareRationalVariable("2"); + + // Lattice + storm::storage::BitVector above(5); + above.set(3); + storm::storage::BitVector below(5); + below.set(4); + storm::storage::BitVector initialMiddle(5); + auto lattice = new storm::analysis::Lattice(&above, &below, &initialMiddle, 5); + + auto assumption = std::make_shared( + storm::expressions::BinaryRelationExpression(*expressionManager, expressionManager->getBooleanType(), + expressionManager->getVariable("1").getExpression().getBaseExpressionPointer(), + expressionManager->getVariable("2").getExpression().getBaseExpressionPointer(), + storm::expressions::BinaryRelationExpression::RelationType::Greater)); + EXPECT_EQ(storm::analysis::AssumptionStatus::INVALID, checker.checkOnSamples(assumption)); + EXPECT_EQ(storm::analysis::AssumptionStatus::INVALID, checker.validateAssumption(assumption, lattice)); + EXPECT_EQ(storm::analysis::AssumptionStatus::INVALID, checker.validateAssumptionSMTSolver(assumption, lattice)); + + assumption = std::make_shared( + storm::expressions::BinaryRelationExpression(*expressionManager, expressionManager->getBooleanType(), + expressionManager->getVariable("2").getExpression().getBaseExpressionPointer(), + expressionManager->getVariable("1").getExpression().getBaseExpressionPointer(), + storm::expressions::BinaryRelationExpression::RelationType::Greater)); + EXPECT_EQ(storm::analysis::AssumptionStatus::UNKNOWN, checker.checkOnSamples(assumption)); + EXPECT_EQ(storm::analysis::AssumptionStatus::VALID, checker.validateAssumption(assumption, lattice)); + EXPECT_EQ(storm::analysis::AssumptionStatus::VALID, checker.validateAssumptionSMTSolver(assumption, lattice)); + + assumption = std::make_shared( + storm::expressions::BinaryRelationExpression(*expressionManager, expressionManager->getBooleanType(), + expressionManager->getVariable("1").getExpression().getBaseExpressionPointer(), + expressionManager->getVariable("2").getExpression().getBaseExpressionPointer(), + storm::expressions::BinaryRelationExpression::RelationType::Equal)); + EXPECT_EQ(storm::analysis::AssumptionStatus::INVALID, checker.checkOnSamples(assumption)); + EXPECT_EQ(storm::analysis::AssumptionStatus::INVALID, checker.validateAssumption(assumption, lattice)); + EXPECT_EQ(storm::analysis::AssumptionStatus::INVALID, checker.validateAssumptionSMTSolver(assumption, lattice)); + + + +} diff --git a/src/test/storm-pars/analysis/AssumptionMakerTest.cpp b/src/test/storm-pars/analysis/AssumptionMakerTest.cpp index bcdac1227..71b7b1e7f 100644 --- a/src/test/storm-pars/analysis/AssumptionMakerTest.cpp +++ b/src/test/storm-pars/analysis/AssumptionMakerTest.cpp @@ -28,7 +28,6 @@ #include "storm-parsers/api/storm-parsers.h" -//TODO: voor als validate uit staat TEST(AssumptionMakerTest, Brp_without_bisimulation) { std::string programFile = STORM_TEST_RESOURCES_DIR "/pdtmc/brp16_2.pm"; std::string formulaAsString = "P=? [F s=4 & i=N ]"; @@ -45,6 +44,10 @@ TEST(AssumptionMakerTest, Brp_without_bisimulation) { model = simplifier.getSimplifiedModel(); dtmc = model->as>(); + // Create the region + auto vars = storm::models::sparse::getProbabilityParameters(*dtmc); + auto region = storm::api::parseRegion("0.00001 <= pK <= 0.999999, 0.00001 <= pL <= 0.999999", vars); + ASSERT_EQ(dtmc->getNumberOfStates(), 193ull); ASSERT_EQ(dtmc->getNumberOfTransitions(), 383ull); @@ -53,7 +56,7 @@ TEST(AssumptionMakerTest, Brp_without_bisimulation) { ASSERT_EQ(183, std::get<1>(criticalTuple)); ASSERT_EQ(186, std::get<2>(criticalTuple)); - auto assumptionChecker = storm::analysis::AssumptionChecker(formulas[0], dtmc, 3); + auto assumptionChecker = storm::analysis::AssumptionChecker(formulas[0], dtmc, region, 3); auto assumptionMaker = storm::analysis::AssumptionMaker(&assumptionChecker, dtmc->getNumberOfStates(), true); auto result = assumptionMaker.createAndCheckAssumption(std::get<1>(criticalTuple), std::get<2>(criticalTuple), std::get<0>(criticalTuple)); @@ -111,6 +114,10 @@ TEST(AssumptionMakerTest, Brp_without_bisimulation_no_validation) { model = simplifier.getSimplifiedModel(); dtmc = model->as>(); + // Create the region + auto vars = storm::models::sparse::getProbabilityParameters(*dtmc); + auto region = storm::api::parseRegion("0.00001 <= pK <= 0.999999, 0.00001 <= pL <= 0.999999", vars); + ASSERT_EQ(dtmc->getNumberOfStates(), 193ull); ASSERT_EQ(dtmc->getNumberOfTransitions(), 383ull); @@ -119,7 +126,7 @@ TEST(AssumptionMakerTest, Brp_without_bisimulation_no_validation) { ASSERT_EQ(183, std::get<1>(criticalTuple)); ASSERT_EQ(186, std::get<2>(criticalTuple)); - auto assumptionChecker = storm::analysis::AssumptionChecker(formulas[0], dtmc, 3); + auto assumptionChecker = storm::analysis::AssumptionChecker(formulas[0], dtmc, region, 3); // This one does not validate the assumptions! auto assumptionMaker = storm::analysis::AssumptionMaker(&assumptionChecker, dtmc->getNumberOfStates(), false); auto result = assumptionMaker.createAndCheckAssumption(std::get<1>(criticalTuple), std::get<2>(criticalTuple), std::get<0>(criticalTuple)); @@ -177,6 +184,10 @@ TEST(AssumptionMakerTest, Simple1) { model = simplifier.getSimplifiedModel(); dtmc = model->as>(); + // Create the region + auto vars = storm::models::sparse::getProbabilityParameters(*dtmc); + auto region = storm::api::parseRegion("0.00001 <= p <= 0.999999", vars); + ASSERT_EQ(dtmc->getNumberOfStates(), 5); ASSERT_EQ(dtmc->getNumberOfTransitions(), 8); @@ -188,7 +199,7 @@ TEST(AssumptionMakerTest, Simple1) { auto lattice = new storm::analysis::Lattice(&above, &below, &initialMiddle, 5); - auto assumptionChecker = storm::analysis::AssumptionChecker(formulas[0], dtmc, 3); + auto assumptionChecker = storm::analysis::AssumptionChecker(formulas[0], dtmc, region, 3); auto assumptionMaker = storm::analysis::AssumptionMaker(&assumptionChecker, dtmc->getNumberOfStates(), true); auto result = assumptionMaker.createAndCheckAssumption(1, 2, lattice); @@ -244,6 +255,9 @@ TEST(AssumptionMakerTest, Simple2) { ASSERT_TRUE(simplifier.simplify(*(formulas[0]))); model = simplifier.getSimplifiedModel(); dtmc = model->as>(); + // Create the region + auto vars = storm::models::sparse::getProbabilityParameters(*dtmc); + auto region = storm::api::parseRegion("0.00001 <= p <= 0.999999", vars); ASSERT_EQ(dtmc->getNumberOfStates(), 5); ASSERT_EQ(dtmc->getNumberOfTransitions(), 8); @@ -256,7 +270,7 @@ TEST(AssumptionMakerTest, Simple2) { auto lattice = new storm::analysis::Lattice(&above, &below, &initialMiddle, 5); - auto assumptionChecker = storm::analysis::AssumptionChecker(formulas[0], dtmc, 3); + auto assumptionChecker = storm::analysis::AssumptionChecker(formulas[0], dtmc, region, 3); auto assumptionMaker = storm::analysis::AssumptionMaker(&assumptionChecker, dtmc->getNumberOfStates(), true); auto result = assumptionMaker.createAndCheckAssumption(1, 2, lattice); diff --git a/src/test/storm-pars/analysis/MonotonicityCheckerTest.cpp b/src/test/storm-pars/analysis/MonotonicityCheckerTest.cpp index 27ba61483..4dfc2e38b 100644 --- a/src/test/storm-pars/analysis/MonotonicityCheckerTest.cpp +++ b/src/test/storm-pars/analysis/MonotonicityCheckerTest.cpp @@ -27,55 +27,83 @@ #include "storm-parsers/api/storm-parsers.h" TEST(MonotonicityCheckerTest, Derivative_checker) { + + // Create the region + typename storm::storage::ParameterRegion::Valuation lowerBoundaries; + typename storm::storage::ParameterRegion::Valuation upperBoundaries; + auto region = storm::storage::ParameterRegion(std::move(lowerBoundaries), std::move(upperBoundaries)); + // Derivative 0 auto constFunction = storm::RationalFunction(0); - auto constFunctionRes = storm::analysis::MonotonicityChecker::checkDerivative(constFunction); + auto constFunctionRes = storm::analysis::MonotonicityChecker::checkDerivative(constFunction, region); EXPECT_TRUE(constFunctionRes.first); EXPECT_TRUE(constFunctionRes.second); // Derivative 5 constFunction = storm::RationalFunction(5); - constFunctionRes = storm::analysis::MonotonicityChecker::checkDerivative(constFunction); + constFunctionRes = storm::analysis::MonotonicityChecker::checkDerivative(constFunction, region); EXPECT_TRUE(constFunctionRes.first); EXPECT_FALSE(constFunctionRes.second); // Derivative -4 constFunction = storm::RationalFunction(storm::RationalFunction(1)-constFunction); - constFunctionRes = storm::analysis::MonotonicityChecker::checkDerivative(constFunction); + constFunctionRes = storm::analysis::MonotonicityChecker::checkDerivative(constFunction, region); EXPECT_FALSE(constFunctionRes.first); EXPECT_TRUE(constFunctionRes.second); std::shared_ptr cache = std::make_shared(); carl::StringParser parser; parser.setVariables({"p", "q"}); + + // Create the region + auto functionP = storm::RationalFunction(storm::Polynomial(parser.template parseMultivariatePolynomial("p"), cache)); + auto functionQ = storm::RationalFunction(storm::Polynomial(parser.template parseMultivariatePolynomial("q"), cache)); + + auto varsP = functionP.gatherVariables(); + auto varsQ = functionQ.gatherVariables(); + storm::utility::parametric::Valuation lowerBoundaries2; + storm::utility::parametric::Valuation upperBoundaries2; + for (auto var : varsP) { + typename storm::storage::ParameterRegion::CoefficientType lb = storm::utility::convertNumber::CoefficientType>(0 + 0.000001); + typename storm::storage::ParameterRegion::CoefficientType ub = storm::utility::convertNumber::CoefficientType>(1 - 0.000001); + lowerBoundaries2.emplace(std::make_pair(var, lb)); + upperBoundaries2.emplace(std::make_pair(var, ub)); + } + for (auto var : varsQ) { + typename storm::storage::ParameterRegion::CoefficientType lb = storm::utility::convertNumber::CoefficientType>(0 + 0.000001); + typename storm::storage::ParameterRegion::CoefficientType ub = storm::utility::convertNumber::CoefficientType>(1 - 0.000001); + lowerBoundaries2.emplace(std::make_pair(var, lb)); + upperBoundaries2.emplace(std::make_pair(var, ub)); + } + region = storm::storage::ParameterRegion(std::move(lowerBoundaries2), std::move(upperBoundaries2)); + // Derivative p - auto function = storm::RationalFunction(storm::Polynomial(parser.template parseMultivariatePolynomial("p"), cache)); - auto functionRes = storm::analysis::MonotonicityChecker::checkDerivative(function); + auto function = functionP; + auto functionRes = storm::analysis::MonotonicityChecker::checkDerivative(function, region); EXPECT_TRUE(functionRes.first); EXPECT_FALSE(functionRes.second); // Derivative 1-p auto functionDecr = storm::RationalFunction(storm::RationalFunction(1)-function); - auto functionDecrRes = storm::analysis::MonotonicityChecker::checkDerivative(functionDecr); + auto functionDecrRes = storm::analysis::MonotonicityChecker::checkDerivative(functionDecr, region); EXPECT_TRUE(functionDecrRes.first); EXPECT_FALSE(functionDecrRes.second); // Derivative 1-2p auto functionNonMonotonic = storm::RationalFunction(storm::RationalFunction(1)-storm::RationalFunction(2)*function); - auto functionNonMonotonicRes = storm::analysis::MonotonicityChecker::checkDerivative(functionNonMonotonic); + auto functionNonMonotonicRes = storm::analysis::MonotonicityChecker::checkDerivative(functionNonMonotonic, region); EXPECT_FALSE(functionNonMonotonicRes.first); EXPECT_FALSE(functionNonMonotonicRes.second); // Derivative -p functionDecr = storm::RationalFunction(storm::RationalFunction(0)-function); - functionDecrRes = storm::analysis::MonotonicityChecker::checkDerivative(functionDecr); + functionDecrRes = storm::analysis::MonotonicityChecker::checkDerivative(functionDecr, region); EXPECT_FALSE(functionDecrRes.first); EXPECT_TRUE(functionDecrRes.second); // Derivative p*q - function = storm::RationalFunction(storm::Polynomial(parser.template parseMultivariatePolynomial("p"), cache)) - * storm::RationalFunction(storm::Polynomial(parser.template parseMultivariatePolynomial("q"), cache)) ; - functionRes = storm::analysis::MonotonicityChecker::checkDerivative(function); + function = functionP * functionQ ; + functionRes = storm::analysis::MonotonicityChecker::checkDerivative(function, region); EXPECT_TRUE(functionRes.first); EXPECT_FALSE(functionRes.second); } @@ -103,10 +131,24 @@ TEST(MonotonicityCheckerTest, Brp_with_bisimulation_no_samples) { dtmc = storm::api::performBisimulationMinimization(model, formulas, bisimType)->as>(); + + // Create the region + typename storm::storage::ParameterRegion::Valuation lowerBoundaries; + typename storm::storage::ParameterRegion::Valuation upperBoundaries; + std::set::VariableType> vars = storm::models::sparse::getProbabilityParameters(*dtmc); + for (auto var : vars) { + typename storm::storage::ParameterRegion::CoefficientType lb = storm::utility::convertNumber::CoefficientType>(0 + 0.000001); + typename storm::storage::ParameterRegion::CoefficientType ub = storm::utility::convertNumber::CoefficientType>(1 - 0.000001); + lowerBoundaries.emplace(std::make_pair(var, lb)); + upperBoundaries.emplace(std::make_pair(var, ub)); + } + auto region = storm::storage::ParameterRegion(std::move(lowerBoundaries), std::move(upperBoundaries)); +std::vector> regions = {region}; + ASSERT_EQ(dtmc->getNumberOfStates(), 99ull); ASSERT_EQ(dtmc->getNumberOfTransitions(), 195ull); - storm::analysis::MonotonicityChecker monotonicityChecker = storm::analysis::MonotonicityChecker(dtmc, formulas, true); + storm::analysis::MonotonicityChecker monotonicityChecker = storm::analysis::MonotonicityChecker(dtmc, formulas, regions, true); auto result = monotonicityChecker.checkMonotonicity(); EXPECT_EQ(1, result.size()); EXPECT_EQ(2, result.begin()->second.size()); @@ -138,10 +180,23 @@ TEST(MonotonicityCheckerTest, Brp_with_bisimulation_samples) { dtmc = storm::api::performBisimulationMinimization(model, formulas, bisimType)->as>(); + // Create the region + typename storm::storage::ParameterRegion::Valuation lowerBoundaries; + typename storm::storage::ParameterRegion::Valuation upperBoundaries; + std::set::VariableType> vars = storm::models::sparse::getProbabilityParameters(*dtmc); + for (auto var : vars) { + typename storm::storage::ParameterRegion::CoefficientType lb = storm::utility::convertNumber::CoefficientType>(0 + 0.000001); + typename storm::storage::ParameterRegion::CoefficientType ub = storm::utility::convertNumber::CoefficientType>(1 - 0.000001); + lowerBoundaries.emplace(std::make_pair(var, lb)); + upperBoundaries.emplace(std::make_pair(var, ub)); + } + auto region = storm::storage::ParameterRegion(std::move(lowerBoundaries), std::move(upperBoundaries)); + std::vector> regions = {region}; + ASSERT_EQ(dtmc->getNumberOfStates(), 99ull); ASSERT_EQ(dtmc->getNumberOfTransitions(), 195ull); - storm::analysis::MonotonicityChecker monotonicityChecker = storm::analysis::MonotonicityChecker(dtmc, formulas, true, 50); + auto monotonicityChecker = storm::analysis::MonotonicityChecker(dtmc, formulas, regions, true, 50); auto result = monotonicityChecker.checkMonotonicity(); EXPECT_EQ(1, result.size()); EXPECT_EQ(2, result.begin()->second.size()); From 8214c5758eeaf99289bb9cf5244ce82ddb29d460 Mon Sep 17 00:00:00 2001 From: Jip Spel Date: Thu, 25 Jul 2019 13:56:48 +0200 Subject: [PATCH 165/178] Use parameter lifting for initial ro construction --- src/storm-pars/analysis/Lattice.cpp | 43 ++++ src/storm-pars/analysis/Lattice.h | 34 +++ src/storm-pars/analysis/LatticeExtender.cpp | 201 +++++++++++++++--- src/storm-pars/analysis/LatticeExtender.h | 33 ++- .../analysis/MonotonicityChecker.cpp | 26 ++- .../analysis/AssumptionCheckerTest.cpp | 2 +- .../analysis/MonotonicityCheckerTest.cpp | 4 +- 7 files changed, 302 insertions(+), 41 deletions(-) diff --git a/src/storm-pars/analysis/Lattice.cpp b/src/storm-pars/analysis/Lattice.cpp index 8c0e04136..404ffe47e 100644 --- a/src/storm-pars/analysis/Lattice.cpp +++ b/src/storm-pars/analysis/Lattice.cpp @@ -38,6 +38,30 @@ namespace storm { } } + Lattice::Lattice(uint_fast64_t topState, uint_fast64_t bottomState, uint_fast64_t numberOfStates) { + nodes = std::vector(numberOfStates); + + this->numberOfStates = numberOfStates; + this->addedStates = new storm::storage::BitVector(numberOfStates); + this->doneBuilding = false; + + top = new Node(); + bottom = new Node(); + + top->statesAbove = storm::storage::BitVector(numberOfStates); + bottom->statesAbove = storm::storage::BitVector(numberOfStates); + + addedStates->set(topState); + bottom->statesAbove.set(topState); + top->states.insert(topState); + nodes[topState] = top; + + addedStates->set(bottomState); + bottom->states.insert(bottomState); + nodes[bottomState] = bottom; + assert (addedStates->getNumberOfSetBits() == 2); + } + Lattice::Lattice(Lattice* lattice) { numberOfStates = lattice->getAddedStates()->size(); nodes = std::vector(numberOfStates); @@ -90,6 +114,16 @@ namespace storm { addedStates->set(state); } + void Lattice::addBetween(uint_fast64_t state, uint_fast64_t above, uint_fast64_t below) { + assert(!(*addedStates)[state]); + assert(compare(above, below) == ABOVE); + + assert (getNode(below)->states.find(below) != getNode(below)->states.end()); + assert (getNode(above)->states.find(above) != getNode(above)->states.end()); + addBetween(state, getNode(above), getNode(below)); + + } + void Lattice::addToNode(uint_fast64_t state, Node *node) { assert(!(*addedStates)[state]); node->states.insert(state); @@ -111,6 +145,10 @@ namespace storm { assert (compare(above, below) == ABOVE); } + void Lattice::addRelation(uint_fast64_t above, uint_fast64_t below) { + addRelationNodes(getNode(above), getNode(below)); + } + Lattice::NodeComparison Lattice::compare(uint_fast64_t state1, uint_fast64_t state2) { return compare(getNode(state1), getNode(state2)); } @@ -147,6 +185,11 @@ namespace storm { return UNKNOWN; } + + bool Lattice::contains(uint_fast64_t state) { + return state >= 0 && state < addedStates->size() && addedStates->get(state); + } + Lattice::Node *Lattice::getNode(uint_fast64_t stateNumber) { return nodes.at(stateNumber); } diff --git a/src/storm-pars/analysis/Lattice.h b/src/storm-pars/analysis/Lattice.h index e0aef5acd..bdd25a5f2 100644 --- a/src/storm-pars/analysis/Lattice.h +++ b/src/storm-pars/analysis/Lattice.h @@ -40,6 +40,17 @@ namespace storm { storm::storage::BitVector* initialMiddleStates, uint_fast64_t numberOfStates); + /*! + * Constructs a lattice with the given top state and bottom state. + * + * @param top The top state of the resulting lattice. + * @param bottom The bottom state of the resulting lattice. + * @param numberOfStates Max number of states in endlattice. + */ + Lattice(uint_fast64_t top, + uint_fast64_t bottom, + uint_fast64_t numberOfStates); + /*! * Constructs a copy of the given lattice. * @@ -55,6 +66,15 @@ namespace storm { */ void addBetween(uint_fast64_t state, Node *node1, Node *node2); + /*! + * Adds a node with the given state between the nodes of below and above. + * Result: below -> state -> above + * @param state The given state. + * @param above The state number of the state below which a new node (with state) is added + * @param below The state number of the state above which a new node (with state) is added + */ + void addBetween(uint_fast64_t state, uint_fast64_t above, uint_fast64_t below); + /*! * Adds state to the states of the given node. * @param state The state which is added. @@ -75,6 +95,13 @@ namespace storm { */ void addRelationNodes(storm::analysis::Lattice::Node *above, storm::analysis::Lattice::Node * below); + /*! + * Adds a new relation between two states to the lattice + * @param above The state closest to the top Node of the Lattice. + * @param below The state closest to the bottom Node of the Lattice. + */ + void addRelation(uint_fast64_t above, uint_fast64_t below); + /*! * Compares the level of the nodes of the states. * Behaviour unknown when one or more of the states doesnot occur at any Node in the Lattice. @@ -87,6 +114,13 @@ namespace storm { */ Lattice::NodeComparison compare(uint_fast64_t state1, uint_fast64_t state2); + /*! + * Check if state is already in lattice + * @param state + * @return + */ + bool contains(uint_fast64_t state); + /*! * Retrieves the pointer to a Node at which the state occurs. * diff --git a/src/storm-pars/analysis/LatticeExtender.cpp b/src/storm-pars/analysis/LatticeExtender.cpp index dc0817a8b..f8cabe47a 100644 --- a/src/storm-pars/analysis/LatticeExtender.cpp +++ b/src/storm-pars/analysis/LatticeExtender.cpp @@ -33,7 +33,33 @@ namespace storm { template LatticeExtender::LatticeExtender(std::shared_ptr> model) { this->model = model; - assumptionSeen = false; + this->matrix = model->getTransitionMatrix(); + this->assumptionSeen = false; + uint_fast64_t numberOfStates = this->model->getNumberOfStates(); + + // Build stateMap + // TODO: is dit wel nodig + for (uint_fast64_t i = 0; i < numberOfStates; ++i) { + stateMap[i] = new storm::storage::BitVector(numberOfStates, false); + + auto row = matrix.getRow(i); + for (auto rowItr = row.begin(); rowItr != row.end(); ++rowItr) { + // ignore self-loops when there are more transitions + if (i != rowItr->getColumn() || row.getNumberOfEntries() == 1) { + stateMap[i]->set(rowItr->getColumn(), true); + } + } + } + + // Check if MC contains cycles + storm::storage::StronglyConnectedComponentDecompositionOptions const options; + this->sccs = storm::storage::StronglyConnectedComponentDecomposition(matrix, options); + acyclic = true; + for (auto i = 0; acyclic && i < sccs.size(); ++i) { + acyclic &= sccs.getBlock(i).size() <= 1; + } + statesSorted = storm::utility::graph::getTopologicalSort(matrix); + } template @@ -45,6 +71,7 @@ namespace storm { uint_fast64_t numberOfStates = this->model->getNumberOfStates(); + // TODO: dit moet anders kunnen storm::modelchecker::SparsePropositionalModelChecker> propositionalChecker(*model); storm::storage::BitVector phiStates; storm::storage::BitVector psiStates; @@ -56,6 +83,7 @@ namespace storm { psiStates = propositionalChecker.check((*(formulas[0])).asProbabilityOperatorFormula().getSubformula().asEventuallyFormula().getSubformula())->asExplicitQualitativeCheckResult().getTruthValuesVector(); } + // Get the maybeStates std::pair statesWithProbability01 = storm::utility::graph::performProb01(this->model->getBackwardTransitions(), phiStates, psiStates); storm::storage::BitVector topStates = statesWithProbability01.second; @@ -75,10 +103,13 @@ namespace storm { for (auto i = 0; acyclic && i < decomposition.size(); ++i) { acyclic &= decomposition.getBlock(i).size() <= 1; } + statesSorted = storm::utility::graph::getTopologicalSort(matrix); + + // Create the Lattice + Lattice *lattice = new Lattice(&topStates, &bottomStates, &initialMiddleStates, numberOfStates); + if (acyclic) { - statesSorted = storm::utility::graph::getTopologicalSort(matrix); } else { - statesSorted = storm::utility::graph::getTopologicalSort(matrix); for (uint_fast64_t i = 0; i < numberOfStates; ++i) { stateMap[i] = new storm::storage::BitVector(numberOfStates, false); @@ -91,6 +122,7 @@ namespace storm { } } for (auto i = 0; i < decomposition.size(); ++i) { + // TODO: alleen als er nog geen van in de lattice zit auto scc = decomposition.getBlock(i); if (scc.size() > 1) { auto states = scc.getStates(); @@ -103,6 +135,7 @@ namespace storm { auto intersection = bottomStates | topStates; if (intersection[succ1] || intersection[succ2]) { initialMiddleStates.set(state); + // ipv daaraan toevoegen, hem toevoegen aan de lattice die we eerder al gecreerd hebben break; } } @@ -110,15 +143,128 @@ namespace storm { } } } - statesToHandle = &initialMiddleStates; - // Create the Lattice - Lattice *lattice = new Lattice(&topStates, &bottomStates, &initialMiddleStates, numberOfStates); + return this->extendLattice(lattice); + } + + + template + std::tuple LatticeExtender::toLattice(std::vector> formulas, std::vector minValues, std::vector maxValues) { + uint_fast64_t numberOfStates = this->model->getNumberOfStates(); + + // Compare min/max for all states + STORM_LOG_THROW((++formulas.begin()) == formulas.end(), storm::exceptions::NotSupportedException, "Only one formula allowed for monotonicity analysis"); + STORM_LOG_THROW((*(formulas[0])).isProbabilityOperatorFormula() + && ((*(formulas[0])).asProbabilityOperatorFormula().getSubformula().isUntilFormula() + || (*(formulas[0])).asProbabilityOperatorFormula().getSubformula().isEventuallyFormula()), storm::exceptions::NotSupportedException, "Expecting until or eventually formula"); + storm::modelchecker::SparsePropositionalModelChecker> propositionalChecker(*model); + storm::storage::BitVector phiStates; + storm::storage::BitVector psiStates; + if ((*(formulas[0])).asProbabilityOperatorFormula().getSubformula().isUntilFormula()) { + phiStates = propositionalChecker.check((*(formulas[0])).asProbabilityOperatorFormula().getSubformula().asUntilFormula().getLeftSubformula())->asExplicitQualitativeCheckResult().getTruthValuesVector(); + psiStates = propositionalChecker.check((*(formulas[0])).asProbabilityOperatorFormula().getSubformula().asUntilFormula().getRightSubformula())->asExplicitQualitativeCheckResult().getTruthValuesVector(); + } else { + phiStates = storm::storage::BitVector(numberOfStates, true); + psiStates = propositionalChecker.check((*(formulas[0])).asProbabilityOperatorFormula().getSubformula().asEventuallyFormula().getSubformula())->asExplicitQualitativeCheckResult().getTruthValuesVector(); + } + + // Get the maybeStates + std::pair statesWithProbability01 = storm::utility::graph::performProb01(this->model->getBackwardTransitions(), phiStates, psiStates); + storm::storage::BitVector topStates = statesWithProbability01.second; + storm::storage::BitVector bottomStates = statesWithProbability01.first; + + STORM_LOG_THROW(topStates.begin() != topStates.end(), storm::exceptions::NotImplementedException, "Formula yields to no 1 states"); + STORM_LOG_THROW(bottomStates.begin() != bottomStates.end(), storm::exceptions::NotImplementedException, "Formula yields to no zero states"); + + uint_fast64_t bottom = bottomStates.getNextSetIndex(0); + uint_fast64_t top = topStates.getNextSetIndex(0); + Lattice* lattice = new Lattice(top, bottom, numberOfStates); + + + for (auto state : statesSorted) { + if (state != bottom && state != top) { + assert (lattice != nullptr); + auto successors = stateMap[state]; + if (successors->size() > 1) { + uint_fast64_t min = numberOfStates; + uint_fast64_t max = numberOfStates; + bool allSorted = true; + + for (auto succ = successors->getNextSetIndex(0); + succ < numberOfStates; succ = successors->getNextSetIndex(succ + 1)) { + if (min == numberOfStates) { + assert (max == numberOfStates); + min = succ; + max = succ; + } else { + if (minValues[succ] > maxValues[max]) { + max = succ; + } else if (maxValues[succ] < minValues[min]) { + min = succ; + } else { + allSorted = false; + break; + } + } + } + + if (allSorted && min != max) { + if (lattice->contains(min) && lattice->contains(max)) { + assert (lattice->compare(min,max) == Lattice::UNKNOWN || lattice->compare(min,max) == Lattice::BELOW); + if (lattice->compare(min, max) == Lattice::UNKNOWN) { + lattice->addRelation(max, min); + } + } + if (!lattice->contains(min)) { + if (lattice->contains(max)) { + lattice->addBetween(min, lattice->getNode(max), lattice->getBottom()); + } else { + lattice->add(min); + } + } + if (!lattice->contains(max)) { + // Because of construction min is in the lattice + lattice->addBetween(max, lattice->getNode(min), lattice->getTop()); + } + assert (lattice->compare(max, min) == Lattice::ABOVE); + lattice->addBetween(state, max, min); + } + } + } + } + + // Handle sccs + auto addedStates = lattice->getAddedStates(); + for (auto scc : sccs) { + if (scc.size() > 1) { + auto states = scc.getStates(); + auto candidate = -1; + for (auto const& state : states) { + if (addedStates->get(state)) { + candidate = -1; + break; + // if there is a state of the scc already present in the lattice, there is no need to add one. + } + auto successors = stateMap[state]; + if (candidate == -1 && successors->getNumberOfSetBits() == 2) { + auto succ1 = successors->getNextSetIndex(0); + auto succ2 = successors->getNextSetIndex(succ1 + 1); + if (addedStates->get(succ1) || addedStates->get(succ2)) { + candidate = state; + } + } + } + if (candidate != -1) { + lattice->add(candidate); + } + } + } return this->extendLattice(lattice); } + template void LatticeExtender::handleAssumption(Lattice* lattice, std::shared_ptr assumption) { assert (assumption != nullptr); @@ -250,15 +396,15 @@ namespace storm { if (statesSorted.size() > 0) { auto nextState = *(statesSorted.begin()); - while ((*(lattice->getAddedStates()))[nextState] && statesSorted.size() > 1) { + while (lattice->contains(nextState) && statesSorted.size() > 1) { // states.size()>1 such that there is at least one state left after erase statesSorted.erase(statesSorted.begin()); nextState = *(statesSorted.begin()); } - if (!(*(lattice->getAddedStates()))[nextState]) { + if (!lattice->contains(nextState)) { auto row = this->model->getTransitionMatrix().getRow(nextState); - auto successors = new storm::storage::BitVector(lattice->getAddedStates()->size()); + auto successors = new storm::storage::BitVector(numberOfStates); for (auto rowItr = row.begin(); rowItr != row.end(); ++rowItr) { // ignore self-loops when there are more transitions if (nextState != rowItr->getColumn()) { @@ -278,22 +424,22 @@ namespace storm { } auto added = lattice->getAddedStates()->getNumberOfSetBits(); assert (lattice->getNode(nextState) != nullptr); - assert ((*lattice->getAddedStates())[nextState]); + assert (lattice->contains(nextState)); } } else if (assumptionSeen && acyclic) { auto states = statesSorted; if (states.size() > 0) { auto nextState = *(states.begin()); - while ((*(lattice->getAddedStates()))[nextState] && states.size() > 1) { + while (lattice->contains(nextState) && states.size() > 1) { // states.size()>1 such that there is at least one state left after erase states.erase(states.begin()); nextState = *(states.begin()); } - if (!(*(lattice->getAddedStates()))[nextState]) { + if (!lattice->contains(nextState)) { auto row = this->model->getTransitionMatrix().getRow(nextState); - auto successors = new storm::storage::BitVector(lattice->getAddedStates()->size()); + auto successors = new storm::storage::BitVector(numberOfStates); for (auto rowItr = row.begin(); rowItr != row.end(); ++rowItr) { // ignore self-loops when there are more transitions if (nextState != rowItr->getColumn()) { @@ -316,25 +462,23 @@ namespace storm { } } assert (lattice->getNode(nextState) != nullptr); - assert ((*lattice->getAddedStates())[nextState]); + assert (lattice->contains(nextState)); } } else if (!acyclic) { - auto addedStates = lattice->getAddedStates(); if (assumptionSeen) { - statesToHandle = addedStates; + statesToHandle = lattice->getAddedStates(); } auto stateNumber = statesToHandle->getNextSetIndex(0); while (stateNumber != numberOfStates) { - addedStates = lattice->getAddedStates(); storm::storage::BitVector* successors = stateMap[stateNumber]; // Checking for states which are already added to the lattice, and only have one successor left which haven't been added yet auto succ1 = successors->getNextSetIndex(0); auto succ2 = successors->getNextSetIndex(succ1 + 1); - assert ((*addedStates)[stateNumber]); + assert (lattice->contains(stateNumber)); if (successors->getNumberOfSetBits() == 1) { - if (!(*addedStates)[succ1]) { + if (!lattice->contains(succ1)) { lattice->addToNode(succ1, lattice->getNode(stateNumber)); statesToHandle->set(succ1, true); auto itr = std::find(statesSorted.begin(), statesSorted.end(), succ1); @@ -345,10 +489,10 @@ namespace storm { statesToHandle->set(stateNumber, false); stateNumber = statesToHandle->getNextSetIndex(0); } else if (successors->getNumberOfSetBits() == 2 - && (((*(addedStates))[succ1] && !(*(addedStates))[succ2]) - || (!(*(addedStates))[succ1] && (*(addedStates))[succ2]))) { + && ((lattice->contains(succ1) && !lattice->contains(succ2)) + || (!lattice->contains(succ1) && lattice->contains(succ2)))) { - if (!(*(addedStates))[succ1]) { + if (!lattice->contains(succ1)) { std::swap(succ1, succ2); } @@ -377,8 +521,8 @@ namespace storm { stateNumber = statesToHandle->getNextSetIndex(0); } - } else if (!(((*(addedStates))[succ1] && !(*(addedStates))[succ2]) - || (!(*(addedStates))[succ1] && (*(addedStates))[succ2]))) { + } else if (!((lattice->contains(succ1) && !lattice->contains(succ2)) + || (!lattice->contains(succ1) && lattice->contains(succ2)))) { stateNumber = statesToHandle->getNextSetIndex(stateNumber + 1); } else { statesToHandle->set(stateNumber, false); @@ -393,7 +537,7 @@ namespace storm { stateNumber = numberOfStates; } while (stateNumber != numberOfStates - && (*(lattice->getAddedStates()))[stateNumber]) { + && lattice->contains(stateNumber)) { statesSorted.erase(statesSorted.begin()); if (statesSorted.size() > 0) { stateNumber = *(statesSorted.begin()); @@ -407,7 +551,7 @@ namespace storm { // Check if current state has not been added yet, and all successors have, ignore selfloop in this successors->set(stateNumber, false); - if ((*successors & *addedStates) == *successors) { + if ((*successors & *(lattice->getAddedStates())) == *successors) { auto result = extendAllSuccAdded(lattice, stateNumber, successors); if (std::get<1>(result) != successors->size()) { return result; @@ -416,15 +560,14 @@ namespace storm { } } } else { - addedStates = lattice->getAddedStates(); - auto notAddedStates = addedStates->operator~(); + auto notAddedStates = lattice->getAddedStates()->operator~(); for (auto stateNumber : notAddedStates) { // Iterate over all not yet added states storm::storage::BitVector* successors = stateMap[stateNumber]; // Check if current state has not been added yet, and all successors have, ignore selfloop in this successors->set(stateNumber, false); - if ((*successors & *addedStates) == *successors) { + if ((*successors & *(lattice->getAddedStates())) == *successors) { auto result = extendAllSuccAdded(lattice, stateNumber, successors); if (std::get<1>(result) != successors->size()) { return result; diff --git a/src/storm-pars/analysis/LatticeExtender.h b/src/storm-pars/analysis/LatticeExtender.h index 4899fdf46..42b743fa5 100644 --- a/src/storm-pars/analysis/LatticeExtender.h +++ b/src/storm-pars/analysis/LatticeExtender.h @@ -5,6 +5,10 @@ #include "storm/models/sparse/Dtmc.h" #include "storm-pars/analysis/Lattice.h" #include "storm/api/storm.h" +#include "storm-pars/storage/ParameterRegion.h" +#include "storm/storage/StronglyConnectedComponentDecomposition.h" +#include "storm/storage/StronglyConnectedComponent.h" + namespace storm { @@ -23,25 +27,36 @@ namespace storm { LatticeExtender(std::shared_ptr> model); /*! - * Extends the lattice based on the given assumption. + * Creates a lattice based on the given formula. * - * @param lattice The lattice. - * @param assumption The assumption on states. + * @param formulas The formulas based on which the lattice is created, only the first is used. * @return A triple with a pointer to the lattice and two states of which the current place in the lattice * is unknown but needed. When the states have as number the number of states, no states are * unplaced but needed. */ - std::tuple extendLattice(storm::analysis::Lattice* lattice, std::shared_ptr assumption = nullptr); + std::tuple toLattice(std::vector> formulas); /*! - * Creates a lattice based on the given formula. + * Creates a lattice based on the given extremal values. * - * @param formulas The formulas based on which the lattice is created, only the first is used. * @return A triple with a pointer to the lattice and two states of which the current place in the lattice * is unknown but needed. When the states have as number the number of states, no states are * unplaced but needed. */ - std::tuple toLattice(std::vector> formulas); + std::tuple toLattice(std::vector> formulas, std::vector minValues, std::vector maxValues); + + + /*! + * Extends the lattice based on the given assumption. + * + * @param lattice The lattice. + * @param assumption The assumption on states. + * @return A triple with a pointer to the lattice and two states of which the current place in the lattice + * is unknown but needed. When the states have as number the number of states, no states are + * unplaced but needed. + */ + std::tuple extendLattice(storm::analysis::Lattice* lattice, std::shared_ptr assumption = nullptr); + private: std::shared_ptr> model; @@ -56,6 +71,10 @@ namespace storm { storm::storage::BitVector* statesToHandle; + storm::storage::StronglyConnectedComponentDecomposition sccs; + + storm::storage::SparseMatrix matrix; + void handleAssumption(Lattice* lattice, std::shared_ptr assumption); std::tuple extendAllSuccAdded(Lattice* lattice, uint_fast64_t const & stateNumber, storm::storage::BitVector* successors); diff --git a/src/storm-pars/analysis/MonotonicityChecker.cpp b/src/storm-pars/analysis/MonotonicityChecker.cpp index f451f7df7..8565d97d3 100644 --- a/src/storm-pars/analysis/MonotonicityChecker.cpp +++ b/src/storm-pars/analysis/MonotonicityChecker.cpp @@ -175,8 +175,31 @@ namespace storm { std::map>> MonotonicityChecker::createLattice() { // Transform to Lattices storm::utility::Stopwatch latticeWatch(true); - std::tuple criticalTuple = extender->toLattice(formulas); + // Use parameter lifting modelchecker to get initial min/max values for lattice creation + storm::modelchecker::SparseDtmcParameterLiftingModelChecker, double> plaModelChecker; + std::unique_ptr checkResult; + auto env = Environment(); + + auto formula = formulas[0]; + const storm::modelchecker::CheckTask checkTask + = storm::modelchecker::CheckTask(*formula); + STORM_LOG_THROW(plaModelChecker.canHandle(model, checkTask), storm::exceptions::NotSupportedException, + "Cannot handle this formula"); + plaModelChecker.specify(env, model, checkTask); + + std::unique_ptr minCheck = plaModelChecker.check(env, region,storm::solver::OptimizationDirection::Minimize); + std::unique_ptr maxCheck = plaModelChecker.check(env, region,storm::solver::OptimizationDirection::Maximize); + auto minRes = minCheck->asExplicitQuantitativeCheckResult(); + auto maxRes = maxCheck->asExplicitQuantitativeCheckResult(); + + std::vector minValues = minRes.getValueVector(); + std::vector maxValues = maxRes.getValueVector(); + // Create initial lattice + std::tuple criticalTuple = extender->toLattice(formulas, minValues, maxValues); + + + // Continue based on not (yet) sorted states std::map>> result; auto val1 = std::get<1>(criticalTuple); @@ -515,7 +538,6 @@ namespace storm { return result; } - template std::map::type, std::pair> MonotonicityChecker::checkOnSamples(std::shared_ptr> model, uint_fast64_t numberOfSamples) { storm::utility::Stopwatch samplesWatch(true); diff --git a/src/test/storm-pars/analysis/AssumptionCheckerTest.cpp b/src/test/storm-pars/analysis/AssumptionCheckerTest.cpp index 08e7319a6..bc331296d 100644 --- a/src/test/storm-pars/analysis/AssumptionCheckerTest.cpp +++ b/src/test/storm-pars/analysis/AssumptionCheckerTest.cpp @@ -331,7 +331,7 @@ TEST(AssumptionCheckerTest, Simple4) { below.set(4); storm::storage::BitVector initialMiddle(5); auto lattice = new storm::analysis::Lattice(&above, &below, &initialMiddle, 5); - + auto assumption = std::make_shared( storm::expressions::BinaryRelationExpression(*expressionManager, expressionManager->getBooleanType(), expressionManager->getVariable("1").getExpression().getBaseExpressionPointer(), diff --git a/src/test/storm-pars/analysis/MonotonicityCheckerTest.cpp b/src/test/storm-pars/analysis/MonotonicityCheckerTest.cpp index 4dfc2e38b..3f1afd50c 100644 --- a/src/test/storm-pars/analysis/MonotonicityCheckerTest.cpp +++ b/src/test/storm-pars/analysis/MonotonicityCheckerTest.cpp @@ -110,7 +110,7 @@ TEST(MonotonicityCheckerTest, Derivative_checker) { TEST(MonotonicityCheckerTest, Brp_with_bisimulation_no_samples) { std::string programFile = STORM_TEST_RESOURCES_DIR "/pdtmc/brp16_2.pm"; - std::string formulaAsString = "P=? [F s=4 & i=N ]"; + std::string formulaAsString = "P=? [true U s=4 & i=N ]"; std::string constantsAsString = ""; //e.g. pL=0.9,TOACK=0.5 // Program and formula @@ -159,7 +159,7 @@ std::vector> regions = TEST(MonotonicityCheckerTest, Brp_with_bisimulation_samples) { std::string programFile = STORM_TEST_RESOURCES_DIR "/pdtmc/brp16_2.pm"; - std::string formulaAsString = "P=? [F s=4 & i=N ]"; + std::string formulaAsString = "P=? [true U s=4 & i=N ]"; std::string constantsAsString = ""; //e.g. pL=0.9,TOACK=0.5 // Program and formula From 1c5d6b72371a5b2a23e0f21b7ac425a9b2b44554 Mon Sep 17 00:00:00 2001 From: Jip Spel Date: Thu, 25 Jul 2019 16:01:42 +0200 Subject: [PATCH 166/178] Clean up lattice creation code --- src/storm-pars/analysis/Lattice.cpp | 12 +- src/storm-pars/analysis/Lattice.h | 10 +- src/storm-pars/analysis/LatticeExtender.cpp | 248 ++++++------------ src/storm-pars/analysis/LatticeExtender.h | 6 +- .../analysis/AssumptionCheckerTest.cpp | 19 +- .../analysis/AssumptionMakerTest.cpp | 7 +- src/test/storm-pars/analysis/LatticeTest.cpp | 6 +- 7 files changed, 119 insertions(+), 189 deletions(-) diff --git a/src/storm-pars/analysis/Lattice.cpp b/src/storm-pars/analysis/Lattice.cpp index 404ffe47e..3253a7d44 100644 --- a/src/storm-pars/analysis/Lattice.cpp +++ b/src/storm-pars/analysis/Lattice.cpp @@ -7,12 +7,15 @@ namespace storm { Lattice::Lattice(storm::storage::BitVector* topStates, storm::storage::BitVector* bottomStates, storm::storage::BitVector* initialMiddleStates, - uint_fast64_t numberOfStates) { + uint_fast64_t numberOfStates, + std::vector* statesSorted) { nodes = std::vector(numberOfStates); this->numberOfStates = numberOfStates; this->addedStates = new storm::storage::BitVector(numberOfStates); this->doneBuilding = false; + this->statesSorted = statesSorted; + this->statesToHandle = initialMiddleStates; top = new Node(); bottom = new Node(); @@ -38,12 +41,14 @@ namespace storm { } } - Lattice::Lattice(uint_fast64_t topState, uint_fast64_t bottomState, uint_fast64_t numberOfStates) { + Lattice::Lattice(uint_fast64_t topState, uint_fast64_t bottomState, uint_fast64_t numberOfStates, std::vector* statesSorted) { nodes = std::vector(numberOfStates); this->numberOfStates = numberOfStates; this->addedStates = new storm::storage::BitVector(numberOfStates); this->doneBuilding = false; + this->statesSorted = statesSorted; + this->statesToHandle = new storm::storage::BitVector(numberOfStates); top = new Node(); bottom = new Node(); @@ -96,6 +101,9 @@ namespace storm { newNode->statesAbove = storm::storage::BitVector((oldNode->statesAbove)); } } + + this->statesSorted = lattice->statesSorted; + this->statesToHandle = lattice->statesToHandle; } void Lattice::addBetween(uint_fast64_t state, Node *above, Node *below) { diff --git a/src/storm-pars/analysis/Lattice.h b/src/storm-pars/analysis/Lattice.h index bdd25a5f2..9de5ed07b 100644 --- a/src/storm-pars/analysis/Lattice.h +++ b/src/storm-pars/analysis/Lattice.h @@ -38,7 +38,8 @@ namespace storm { Lattice(storm::storage::BitVector* topStates, storm::storage::BitVector* bottomStates, storm::storage::BitVector* initialMiddleStates, - uint_fast64_t numberOfStates); + uint_fast64_t numberOfStates, + std::vector* statesSorted); /*! * Constructs a lattice with the given top state and bottom state. @@ -49,7 +50,8 @@ namespace storm { */ Lattice(uint_fast64_t top, uint_fast64_t bottom, - uint_fast64_t numberOfStates); + uint_fast64_t numberOfStates, + std::vector* statesSorted); /*! * Constructs a copy of the given lattice. @@ -208,6 +210,10 @@ namespace storm { */ void merge(uint_fast64_t var1, uint_fast64_t var2); + storm::storage::BitVector* statesToHandle; + + std::vector* statesSorted; + private: std::vector nodes; diff --git a/src/storm-pars/analysis/LatticeExtender.cpp b/src/storm-pars/analysis/LatticeExtender.cpp index f8cabe47a..b36230492 100644 --- a/src/storm-pars/analysis/LatticeExtender.cpp +++ b/src/storm-pars/analysis/LatticeExtender.cpp @@ -58,8 +58,6 @@ namespace storm { for (auto i = 0; acyclic && i < sccs.size(); ++i) { acyclic &= sccs.getBlock(i).size() <= 1; } - statesSorted = storm::utility::graph::getTopologicalSort(matrix); - } template @@ -98,32 +96,12 @@ namespace storm { auto initialMiddleStates = storm::storage::BitVector(numberOfStates); // Check if MC contains cycles storm::storage::StronglyConnectedComponentDecompositionOptions const options; - auto decomposition = storm::storage::StronglyConnectedComponentDecomposition(model->getTransitionMatrix(), options); - acyclic = true; - for (auto i = 0; acyclic && i < decomposition.size(); ++i) { - acyclic &= decomposition.getBlock(i).size() <= 1; - } - statesSorted = storm::utility::graph::getTopologicalSort(matrix); // Create the Lattice - Lattice *lattice = new Lattice(&topStates, &bottomStates, &initialMiddleStates, numberOfStates); - if (acyclic) { - } else { - for (uint_fast64_t i = 0; i < numberOfStates; ++i) { - stateMap[i] = new storm::storage::BitVector(numberOfStates, false); - - auto row = matrix.getRow(i); - for (auto rowItr = row.begin(); rowItr != row.end(); ++rowItr) { - // ignore self-loops when there are more transitions - if (i != rowItr->getColumn() || row.getNumberOfEntries() == 1) { - stateMap[i]->set(rowItr->getColumn(), true); - } - } - } - for (auto i = 0; i < decomposition.size(); ++i) { - // TODO: alleen als er nog geen van in de lattice zit - auto scc = decomposition.getBlock(i); + if (!acyclic) { + for (auto i = 0; i < sccs.size(); ++i) { + auto scc = sccs.getBlock(i); if (scc.size() > 1) { auto states = scc.getStates(); // check if the state has already one successor in bottom of top, in that case pick it @@ -135,7 +113,6 @@ namespace storm { auto intersection = bottomStates | topStates; if (intersection[succ1] || intersection[succ2]) { initialMiddleStates.set(state); - // ipv daaraan toevoegen, hem toevoegen aan de lattice die we eerder al gecreerd hebben break; } } @@ -143,7 +120,8 @@ namespace storm { } } } - statesToHandle = &initialMiddleStates; + std::vector statesSorted = storm::utility::graph::getTopologicalSort(matrix); + Lattice *lattice = new Lattice(&topStates, &bottomStates, &initialMiddleStates, numberOfStates, &statesSorted); return this->extendLattice(lattice); } @@ -180,10 +158,11 @@ namespace storm { uint_fast64_t bottom = bottomStates.getNextSetIndex(0); uint_fast64_t top = topStates.getNextSetIndex(0); - Lattice* lattice = new Lattice(top, bottom, numberOfStates); + std::vector statesSorted = storm::utility::graph::getTopologicalSort(matrix); + Lattice *lattice = new Lattice(top, bottom, numberOfStates, &statesSorted); - for (auto state : statesSorted) { + for (auto state : *(lattice->statesSorted)) { if (state != bottom && state != top) { assert (lattice != nullptr); auto successors = stateMap[state]; @@ -258,6 +237,7 @@ namespace storm { } if (candidate != -1) { lattice->add(candidate); + lattice->statesToHandle->set(candidate); } } } @@ -388,90 +368,19 @@ namespace storm { handleAssumption(lattice, assumption); } + auto statesSorted = lattice->statesSorted; + auto oldNumberSet = numberOfStates; while (oldNumberSet != lattice->getAddedStates()->getNumberOfSetBits()) { oldNumberSet = lattice->getAddedStates()->getNumberOfSetBits(); - if (!assumptionSeen && acyclic) { - - if (statesSorted.size() > 0) { - auto nextState = *(statesSorted.begin()); - while (lattice->contains(nextState) && statesSorted.size() > 1) { - // states.size()>1 such that there is at least one state left after erase - statesSorted.erase(statesSorted.begin()); - nextState = *(statesSorted.begin()); - } - - if (!lattice->contains(nextState)) { - auto row = this->model->getTransitionMatrix().getRow(nextState); - auto successors = new storm::storage::BitVector(numberOfStates); - for (auto rowItr = row.begin(); rowItr != row.end(); ++rowItr) { - // ignore self-loops when there are more transitions - if (nextState != rowItr->getColumn()) { - successors->set(rowItr->getColumn()); - } - } - - assert ((*(lattice->getAddedStates()) & *successors) == *successors); - - auto result = extendAllSuccAdded(lattice, nextState, successors); - if (std::get<1>(result) != numberOfStates) { - return result; - } else { - assert (lattice->getNode(nextState) != nullptr); - statesSorted.erase(statesSorted.begin()); - } - } - auto added = lattice->getAddedStates()->getNumberOfSetBits(); - assert (lattice->getNode(nextState) != nullptr); - assert (lattice->contains(nextState)); - } - } else if (assumptionSeen && acyclic) { - auto states = statesSorted; - - if (states.size() > 0) { - auto nextState = *(states.begin()); - while (lattice->contains(nextState) && states.size() > 1) { - // states.size()>1 such that there is at least one state left after erase - states.erase(states.begin()); - nextState = *(states.begin()); - } - - if (!lattice->contains(nextState)) { - auto row = this->model->getTransitionMatrix().getRow(nextState); - auto successors = new storm::storage::BitVector(numberOfStates); - for (auto rowItr = row.begin(); rowItr != row.end(); ++rowItr) { - // ignore self-loops when there are more transitions - if (nextState != rowItr->getColumn()) { - successors->set(rowItr->getColumn()); - } - } - - assert ((*(lattice->getAddedStates()) & *successors) == *successors); - - auto result = extendAllSuccAdded(lattice, nextState, successors); - if (std::get<1>(result) != numberOfStates) { - return result; - } else { - assert (lattice->getNode(nextState) != nullptr); - states.erase(states.begin()); - } - if (!assumptionSeen) { - statesSorted = states; - - } - } - assert (lattice->getNode(nextState) != nullptr); - assert (lattice->contains(nextState)); - } - - } else if (!acyclic) { - if (assumptionSeen) { - statesToHandle = lattice->getAddedStates(); - } + // Forward reasoning for cycles; + if (!acyclic) { + auto statesToHandle = lattice->statesToHandle; auto stateNumber = statesToHandle->getNextSetIndex(0); + while (stateNumber != numberOfStates) { - storm::storage::BitVector* successors = stateMap[stateNumber]; + storm::storage::BitVector *successors = stateMap[stateNumber]; // Checking for states which are already added to the lattice, and only have one successor left which haven't been added yet auto succ1 = successors->getNextSetIndex(0); auto succ2 = successors->getNextSetIndex(succ1 + 1); @@ -481,16 +390,16 @@ namespace storm { if (!lattice->contains(succ1)) { lattice->addToNode(succ1, lattice->getNode(stateNumber)); statesToHandle->set(succ1, true); - auto itr = std::find(statesSorted.begin(), statesSorted.end(), succ1); - if (itr != statesSorted.end()) { - statesSorted.erase(itr); + auto itr = std::find(statesSorted->begin(), statesSorted->end(), succ1); + if (itr != statesSorted->end()) { + statesSorted->erase(itr); } } statesToHandle->set(stateNumber, false); stateNumber = statesToHandle->getNextSetIndex(0); } else if (successors->getNumberOfSetBits() == 2 - && ((lattice->contains(succ1) && !lattice->contains(succ2)) - || (!lattice->contains(succ1) && lattice->contains(succ2)))) { + && ((lattice->contains(succ1) && !lattice->contains(succ2)) + || (!lattice->contains(succ1) && lattice->contains(succ2)))) { if (!lattice->contains(succ1)) { std::swap(succ1, succ2); @@ -498,18 +407,18 @@ namespace storm { auto compare = lattice->compare(stateNumber, succ1); if (compare == Lattice::ABOVE) { - auto itr = std::find(statesSorted.begin(), statesSorted.end(), succ2); - if (itr != statesSorted.end()) { - statesSorted.erase(itr); + auto itr = std::find(statesSorted->begin(), statesSorted->end(), succ2); + if (itr != statesSorted->end()) { + statesSorted->erase(itr); } lattice->addBetween(succ2, lattice->getTop(), lattice->getNode(stateNumber)); statesToHandle->set(succ2); statesToHandle->set(stateNumber, false); stateNumber = statesToHandle->getNextSetIndex(0); } else if (compare == Lattice::BELOW) { - auto itr = std::find(statesSorted.begin(), statesSorted.end(), succ2); - if (itr != statesSorted.end()) { - statesSorted.erase(itr); + auto itr = std::find(statesSorted->begin(), statesSorted->end(), succ2); + if (itr != statesSorted->end()) { + statesSorted->erase(itr); } lattice->addBetween(succ2, lattice->getNode(stateNumber), lattice->getBottom()); statesToHandle->set(succ2); @@ -530,73 +439,70 @@ namespace storm { } } - if (!assumptionSeen) { - if (statesSorted.size() > 0) { - stateNumber = *(statesSorted.begin()); - } else { - stateNumber = numberOfStates; - } - while (stateNumber != numberOfStates - && lattice->contains(stateNumber)) { - statesSorted.erase(statesSorted.begin()); - if (statesSorted.size() > 0) { - stateNumber = *(statesSorted.begin()); - } else { - stateNumber = numberOfStates; - } - } - - if (stateNumber != numberOfStates) { - storm::storage::BitVector *successors = stateMap[stateNumber]; + } - // Check if current state has not been added yet, and all successors have, ignore selfloop in this - successors->set(stateNumber, false); - if ((*successors & *(lattice->getAddedStates())) == *successors) { - auto result = extendAllSuccAdded(lattice, stateNumber, successors); - if (std::get<1>(result) != successors->size()) { - return result; - } - statesToHandle->set(stateNumber); - } - } - } else { - auto notAddedStates = lattice->getAddedStates()->operator~(); - for (auto stateNumber : notAddedStates) { - // Iterate over all not yet added states - storm::storage::BitVector* successors = stateMap[stateNumber]; - - // Check if current state has not been added yet, and all successors have, ignore selfloop in this - successors->set(stateNumber, false); - if ((*successors & *(lattice->getAddedStates())) == *successors) { - auto result = extendAllSuccAdded(lattice, stateNumber, successors); - if (std::get<1>(result) != successors->size()) { - return result; - } - statesToHandle->set(stateNumber); - } + // Normal backwardreasoning + if (statesSorted->size() > 0) { + auto stateNumber = *(statesSorted->begin()); + while (lattice->contains(stateNumber) && statesSorted->size() > 1) { + // states.size()>1 such that there is at least one state left after erase + statesSorted->erase(statesSorted->begin()); + stateNumber = *(statesSorted->begin()); + + if (lattice->contains(stateNumber)) { + auto resAllAdded = allSuccAdded(lattice, stateNumber); + if (!std::get<0>(resAllAdded)) { + return std::make_tuple(lattice, std::get<1>(resAllAdded), std::get<2>(resAllAdded)); } } + } + if (!lattice->contains(stateNumber)) { + auto successors = stateMap[stateNumber]; - // if nothing changed and there are states left, then add a state between top and bottom - if (oldNumberSet == lattice->getAddedStates()->getNumberOfSetBits() && oldNumberSet != numberOfStates) { - if (assumptionSeen || statesSorted.size() == 0) { - stateNumber = lattice->getAddedStates()->getNextUnsetIndex(0); + auto result = extendAllSuccAdded(lattice, stateNumber, successors); + if (std::get<1>(result) != numberOfStates) { + // So we don't know the relation between all successor states + return result; } else { - stateNumber = *(statesSorted.begin());//lattice->getAddedStates()->getNextUnsetIndex(0); - statesSorted.erase(statesSorted.begin()); + assert (lattice->getNode(stateNumber) != nullptr); + if (!acyclic) { + lattice->statesToHandle->set(stateNumber); + } + statesSorted->erase(statesSorted->begin()); } - - lattice->add(stateNumber); - statesToHandle->set(stateNumber); } + assert (lattice->getNode(stateNumber) != nullptr); + assert (lattice->contains(stateNumber)); } + } assert (lattice->getAddedStates()->getNumberOfSetBits() == numberOfStates); - lattice->setDoneBuilding(true); + lattice->setDoneBuilding(true); return std::make_tuple(lattice, numberOfStates, numberOfStates); } + template + std::tuple LatticeExtender::allSuccAdded(storm::analysis::Lattice *lattice, uint_fast64_t stateNumber) { + auto successors = stateMap[stateNumber]; + auto numberOfStates = successors->size(); + + if (successors->getNumberOfSetBits() == 1) { + auto succ = successors->getNextSetIndex(0); + return std::make_tuple(lattice->contains(succ), succ, succ); + } else if (successors->getNumberOfSetBits() > 2) { + for (auto const& i : *successors) { + for (auto j = successors->getNextSetIndex(i+1); j < numberOfStates; j = successors->getNextSetIndex(j+1)) { + if (lattice->compare(i,j) == Lattice::UNKNOWN) { + return std::make_tuple(false, i, j); + } + } + } + } + return std::make_tuple(true, numberOfStates, numberOfStates); + + } + template class LatticeExtender; } } diff --git a/src/storm-pars/analysis/LatticeExtender.h b/src/storm-pars/analysis/LatticeExtender.h index 42b743fa5..cc4e7370f 100644 --- a/src/storm-pars/analysis/LatticeExtender.h +++ b/src/storm-pars/analysis/LatticeExtender.h @@ -63,14 +63,10 @@ namespace storm { std::map stateMap; - std::vector statesSorted; - bool acyclic; bool assumptionSeen; - storm::storage::BitVector* statesToHandle; - storm::storage::StronglyConnectedComponentDecomposition sccs; storm::storage::SparseMatrix matrix; @@ -78,6 +74,8 @@ namespace storm { void handleAssumption(Lattice* lattice, std::shared_ptr assumption); std::tuple extendAllSuccAdded(Lattice* lattice, uint_fast64_t const & stateNumber, storm::storage::BitVector* successors); + + std::tuple allSuccAdded(Lattice* lattice, uint_fast64_t stateNumber); }; } } diff --git a/src/test/storm-pars/analysis/AssumptionCheckerTest.cpp b/src/test/storm-pars/analysis/AssumptionCheckerTest.cpp index bc331296d..987ef4ef7 100644 --- a/src/test/storm-pars/analysis/AssumptionCheckerTest.cpp +++ b/src/test/storm-pars/analysis/AssumptionCheckerTest.cpp @@ -88,7 +88,9 @@ TEST(AssumptionCheckerTest, Brp_no_bisimulation) { below.set(1); storm::storage::BitVector initialMiddle(8); - auto dummyLattice = new storm::analysis::Lattice(&above, &below, &initialMiddle, 8); + std::vector statesSorted = storm::utility::graph::getTopologicalSort(model->getTransitionMatrix()); + + auto dummyLattice = new storm::analysis::Lattice(&above, &below, &initialMiddle, 8, &statesSorted); // Validate assumption EXPECT_EQ(storm::analysis::AssumptionStatus::INVALID, checker.validateAssumption(assumption, dummyLattice)); // EXPECT_FALSE(checker.validated(assumption)); @@ -105,7 +107,8 @@ TEST(AssumptionCheckerTest, Brp_no_bisimulation) { below = storm::storage::BitVector(13); below.set(9); initialMiddle = storm::storage::BitVector(13); - dummyLattice = new storm::analysis::Lattice(&above, &below, &initialMiddle, 13); + + dummyLattice = new storm::analysis::Lattice(&above, &below, &initialMiddle, 13, &statesSorted); EXPECT_EQ(storm::analysis::AssumptionStatus::INVALID, checker.checkOnSamples(assumption)); EXPECT_EQ(storm::analysis::AssumptionStatus::INVALID, checker.validateAssumption(assumption, dummyLattice)); // EXPECT_EQ(checker.validated(assumption)); @@ -199,7 +202,9 @@ TEST(AssumptionCheckerTest, Simple2) { below.set(4); storm::storage::BitVector initialMiddle(5); - auto lattice = new storm::analysis::Lattice(&above, &below, &initialMiddle, 5); + std::vector statesSorted = storm::utility::graph::getTopologicalSort(model->getTransitionMatrix()); + + auto lattice = new storm::analysis::Lattice(&above, &below, &initialMiddle, 5, &statesSorted); // Checking on samples and validate auto assumption = std::make_shared( @@ -263,7 +268,9 @@ TEST(AssumptionCheckerTest, Simple3) { below.set(5); storm::storage::BitVector initialMiddle(6); - auto lattice = new storm::analysis::Lattice(&above, &below, &initialMiddle, 6); + std::vector statesSorted = storm::utility::graph::getTopologicalSort(model->getTransitionMatrix()); + + auto lattice = new storm::analysis::Lattice(&above, &below, &initialMiddle, 6, &statesSorted); lattice->add(3); // Checking on samples and validate @@ -330,7 +337,9 @@ TEST(AssumptionCheckerTest, Simple4) { storm::storage::BitVector below(5); below.set(4); storm::storage::BitVector initialMiddle(5); - auto lattice = new storm::analysis::Lattice(&above, &below, &initialMiddle, 5); + std::vector statesSorted = storm::utility::graph::getTopologicalSort(model->getTransitionMatrix()); + + auto lattice = new storm::analysis::Lattice(&above, &below, &initialMiddle, 5, &statesSorted); auto assumption = std::make_shared( storm::expressions::BinaryRelationExpression(*expressionManager, expressionManager->getBooleanType(), diff --git a/src/test/storm-pars/analysis/AssumptionMakerTest.cpp b/src/test/storm-pars/analysis/AssumptionMakerTest.cpp index 71b7b1e7f..7268d0c5f 100644 --- a/src/test/storm-pars/analysis/AssumptionMakerTest.cpp +++ b/src/test/storm-pars/analysis/AssumptionMakerTest.cpp @@ -196,8 +196,9 @@ TEST(AssumptionMakerTest, Simple1) { storm::storage::BitVector below(5); below.set(4); storm::storage::BitVector initialMiddle(5); + std::vector statesSorted = storm::utility::graph::getTopologicalSort(model->getTransitionMatrix()); - auto lattice = new storm::analysis::Lattice(&above, &below, &initialMiddle, 5); + auto lattice = new storm::analysis::Lattice(&above, &below, &initialMiddle, 5, &statesSorted); auto assumptionChecker = storm::analysis::AssumptionChecker(formulas[0], dtmc, region, 3); auto assumptionMaker = storm::analysis::AssumptionMaker(&assumptionChecker, dtmc->getNumberOfStates(), true); @@ -268,7 +269,9 @@ TEST(AssumptionMakerTest, Simple2) { below.set(4); storm::storage::BitVector initialMiddle(5); - auto lattice = new storm::analysis::Lattice(&above, &below, &initialMiddle, 5); + std::vector statesSorted = storm::utility::graph::getTopologicalSort(model->getTransitionMatrix()); + + auto lattice = new storm::analysis::Lattice(&above, &below, &initialMiddle, 5, &statesSorted); auto assumptionChecker = storm::analysis::AssumptionChecker(formulas[0], dtmc, region, 3); auto assumptionMaker = storm::analysis::AssumptionMaker(&assumptionChecker, dtmc->getNumberOfStates(), true); diff --git a/src/test/storm-pars/analysis/LatticeTest.cpp b/src/test/storm-pars/analysis/LatticeTest.cpp index dbb590c41..3b9011b04 100644 --- a/src/test/storm-pars/analysis/LatticeTest.cpp +++ b/src/test/storm-pars/analysis/LatticeTest.cpp @@ -12,7 +12,7 @@ TEST(LatticeTest, Simple) { below.set(1); auto initialMiddle = storm::storage::BitVector(numberOfStates); - auto lattice = storm::analysis::Lattice(&above, &below, &initialMiddle, numberOfStates); + auto lattice = storm::analysis::Lattice(&above, &below, &initialMiddle, numberOfStates, nullptr); EXPECT_EQ(storm::analysis::Lattice::NodeComparison::ABOVE, lattice.compare(0,1)); EXPECT_EQ(storm::analysis::Lattice::NodeComparison::BELOW, lattice.compare(1,0)); EXPECT_EQ(nullptr, lattice.getNode(2)); @@ -78,7 +78,7 @@ TEST(LatticeTest, copy_lattice) { below.set(1); auto initialMiddle = storm::storage::BitVector(numberOfStates); - auto lattice = storm::analysis::Lattice(&above, &below, &initialMiddle, numberOfStates); + auto lattice = storm::analysis::Lattice(&above, &below, &initialMiddle, numberOfStates, nullptr); lattice.add(2); lattice.add(3); lattice.addToNode(4, lattice.getNode(2)); @@ -143,7 +143,7 @@ TEST(LatticeTest, merge_nodes) { below.set(1); auto initialMiddle = storm::storage::BitVector(numberOfStates); - auto lattice = storm::analysis::Lattice(&above, &below, &initialMiddle, numberOfStates); + auto lattice = storm::analysis::Lattice(&above, &below, &initialMiddle, numberOfStates, nullptr); lattice.add(2); lattice.add(3); lattice.addToNode(4, lattice.getNode(2)); From 08d2893b2c3bd69e47589707a776ae54e0a1d0ec Mon Sep 17 00:00:00 2001 From: Jip Spel Date: Thu, 25 Jul 2019 17:28:09 +0200 Subject: [PATCH 167/178] Renamed Lattice -> Order --- src/storm-pars/analysis/AssumptionChecker.cpp | 36 +-- src/storm-pars/analysis/AssumptionChecker.h | 16 +- src/storm-pars/analysis/AssumptionMaker.cpp | 8 +- src/storm-pars/analysis/AssumptionMaker.h | 12 +- src/storm-pars/analysis/LatticeExtender.h | 83 ------- .../analysis/MonotonicityChecker.cpp | 100 ++++----- src/storm-pars/analysis/MonotonicityChecker.h | 20 +- .../analysis/{Lattice.cpp => Order.cpp} | 70 +++--- .../analysis/{Lattice.h => Order.h} | 74 +++--- ...{LatticeExtender.cpp => OrderExtender.cpp} | 212 +++++++++--------- src/storm-pars/analysis/OrderExtender.h | 83 +++++++ .../analysis/AssumptionCheckerTest.cpp | 50 ++--- .../analysis/AssumptionMakerTest.cpp | 20 +- src/test/storm-pars/analysis/LatticeTest.cpp | 170 -------------- ...ExtenderTest.cpp => OrderExtenderTest.cpp} | 30 +-- src/test/storm-pars/analysis/OrderTest.cpp | 170 ++++++++++++++ 16 files changed, 577 insertions(+), 577 deletions(-) delete mode 100644 src/storm-pars/analysis/LatticeExtender.h rename src/storm-pars/analysis/{Lattice.cpp => Order.cpp} (81%) rename src/storm-pars/analysis/{Lattice.h => Order.h} (82%) rename src/storm-pars/analysis/{LatticeExtender.cpp => OrderExtender.cpp} (70%) create mode 100644 src/storm-pars/analysis/OrderExtender.h delete mode 100644 src/test/storm-pars/analysis/LatticeTest.cpp rename src/test/storm-pars/analysis/{LatticeExtenderTest.cpp => OrderExtenderTest.cpp} (80%) create mode 100644 src/test/storm-pars/analysis/OrderTest.cpp diff --git a/src/storm-pars/analysis/AssumptionChecker.cpp b/src/storm-pars/analysis/AssumptionChecker.cpp index 5fe86eff5..43d0e75e4 100644 --- a/src/storm-pars/analysis/AssumptionChecker.cpp +++ b/src/storm-pars/analysis/AssumptionChecker.cpp @@ -130,7 +130,7 @@ namespace storm { } template - AssumptionStatus AssumptionChecker::validateAssumption(std::shared_ptr assumption, Lattice* lattice) { + AssumptionStatus AssumptionChecker::validateAssumption(std::shared_ptr assumption, Order* order) { // First check if based on sample points the assumption can be discharged auto result = checkOnSamples(assumption); assert (result != AssumptionStatus::VALID); @@ -156,7 +156,7 @@ namespace storm { std::stoi(assumption->getSecondOperand()->asVariableExpression().getVariableName())); if (row1.getNumberOfEntries() == 2 && row2.getNumberOfEntries() == 2) { - // If the states have the same successors for which we know the position in the lattice + // If the states have the same successors for which we know the position in the order // We can check with a function if the assumption holds auto state1succ1 = row1.begin(); @@ -171,12 +171,12 @@ namespace storm { if (state1succ1->getColumn() == state2succ1->getColumn() && state1succ2->getColumn() == state2succ2->getColumn()) { if (assumption->getRelationType() == expressions::BinaryRelationExpression::RelationType::Greater - && lattice->compare(state1succ1->getColumn(), state1succ2->getColumn()) != Lattice::NodeComparison::UNKNOWN) { + && order->compare(state1succ1->getColumn(), state1succ2->getColumn()) != Order::NodeComparison::UNKNOWN) { // The assumption should be the greater assumption // If the result is unknown, we cannot compare, also SMTSolver will not help - result = validateAssumptionSMTSolver(assumption, lattice); + result = validateAssumptionSMTSolver(assumption, order); -// result = validateAssumptionFunction(lattice, state1succ1, state1succ2, state2succ1, +// result = validateAssumptionFunction(order, state1succ1, state1succ2, state2succ1, // state2succ2); } else if (assumption->getRelationType() == expressions::BinaryRelationExpression::RelationType::Equal) { // The assumption is equal, the successors are the same, @@ -188,17 +188,17 @@ namespace storm { result = AssumptionStatus::UNKNOWN; } } else { - result = validateAssumptionSMTSolver(assumption, lattice); + result = validateAssumptionSMTSolver(assumption, order); } } else { - result = validateAssumptionSMTSolver(assumption, lattice); + result = validateAssumptionSMTSolver(assumption, order); } } return result; } template - AssumptionStatus AssumptionChecker::validateAssumptionFunction(Lattice* lattice, + AssumptionStatus AssumptionChecker::validateAssumptionFunction(Order* order, typename storage::SparseMatrix::iterator state1succ1, typename storage::SparseMatrix::iterator state1succ2, typename storage::SparseMatrix::iterator state2succ1, @@ -212,11 +212,11 @@ namespace storm { // Calculate the difference in probability for the "highest" successor state ValueType prob; - auto comp = lattice->compare(state1succ1->getColumn(), state1succ2->getColumn()); - assert (comp == Lattice::NodeComparison::ABOVE || comp == Lattice::NodeComparison::BELOW); - if (comp == Lattice::NodeComparison::ABOVE) { + auto comp = order->compare(state1succ1->getColumn(), state1succ2->getColumn()); + assert (comp == Order::NodeComparison::ABOVE || comp == Order::NodeComparison::BELOW); + if (comp == Order::NodeComparison::ABOVE) { prob = state1succ1->getValue() - state2succ1->getValue(); - } else if (comp == Lattice::NodeComparison::BELOW) { + } else if (comp == Order::NodeComparison::BELOW) { prob = state1succ2->getValue() - state2succ2->getValue(); } @@ -246,7 +246,7 @@ namespace storm { template - AssumptionStatus AssumptionChecker::validateAssumptionSMTSolver(std::shared_ptr assumption, Lattice* lattice) { + AssumptionStatus AssumptionChecker::validateAssumptionSMTSolver(std::shared_ptr assumption, Order* order) { std::shared_ptr smtSolverFactory = std::make_shared(); std::shared_ptr manager(new expressions::ExpressionManager()); @@ -272,14 +272,14 @@ namespace storm { if (!manager->hasVariable(varname2)) { stateVariables.insert(manager->declareRationalVariable(varname2)); } - auto comp = lattice->compare(itr1->getColumn(), itr2->getColumn()); - if (comp == Lattice::NodeComparison::ABOVE) { + auto comp = order->compare(itr1->getColumn(), itr2->getColumn()); + if (comp == Order::NodeComparison::ABOVE) { exprOrderSucc = exprOrderSucc && !(manager->getVariable(varname1) <= manager->getVariable(varname2)); - } else if (comp == Lattice::NodeComparison::BELOW) { + } else if (comp == Order::NodeComparison::BELOW) { exprOrderSucc = exprOrderSucc && !(manager->getVariable(varname1) >= manager->getVariable(varname2)); - } else if (comp == Lattice::NodeComparison::SAME) { + } else if (comp == Order::NodeComparison::SAME) { exprOrderSucc = exprOrderSucc && (manager->getVariable(varname1) = manager->getVariable(varname2)); } else { @@ -331,7 +331,7 @@ namespace storm { s.add(exprOrderSucc); s.add(exprBounds); - // assert that sorting of successors in the lattice and the bounds on the expression are at least satisfiable + // assert that sorting of successors in the order and the bounds on the expression are at least satisfiable assert (s.check() == solver::SmtSolver::CheckResult::Sat); s.add(exprToCheck); auto smtRes = s.check(); diff --git a/src/storm-pars/analysis/AssumptionChecker.h b/src/storm-pars/analysis/AssumptionChecker.h index c1e58dd69..802291291 100644 --- a/src/storm-pars/analysis/AssumptionChecker.h +++ b/src/storm-pars/analysis/AssumptionChecker.h @@ -7,7 +7,7 @@ #include "storm/environment/Environment.h" #include "storm/storage/expressions/BinaryRelationExpression.h" #include "storm-pars/storage/ParameterRegion.h" -#include "Lattice.h" +#include "Order.h" namespace storm { namespace analysis { @@ -50,22 +50,22 @@ namespace storm { AssumptionStatus checkOnSamples(std::shared_ptr assumption); /*! - * Tries to validate an assumption based on the lattice and underlying transition matrix. + * Tries to validate an assumption based on the order and underlying transition matrix. * * @param assumption The assumption to validate. - * @param lattice The lattice. + * @param order The order. * @return AssumptionStatus::VALID, or AssumptionStatus::UNKNOWN, or AssumptionStatus::INVALID */ - AssumptionStatus validateAssumption(std::shared_ptr assumption, Lattice* lattice); + AssumptionStatus validateAssumption(std::shared_ptr assumption, Order* order); /*! - * Tries to validate an assumption based on the lattice, and SMT solving techniques + * Tries to validate an assumption based on the order, and SMT solving techniques * * @param assumption The assumption to validate. - * @param lattice The lattice. + * @param order The order. * @return AssumptionStatus::VALID, or AssumptionStatus::UNKNOWN, or AssumptionStatus::INVALID */ - AssumptionStatus validateAssumptionSMTSolver(std::shared_ptr assumption, Lattice* lattice); + AssumptionStatus validateAssumptionSMTSolver(std::shared_ptr assumption, Order* order); private: std::shared_ptr formula; @@ -76,7 +76,7 @@ namespace storm { void createSamples(); - AssumptionStatus validateAssumptionFunction(Lattice* lattice, + AssumptionStatus validateAssumptionFunction(Order* order, typename storage::SparseMatrix::iterator state1succ1, typename storage::SparseMatrix::iterator state1succ2, typename storage::SparseMatrix::iterator state2succ1, diff --git a/src/storm-pars/analysis/AssumptionMaker.cpp b/src/storm-pars/analysis/AssumptionMaker.cpp index 78cebe88e..d889e3f13 100644 --- a/src/storm-pars/analysis/AssumptionMaker.cpp +++ b/src/storm-pars/analysis/AssumptionMaker.cpp @@ -16,7 +16,7 @@ namespace storm { template - std::map, AssumptionStatus> AssumptionMaker::createAndCheckAssumption(uint_fast64_t val1, uint_fast64_t val2, Lattice* lattice) { + std::map, AssumptionStatus> AssumptionMaker::createAndCheckAssumption(uint_fast64_t val1, uint_fast64_t val2, Order* order) { std::map, AssumptionStatus> result; expressions::Variable var1 = expressionManager->getVariable(std::to_string(val1)); @@ -29,7 +29,7 @@ namespace storm { AssumptionStatus result2; AssumptionStatus result3; if (validate) { - result1 = assumptionChecker->validateAssumption(assumption1, lattice); + result1 = assumptionChecker->validateAssumption(assumption1, order); } else { result1 = AssumptionStatus::UNKNOWN; } @@ -42,7 +42,7 @@ namespace storm { expressions::BinaryRelationExpression::RelationType::Greater)); if (validate) { - result2 = assumptionChecker->validateAssumption(assumption2, lattice); + result2 = assumptionChecker->validateAssumption(assumption2, order); } else { result2 = AssumptionStatus::UNKNOWN; } @@ -53,7 +53,7 @@ namespace storm { var2.getExpression().getBaseExpressionPointer(), var1.getExpression().getBaseExpressionPointer(), expressions::BinaryRelationExpression::RelationType::Equal)); if (validate) { - result3 = assumptionChecker->validateAssumption(assumption3, lattice); + result3 = assumptionChecker->validateAssumption(assumption3, order); } else { result3 = AssumptionStatus::UNKNOWN; } diff --git a/src/storm-pars/analysis/AssumptionMaker.h b/src/storm-pars/analysis/AssumptionMaker.h index 42710fcc6..41643fb5a 100644 --- a/src/storm-pars/analysis/AssumptionMaker.h +++ b/src/storm-pars/analysis/AssumptionMaker.h @@ -2,8 +2,8 @@ #define STORM_ASSUMPTIONMAKER_H #include "AssumptionChecker.h" -#include "Lattice.h" -#include "LatticeExtender.h" +#include "Order.h" +#include "OrderExtender.h" #include "storm/storage/expressions/BinaryRelationExpression.h" #include "storm-pars/utility/ModelInstantiator.h" @@ -16,9 +16,9 @@ namespace storm { typedef std::shared_ptr AssumptionType; public: /*! - * Constructs AssumptionMaker based on the lattice extender, the assumption checker and number of states of the mode + * Constructs AssumptionMaker based on the order extender, the assumption checker and number of states of the mode * - * @param latticeExtender The LatticeExtender which needs the assumptions made by the AssumptionMaker. + * @param orderExtender The OrderExtender which needs the assumptions made by the AssumptionMaker. * @param checker The AssumptionChecker which checks the assumptions at sample points. * @param numberOfStates The number of states of the model. */ @@ -31,10 +31,10 @@ namespace storm { * * @param val1 First state number * @param val2 Second state number - * @param lattice The lattice on which the assumptions are checked + * @param order The order on which the assumptions are checked * @return Map with three assumptions, and the validation */ - std::map, AssumptionStatus> createAndCheckAssumption(uint_fast64_t val1, uint_fast64_t val2, Lattice* lattice); + std::map, AssumptionStatus> createAndCheckAssumption(uint_fast64_t val1, uint_fast64_t val2, Order* order); private: AssumptionChecker* assumptionChecker; diff --git a/src/storm-pars/analysis/LatticeExtender.h b/src/storm-pars/analysis/LatticeExtender.h deleted file mode 100644 index cc4e7370f..000000000 --- a/src/storm-pars/analysis/LatticeExtender.h +++ /dev/null @@ -1,83 +0,0 @@ -#ifndef STORM_LATTICEEXTENDER_H -#define STORM_LATTICEEXTENDER_H - -#include -#include "storm/models/sparse/Dtmc.h" -#include "storm-pars/analysis/Lattice.h" -#include "storm/api/storm.h" -#include "storm-pars/storage/ParameterRegion.h" -#include "storm/storage/StronglyConnectedComponentDecomposition.h" -#include "storm/storage/StronglyConnectedComponent.h" - - - -namespace storm { - namespace analysis { - - - template - class LatticeExtender { - - public: - /*! - * Constructs LatticeExtender which can extend a lattice - * - * @param model The model for which the lattice should be extended. - */ - LatticeExtender(std::shared_ptr> model); - - /*! - * Creates a lattice based on the given formula. - * - * @param formulas The formulas based on which the lattice is created, only the first is used. - * @return A triple with a pointer to the lattice and two states of which the current place in the lattice - * is unknown but needed. When the states have as number the number of states, no states are - * unplaced but needed. - */ - std::tuple toLattice(std::vector> formulas); - - /*! - * Creates a lattice based on the given extremal values. - * - * @return A triple with a pointer to the lattice and two states of which the current place in the lattice - * is unknown but needed. When the states have as number the number of states, no states are - * unplaced but needed. - */ - std::tuple toLattice(std::vector> formulas, std::vector minValues, std::vector maxValues); - - - /*! - * Extends the lattice based on the given assumption. - * - * @param lattice The lattice. - * @param assumption The assumption on states. - * @return A triple with a pointer to the lattice and two states of which the current place in the lattice - * is unknown but needed. When the states have as number the number of states, no states are - * unplaced but needed. - */ - std::tuple extendLattice(storm::analysis::Lattice* lattice, std::shared_ptr assumption = nullptr); - - - private: - std::shared_ptr> model; - - std::map stateMap; - - bool acyclic; - - bool assumptionSeen; - - storm::storage::StronglyConnectedComponentDecomposition sccs; - - storm::storage::SparseMatrix matrix; - - void handleAssumption(Lattice* lattice, std::shared_ptr assumption); - - std::tuple extendAllSuccAdded(Lattice* lattice, uint_fast64_t const & stateNumber, storm::storage::BitVector* successors); - - std::tuple allSuccAdded(Lattice* lattice, uint_fast64_t stateNumber); - }; - } -} - -#endif //STORM_LATTICEEXTENDER_H diff --git a/src/storm-pars/analysis/MonotonicityChecker.cpp b/src/storm-pars/analysis/MonotonicityChecker.cpp index 8565d97d3..1137d8ce1 100644 --- a/src/storm-pars/analysis/MonotonicityChecker.cpp +++ b/src/storm-pars/analysis/MonotonicityChecker.cpp @@ -1,8 +1,8 @@ #include "MonotonicityChecker.h" #include "storm-pars/analysis/AssumptionMaker.h" #include "storm-pars/analysis/AssumptionChecker.h" -#include "storm-pars/analysis/Lattice.h" -#include "storm-pars/analysis/LatticeExtender.h" +#include "storm-pars/analysis/Order.h" +#include "storm-pars/analysis/OrderExtender.h" #include "storm/exceptions/NotSupportedException.h" #include "storm/exceptions/UnexpectedException.h" @@ -64,28 +64,28 @@ namespace storm { region = storm::storage::ParameterRegion(std::move(lowerBoundaries), std::move(upperBoundaries)); } - this->extender = new storm::analysis::LatticeExtender(sparseModel); + this->extender = new storm::analysis::OrderExtender(sparseModel); } template - std::map::type, std::pair>> MonotonicityChecker::checkMonotonicity() { - auto map = createLattice(); + std::map::type, std::pair>> MonotonicityChecker::checkMonotonicity() { + auto map = createOrder(); std::shared_ptr> sparseModel = model->as>(); auto matrix = sparseModel->getTransitionMatrix(); return checkMonotonicity(map, matrix); } template - std::map::type, std::pair>> MonotonicityChecker::checkMonotonicity(std::map>> map, storm::storage::SparseMatrix matrix) { + std::map::type, std::pair>> MonotonicityChecker::checkMonotonicity(std::map>> map, storm::storage::SparseMatrix matrix) { storm::utility::Stopwatch monotonicityCheckWatch(true); - std::map::type, std::pair>> result; + std::map::type, std::pair>> result; outfile.open(filename, std::ios_base::app); if (map.size() == 0) { // Nothing is known outfile << " No assumptions -"; - STORM_PRINT("No valid assumptions, couldn't build a sufficient lattice"); + STORM_PRINT("No valid assumptions, couldn't build a sufficient order"); if (resultCheckOnSamples.size() != 0) { STORM_PRINT("\n" << "Based results on samples"); } else { @@ -107,11 +107,11 @@ namespace storm { } else { auto i = 0; for (auto itr = map.begin(); i < map.size() && itr != map.end(); ++itr) { - auto lattice = itr->first; + auto order = itr->first; - auto addedStates = lattice->getAddedStates()->getNumberOfSetBits(); - assert (addedStates == lattice->getAddedStates()->size()); - std::map::type, std::pair> varsMonotone = analyseMonotonicity(i, lattice, + auto addedStates = order->getAddedStates()->getNumberOfSetBits(); + assert (addedStates == order->getAddedStates()->size()); + std::map::type, std::pair> varsMonotone = analyseMonotonicity(i, order, matrix); auto assumptions = itr->second; @@ -157,8 +157,8 @@ namespace storm { } } result.insert( - std::pair::type, std::pair>>( - lattice, varsMonotone)); + std::pair::type, std::pair>>( + order, varsMonotone)); } ++i; outfile << ";"; @@ -172,11 +172,11 @@ namespace storm { } template - std::map>> MonotonicityChecker::createLattice() { - // Transform to Lattices - storm::utility::Stopwatch latticeWatch(true); + std::map>> MonotonicityChecker::createOrder() { + // Transform to Orders + storm::utility::Stopwatch orderWatch(true); - // Use parameter lifting modelchecker to get initial min/max values for lattice creation + // Use parameter lifting modelchecker to get initial min/max values for order creation storm::modelchecker::SparseDtmcParameterLiftingModelChecker, double> plaModelChecker; std::unique_ptr checkResult; auto env = Environment(); @@ -195,12 +195,12 @@ namespace storm { std::vector minValues = minRes.getValueVector(); std::vector maxValues = maxRes.getValueVector(); - // Create initial lattice - std::tuple criticalTuple = extender->toLattice(formulas, minValues, maxValues); + // Create initial order + std::tuple criticalTuple = extender->toOrder(formulas, minValues, maxValues); // Continue based on not (yet) sorted states - std::map>> result; + std::map>> result; auto val1 = std::get<1>(criticalTuple); auto val2 = std::get<2>(criticalTuple); @@ -208,7 +208,7 @@ namespace storm { std::vector> assumptions; if (val1 == numberOfStates && val2 == numberOfStates) { - result.insert(std::pair>>(std::get<0>(criticalTuple), assumptions)); + result.insert(std::pair>>(std::get<0>(criticalTuple), assumptions)); } else if (val1 != numberOfStates && val2 != numberOfStates) { storm::analysis::AssumptionChecker *assumptionChecker; @@ -223,26 +223,26 @@ namespace storm { "Unable to perform monotonicity analysis on the provided model type."); } auto assumptionMaker = new storm::analysis::AssumptionMaker(assumptionChecker, numberOfStates, validate); - result = extendLatticeWithAssumptions(std::get<0>(criticalTuple), assumptionMaker, val1, val2, assumptions); + result = extendOrderWithAssumptions(std::get<0>(criticalTuple), assumptionMaker, val1, val2, assumptions); } else { assert(false); } - latticeWatch.stop(); + orderWatch.stop(); return result; } template - std::map>> MonotonicityChecker::extendLatticeWithAssumptions(storm::analysis::Lattice* lattice, storm::analysis::AssumptionMaker* assumptionMaker, uint_fast64_t val1, uint_fast64_t val2, std::vector> assumptions) { - std::map>> result; + std::map>> MonotonicityChecker::extendOrderWithAssumptions(storm::analysis::Order* order, storm::analysis::AssumptionMaker* assumptionMaker, uint_fast64_t val1, uint_fast64_t val2, std::vector> assumptions) { + std::map>> result; auto numberOfStates = model->getNumberOfStates(); if (val1 == numberOfStates || val2 == numberOfStates) { assert (val1 == val2); - assert (lattice->getAddedStates()->size() == lattice->getAddedStates()->getNumberOfSetBits()); - result.insert(std::pair>>(lattice, assumptions)); + assert (order->getAddedStates()->size() == order->getAddedStates()->getNumberOfSetBits()); + result.insert(std::pair>>(order, assumptions)); } else { // Make the three assumptions - auto assumptionTriple = assumptionMaker->createAndCheckAssumption(val1, val2, lattice); + auto assumptionTriple = assumptionMaker->createAndCheckAssumption(val1, val2, order); assert (assumptionTriple.size() == 3); auto itr = assumptionTriple.begin(); auto assumption1 = *itr; @@ -252,7 +252,7 @@ namespace storm { auto assumption3 = *itr; if (assumption1.second != AssumptionStatus::INVALID) { - auto latticeCopy = new Lattice(lattice); + auto orderCopy = new Order(order); auto assumptionsCopy = std::vector>(assumptions); if (assumption1.second == AssumptionStatus::UNKNOWN) { @@ -260,9 +260,9 @@ namespace storm { assumptionsCopy.push_back(assumption1.first); } - auto criticalTuple = extender->extendLattice(latticeCopy, assumption1.first); + auto criticalTuple = extender->extendOrder(orderCopy, assumption1.first); if (somewhereMonotonicity(std::get<0>(criticalTuple))) { - auto map = extendLatticeWithAssumptions(std::get<0>(criticalTuple), assumptionMaker, + auto map = extendOrderWithAssumptions(std::get<0>(criticalTuple), assumptionMaker, std::get<1>(criticalTuple), std::get<2>(criticalTuple), assumptionsCopy); result.insert(map.begin(), map.end()); @@ -270,16 +270,16 @@ namespace storm { } if (assumption2.second != AssumptionStatus::INVALID) { - auto latticeCopy = new Lattice(lattice); + auto orderCopy = new Order(order); auto assumptionsCopy = std::vector>(assumptions); if (assumption2.second == AssumptionStatus::UNKNOWN) { assumptionsCopy.push_back(assumption2.first); } - auto criticalTuple = extender->extendLattice(latticeCopy, assumption2.first); + auto criticalTuple = extender->extendOrder(orderCopy, assumption2.first); if (somewhereMonotonicity(std::get<0>(criticalTuple))) { - auto map = extendLatticeWithAssumptions(std::get<0>(criticalTuple), assumptionMaker, + auto map = extendOrderWithAssumptions(std::get<0>(criticalTuple), assumptionMaker, std::get<1>(criticalTuple), std::get<2>(criticalTuple), assumptionsCopy); result.insert(map.begin(), map.end()); @@ -287,14 +287,14 @@ namespace storm { } if (assumption3.second != AssumptionStatus::INVALID) { - // Here we can use the original lattice and assumptions set + // Here we can use the original order and assumptions set if (assumption3.second == AssumptionStatus::UNKNOWN) { assumptions.push_back(assumption3.first); } - auto criticalTuple = extender->extendLattice(lattice, assumption3.first); + auto criticalTuple = extender->extendOrder(order, assumption3.first); if (somewhereMonotonicity(std::get<0>(criticalTuple))) { - auto map = extendLatticeWithAssumptions(std::get<0>(criticalTuple), assumptionMaker, + auto map = extendOrderWithAssumptions(std::get<0>(criticalTuple), assumptionMaker, std::get<1>(criticalTuple), std::get<2>(criticalTuple), assumptions); result.insert(map.begin(), map.end()); @@ -317,7 +317,7 @@ namespace storm { } template - std::map::type, std::pair> MonotonicityChecker::analyseMonotonicity(uint_fast64_t j, storm::analysis::Lattice* lattice, storm::storage::SparseMatrix matrix) { + std::map::type, std::pair> MonotonicityChecker::analyseMonotonicity(uint_fast64_t j, storm::analysis::Order* order, storm::storage::SparseMatrix matrix) { std::map::type, std::pair> varsMonotone; // go over all rows, check for each row local monotonicity @@ -365,8 +365,8 @@ namespace storm { - // Sort the states based on the lattice - auto sortedStates = lattice->sortStates(states); + // Sort the states based on the order + auto sortedStates = order->sortStates(states); if (sortedStates[sortedStates.size() - 1] == matrix.getColumnCount()) { // If the states are not all sorted, we still might obtain some monotonicity for (auto var: vars) { @@ -383,16 +383,16 @@ namespace storm { auto derivative2 = getDerivative(itr2->second, var); auto derivative3 = getDerivative(itr3->second, var); - auto compare = lattice->compare(itr2->first, itr3->first); + auto compare = order->compare(itr2->first, itr3->first); - if (compare == Lattice::ABOVE) { + if (compare == Order::ABOVE) { // As the first state (itr2) is above the second state (itr3) it // is sufficient to look at the derivative of itr2. std::pair mon2; mon2 = checkDerivative(derivative2, region); value->first &= mon2.first; value->second &= mon2.second; - } else if (compare == Lattice::BELOW) { + } else if (compare == Order::BELOW) { // As the second state (itr3) is above the first state (itr2) it // is sufficient to look at the derivative of itr3. std::pair mon3; @@ -400,7 +400,7 @@ namespace storm { mon3 = checkDerivative(derivative3, region); value->first &= mon3.first; value->second &= mon3.second; - } else if (compare == Lattice::SAME) { + } else if (compare == Order::SAME) { // Behaviour doesn't matter, as the states are at the same level. } else { // only if derivatives are the same we can continue @@ -447,7 +447,7 @@ namespace storm { } template - bool MonotonicityChecker::somewhereMonotonicity(Lattice* lattice) { + bool MonotonicityChecker::somewhereMonotonicity(Order* order) { std::shared_ptr> sparseModel = model->as>(); auto matrix = sparseModel->getTransitionMatrix(); @@ -501,16 +501,16 @@ namespace storm { auto derivative2 = getDerivative(itr2->second, var); auto derivative3 = getDerivative(itr3->second, var); - auto compare = lattice->compare(itr2->first, itr3->first); + auto compare = order->compare(itr2->first, itr3->first); - if (compare == Lattice::ABOVE) { + if (compare == Order::ABOVE) { // As the first state (itr2) is above the second state (itr3) it // is sufficient to look at the derivative of itr2. std::pair mon2; mon2 = checkDerivative(derivative2, region); value->first &= mon2.first; value->second &= mon2.second; - } else if (compare == Lattice::BELOW) { + } else if (compare == Order::BELOW) { // As the second state (itr3) is above the first state (itr2) it // is sufficient to look at the derivative of itr3. std::pair mon3; @@ -518,7 +518,7 @@ namespace storm { mon3 = checkDerivative(derivative3, region); value->first &= mon3.first; value->second &= mon3.second; - } else if (compare == Lattice::SAME) { + } else if (compare == Order::SAME) { // Behaviour doesn't matter, as the states are at the same level. } else { // As the relation between the states is unknown, we don't do anything diff --git a/src/storm-pars/analysis/MonotonicityChecker.h b/src/storm-pars/analysis/MonotonicityChecker.h index 0ef738154..5d32ecf70 100644 --- a/src/storm-pars/analysis/MonotonicityChecker.h +++ b/src/storm-pars/analysis/MonotonicityChecker.h @@ -2,8 +2,8 @@ #define STORM_MONOTONICITYCHECKER_H #include -#include "Lattice.h" -#include "LatticeExtender.h" +#include "Order.h" +#include "OrderExtender.h" #include "AssumptionMaker.h" #include "storm/storage/expressions/BinaryRelationExpression.h" #include "storm/storage/expressions/ExpressionManager.h" @@ -41,12 +41,12 @@ namespace storm { /*! * Checks for model and formula as provided in constructor for monotonicity */ - std::map::type, std::pair>> checkMonotonicity(); + std::map::type, std::pair>> checkMonotonicity(); /*! - * Checks if monotonicity can be found in this lattice. Unordered states are not checked + * Checks if monotonicity can be found in this order. Unordered states are not checked */ - bool somewhereMonotonicity(storm::analysis::Lattice* lattice) ; + bool somewhereMonotonicity(storm::analysis::Order* order) ; /*! * Checks if a derivative >=0 or/and <=0 @@ -113,11 +113,11 @@ namespace storm { } private: - std::map::type, std::pair>> checkMonotonicity(std::map>> map, storm::storage::SparseMatrix matrix); + std::map::type, std::pair>> checkMonotonicity(std::map>> map, storm::storage::SparseMatrix matrix); - std::map::type, std::pair> analyseMonotonicity(uint_fast64_t i, Lattice* lattice, storm::storage::SparseMatrix matrix) ; + std::map::type, std::pair> analyseMonotonicity(uint_fast64_t i, Order* order, storm::storage::SparseMatrix matrix) ; - std::map>> createLattice(); + std::map>> createOrder(); std::map::type, std::pair> checkOnSamples(std::shared_ptr> model, uint_fast64_t numberOfSamples); @@ -127,7 +127,7 @@ namespace storm { ValueType getDerivative(ValueType function, typename utility::parametric::VariableType::type var); - std::map>> extendLatticeWithAssumptions(Lattice* lattice, AssumptionMaker* assumptionMaker, uint_fast64_t val1, uint_fast64_t val2, std::vector> assumptions); + std::map>> extendOrderWithAssumptions(Order* order, AssumptionMaker* assumptionMaker, uint_fast64_t val1, uint_fast64_t val2, std::vector> assumptions); std::shared_ptr model; @@ -139,7 +139,7 @@ namespace storm { std::map::type, std::pair> resultCheckOnSamples; - LatticeExtender *extender; + OrderExtender *extender; std::ofstream outfile; diff --git a/src/storm-pars/analysis/Lattice.cpp b/src/storm-pars/analysis/Order.cpp similarity index 81% rename from src/storm-pars/analysis/Lattice.cpp rename to src/storm-pars/analysis/Order.cpp index 3253a7d44..fe8b94233 100644 --- a/src/storm-pars/analysis/Lattice.cpp +++ b/src/storm-pars/analysis/Order.cpp @@ -1,10 +1,10 @@ #include #include -#include "Lattice.h" +#include "Order.h" namespace storm { namespace analysis { - Lattice::Lattice(storm::storage::BitVector* topStates, + Order::Order(storm::storage::BitVector* topStates, storm::storage::BitVector* bottomStates, storm::storage::BitVector* initialMiddleStates, uint_fast64_t numberOfStates, @@ -41,7 +41,7 @@ namespace storm { } } - Lattice::Lattice(uint_fast64_t topState, uint_fast64_t bottomState, uint_fast64_t numberOfStates, std::vector* statesSorted) { + Order::Order(uint_fast64_t topState, uint_fast64_t bottomState, uint_fast64_t numberOfStates, std::vector* statesSorted) { nodes = std::vector(numberOfStates); this->numberOfStates = numberOfStates; @@ -67,13 +67,13 @@ namespace storm { assert (addedStates->getNumberOfSetBits() == 2); } - Lattice::Lattice(Lattice* lattice) { - numberOfStates = lattice->getAddedStates()->size(); + Order::Order(Order* order) { + numberOfStates = order->getAddedStates()->size(); nodes = std::vector(numberOfStates); addedStates = new storm::storage::BitVector(numberOfStates); - this->doneBuilding = lattice->getDoneBuilding(); + this->doneBuilding = order->getDoneBuilding(); - auto oldNodes = lattice->getNodes(); + auto oldNodes = order->getNodes(); // Create nodes for (auto itr = oldNodes.begin(); itr != oldNodes.end(); ++itr) { Node *oldNode = (*itr); @@ -84,14 +84,14 @@ namespace storm { addedStates->set(i); nodes[i] = newNode; } - if (oldNode == lattice->getTop()) { + if (oldNode == order->getTop()) { top = newNode; - } else if (oldNode == lattice->getBottom()) { + } else if (oldNode == order->getBottom()) { bottom = newNode; } } } - assert(*addedStates == *(lattice->getAddedStates())); + assert(*addedStates == *(order->getAddedStates())); // set all states above and below for (auto itr = oldNodes.begin(); itr != oldNodes.end(); ++itr) { @@ -102,11 +102,11 @@ namespace storm { } } - this->statesSorted = lattice->statesSorted; - this->statesToHandle = lattice->statesToHandle; + this->statesSorted = order->statesSorted; + this->statesToHandle = order->statesToHandle; } - void Lattice::addBetween(uint_fast64_t state, Node *above, Node *below) { + void Order::addBetween(uint_fast64_t state, Node *above, Node *below) { assert(!(*addedStates)[state]); assert(compare(above, below) == ABOVE); @@ -122,7 +122,7 @@ namespace storm { addedStates->set(state); } - void Lattice::addBetween(uint_fast64_t state, uint_fast64_t above, uint_fast64_t below) { + void Order::addBetween(uint_fast64_t state, uint_fast64_t above, uint_fast64_t below) { assert(!(*addedStates)[state]); assert(compare(above, below) == ABOVE); @@ -132,19 +132,19 @@ namespace storm { } - void Lattice::addToNode(uint_fast64_t state, Node *node) { + void Order::addToNode(uint_fast64_t state, Node *node) { assert(!(*addedStates)[state]); node->states.insert(state); nodes[state] = node; addedStates->set(state); } - void Lattice::add(uint_fast64_t state) { + void Order::add(uint_fast64_t state) { assert(!(*addedStates)[state]); addBetween(state, top, bottom); } - void Lattice::addRelationNodes(Lattice::Node *above, Lattice::Node * below) { + void Order::addRelationNodes(Order::Node *above, Order::Node * below) { assert (compare(above, below) == UNKNOWN); for (auto const& state : above->states) { below->statesAbove.set(state); @@ -153,15 +153,15 @@ namespace storm { assert (compare(above, below) == ABOVE); } - void Lattice::addRelation(uint_fast64_t above, uint_fast64_t below) { + void Order::addRelation(uint_fast64_t above, uint_fast64_t below) { addRelationNodes(getNode(above), getNode(below)); } - Lattice::NodeComparison Lattice::compare(uint_fast64_t state1, uint_fast64_t state2) { + Order::NodeComparison Order::compare(uint_fast64_t state1, uint_fast64_t state2) { return compare(getNode(state1), getNode(state2)); } - Lattice::NodeComparison Lattice::compare(Node* node1, Node* node2) { + Order::NodeComparison Order::compare(Node* node1, Node* node2) { if (node1 != nullptr && node2 != nullptr) { if (node1 == node2) { return SAME; @@ -194,39 +194,39 @@ namespace storm { } - bool Lattice::contains(uint_fast64_t state) { + bool Order::contains(uint_fast64_t state) { return state >= 0 && state < addedStates->size() && addedStates->get(state); } - Lattice::Node *Lattice::getNode(uint_fast64_t stateNumber) { + Order::Node *Order::getNode(uint_fast64_t stateNumber) { return nodes.at(stateNumber); } - Lattice::Node *Lattice::getTop() { + Order::Node *Order::getTop() { return top; } - Lattice::Node *Lattice::getBottom() { + Order::Node *Order::getBottom() { return bottom; } - std::vector Lattice::getNodes() { + std::vector Order::getNodes() { return nodes; } - storm::storage::BitVector* Lattice::getAddedStates() { + storm::storage::BitVector* Order::getAddedStates() { return addedStates; } - bool Lattice::getDoneBuilding() { + bool Order::getDoneBuilding() { return doneBuilding; } - void Lattice::setDoneBuilding(bool done) { + void Order::setDoneBuilding(bool done) { doneBuilding = done; } - std::vector Lattice::sortStates(storm::storage::BitVector* states) { + std::vector Order::sortStates(storm::storage::BitVector* states) { auto numberOfSetBits = states->getNumberOfSetBits(); auto stateSize = states->size(); auto result = std::vector(numberOfSetBits, stateSize); @@ -273,11 +273,11 @@ namespace storm { return result; } - void Lattice::toString(std::ostream &out) { + void Order::toString(std::ostream &out) { } - bool Lattice::above(Node *node1, Node *node2) { + bool Order::above(Node *node1, Node *node2) { bool found = false; for (auto const& state : node1->states) { found = ((node2->statesAbove))[state]; @@ -304,8 +304,8 @@ namespace storm { return found; } - bool Lattice::above(storm::analysis::Lattice::Node *node1, storm::analysis::Lattice::Node *node2, - storm::analysis::Lattice::Node *nodePrev, storm::storage::BitVector *statesSeen) { + bool Order::above(storm::analysis::Order::Node *node1, storm::analysis::Order::Node *node2, + storm::analysis::Order::Node *nodePrev, storm::storage::BitVector *statesSeen) { bool found = false; for (auto const& state : node1->states) { found = ((node2->statesAbove))[state]; @@ -333,7 +333,7 @@ namespace storm { return found; } - void Lattice::mergeNodes(storm::analysis::Lattice::Node *node1, storm::analysis::Lattice::Node *node2) { + void Order::mergeNodes(storm::analysis::Order::Node *node1, storm::analysis::Order::Node *node2) { // Merges node2 into node 1 // everything above n2 also above n1 node1->statesAbove|=((node2->statesAbove)); @@ -347,7 +347,7 @@ namespace storm { } } - void Lattice::merge(uint_fast64_t var1, uint_fast64_t var2) { + void Order::merge(uint_fast64_t var1, uint_fast64_t var2) { mergeNodes(getNode(var1), getNode(var2)); } } diff --git a/src/storm-pars/analysis/Lattice.h b/src/storm-pars/analysis/Order.h similarity index 82% rename from src/storm-pars/analysis/Lattice.h rename to src/storm-pars/analysis/Order.h index 9de5ed07b..bd5270e30 100644 --- a/src/storm-pars/analysis/Lattice.h +++ b/src/storm-pars/analysis/Order.h @@ -1,5 +1,5 @@ -#ifndef LATTICE_LATTICE_H -#define LATTICE_LATTICE_H +#ifndef ORDER_ORDER_H +#define ORDER_ORDER_H #include #include @@ -12,7 +12,7 @@ namespace storm { namespace analysis { - class Lattice { + class Order { public: /*! @@ -30,35 +30,35 @@ namespace storm { }; /*! - * Constructs a lattice with the given top node and bottom node. + * Constructs an order with the given top node and bottom node. * - * @param topNode The top node of the resulting lattice. - * @param bottomNode The bottom node of the resulting lattice. + * @param topNode The top node of the resulting order. + * @param bottomNode The bottom node of the resulting order. */ - Lattice(storm::storage::BitVector* topStates, + Order(storm::storage::BitVector* topStates, storm::storage::BitVector* bottomStates, storm::storage::BitVector* initialMiddleStates, uint_fast64_t numberOfStates, std::vector* statesSorted); /*! - * Constructs a lattice with the given top state and bottom state. + * Constructs an order with the given top state and bottom state. * - * @param top The top state of the resulting lattice. - * @param bottom The bottom state of the resulting lattice. - * @param numberOfStates Max number of states in endlattice. + * @param top The top state of the resulting order. + * @param bottom The bottom state of the resulting order. + * @param numberOfStates Max number of states in order. */ - Lattice(uint_fast64_t top, + Order(uint_fast64_t top, uint_fast64_t bottom, uint_fast64_t numberOfStates, std::vector* statesSorted); /*! - * Constructs a copy of the given lattice. + * Constructs a copy of the given order. * - * @param lattice The original lattice. + * @param order The original order. */ - Lattice(Lattice* lattice); + Order(Order* order); /*! * Adds a node with the given state below node1 and above node2. @@ -85,39 +85,39 @@ namespace storm { void addToNode(uint_fast64_t state, Node *node); /*! - * Adds state between the top and bottom node of the lattice + * Adds state between the top and bottom node of the order * @param state The given state */ void add(uint_fast64_t state); /*! - * Adds a new relation between two nodes to the lattice - * @param above The node closest to the top Node of the Lattice. - * @param below The node closest to the bottom Node of the Lattice. + * Adds a new relation between two nodes to the order + * @param above The node closest to the top Node of the Order. + * @param below The node closest to the bottom Node of the Order. */ - void addRelationNodes(storm::analysis::Lattice::Node *above, storm::analysis::Lattice::Node * below); + void addRelationNodes(storm::analysis::Order::Node *above, storm::analysis::Order::Node * below); /*! - * Adds a new relation between two states to the lattice - * @param above The state closest to the top Node of the Lattice. - * @param below The state closest to the bottom Node of the Lattice. + * Adds a new relation between two states to the order + * @param above The state closest to the top Node of the Order. + * @param below The state closest to the bottom Node of the Order. */ void addRelation(uint_fast64_t above, uint_fast64_t below); /*! * Compares the level of the nodes of the states. - * Behaviour unknown when one or more of the states doesnot occur at any Node in the Lattice. + * Behaviour unknown when one or more of the states doesnot occur at any Node in the Order. * @param state1 The first state. * @param state2 The second state. * @return SAME if the nodes are on the same level; * ABOVE if the node of the first state is closer to top then the node of the second state; * BELOW if the node of the second state is closer to top then the node of the first state; - * UNKNOWN if it is unclear from the structure of the lattice how the nodes relate. + * UNKNOWN if it is unclear from the structure of the order how the nodes relate. */ - Lattice::NodeComparison compare(uint_fast64_t state1, uint_fast64_t state2); + Order::NodeComparison compare(uint_fast64_t state1, uint_fast64_t state2); /*! - * Check if state is already in lattice + * Check if state is already in order * @param state * @return */ @@ -133,25 +133,25 @@ namespace storm { Node *getNode(uint_fast64_t state); /*! - * Retrieves the top node of the lattice. + * Retrieves the top node of the order. * * @return The top node. */ Node* getTop(); /*! - * Retrieves the bottom node of the lattice. + * Retrieves the bottom node of the order. * * @return The bottom node. */ Node* getBottom(); /*! - * Returns the vector with the nodes of the lattice. + * Returns the vector with the nodes of the order. * Each index in the vector refers to a state. * When the state is not yet added at a node, it will contain the nullptr. * - * @return The vector with nodes of the lattice. + * @return The vector with nodes of the order. */ std::vector getNodes(); @@ -163,13 +163,13 @@ namespace storm { storm::storage::BitVector* getAddedStates(); /*! - * Returns true if done building the lattice. + * Returns true if done building the order. * @return */ bool getDoneBuilding(); /*! - * Compares two nodes in the lattice + * Compares two nodes in the order * @param node1 * @param node2 * @return BELOW, ABOVE, SAME or UNKNOWN @@ -186,12 +186,12 @@ namespace storm { std::vector sortStates(storm::storage::BitVector* states); /*! - * If the lattice is fully build, this can be set to true. + * If the order is fully build, this can be set to true. */ void setDoneBuilding(bool done); /*! - * Prints a string representation of the lattice to the output stream. + * Prints a string representation of the order to the output stream. * * @param out The stream to output to. */ @@ -227,10 +227,10 @@ namespace storm { bool above(Node * node1, Node * node2); - bool above(Node * node1, Node * node2, storm::analysis::Lattice::Node *nodePrev, storm::storage::BitVector *statesSeen); + bool above(Node * node1, Node * node2, storm::analysis::Order::Node *nodePrev, storm::storage::BitVector *statesSeen); bool doneBuilding; }; } } -#endif //LATTICE_LATTICE_H +#endif //ORDER_ORDER_H diff --git a/src/storm-pars/analysis/LatticeExtender.cpp b/src/storm-pars/analysis/OrderExtender.cpp similarity index 70% rename from src/storm-pars/analysis/LatticeExtender.cpp rename to src/storm-pars/analysis/OrderExtender.cpp index b36230492..6662e2757 100644 --- a/src/storm-pars/analysis/LatticeExtender.cpp +++ b/src/storm-pars/analysis/OrderExtender.cpp @@ -2,7 +2,7 @@ // Created by Jip Spel on 28.08.18. // -#include "LatticeExtender.h" +#include "OrderExtender.h" #include "storm/utility/macros.h" #include "storm/utility/graph.h" #include "storm/storage/SparseMatrix.h" @@ -31,7 +31,7 @@ namespace storm { namespace analysis { template - LatticeExtender::LatticeExtender(std::shared_ptr> model) { + OrderExtender::OrderExtender(std::shared_ptr> model) { this->model = model; this->matrix = model->getTransitionMatrix(); this->assumptionSeen = false; @@ -61,7 +61,7 @@ namespace storm { } template - std::tuple LatticeExtender::toLattice(std::vector> formulas) { + std::tuple OrderExtender::toOrder(std::vector> formulas) { STORM_LOG_THROW((++formulas.begin()) == formulas.end(), storm::exceptions::NotSupportedException, "Only one formula allowed for monotonicity analysis"); STORM_LOG_THROW((*(formulas[0])).isProbabilityOperatorFormula() && ((*(formulas[0])).asProbabilityOperatorFormula().getSubformula().isUntilFormula() @@ -90,14 +90,14 @@ namespace storm { STORM_LOG_THROW(topStates.begin() != topStates.end(), storm::exceptions::NotImplementedException, "Formula yields to no 1 states"); STORM_LOG_THROW(bottomStates.begin() != bottomStates.end(), storm::exceptions::NotImplementedException, "Formula yields to no zero states"); - // Transform to Lattice + // Transform to Order auto matrix = this->model->getTransitionMatrix(); auto initialMiddleStates = storm::storage::BitVector(numberOfStates); // Check if MC contains cycles storm::storage::StronglyConnectedComponentDecompositionOptions const options; - // Create the Lattice + // Create the Order if (!acyclic) { for (auto i = 0; i < sccs.size(); ++i) { @@ -121,14 +121,14 @@ namespace storm { } } std::vector statesSorted = storm::utility::graph::getTopologicalSort(matrix); - Lattice *lattice = new Lattice(&topStates, &bottomStates, &initialMiddleStates, numberOfStates, &statesSorted); + Order *order = new Order(&topStates, &bottomStates, &initialMiddleStates, numberOfStates, &statesSorted); - return this->extendLattice(lattice); + return this->extendOrder(order); } template - std::tuple LatticeExtender::toLattice(std::vector> formulas, std::vector minValues, std::vector maxValues) { + std::tuple OrderExtender::toOrder(std::vector> formulas, std::vector minValues, std::vector maxValues) { uint_fast64_t numberOfStates = this->model->getNumberOfStates(); // Compare min/max for all states @@ -159,12 +159,12 @@ namespace storm { uint_fast64_t bottom = bottomStates.getNextSetIndex(0); uint_fast64_t top = topStates.getNextSetIndex(0); std::vector statesSorted = storm::utility::graph::getTopologicalSort(matrix); - Lattice *lattice = new Lattice(top, bottom, numberOfStates, &statesSorted); + Order *order = new Order(top, bottom, numberOfStates, &statesSorted); - for (auto state : *(lattice->statesSorted)) { + for (auto state : *(order->statesSorted)) { if (state != bottom && state != top) { - assert (lattice != nullptr); + assert (order != nullptr); auto successors = stateMap[state]; if (successors->size() > 1) { uint_fast64_t min = numberOfStates; @@ -190,32 +190,32 @@ namespace storm { } if (allSorted && min != max) { - if (lattice->contains(min) && lattice->contains(max)) { - assert (lattice->compare(min,max) == Lattice::UNKNOWN || lattice->compare(min,max) == Lattice::BELOW); - if (lattice->compare(min, max) == Lattice::UNKNOWN) { - lattice->addRelation(max, min); + if (order->contains(min) && order->contains(max)) { + assert (order->compare(min,max) == Order::UNKNOWN || order->compare(min,max) == Order::BELOW); + if (order->compare(min, max) == Order::UNKNOWN) { + order->addRelation(max, min); } } - if (!lattice->contains(min)) { - if (lattice->contains(max)) { - lattice->addBetween(min, lattice->getNode(max), lattice->getBottom()); + if (!order->contains(min)) { + if (order->contains(max)) { + order->addBetween(min, order->getNode(max), order->getBottom()); } else { - lattice->add(min); + order->add(min); } } - if (!lattice->contains(max)) { - // Because of construction min is in the lattice - lattice->addBetween(max, lattice->getNode(min), lattice->getTop()); + if (!order->contains(max)) { + // Because of construction min is in the order + order->addBetween(max, order->getNode(min), order->getTop()); } - assert (lattice->compare(max, min) == Lattice::ABOVE); - lattice->addBetween(state, max, min); + assert (order->compare(max, min) == Order::ABOVE); + order->addBetween(state, max, min); } } } } // Handle sccs - auto addedStates = lattice->getAddedStates(); + auto addedStates = order->getAddedStates(); for (auto scc : sccs) { if (scc.size() > 1) { auto states = scc.getStates(); @@ -224,7 +224,7 @@ namespace storm { if (addedStates->get(state)) { candidate = -1; break; - // if there is a state of the scc already present in the lattice, there is no need to add one. + // if there is a state of the scc already present in the order, there is no need to add one. } auto successors = stateMap[state]; if (candidate == -1 && successors->getNumberOfSetBits() == 2) { @@ -236,17 +236,17 @@ namespace storm { } } if (candidate != -1) { - lattice->add(candidate); - lattice->statesToHandle->set(candidate); + order->add(candidate); + order->statesToHandle->set(candidate); } } } - return this->extendLattice(lattice); + return this->extendOrder(order); } template - void LatticeExtender::handleAssumption(Lattice* lattice, std::shared_ptr assumption) { + void OrderExtender::handleAssumption(Order* order, std::shared_ptr assumption) { assert (assumption != nullptr); assumptionSeen = true; @@ -260,21 +260,21 @@ namespace storm { storm::expressions::Variable var2 = expr.getSecondOperand()->asVariableExpression().getVariable(); auto val1 = std::stoul(var1.getName(), nullptr, 0); auto val2 = std::stoul(var2.getName(), nullptr, 0); - auto comp = lattice->compare(val1, val2); + auto comp = order->compare(val1, val2); - assert (comp == Lattice::UNKNOWN); - Lattice::Node *n1 = lattice->getNode(val1); - Lattice::Node *n2 = lattice->getNode(val2); + assert (comp == Order::UNKNOWN); + Order::Node *n1 = order->getNode(val1); + Order::Node *n2 = order->getNode(val2); if (n1 != nullptr && n2 != nullptr) { - lattice->mergeNodes(n1,n2); + order->mergeNodes(n1,n2); } else if (n1 != nullptr) { - lattice->addToNode(val2, n1); + order->addToNode(val2, n1); } else if (n2 != nullptr) { - lattice->addToNode(val1, n2); + order->addToNode(val1, n2); } else { - lattice->add(val1); - lattice->addToNode(val2, lattice->getNode(val1)); + order->add(val1); + order->addToNode(val2, order->getNode(val1)); } } else { assert (expr.getFirstOperand()->isVariable() && expr.getSecondOperand()->isVariable()); @@ -282,59 +282,59 @@ namespace storm { storm::expressions::Variable smallest = expr.getSecondOperand()->asVariableExpression().getVariable(); auto val1 = std::stoul(largest.getName(), nullptr, 0); auto val2 = std::stoul(smallest.getName(), nullptr, 0); - auto compareRes = lattice->compare(val1, val2); + auto compareRes = order->compare(val1, val2); - assert(compareRes == Lattice::UNKNOWN); - Lattice::Node *n1 = lattice->getNode(val1); - Lattice::Node *n2 = lattice->getNode(val2); + assert(compareRes == Order::UNKNOWN); + Order::Node *n1 = order->getNode(val1); + Order::Node *n2 = order->getNode(val2); if (n1 != nullptr && n2 != nullptr) { - lattice->addRelationNodes(n1, n2); + order->addRelationNodes(n1, n2); } else if (n1 != nullptr) { - lattice->addBetween(val2, n1, lattice->getBottom()); + order->addBetween(val2, n1, order->getBottom()); } else if (n2 != nullptr) { - lattice->addBetween(val1, lattice->getTop(), n2); + order->addBetween(val1, order->getTop(), n2); } else { - lattice->add(val1); - lattice->addBetween(val2, lattice->getNode(val1), lattice->getBottom()); + order->add(val1); + order->addBetween(val2, order->getNode(val1), order->getBottom()); } } } template - std::tuple LatticeExtender::extendAllSuccAdded(Lattice* lattice, uint_fast64_t const & stateNumber, storm::storage::BitVector* successors) { + std::tuple OrderExtender::extendAllSuccAdded(Order* order, uint_fast64_t const & stateNumber, storm::storage::BitVector* successors) { auto numberOfStates = successors->size(); - assert (lattice->getAddedStates()->size() == numberOfStates); + assert (order->getAddedStates()->size() == numberOfStates); if (successors->getNumberOfSetBits() == 1) { // As there is only one successor the current state and its successor must be at the same nodes. - lattice->addToNode(stateNumber, lattice->getNode(successors->getNextSetIndex(0))); + order->addToNode(stateNumber, order->getNode(successors->getNextSetIndex(0))); } else if (successors->getNumberOfSetBits() == 2) { // Otherwise, check how the two states compare, and add if the comparison is possible. uint_fast64_t successor1 = successors->getNextSetIndex(0); uint_fast64_t successor2 = successors->getNextSetIndex(successor1 + 1); - int compareResult = lattice->compare(successor1, successor2); - if (compareResult == Lattice::ABOVE) { + int compareResult = order->compare(successor1, successor2); + if (compareResult == Order::ABOVE) { // successor 1 is closer to top than successor 2 - lattice->addBetween(stateNumber, lattice->getNode(successor1), - lattice->getNode(successor2)); - } else if (compareResult == Lattice::BELOW) { + order->addBetween(stateNumber, order->getNode(successor1), + order->getNode(successor2)); + } else if (compareResult == Order::BELOW) { // successor 2 is closer to top than successor 1 - lattice->addBetween(stateNumber, lattice->getNode(successor2), - lattice->getNode(successor1)); - } else if (compareResult == Lattice::SAME) { + order->addBetween(stateNumber, order->getNode(successor2), + order->getNode(successor1)); + } else if (compareResult == Order::SAME) { // the successors are at the same level - lattice->addToNode(stateNumber, lattice->getNode(successor1)); + order->addToNode(stateNumber, order->getNode(successor1)); } else { - assert(lattice->compare(successor1, successor2) == Lattice::UNKNOWN); - return std::make_tuple(lattice, successor1, successor2); + assert(order->compare(successor1, successor2) == Order::UNKNOWN); + return std::make_tuple(order, successor1, successor2); } } else if (successors->getNumberOfSetBits() > 2) { for (auto const& i : *successors) { for (auto j = successors->getNextSetIndex(i+1); j < numberOfStates; j = successors->getNextSetIndex(j+1)) { - if (lattice->compare(i,j) == Lattice::UNKNOWN) { - return std::make_tuple(lattice, i, j); + if (order->compare(i,j) == Order::UNKNOWN) { + return std::make_tuple(order, i, j); } } } @@ -342,53 +342,53 @@ namespace storm { auto highest = successors->getNextSetIndex(0); auto lowest = highest; for (auto i = successors->getNextSetIndex(highest+1); i < numberOfStates; i = successors->getNextSetIndex(i+1)) { - if (lattice->compare(i, highest) == Lattice::ABOVE) { + if (order->compare(i, highest) == Order::ABOVE) { highest = i; } - if (lattice->compare(lowest, i) == Lattice::ABOVE) { + if (order->compare(lowest, i) == Order::ABOVE) { lowest = i; } } if (lowest == highest) { - lattice->addToNode(stateNumber, lattice->getNode(highest)); + order->addToNode(stateNumber, order->getNode(highest)); } else { - lattice->addBetween(stateNumber, lattice->getNode(highest), lattice->getNode(lowest)); + order->addBetween(stateNumber, order->getNode(highest), order->getNode(lowest)); } } - return std::make_tuple(lattice, numberOfStates, numberOfStates); + return std::make_tuple(order, numberOfStates, numberOfStates); } template - std::tuple LatticeExtender::extendLattice(Lattice* lattice, std::shared_ptr assumption) { + std::tuple OrderExtender::extendOrder(Order* order, std::shared_ptr assumption) { auto numberOfStates = this->model->getNumberOfStates(); if (assumption != nullptr) { - handleAssumption(lattice, assumption); + handleAssumption(order, assumption); } - auto statesSorted = lattice->statesSorted; + auto statesSorted = order->statesSorted; auto oldNumberSet = numberOfStates; - while (oldNumberSet != lattice->getAddedStates()->getNumberOfSetBits()) { - oldNumberSet = lattice->getAddedStates()->getNumberOfSetBits(); + while (oldNumberSet != order->getAddedStates()->getNumberOfSetBits()) { + oldNumberSet = order->getAddedStates()->getNumberOfSetBits(); // Forward reasoning for cycles; if (!acyclic) { - auto statesToHandle = lattice->statesToHandle; + auto statesToHandle = order->statesToHandle; auto stateNumber = statesToHandle->getNextSetIndex(0); while (stateNumber != numberOfStates) { storm::storage::BitVector *successors = stateMap[stateNumber]; - // Checking for states which are already added to the lattice, and only have one successor left which haven't been added yet + // Checking for states which are already added to the order, and only have one successor left which haven't been added yet auto succ1 = successors->getNextSetIndex(0); auto succ2 = successors->getNextSetIndex(succ1 + 1); - assert (lattice->contains(stateNumber)); + assert (order->contains(stateNumber)); if (successors->getNumberOfSetBits() == 1) { - if (!lattice->contains(succ1)) { - lattice->addToNode(succ1, lattice->getNode(stateNumber)); + if (!order->contains(succ1)) { + order->addToNode(succ1, order->getNode(stateNumber)); statesToHandle->set(succ1, true); auto itr = std::find(statesSorted->begin(), statesSorted->end(), succ1); if (itr != statesSorted->end()) { @@ -398,29 +398,29 @@ namespace storm { statesToHandle->set(stateNumber, false); stateNumber = statesToHandle->getNextSetIndex(0); } else if (successors->getNumberOfSetBits() == 2 - && ((lattice->contains(succ1) && !lattice->contains(succ2)) - || (!lattice->contains(succ1) && lattice->contains(succ2)))) { + && ((order->contains(succ1) && !order->contains(succ2)) + || (!order->contains(succ1) && order->contains(succ2)))) { - if (!lattice->contains(succ1)) { + if (!order->contains(succ1)) { std::swap(succ1, succ2); } - auto compare = lattice->compare(stateNumber, succ1); - if (compare == Lattice::ABOVE) { + auto compare = order->compare(stateNumber, succ1); + if (compare == Order::ABOVE) { auto itr = std::find(statesSorted->begin(), statesSorted->end(), succ2); if (itr != statesSorted->end()) { statesSorted->erase(itr); } - lattice->addBetween(succ2, lattice->getTop(), lattice->getNode(stateNumber)); + order->addBetween(succ2, order->getTop(), order->getNode(stateNumber)); statesToHandle->set(succ2); statesToHandle->set(stateNumber, false); stateNumber = statesToHandle->getNextSetIndex(0); - } else if (compare == Lattice::BELOW) { + } else if (compare == Order::BELOW) { auto itr = std::find(statesSorted->begin(), statesSorted->end(), succ2); if (itr != statesSorted->end()) { statesSorted->erase(itr); } - lattice->addBetween(succ2, lattice->getNode(stateNumber), lattice->getBottom()); + order->addBetween(succ2, order->getNode(stateNumber), order->getBottom()); statesToHandle->set(succ2); statesToHandle->set(stateNumber, false); stateNumber = statesToHandle->getNextSetIndex(0); @@ -430,8 +430,8 @@ namespace storm { stateNumber = statesToHandle->getNextSetIndex(0); } - } else if (!((lattice->contains(succ1) && !lattice->contains(succ2)) - || (!lattice->contains(succ1) && lattice->contains(succ2)))) { + } else if (!((order->contains(succ1) && !order->contains(succ2)) + || (!order->contains(succ1) && order->contains(succ2)))) { stateNumber = statesToHandle->getNextSetIndex(stateNumber + 1); } else { statesToHandle->set(stateNumber, false); @@ -444,56 +444,56 @@ namespace storm { // Normal backwardreasoning if (statesSorted->size() > 0) { auto stateNumber = *(statesSorted->begin()); - while (lattice->contains(stateNumber) && statesSorted->size() > 1) { + while (order->contains(stateNumber) && statesSorted->size() > 1) { // states.size()>1 such that there is at least one state left after erase statesSorted->erase(statesSorted->begin()); stateNumber = *(statesSorted->begin()); - if (lattice->contains(stateNumber)) { - auto resAllAdded = allSuccAdded(lattice, stateNumber); + if (order->contains(stateNumber)) { + auto resAllAdded = allSuccAdded(order, stateNumber); if (!std::get<0>(resAllAdded)) { - return std::make_tuple(lattice, std::get<1>(resAllAdded), std::get<2>(resAllAdded)); + return std::make_tuple(order, std::get<1>(resAllAdded), std::get<2>(resAllAdded)); } } } - if (!lattice->contains(stateNumber)) { + if (!order->contains(stateNumber)) { auto successors = stateMap[stateNumber]; - auto result = extendAllSuccAdded(lattice, stateNumber, successors); + auto result = extendAllSuccAdded(order, stateNumber, successors); if (std::get<1>(result) != numberOfStates) { // So we don't know the relation between all successor states return result; } else { - assert (lattice->getNode(stateNumber) != nullptr); + assert (order->getNode(stateNumber) != nullptr); if (!acyclic) { - lattice->statesToHandle->set(stateNumber); + order->statesToHandle->set(stateNumber); } statesSorted->erase(statesSorted->begin()); } } - assert (lattice->getNode(stateNumber) != nullptr); - assert (lattice->contains(stateNumber)); + assert (order->getNode(stateNumber) != nullptr); + assert (order->contains(stateNumber)); } } - assert (lattice->getAddedStates()->getNumberOfSetBits() == numberOfStates); - lattice->setDoneBuilding(true); - return std::make_tuple(lattice, numberOfStates, numberOfStates); + assert (order->getAddedStates()->getNumberOfSetBits() == numberOfStates); + order->setDoneBuilding(true); + return std::make_tuple(order, numberOfStates, numberOfStates); } template - std::tuple LatticeExtender::allSuccAdded(storm::analysis::Lattice *lattice, uint_fast64_t stateNumber) { + std::tuple OrderExtender::allSuccAdded(storm::analysis::Order *order, uint_fast64_t stateNumber) { auto successors = stateMap[stateNumber]; auto numberOfStates = successors->size(); if (successors->getNumberOfSetBits() == 1) { auto succ = successors->getNextSetIndex(0); - return std::make_tuple(lattice->contains(succ), succ, succ); + return std::make_tuple(order->contains(succ), succ, succ); } else if (successors->getNumberOfSetBits() > 2) { for (auto const& i : *successors) { for (auto j = successors->getNextSetIndex(i+1); j < numberOfStates; j = successors->getNextSetIndex(j+1)) { - if (lattice->compare(i,j) == Lattice::UNKNOWN) { + if (order->compare(i,j) == Order::UNKNOWN) { return std::make_tuple(false, i, j); } } @@ -503,6 +503,6 @@ namespace storm { } - template class LatticeExtender; + template class OrderExtender; } } diff --git a/src/storm-pars/analysis/OrderExtender.h b/src/storm-pars/analysis/OrderExtender.h new file mode 100644 index 000000000..30d3d4137 --- /dev/null +++ b/src/storm-pars/analysis/OrderExtender.h @@ -0,0 +1,83 @@ +#ifndef STORM_LATTICEEXTENDER_H +#define STORM_LATTICEEXTENDER_H + +#include +#include "storm/models/sparse/Dtmc.h" +#include "storm-pars/analysis/Order.h" +#include "storm/api/storm.h" +#include "storm-pars/storage/ParameterRegion.h" +#include "storm/storage/StronglyConnectedComponentDecomposition.h" +#include "storm/storage/StronglyConnectedComponent.h" + + + +namespace storm { + namespace analysis { + + + template + class OrderExtender { + + public: + /*! + * Constructs OrderExtender which can extend an order + * + * @param model The model for which the order should be extended. + */ + OrderExtender(std::shared_ptr> model); + + /*! + * Creates an order based on the given formula. + * + * @param formulas The formulas based on which the order is created, only the first is used. + * @return A triple with a pointer to the order and two states of which the current place in the order + * is unknown but needed. When the states have as number the number of states, no states are + * unplaced but needed. + */ + std::tuple toOrder(std::vector> formulas); + + /*! + * Creates an order based on the given extremal values. + * + * @return A triple with a pointer to the order and two states of which the current place in the order + * is unknown but needed. When the states have as number the number of states, no states are + * unplaced but needed. + */ + std::tuple toOrder(std::vector> formulas, std::vector minValues, std::vector maxValues); + + + /*! + * Extends the order based on the given assumption. + * + * @param order The order. + * @param assumption The assumption on states. + * @return A triple with a pointer to the order and two states of which the current place in the order + * is unknown but needed. When the states have as number the number of states, no states are + * unplaced but needed. + */ + std::tuple extendOrder(storm::analysis::Order* order, std::shared_ptr assumption = nullptr); + + + private: + std::shared_ptr> model; + + std::map stateMap; + + bool acyclic; + + bool assumptionSeen; + + storm::storage::StronglyConnectedComponentDecomposition sccs; + + storm::storage::SparseMatrix matrix; + + void handleAssumption(Order* order, std::shared_ptr assumption); + + std::tuple extendAllSuccAdded(Order* order, uint_fast64_t const & stateNumber, storm::storage::BitVector* successors); + + std::tuple allSuccAdded(Order* order, uint_fast64_t stateNumber); + }; + } +} + +#endif //STORM_ORDEREXTENDER_H diff --git a/src/test/storm-pars/analysis/AssumptionCheckerTest.cpp b/src/test/storm-pars/analysis/AssumptionCheckerTest.cpp index 987ef4ef7..e08e4287e 100644 --- a/src/test/storm-pars/analysis/AssumptionCheckerTest.cpp +++ b/src/test/storm-pars/analysis/AssumptionCheckerTest.cpp @@ -13,7 +13,7 @@ #include "storm/api/builder.h" #include "storm-pars/analysis/AssumptionChecker.h" -#include "storm-pars/analysis/Lattice.h" +#include "storm-pars/analysis/Order.h" #include "storm/storage/expressions/BinaryRelationExpression.h" #include "storm-pars/transformer/SparseParametricDtmcSimplifier.h" #include "storm-pars/storage/ParameterRegion.h" @@ -90,9 +90,9 @@ TEST(AssumptionCheckerTest, Brp_no_bisimulation) { std::vector statesSorted = storm::utility::graph::getTopologicalSort(model->getTransitionMatrix()); - auto dummyLattice = new storm::analysis::Lattice(&above, &below, &initialMiddle, 8, &statesSorted); + auto dummyOrder = new storm::analysis::Order(&above, &below, &initialMiddle, 8, &statesSorted); // Validate assumption - EXPECT_EQ(storm::analysis::AssumptionStatus::INVALID, checker.validateAssumption(assumption, dummyLattice)); + EXPECT_EQ(storm::analysis::AssumptionStatus::INVALID, checker.validateAssumption(assumption, dummyOrder)); // EXPECT_FALSE(checker.validated(assumption)); expressionManager->declareRationalVariable("6"); @@ -108,9 +108,9 @@ TEST(AssumptionCheckerTest, Brp_no_bisimulation) { below.set(9); initialMiddle = storm::storage::BitVector(13); - dummyLattice = new storm::analysis::Lattice(&above, &below, &initialMiddle, 13, &statesSorted); + dummyOrder = new storm::analysis::Order(&above, &below, &initialMiddle, 13, &statesSorted); EXPECT_EQ(storm::analysis::AssumptionStatus::INVALID, checker.checkOnSamples(assumption)); - EXPECT_EQ(storm::analysis::AssumptionStatus::INVALID, checker.validateAssumption(assumption, dummyLattice)); + EXPECT_EQ(storm::analysis::AssumptionStatus::INVALID, checker.validateAssumption(assumption, dummyOrder)); // EXPECT_EQ(checker.validated(assumption)); // EXPECT_FALSE(checker.valid(assumption)); } @@ -204,7 +204,7 @@ TEST(AssumptionCheckerTest, Simple2) { std::vector statesSorted = storm::utility::graph::getTopologicalSort(model->getTransitionMatrix()); - auto lattice = new storm::analysis::Lattice(&above, &below, &initialMiddle, 5, &statesSorted); + auto order = new storm::analysis::Order(&above, &below, &initialMiddle, 5, &statesSorted); // Checking on samples and validate auto assumption = std::make_shared( @@ -213,7 +213,7 @@ TEST(AssumptionCheckerTest, Simple2) { expressionManager->getVariable("2").getExpression().getBaseExpressionPointer(), storm::expressions::BinaryRelationExpression::RelationType::Greater)); EXPECT_EQ(storm::analysis::AssumptionStatus::UNKNOWN, checker.checkOnSamples(assumption)); - EXPECT_EQ(storm::analysis::AssumptionStatus::VALID, checker.validateAssumption(assumption, lattice)); + EXPECT_EQ(storm::analysis::AssumptionStatus::VALID, checker.validateAssumption(assumption, order)); assumption = std::make_shared( storm::expressions::BinaryRelationExpression(*expressionManager, expressionManager->getBooleanType(), @@ -221,7 +221,7 @@ TEST(AssumptionCheckerTest, Simple2) { expressionManager->getVariable("1").getExpression().getBaseExpressionPointer(), storm::expressions::BinaryRelationExpression::RelationType::Greater)); EXPECT_EQ(storm::analysis::AssumptionStatus::INVALID, checker.checkOnSamples(assumption)); - EXPECT_EQ(storm::analysis::AssumptionStatus::INVALID, checker.validateAssumption(assumption, lattice)); + EXPECT_EQ(storm::analysis::AssumptionStatus::INVALID, checker.validateAssumption(assumption, order)); assumption = std::make_shared( @@ -230,7 +230,7 @@ TEST(AssumptionCheckerTest, Simple2) { expressionManager->getVariable("2").getExpression().getBaseExpressionPointer(), storm::expressions::BinaryRelationExpression::RelationType::Equal)); EXPECT_EQ(storm::analysis::AssumptionStatus::INVALID, checker.checkOnSamples(assumption)); - EXPECT_EQ(storm::analysis::AssumptionStatus::INVALID, checker.validateAssumption(assumption, lattice)); + EXPECT_EQ(storm::analysis::AssumptionStatus::INVALID, checker.validateAssumption(assumption, order)); } TEST(AssumptionCheckerTest, Simple3) { @@ -270,8 +270,8 @@ TEST(AssumptionCheckerTest, Simple3) { std::vector statesSorted = storm::utility::graph::getTopologicalSort(model->getTransitionMatrix()); - auto lattice = new storm::analysis::Lattice(&above, &below, &initialMiddle, 6, &statesSorted); - lattice->add(3); + auto order = new storm::analysis::Order(&above, &below, &initialMiddle, 6, &statesSorted); + order->add(3); // Checking on samples and validate auto assumption = std::make_shared( @@ -280,8 +280,8 @@ TEST(AssumptionCheckerTest, Simple3) { expressionManager->getVariable("2").getExpression().getBaseExpressionPointer(), storm::expressions::BinaryRelationExpression::RelationType::Greater)); EXPECT_EQ(storm::analysis::AssumptionStatus::UNKNOWN, checker.checkOnSamples(assumption)); - EXPECT_EQ(storm::analysis::AssumptionStatus::VALID, checker.validateAssumption(assumption, lattice)); - EXPECT_EQ(storm::analysis::AssumptionStatus::VALID, checker.validateAssumptionSMTSolver(assumption, lattice)); + EXPECT_EQ(storm::analysis::AssumptionStatus::VALID, checker.validateAssumption(assumption, order)); + EXPECT_EQ(storm::analysis::AssumptionStatus::VALID, checker.validateAssumptionSMTSolver(assumption, order)); assumption = std::make_shared( storm::expressions::BinaryRelationExpression(*expressionManager, expressionManager->getBooleanType(), @@ -289,8 +289,8 @@ TEST(AssumptionCheckerTest, Simple3) { expressionManager->getVariable("1").getExpression().getBaseExpressionPointer(), storm::expressions::BinaryRelationExpression::RelationType::Greater)); EXPECT_EQ(storm::analysis::AssumptionStatus::INVALID, checker.checkOnSamples(assumption)); - EXPECT_EQ(storm::analysis::AssumptionStatus::INVALID, checker.validateAssumption(assumption, lattice)); - EXPECT_EQ(storm::analysis::AssumptionStatus::INVALID, checker.validateAssumptionSMTSolver(assumption, lattice)); + EXPECT_EQ(storm::analysis::AssumptionStatus::INVALID, checker.validateAssumption(assumption, order)); + EXPECT_EQ(storm::analysis::AssumptionStatus::INVALID, checker.validateAssumptionSMTSolver(assumption, order)); assumption = std::make_shared( storm::expressions::BinaryRelationExpression(*expressionManager, expressionManager->getBooleanType(), @@ -298,8 +298,8 @@ TEST(AssumptionCheckerTest, Simple3) { expressionManager->getVariable("2").getExpression().getBaseExpressionPointer(), storm::expressions::BinaryRelationExpression::RelationType::Equal)); EXPECT_EQ(storm::analysis::AssumptionStatus::INVALID, checker.checkOnSamples(assumption)); - EXPECT_EQ(storm::analysis::AssumptionStatus::INVALID, checker.validateAssumption(assumption, lattice)); - EXPECT_EQ(storm::analysis::AssumptionStatus::INVALID, checker.validateAssumptionSMTSolver(assumption, lattice)); + EXPECT_EQ(storm::analysis::AssumptionStatus::INVALID, checker.validateAssumption(assumption, order)); + EXPECT_EQ(storm::analysis::AssumptionStatus::INVALID, checker.validateAssumptionSMTSolver(assumption, order)); } TEST(AssumptionCheckerTest, Simple4) { @@ -331,7 +331,7 @@ TEST(AssumptionCheckerTest, Simple4) { expressionManager->declareRationalVariable("1"); expressionManager->declareRationalVariable("2"); - // Lattice + // Order storm::storage::BitVector above(5); above.set(3); storm::storage::BitVector below(5); @@ -339,7 +339,7 @@ TEST(AssumptionCheckerTest, Simple4) { storm::storage::BitVector initialMiddle(5); std::vector statesSorted = storm::utility::graph::getTopologicalSort(model->getTransitionMatrix()); - auto lattice = new storm::analysis::Lattice(&above, &below, &initialMiddle, 5, &statesSorted); + auto order = new storm::analysis::Order(&above, &below, &initialMiddle, 5, &statesSorted); auto assumption = std::make_shared( storm::expressions::BinaryRelationExpression(*expressionManager, expressionManager->getBooleanType(), @@ -347,8 +347,8 @@ TEST(AssumptionCheckerTest, Simple4) { expressionManager->getVariable("2").getExpression().getBaseExpressionPointer(), storm::expressions::BinaryRelationExpression::RelationType::Greater)); EXPECT_EQ(storm::analysis::AssumptionStatus::INVALID, checker.checkOnSamples(assumption)); - EXPECT_EQ(storm::analysis::AssumptionStatus::INVALID, checker.validateAssumption(assumption, lattice)); - EXPECT_EQ(storm::analysis::AssumptionStatus::INVALID, checker.validateAssumptionSMTSolver(assumption, lattice)); + EXPECT_EQ(storm::analysis::AssumptionStatus::INVALID, checker.validateAssumption(assumption, order)); + EXPECT_EQ(storm::analysis::AssumptionStatus::INVALID, checker.validateAssumptionSMTSolver(assumption, order)); assumption = std::make_shared( storm::expressions::BinaryRelationExpression(*expressionManager, expressionManager->getBooleanType(), @@ -356,8 +356,8 @@ TEST(AssumptionCheckerTest, Simple4) { expressionManager->getVariable("1").getExpression().getBaseExpressionPointer(), storm::expressions::BinaryRelationExpression::RelationType::Greater)); EXPECT_EQ(storm::analysis::AssumptionStatus::UNKNOWN, checker.checkOnSamples(assumption)); - EXPECT_EQ(storm::analysis::AssumptionStatus::VALID, checker.validateAssumption(assumption, lattice)); - EXPECT_EQ(storm::analysis::AssumptionStatus::VALID, checker.validateAssumptionSMTSolver(assumption, lattice)); + EXPECT_EQ(storm::analysis::AssumptionStatus::VALID, checker.validateAssumption(assumption, order)); + EXPECT_EQ(storm::analysis::AssumptionStatus::VALID, checker.validateAssumptionSMTSolver(assumption, order)); assumption = std::make_shared( storm::expressions::BinaryRelationExpression(*expressionManager, expressionManager->getBooleanType(), @@ -365,8 +365,8 @@ TEST(AssumptionCheckerTest, Simple4) { expressionManager->getVariable("2").getExpression().getBaseExpressionPointer(), storm::expressions::BinaryRelationExpression::RelationType::Equal)); EXPECT_EQ(storm::analysis::AssumptionStatus::INVALID, checker.checkOnSamples(assumption)); - EXPECT_EQ(storm::analysis::AssumptionStatus::INVALID, checker.validateAssumption(assumption, lattice)); - EXPECT_EQ(storm::analysis::AssumptionStatus::INVALID, checker.validateAssumptionSMTSolver(assumption, lattice)); + EXPECT_EQ(storm::analysis::AssumptionStatus::INVALID, checker.validateAssumption(assumption, order)); + EXPECT_EQ(storm::analysis::AssumptionStatus::INVALID, checker.validateAssumptionSMTSolver(assumption, order)); diff --git a/src/test/storm-pars/analysis/AssumptionMakerTest.cpp b/src/test/storm-pars/analysis/AssumptionMakerTest.cpp index 7268d0c5f..7ede1cc08 100644 --- a/src/test/storm-pars/analysis/AssumptionMakerTest.cpp +++ b/src/test/storm-pars/analysis/AssumptionMakerTest.cpp @@ -17,10 +17,10 @@ #include "storm/storage/expressions/ExpressionManager.h" #include "storm/api/builder.h" -#include "storm-pars/analysis/Lattice.h" +#include "storm-pars/analysis/Order.h" #include "storm-pars/analysis/AssumptionMaker.h" #include "storm-pars/analysis/AssumptionChecker.h" -#include "storm-pars/analysis/LatticeExtender.h" +#include "storm-pars/analysis/OrderExtender.h" #include "storm-pars/transformer/SparseParametricDtmcSimplifier.h" #include "storm-pars/api/storm-pars.h" @@ -51,8 +51,8 @@ TEST(AssumptionMakerTest, Brp_without_bisimulation) { ASSERT_EQ(dtmc->getNumberOfStates(), 193ull); ASSERT_EQ(dtmc->getNumberOfTransitions(), 383ull); - auto *extender = new storm::analysis::LatticeExtender(dtmc); - auto criticalTuple = extender->toLattice(formulas); + auto *extender = new storm::analysis::OrderExtender(dtmc); + auto criticalTuple = extender->toOrder(formulas); ASSERT_EQ(183, std::get<1>(criticalTuple)); ASSERT_EQ(186, std::get<2>(criticalTuple)); @@ -121,8 +121,8 @@ TEST(AssumptionMakerTest, Brp_without_bisimulation_no_validation) { ASSERT_EQ(dtmc->getNumberOfStates(), 193ull); ASSERT_EQ(dtmc->getNumberOfTransitions(), 383ull); - auto *extender = new storm::analysis::LatticeExtender(dtmc); - auto criticalTuple = extender->toLattice(formulas); + auto *extender = new storm::analysis::OrderExtender(dtmc); + auto criticalTuple = extender->toOrder(formulas); ASSERT_EQ(183, std::get<1>(criticalTuple)); ASSERT_EQ(186, std::get<2>(criticalTuple)); @@ -198,11 +198,11 @@ TEST(AssumptionMakerTest, Simple1) { storm::storage::BitVector initialMiddle(5); std::vector statesSorted = storm::utility::graph::getTopologicalSort(model->getTransitionMatrix()); - auto lattice = new storm::analysis::Lattice(&above, &below, &initialMiddle, 5, &statesSorted); + auto order = new storm::analysis::Order(&above, &below, &initialMiddle, 5, &statesSorted); auto assumptionChecker = storm::analysis::AssumptionChecker(formulas[0], dtmc, region, 3); auto assumptionMaker = storm::analysis::AssumptionMaker(&assumptionChecker, dtmc->getNumberOfStates(), true); - auto result = assumptionMaker.createAndCheckAssumption(1, 2, lattice); + auto result = assumptionMaker.createAndCheckAssumption(1, 2, order); EXPECT_EQ(3, result.size()); @@ -271,11 +271,11 @@ TEST(AssumptionMakerTest, Simple2) { std::vector statesSorted = storm::utility::graph::getTopologicalSort(model->getTransitionMatrix()); - auto lattice = new storm::analysis::Lattice(&above, &below, &initialMiddle, 5, &statesSorted); + auto order = new storm::analysis::Order(&above, &below, &initialMiddle, 5, &statesSorted); auto assumptionChecker = storm::analysis::AssumptionChecker(formulas[0], dtmc, region, 3); auto assumptionMaker = storm::analysis::AssumptionMaker(&assumptionChecker, dtmc->getNumberOfStates(), true); - auto result = assumptionMaker.createAndCheckAssumption(1, 2, lattice); + auto result = assumptionMaker.createAndCheckAssumption(1, 2, order); auto itr = result.begin(); diff --git a/src/test/storm-pars/analysis/LatticeTest.cpp b/src/test/storm-pars/analysis/LatticeTest.cpp deleted file mode 100644 index 3b9011b04..000000000 --- a/src/test/storm-pars/analysis/LatticeTest.cpp +++ /dev/null @@ -1,170 +0,0 @@ -#include "gtest/gtest.h" -#include "storm-config.h" -#include "test/storm_gtest.h" -#include "storm-pars/analysis/Lattice.h" -#include "storm/storage/BitVector.h" - -TEST(LatticeTest, Simple) { - auto numberOfStates = 7; - auto above = storm::storage::BitVector(numberOfStates); - above.set(0); - auto below = storm::storage::BitVector(numberOfStates); - below.set(1); - auto initialMiddle = storm::storage::BitVector(numberOfStates); - - auto lattice = storm::analysis::Lattice(&above, &below, &initialMiddle, numberOfStates, nullptr); - EXPECT_EQ(storm::analysis::Lattice::NodeComparison::ABOVE, lattice.compare(0,1)); - EXPECT_EQ(storm::analysis::Lattice::NodeComparison::BELOW, lattice.compare(1,0)); - EXPECT_EQ(nullptr, lattice.getNode(2)); - - lattice.add(2); - EXPECT_EQ(storm::analysis::Lattice::NodeComparison::ABOVE, lattice.compare(0,2)); - EXPECT_EQ(storm::analysis::Lattice::NodeComparison::BELOW, lattice.compare(2,0)); - EXPECT_EQ(storm::analysis::Lattice::NodeComparison::ABOVE, lattice.compare(2,1)); - EXPECT_EQ(storm::analysis::Lattice::NodeComparison::BELOW, lattice.compare(1,2)); - - lattice.add(3); - EXPECT_EQ(storm::analysis::Lattice::NodeComparison::UNKNOWN, lattice.compare(2,3)); - EXPECT_EQ(storm::analysis::Lattice::NodeComparison::UNKNOWN, lattice.compare(3,2)); - - lattice.addToNode(4, lattice.getNode(2)); - EXPECT_EQ(storm::analysis::Lattice::NodeComparison::SAME, lattice.compare(2,4)); - EXPECT_EQ(storm::analysis::Lattice::NodeComparison::SAME, lattice.compare(4,2)); - EXPECT_EQ(storm::analysis::Lattice::NodeComparison::ABOVE, lattice.compare(0,4)); - EXPECT_EQ(storm::analysis::Lattice::NodeComparison::BELOW, lattice.compare(4,0)); - EXPECT_EQ(storm::analysis::Lattice::NodeComparison::ABOVE, lattice.compare(4,1)); - EXPECT_EQ(storm::analysis::Lattice::NodeComparison::BELOW, lattice.compare(1,4)); - EXPECT_EQ(storm::analysis::Lattice::NodeComparison::UNKNOWN, lattice.compare(4,3)); - EXPECT_EQ(storm::analysis::Lattice::NodeComparison::UNKNOWN, lattice.compare(3,4)); - - lattice.addBetween(5, lattice.getNode(0), lattice.getNode(3)); - - EXPECT_EQ(storm::analysis::Lattice::NodeComparison::BELOW, lattice.compare(5,0)); - EXPECT_EQ(storm::analysis::Lattice::NodeComparison::ABOVE, lattice.compare(0,5)); - EXPECT_EQ(storm::analysis::Lattice::NodeComparison::ABOVE, lattice.compare(5,3)); - EXPECT_EQ(storm::analysis::Lattice::NodeComparison::BELOW, lattice.compare(3,5)); - EXPECT_EQ(storm::analysis::Lattice::NodeComparison::ABOVE, lattice.compare(5,1)); - EXPECT_EQ(storm::analysis::Lattice::NodeComparison::BELOW, lattice.compare(1,5)); - EXPECT_EQ(storm::analysis::Lattice::NodeComparison::UNKNOWN, lattice.compare(5,2)); - EXPECT_EQ(storm::analysis::Lattice::NodeComparison::UNKNOWN, lattice.compare(2,5)); - EXPECT_EQ(storm::analysis::Lattice::NodeComparison::UNKNOWN, lattice.compare(5,4)); - EXPECT_EQ(storm::analysis::Lattice::NodeComparison::UNKNOWN, lattice.compare(4,5)); - - lattice.addBetween(6, lattice.getNode(5), lattice.getNode(3)); - EXPECT_EQ(storm::analysis::Lattice::NodeComparison::BELOW, lattice.compare(6,0)); - EXPECT_EQ(storm::analysis::Lattice::NodeComparison::ABOVE, lattice.compare(0,6)); - EXPECT_EQ(storm::analysis::Lattice::NodeComparison::ABOVE, lattice.compare(6,1)); - EXPECT_EQ(storm::analysis::Lattice::NodeComparison::BELOW, lattice.compare(1,6)); - EXPECT_EQ(storm::analysis::Lattice::NodeComparison::UNKNOWN, lattice.compare(6,2)); - EXPECT_EQ(storm::analysis::Lattice::NodeComparison::UNKNOWN, lattice.compare(2,6)); - EXPECT_EQ(storm::analysis::Lattice::NodeComparison::ABOVE, lattice.compare(6,3)); - EXPECT_EQ(storm::analysis::Lattice::NodeComparison::BELOW, lattice.compare(3,6)); - EXPECT_EQ(storm::analysis::Lattice::NodeComparison::UNKNOWN, lattice.compare(6,4)); - EXPECT_EQ(storm::analysis::Lattice::NodeComparison::UNKNOWN, lattice.compare(6,4)); - EXPECT_EQ(storm::analysis::Lattice::NodeComparison::BELOW, lattice.compare(6,5)); - EXPECT_EQ(storm::analysis::Lattice::NodeComparison::ABOVE, lattice.compare(5,6)); - - lattice.addRelationNodes(lattice.getNode(6), lattice.getNode(4)); - EXPECT_EQ(storm::analysis::Lattice::NodeComparison::ABOVE, lattice.compare(6,4)); - EXPECT_EQ(storm::analysis::Lattice::NodeComparison::BELOW, lattice.compare(4,6)); - -} - -TEST(LatticeTest, copy_lattice) { - auto numberOfStates = 7; - auto above = storm::storage::BitVector(numberOfStates); - above.set(0); - auto below = storm::storage::BitVector(numberOfStates); - below.set(1); - auto initialMiddle = storm::storage::BitVector(numberOfStates); - - auto lattice = storm::analysis::Lattice(&above, &below, &initialMiddle, numberOfStates, nullptr); - lattice.add(2); - lattice.add(3); - lattice.addToNode(4, lattice.getNode(2)); - lattice.addBetween(5, lattice.getNode(0), lattice.getNode(3)); - lattice.addBetween(6, lattice.getNode(5), lattice.getNode(3)); - - - - auto latticeCopy = storm::analysis::Lattice(lattice); - EXPECT_EQ(storm::analysis::Lattice::NodeComparison::ABOVE, latticeCopy.compare(0,1)); - EXPECT_EQ(storm::analysis::Lattice::NodeComparison::BELOW, latticeCopy.compare(1,0)); - - EXPECT_EQ(storm::analysis::Lattice::NodeComparison::ABOVE, latticeCopy.compare(0,2)); - EXPECT_EQ(storm::analysis::Lattice::NodeComparison::BELOW, latticeCopy.compare(2,0)); - EXPECT_EQ(storm::analysis::Lattice::NodeComparison::ABOVE, latticeCopy.compare(2,1)); - EXPECT_EQ(storm::analysis::Lattice::NodeComparison::BELOW, latticeCopy.compare(1,2)); - - EXPECT_EQ(storm::analysis::Lattice::NodeComparison::UNKNOWN, latticeCopy.compare(2,3)); - EXPECT_EQ(storm::analysis::Lattice::NodeComparison::UNKNOWN, latticeCopy.compare(3,2)); - - EXPECT_EQ(storm::analysis::Lattice::NodeComparison::SAME, latticeCopy.compare(2,4)); - EXPECT_EQ(storm::analysis::Lattice::NodeComparison::SAME, latticeCopy.compare(4,2)); - EXPECT_EQ(storm::analysis::Lattice::NodeComparison::ABOVE, latticeCopy.compare(0,4)); - EXPECT_EQ(storm::analysis::Lattice::NodeComparison::BELOW, latticeCopy.compare(4,0)); - EXPECT_EQ(storm::analysis::Lattice::NodeComparison::ABOVE, latticeCopy.compare(4,1)); - EXPECT_EQ(storm::analysis::Lattice::NodeComparison::BELOW, latticeCopy.compare(1,4)); - EXPECT_EQ(storm::analysis::Lattice::NodeComparison::UNKNOWN, latticeCopy.compare(4,3)); - EXPECT_EQ(storm::analysis::Lattice::NodeComparison::UNKNOWN, latticeCopy.compare(3,4)); - - EXPECT_EQ(storm::analysis::Lattice::NodeComparison::BELOW, latticeCopy.compare(5,0)); - EXPECT_EQ(storm::analysis::Lattice::NodeComparison::ABOVE, latticeCopy.compare(0,5)); - EXPECT_EQ(storm::analysis::Lattice::NodeComparison::ABOVE, latticeCopy.compare(5,3)); - EXPECT_EQ(storm::analysis::Lattice::NodeComparison::BELOW, latticeCopy.compare(3,5)); - EXPECT_EQ(storm::analysis::Lattice::NodeComparison::ABOVE, latticeCopy.compare(5,1)); - EXPECT_EQ(storm::analysis::Lattice::NodeComparison::BELOW, latticeCopy.compare(1,5)); - EXPECT_EQ(storm::analysis::Lattice::NodeComparison::UNKNOWN, latticeCopy.compare(5,2)); - EXPECT_EQ(storm::analysis::Lattice::NodeComparison::UNKNOWN, latticeCopy.compare(5,2)); - EXPECT_EQ(storm::analysis::Lattice::NodeComparison::UNKNOWN, latticeCopy.compare(5,4)); - EXPECT_EQ(storm::analysis::Lattice::NodeComparison::UNKNOWN, latticeCopy.compare(5,4)); - - lattice.addRelationNodes(lattice.getNode(6), lattice.getNode(4)); - latticeCopy = storm::analysis::Lattice(lattice); - EXPECT_EQ(storm::analysis::Lattice::NodeComparison::BELOW, latticeCopy.compare(6,0)); - EXPECT_EQ(storm::analysis::Lattice::NodeComparison::ABOVE, latticeCopy.compare(0,6)); - EXPECT_EQ(storm::analysis::Lattice::NodeComparison::ABOVE, latticeCopy.compare(6,1)); - EXPECT_EQ(storm::analysis::Lattice::NodeComparison::BELOW, latticeCopy.compare(1,6)); - EXPECT_EQ(storm::analysis::Lattice::NodeComparison::ABOVE, latticeCopy.compare(6,2)); - EXPECT_EQ(storm::analysis::Lattice::NodeComparison::BELOW, latticeCopy.compare(2,6)); - EXPECT_EQ(storm::analysis::Lattice::NodeComparison::ABOVE, latticeCopy.compare(6,3)); - EXPECT_EQ(storm::analysis::Lattice::NodeComparison::BELOW, latticeCopy.compare(3,6)); - EXPECT_EQ(storm::analysis::Lattice::NodeComparison::ABOVE, latticeCopy.compare(6,4)); - EXPECT_EQ(storm::analysis::Lattice::NodeComparison::BELOW, latticeCopy.compare(4,6)); - EXPECT_EQ(storm::analysis::Lattice::NodeComparison::BELOW, latticeCopy.compare(6,5)); - EXPECT_EQ(storm::analysis::Lattice::NodeComparison::ABOVE, latticeCopy.compare(5,6)); -} - -TEST(LatticeTest, merge_nodes) { - auto numberOfStates = 7; - auto above = storm::storage::BitVector(numberOfStates); - above.set(0); - auto below = storm::storage::BitVector(numberOfStates); - below.set(1); - auto initialMiddle = storm::storage::BitVector(numberOfStates); - - auto lattice = storm::analysis::Lattice(&above, &below, &initialMiddle, numberOfStates, nullptr); - lattice.add(2); - lattice.add(3); - lattice.addToNode(4, lattice.getNode(2)); - lattice.addBetween(5, lattice.getNode(0), lattice.getNode(3)); - lattice.addBetween(6, lattice.getNode(5), lattice.getNode(3)); - - lattice.mergeNodes(lattice.getNode(4), lattice.getNode(5)); - EXPECT_EQ(storm::analysis::Lattice::NodeComparison::SAME, lattice.compare(2,4)); - EXPECT_EQ(storm::analysis::Lattice::NodeComparison::SAME, lattice.compare(2,5)); - - EXPECT_EQ(storm::analysis::Lattice::NodeComparison::ABOVE, lattice.compare(0,5)); - EXPECT_EQ(storm::analysis::Lattice::NodeComparison::ABOVE, lattice.compare(0,2)); - EXPECT_EQ(storm::analysis::Lattice::NodeComparison::ABOVE, lattice.compare(0,4)); - - EXPECT_EQ(storm::analysis::Lattice::NodeComparison::BELOW, lattice.compare(6,2)); - EXPECT_EQ(storm::analysis::Lattice::NodeComparison::BELOW, lattice.compare(6,4)); - EXPECT_EQ(storm::analysis::Lattice::NodeComparison::BELOW, lattice.compare(6,5)); - EXPECT_EQ(storm::analysis::Lattice::NodeComparison::BELOW, lattice.compare(3,2)); - EXPECT_EQ(storm::analysis::Lattice::NodeComparison::BELOW, lattice.compare(3,4)); - EXPECT_EQ(storm::analysis::Lattice::NodeComparison::BELOW, lattice.compare(3,5)); - EXPECT_EQ(storm::analysis::Lattice::NodeComparison::BELOW, lattice.compare(1,2)); - EXPECT_EQ(storm::analysis::Lattice::NodeComparison::BELOW, lattice.compare(1,4)); - EXPECT_EQ(storm::analysis::Lattice::NodeComparison::BELOW, lattice.compare(1,5)); -} diff --git a/src/test/storm-pars/analysis/LatticeExtenderTest.cpp b/src/test/storm-pars/analysis/OrderExtenderTest.cpp similarity index 80% rename from src/test/storm-pars/analysis/LatticeExtenderTest.cpp rename to src/test/storm-pars/analysis/OrderExtenderTest.cpp index cda1d7233..e9c0c2115 100644 --- a/src/test/storm-pars/analysis/LatticeExtenderTest.cpp +++ b/src/test/storm-pars/analysis/OrderExtenderTest.cpp @@ -12,8 +12,8 @@ #include "storm/storage/expressions/ExpressionManager.h" #include "storm/api/builder.h" -#include "storm-pars/analysis/Lattice.h" -#include "storm-pars/analysis/LatticeExtender.h" +#include "storm-pars/analysis/Order.h" +#include "storm-pars/analysis/OrderExtender.h" #include "storm-pars/transformer/SparseParametricDtmcSimplifier.h" #include "storm-pars/api/storm-pars.h" @@ -21,7 +21,7 @@ #include "storm-parsers/api/storm-parsers.h" -TEST(LatticeExtenderTest, Brp_with_bisimulation) { +TEST(OrderExtenderTest, Brp_with_bisimulation) { std::string programFile = STORM_TEST_RESOURCES_DIR "/pdtmc/brp16_2.pm"; std::string formulaAsString = "P=? [F s=4 & i=N ]"; std::string constantsAsString = ""; //e.g. pL=0.9,TOACK=0.5 @@ -47,25 +47,25 @@ TEST(LatticeExtenderTest, Brp_with_bisimulation) { ASSERT_EQ(dtmc->getNumberOfStates(), 99ull); ASSERT_EQ(dtmc->getNumberOfTransitions(), 195ull); - auto *extender = new storm::analysis::LatticeExtender(dtmc); - auto criticalTuple = extender->toLattice(formulas); + auto *extender = new storm::analysis::OrderExtender(dtmc); + auto criticalTuple = extender->toOrder(formulas); EXPECT_EQ(dtmc->getNumberOfStates(), std::get<1>(criticalTuple)); EXPECT_EQ(dtmc->getNumberOfStates(), std::get<2>(criticalTuple)); - auto lattice = std::get<0>(criticalTuple); + auto order = std::get<0>(criticalTuple); for (auto i = 0; i < dtmc->getNumberOfStates(); ++i) { - EXPECT_TRUE((*lattice->getAddedStates())[i]); + EXPECT_TRUE((*order->getAddedStates())[i]); } // Check on some nodes - EXPECT_EQ(storm::analysis::Lattice::NodeComparison::ABOVE, lattice->compare(1,0)); - EXPECT_EQ(storm::analysis::Lattice::NodeComparison::ABOVE, lattice->compare(1,5)); - EXPECT_EQ(storm::analysis::Lattice::NodeComparison::ABOVE, lattice->compare(5,0)); - EXPECT_EQ(storm::analysis::Lattice::NodeComparison::ABOVE, lattice->compare(94,5)); - EXPECT_EQ(storm::analysis::Lattice::NodeComparison::UNKNOWN, lattice->compare(7,13)); + EXPECT_EQ(storm::analysis::Order::NodeComparison::ABOVE, order->compare(1,0)); + EXPECT_EQ(storm::analysis::Order::NodeComparison::ABOVE, order->compare(1,5)); + EXPECT_EQ(storm::analysis::Order::NodeComparison::ABOVE, order->compare(5,0)); + EXPECT_EQ(storm::analysis::Order::NodeComparison::ABOVE, order->compare(94,5)); + EXPECT_EQ(storm::analysis::Order::NodeComparison::UNKNOWN, order->compare(7,13)); } -TEST(LatticeExtenderTest, Brp_without_bisimulation) { +TEST(OrderExtenderTest, Brp_without_bisimulation) { std::string programFile = STORM_TEST_RESOURCES_DIR "/pdtmc/brp16_2.pm"; std::string formulaAsString = "P=? [F s=4 & i=N ]"; std::string constantsAsString = ""; //e.g. pL=0.9,TOACK=0.5 @@ -84,8 +84,8 @@ TEST(LatticeExtenderTest, Brp_without_bisimulation) { ASSERT_EQ(dtmc->getNumberOfStates(), 193ull); ASSERT_EQ(dtmc->getNumberOfTransitions(), 383ull); - auto *extender = new storm::analysis::LatticeExtender(dtmc); - auto criticalTuple = extender->toLattice(formulas); + auto *extender = new storm::analysis::OrderExtender(dtmc); + auto criticalTuple = extender->toOrder(formulas); EXPECT_EQ(183, std::get<1>(criticalTuple)); EXPECT_EQ(186, std::get<2>(criticalTuple)); } diff --git a/src/test/storm-pars/analysis/OrderTest.cpp b/src/test/storm-pars/analysis/OrderTest.cpp new file mode 100644 index 000000000..8b712508b --- /dev/null +++ b/src/test/storm-pars/analysis/OrderTest.cpp @@ -0,0 +1,170 @@ +#include "gtest/gtest.h" +#include "storm-config.h" +#include "test/storm_gtest.h" +#include "storm-pars/analysis/Order.h" +#include "storm/storage/BitVector.h" + +TEST(OrderTest, Simple) { + auto numberOfStates = 7; + auto above = storm::storage::BitVector(numberOfStates); + above.set(0); + auto below = storm::storage::BitVector(numberOfStates); + below.set(1); + auto initialMiddle = storm::storage::BitVector(numberOfStates); + + auto order = storm::analysis::Order(&above, &below, &initialMiddle, numberOfStates, nullptr); + EXPECT_EQ(storm::analysis::Order::NodeComparison::ABOVE, order.compare(0,1)); + EXPECT_EQ(storm::analysis::Order::NodeComparison::BELOW, order.compare(1,0)); + EXPECT_EQ(nullptr, order.getNode(2)); + + order.add(2); + EXPECT_EQ(storm::analysis::Order::NodeComparison::ABOVE, order.compare(0,2)); + EXPECT_EQ(storm::analysis::Order::NodeComparison::BELOW, order.compare(2,0)); + EXPECT_EQ(storm::analysis::Order::NodeComparison::ABOVE, order.compare(2,1)); + EXPECT_EQ(storm::analysis::Order::NodeComparison::BELOW, order.compare(1,2)); + + order.add(3); + EXPECT_EQ(storm::analysis::Order::NodeComparison::UNKNOWN, order.compare(2,3)); + EXPECT_EQ(storm::analysis::Order::NodeComparison::UNKNOWN, order.compare(3,2)); + + order.addToNode(4, order.getNode(2)); + EXPECT_EQ(storm::analysis::Order::NodeComparison::SAME, order.compare(2,4)); + EXPECT_EQ(storm::analysis::Order::NodeComparison::SAME, order.compare(4,2)); + EXPECT_EQ(storm::analysis::Order::NodeComparison::ABOVE, order.compare(0,4)); + EXPECT_EQ(storm::analysis::Order::NodeComparison::BELOW, order.compare(4,0)); + EXPECT_EQ(storm::analysis::Order::NodeComparison::ABOVE, order.compare(4,1)); + EXPECT_EQ(storm::analysis::Order::NodeComparison::BELOW, order.compare(1,4)); + EXPECT_EQ(storm::analysis::Order::NodeComparison::UNKNOWN, order.compare(4,3)); + EXPECT_EQ(storm::analysis::Order::NodeComparison::UNKNOWN, order.compare(3,4)); + + order.addBetween(5, order.getNode(0), order.getNode(3)); + + EXPECT_EQ(storm::analysis::Order::NodeComparison::BELOW, order.compare(5,0)); + EXPECT_EQ(storm::analysis::Order::NodeComparison::ABOVE, order.compare(0,5)); + EXPECT_EQ(storm::analysis::Order::NodeComparison::ABOVE, order.compare(5,3)); + EXPECT_EQ(storm::analysis::Order::NodeComparison::BELOW, order.compare(3,5)); + EXPECT_EQ(storm::analysis::Order::NodeComparison::ABOVE, order.compare(5,1)); + EXPECT_EQ(storm::analysis::Order::NodeComparison::BELOW, order.compare(1,5)); + EXPECT_EQ(storm::analysis::Order::NodeComparison::UNKNOWN, order.compare(5,2)); + EXPECT_EQ(storm::analysis::Order::NodeComparison::UNKNOWN, order.compare(2,5)); + EXPECT_EQ(storm::analysis::Order::NodeComparison::UNKNOWN, order.compare(5,4)); + EXPECT_EQ(storm::analysis::Order::NodeComparison::UNKNOWN, order.compare(4,5)); + + order.addBetween(6, order.getNode(5), order.getNode(3)); + EXPECT_EQ(storm::analysis::Order::NodeComparison::BELOW, order.compare(6,0)); + EXPECT_EQ(storm::analysis::Order::NodeComparison::ABOVE, order.compare(0,6)); + EXPECT_EQ(storm::analysis::Order::NodeComparison::ABOVE, order.compare(6,1)); + EXPECT_EQ(storm::analysis::Order::NodeComparison::BELOW, order.compare(1,6)); + EXPECT_EQ(storm::analysis::Order::NodeComparison::UNKNOWN, order.compare(6,2)); + EXPECT_EQ(storm::analysis::Order::NodeComparison::UNKNOWN, order.compare(2,6)); + EXPECT_EQ(storm::analysis::Order::NodeComparison::ABOVE, order.compare(6,3)); + EXPECT_EQ(storm::analysis::Order::NodeComparison::BELOW, order.compare(3,6)); + EXPECT_EQ(storm::analysis::Order::NodeComparison::UNKNOWN, order.compare(6,4)); + EXPECT_EQ(storm::analysis::Order::NodeComparison::UNKNOWN, order.compare(6,4)); + EXPECT_EQ(storm::analysis::Order::NodeComparison::BELOW, order.compare(6,5)); + EXPECT_EQ(storm::analysis::Order::NodeComparison::ABOVE, order.compare(5,6)); + + order.addRelationNodes(order.getNode(6), order.getNode(4)); + EXPECT_EQ(storm::analysis::Order::NodeComparison::ABOVE, order.compare(6,4)); + EXPECT_EQ(storm::analysis::Order::NodeComparison::BELOW, order.compare(4,6)); + +} + +TEST(OrderTest, copy_order) { + auto numberOfStates = 7; + auto above = storm::storage::BitVector(numberOfStates); + above.set(0); + auto below = storm::storage::BitVector(numberOfStates); + below.set(1); + auto initialMiddle = storm::storage::BitVector(numberOfStates); + + auto order = storm::analysis::Order(&above, &below, &initialMiddle, numberOfStates, nullptr); + order.add(2); + order.add(3); + order.addToNode(4, order.getNode(2)); + order.addBetween(5, order.getNode(0), order.getNode(3)); + order.addBetween(6, order.getNode(5), order.getNode(3)); + + + + auto orderCopy = storm::analysis::Order(order); + EXPECT_EQ(storm::analysis::Order::NodeComparison::ABOVE, orderCopy.compare(0,1)); + EXPECT_EQ(storm::analysis::Order::NodeComparison::BELOW, orderCopy.compare(1,0)); + + EXPECT_EQ(storm::analysis::Order::NodeComparison::ABOVE, orderCopy.compare(0,2)); + EXPECT_EQ(storm::analysis::Order::NodeComparison::BELOW, orderCopy.compare(2,0)); + EXPECT_EQ(storm::analysis::Order::NodeComparison::ABOVE, orderCopy.compare(2,1)); + EXPECT_EQ(storm::analysis::Order::NodeComparison::BELOW, orderCopy.compare(1,2)); + + EXPECT_EQ(storm::analysis::Order::NodeComparison::UNKNOWN, orderCopy.compare(2,3)); + EXPECT_EQ(storm::analysis::Order::NodeComparison::UNKNOWN, orderCopy.compare(3,2)); + + EXPECT_EQ(storm::analysis::Order::NodeComparison::SAME, orderCopy.compare(2,4)); + EXPECT_EQ(storm::analysis::Order::NodeComparison::SAME, orderCopy.compare(4,2)); + EXPECT_EQ(storm::analysis::Order::NodeComparison::ABOVE, orderCopy.compare(0,4)); + EXPECT_EQ(storm::analysis::Order::NodeComparison::BELOW, orderCopy.compare(4,0)); + EXPECT_EQ(storm::analysis::Order::NodeComparison::ABOVE, orderCopy.compare(4,1)); + EXPECT_EQ(storm::analysis::Order::NodeComparison::BELOW, orderCopy.compare(1,4)); + EXPECT_EQ(storm::analysis::Order::NodeComparison::UNKNOWN, orderCopy.compare(4,3)); + EXPECT_EQ(storm::analysis::Order::NodeComparison::UNKNOWN, orderCopy.compare(3,4)); + + EXPECT_EQ(storm::analysis::Order::NodeComparison::BELOW, orderCopy.compare(5,0)); + EXPECT_EQ(storm::analysis::Order::NodeComparison::ABOVE, orderCopy.compare(0,5)); + EXPECT_EQ(storm::analysis::Order::NodeComparison::ABOVE, orderCopy.compare(5,3)); + EXPECT_EQ(storm::analysis::Order::NodeComparison::BELOW, orderCopy.compare(3,5)); + EXPECT_EQ(storm::analysis::Order::NodeComparison::ABOVE, orderCopy.compare(5,1)); + EXPECT_EQ(storm::analysis::Order::NodeComparison::BELOW, orderCopy.compare(1,5)); + EXPECT_EQ(storm::analysis::Order::NodeComparison::UNKNOWN, orderCopy.compare(5,2)); + EXPECT_EQ(storm::analysis::Order::NodeComparison::UNKNOWN, orderCopy.compare(5,2)); + EXPECT_EQ(storm::analysis::Order::NodeComparison::UNKNOWN, orderCopy.compare(5,4)); + EXPECT_EQ(storm::analysis::Order::NodeComparison::UNKNOWN, orderCopy.compare(5,4)); + + order.addRelationNodes(order.getNode(6), order.getNode(4)); + orderCopy = storm::analysis::Order(order); + EXPECT_EQ(storm::analysis::Order::NodeComparison::BELOW, orderCopy.compare(6,0)); + EXPECT_EQ(storm::analysis::Order::NodeComparison::ABOVE, orderCopy.compare(0,6)); + EXPECT_EQ(storm::analysis::Order::NodeComparison::ABOVE, orderCopy.compare(6,1)); + EXPECT_EQ(storm::analysis::Order::NodeComparison::BELOW, orderCopy.compare(1,6)); + EXPECT_EQ(storm::analysis::Order::NodeComparison::ABOVE, orderCopy.compare(6,2)); + EXPECT_EQ(storm::analysis::Order::NodeComparison::BELOW, orderCopy.compare(2,6)); + EXPECT_EQ(storm::analysis::Order::NodeComparison::ABOVE, orderCopy.compare(6,3)); + EXPECT_EQ(storm::analysis::Order::NodeComparison::BELOW, orderCopy.compare(3,6)); + EXPECT_EQ(storm::analysis::Order::NodeComparison::ABOVE, orderCopy.compare(6,4)); + EXPECT_EQ(storm::analysis::Order::NodeComparison::BELOW, orderCopy.compare(4,6)); + EXPECT_EQ(storm::analysis::Order::NodeComparison::BELOW, orderCopy.compare(6,5)); + EXPECT_EQ(storm::analysis::Order::NodeComparison::ABOVE, orderCopy.compare(5,6)); +} + +TEST(OrderTest, merge_nodes) { + auto numberOfStates = 7; + auto above = storm::storage::BitVector(numberOfStates); + above.set(0); + auto below = storm::storage::BitVector(numberOfStates); + below.set(1); + auto initialMiddle = storm::storage::BitVector(numberOfStates); + + auto order = storm::analysis::Order(&above, &below, &initialMiddle, numberOfStates, nullptr); + order.add(2); + order.add(3); + order.addToNode(4, order.getNode(2)); + order.addBetween(5, order.getNode(0), order.getNode(3)); + order.addBetween(6, order.getNode(5), order.getNode(3)); + + order.mergeNodes(order.getNode(4), order.getNode(5)); + EXPECT_EQ(storm::analysis::Order::NodeComparison::SAME, order.compare(2,4)); + EXPECT_EQ(storm::analysis::Order::NodeComparison::SAME, order.compare(2,5)); + + EXPECT_EQ(storm::analysis::Order::NodeComparison::ABOVE, order.compare(0,5)); + EXPECT_EQ(storm::analysis::Order::NodeComparison::ABOVE, order.compare(0,2)); + EXPECT_EQ(storm::analysis::Order::NodeComparison::ABOVE, order.compare(0,4)); + + EXPECT_EQ(storm::analysis::Order::NodeComparison::BELOW, order.compare(6,2)); + EXPECT_EQ(storm::analysis::Order::NodeComparison::BELOW, order.compare(6,4)); + EXPECT_EQ(storm::analysis::Order::NodeComparison::BELOW, order.compare(6,5)); + EXPECT_EQ(storm::analysis::Order::NodeComparison::BELOW, order.compare(3,2)); + EXPECT_EQ(storm::analysis::Order::NodeComparison::BELOW, order.compare(3,4)); + EXPECT_EQ(storm::analysis::Order::NodeComparison::BELOW, order.compare(3,5)); + EXPECT_EQ(storm::analysis::Order::NodeComparison::BELOW, order.compare(1,2)); + EXPECT_EQ(storm::analysis::Order::NodeComparison::BELOW, order.compare(1,4)); + EXPECT_EQ(storm::analysis::Order::NodeComparison::BELOW, order.compare(1,5)); +} From e0b2869bd53626b76df4b00b6920320fe4536b74 Mon Sep 17 00:00:00 2001 From: Jip Spel Date: Thu, 25 Jul 2019 18:26:36 +0200 Subject: [PATCH 168/178] Fix region check --- src/storm-pars-cli/storm-pars.cpp | 6 +++--- src/storm-pars/analysis/MonotonicityChecker.cpp | 1 + src/storm-pars/analysis/OrderExtender.cpp | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/storm-pars-cli/storm-pars.cpp b/src/storm-pars-cli/storm-pars.cpp index 03665fe25..39218ab43 100644 --- a/src/storm-pars-cli/storm-pars.cpp +++ b/src/storm-pars-cli/storm-pars.cpp @@ -716,13 +716,14 @@ namespace storm { model->printModelInformationToStream(std::cout); } + std::vector> regions = parseRegions(model); + if (monSettings.isMonotonicityAnalysisSet()) { std::vector> formulas = storm::api::extractFormulasFromProperties(input.properties); // Monotonicity storm::utility::Stopwatch monotonicityWatch(true); - std::vector> regions = parseRegions(model); - STORM_LOG_THROW(regions.size() > 1, storm::exceptions::InvalidArgumentException, "Monotonicity analysis only allowed on single region"); + STORM_LOG_THROW(regions.size() <= 1, storm::exceptions::InvalidArgumentException, "Monotonicity analysis only allowed on single region"); storm::analysis::MonotonicityChecker monotonicityChecker = storm::analysis::MonotonicityChecker(model, formulas, regions, monSettings.isValidateAssumptionsSet(), monSettings.getNumberOfSamples(), monSettings.getMonotonicityAnalysisPrecision()); monotonicityChecker.checkMonotonicity(); monotonicityWatch.stop(); @@ -731,7 +732,6 @@ namespace storm { return; } - std::vector> regions = parseRegions(model); std::string samplesAsString = parSettings.getSamples(); SampleInformation samples; if (!samplesAsString.empty()) { diff --git a/src/storm-pars/analysis/MonotonicityChecker.cpp b/src/storm-pars/analysis/MonotonicityChecker.cpp index 1137d8ce1..e4d18e9f6 100644 --- a/src/storm-pars/analysis/MonotonicityChecker.cpp +++ b/src/storm-pars/analysis/MonotonicityChecker.cpp @@ -197,6 +197,7 @@ namespace storm { std::vector maxValues = maxRes.getValueVector(); // Create initial order std::tuple criticalTuple = extender->toOrder(formulas, minValues, maxValues); +// std::tuple criticalTuple = extender->toOrder(formulas); // Continue based on not (yet) sorted states diff --git a/src/storm-pars/analysis/OrderExtender.cpp b/src/storm-pars/analysis/OrderExtender.cpp index 6662e2757..4b32d63eb 100644 --- a/src/storm-pars/analysis/OrderExtender.cpp +++ b/src/storm-pars/analysis/OrderExtender.cpp @@ -205,7 +205,7 @@ namespace storm { } if (!order->contains(max)) { // Because of construction min is in the order - order->addBetween(max, order->getNode(min), order->getTop()); + order->addBetween(max, order->getTop(), order->getNode(min)); } assert (order->compare(max, min) == Order::ABOVE); order->addBetween(state, max, min); From 12e0ef537c218946d305450dbf49b750a248aaf7 Mon Sep 17 00:00:00 2001 From: Jip Spel Date: Fri, 26 Jul 2019 11:12:00 +0200 Subject: [PATCH 169/178] Small fixes --- .../analysis/MonotonicityChecker.cpp | 2 + src/storm-pars/analysis/Order.cpp | 40 ++++- src/storm-pars/analysis/Order.h | 13 +- src/storm-pars/analysis/OrderExtender.cpp | 163 ++++++++++-------- 4 files changed, 137 insertions(+), 81 deletions(-) diff --git a/src/storm-pars/analysis/MonotonicityChecker.cpp b/src/storm-pars/analysis/MonotonicityChecker.cpp index e4d18e9f6..47bc27b69 100644 --- a/src/storm-pars/analysis/MonotonicityChecker.cpp +++ b/src/storm-pars/analysis/MonotonicityChecker.cpp @@ -195,6 +195,8 @@ namespace storm { std::vector minValues = minRes.getValueVector(); std::vector maxValues = maxRes.getValueVector(); + // TODO: zijn de value vectors nu precies omgedraaid? + // Create initial order std::tuple criticalTuple = extender->toOrder(formulas, minValues, maxValues); // std::tuple criticalTuple = extender->toOrder(formulas); diff --git a/src/storm-pars/analysis/Order.cpp b/src/storm-pars/analysis/Order.cpp index fe8b94233..476a9e058 100644 --- a/src/storm-pars/analysis/Order.cpp +++ b/src/storm-pars/analysis/Order.cpp @@ -14,7 +14,7 @@ namespace storm { this->numberOfStates = numberOfStates; this->addedStates = new storm::storage::BitVector(numberOfStates); this->doneBuilding = false; - this->statesSorted = statesSorted; + this->statesSorted = *statesSorted; this->statesToHandle = initialMiddleStates; top = new Node(); @@ -47,7 +47,7 @@ namespace storm { this->numberOfStates = numberOfStates; this->addedStates = new storm::storage::BitVector(numberOfStates); this->doneBuilding = false; - this->statesSorted = statesSorted; + this->statesSorted = *statesSorted; this->statesToHandle = new storm::storage::BitVector(numberOfStates); top = new Node(); @@ -102,14 +102,16 @@ namespace storm { } } - this->statesSorted = order->statesSorted; - this->statesToHandle = order->statesToHandle; + auto statesSortedOrder = order->getStatesSorted(); + for (auto itr = statesSortedOrder.begin(); itr != statesSortedOrder.end(); ++itr) { + this->statesSorted.push_back(*itr); + } + this->statesToHandle = new storm::storage::BitVector(*(order->statesToHandle)); } void Order::addBetween(uint_fast64_t state, Node *above, Node *below) { assert(!(*addedStates)[state]); assert(compare(above, below) == ABOVE); - Node *newNode = new Node(); nodes[state] = newNode; @@ -195,10 +197,11 @@ namespace storm { bool Order::contains(uint_fast64_t state) { - return state >= 0 && state < addedStates->size() && addedStates->get(state); + return state < addedStates->size() && addedStates->get(state); } Order::Node *Order::getNode(uint_fast64_t stateNumber) { + assert (stateNumber < numberOfStates); return nodes.at(stateNumber); } @@ -350,5 +353,30 @@ namespace storm { void Order::merge(uint_fast64_t var1, uint_fast64_t var2) { mergeNodes(getNode(var1), getNode(var2)); } + + std::vector Order::getStatesSorted() { + return statesSorted; + } + + uint_fast64_t Order::getNextSortedState() { + if (statesSorted.begin() != statesSorted.end()) { + return *(statesSorted.begin()); + } else { + return numberOfStates; + } + } + + void Order::removeFirstStatesSorted() { + statesSorted.erase(statesSorted.begin()); + } + + void Order::removeStatesSorted(uint_fast64_t state) { + assert(containsStatesSorted(state)); + statesSorted.erase(std::find(statesSorted.begin(), statesSorted.end(), state)); + } + + bool Order::containsStatesSorted(uint_fast64_t state) { + return std::find(statesSorted.begin(), statesSorted.end(), state) != statesSorted.end(); + } } } diff --git a/src/storm-pars/analysis/Order.h b/src/storm-pars/analysis/Order.h index bd5270e30..fa4397498 100644 --- a/src/storm-pars/analysis/Order.h +++ b/src/storm-pars/analysis/Order.h @@ -212,11 +212,22 @@ namespace storm { storm::storage::BitVector* statesToHandle; - std::vector* statesSorted; + uint_fast64_t getNextSortedState(); + + bool containsStatesSorted(uint_fast64_t state); + + void removeFirstStatesSorted(); + + void removeStatesSorted(uint_fast64_t state); + + protected: + std::vector getStatesSorted(); private: std::vector nodes; + std::vector statesSorted; + storm::storage::BitVector* addedStates; Node* top; diff --git a/src/storm-pars/analysis/OrderExtender.cpp b/src/storm-pars/analysis/OrderExtender.cpp index 4b32d63eb..991f88f35 100644 --- a/src/storm-pars/analysis/OrderExtender.cpp +++ b/src/storm-pars/analysis/OrderExtender.cpp @@ -69,7 +69,6 @@ namespace storm { uint_fast64_t numberOfStates = this->model->getNumberOfStates(); - // TODO: dit moet anders kunnen storm::modelchecker::SparsePropositionalModelChecker> propositionalChecker(*model); storm::storage::BitVector phiStates; storm::storage::BitVector psiStates; @@ -130,43 +129,65 @@ namespace storm { template std::tuple OrderExtender::toOrder(std::vector> formulas, std::vector minValues, std::vector maxValues) { uint_fast64_t numberOfStates = this->model->getNumberOfStates(); - - // Compare min/max for all states - STORM_LOG_THROW((++formulas.begin()) == formulas.end(), storm::exceptions::NotSupportedException, "Only one formula allowed for monotonicity analysis"); - STORM_LOG_THROW((*(formulas[0])).isProbabilityOperatorFormula() - && ((*(formulas[0])).asProbabilityOperatorFormula().getSubformula().isUntilFormula() - || (*(formulas[0])).asProbabilityOperatorFormula().getSubformula().isEventuallyFormula()), storm::exceptions::NotSupportedException, "Expecting until or eventually formula"); - - storm::modelchecker::SparsePropositionalModelChecker> propositionalChecker(*model); - storm::storage::BitVector phiStates; - storm::storage::BitVector psiStates; - if ((*(formulas[0])).asProbabilityOperatorFormula().getSubformula().isUntilFormula()) { - phiStates = propositionalChecker.check((*(formulas[0])).asProbabilityOperatorFormula().getSubformula().asUntilFormula().getLeftSubformula())->asExplicitQualitativeCheckResult().getTruthValuesVector(); - psiStates = propositionalChecker.check((*(formulas[0])).asProbabilityOperatorFormula().getSubformula().asUntilFormula().getRightSubformula())->asExplicitQualitativeCheckResult().getTruthValuesVector(); - } else { - phiStates = storm::storage::BitVector(numberOfStates, true); - psiStates = propositionalChecker.check((*(formulas[0])).asProbabilityOperatorFormula().getSubformula().asEventuallyFormula().getSubformula())->asExplicitQualitativeCheckResult().getTruthValuesVector(); - } - - // Get the maybeStates - std::pair statesWithProbability01 = storm::utility::graph::performProb01(this->model->getBackwardTransitions(), phiStates, psiStates); - storm::storage::BitVector topStates = statesWithProbability01.second; - storm::storage::BitVector bottomStates = statesWithProbability01.first; - - STORM_LOG_THROW(topStates.begin() != topStates.end(), storm::exceptions::NotImplementedException, "Formula yields to no 1 states"); - STORM_LOG_THROW(bottomStates.begin() != bottomStates.end(), storm::exceptions::NotImplementedException, "Formula yields to no zero states"); - - uint_fast64_t bottom = bottomStates.getNextSetIndex(0); - uint_fast64_t top = topStates.getNextSetIndex(0); +// +// // Compare min/max for all states +// STORM_LOG_THROW((++formulas.begin()) == formulas.end(), storm::exceptions::NotSupportedException, "Only one formula allowed for monotonicity analysis"); +// STORM_LOG_THROW((*(formulas[0])).isProbabilityOperatorFormula() +// && ((*(formulas[0])).asProbabilityOperatorFormula().getSubformula().isUntilFormula() +// || (*(formulas[0])).asProbabilityOperatorFormula().getSubformula().isEventuallyFormula()), storm::exceptions::NotSupportedException, "Expecting until or eventually formula"); +// +// // TODO: dit moet anders kunnen +// storm::modelchecker::SparsePropositionalModelChecker> propositionalChecker(*model); +// storm::storage::BitVector phiStates; +// storm::storage::BitVector psiStates; +// if ((*(formulas[0])).asProbabilityOperatorFormula().getSubformula().isUntilFormula()) { +// phiStates = propositionalChecker.check((*(formulas[0])).asProbabilityOperatorFormula().getSubformula().asUntilFormula().getLeftSubformula())->asExplicitQualitativeCheckResult().getTruthValuesVector(); +// psiStates = propositionalChecker.check((*(formulas[0])).asProbabilityOperatorFormula().getSubformula().asUntilFormula().getRightSubformula())->asExplicitQualitativeCheckResult().getTruthValuesVector(); +// } else { +// phiStates = storm::storage::BitVector(numberOfStates, true); +// psiStates = propositionalChecker.check((*(formulas[0])).asProbabilityOperatorFormula().getSubformula().asEventuallyFormula().getSubformula())->asExplicitQualitativeCheckResult().getTruthValuesVector(); +// } +// +// // Get the maybeStates +// std::pair statesWithProbability01 = storm::utility::graph::performProb01(this->model->getBackwardTransitions(), phiStates, psiStates); +// storm::storage::BitVector topStates = statesWithProbability01.second; +// storm::storage::BitVector bottomStates = statesWithProbability01.first; +// +// STORM_LOG_THROW(topStates.begin() != topStates.end(), storm::exceptions::NotImplementedException, "Formula yields to no 1 states"); +// STORM_LOG_THROW(bottomStates.begin() != bottomStates.end(), storm::exceptions::NotImplementedException, "Formula yields to no zero states"); +// + uint_fast64_t bottom = numberOfStates; + uint_fast64_t top = numberOfStates; std::vector statesSorted = storm::utility::graph::getTopologicalSort(matrix); - Order *order = new Order(top, bottom, numberOfStates, &statesSorted); - + Order *order = nullptr; + + for (auto state : statesSorted) { + if ((minValues[numberOfStates - 1 - state] == 1 || maxValues[numberOfStates - 1 - state] == 0) + && minValues[numberOfStates - 1 - state] == maxValues[numberOfStates - 1 - state]) { + if (maxValues[numberOfStates - 1 - state] == 0) { + assert (bottom == numberOfStates); + bottom = state; + } + if (minValues[numberOfStates - 1 - state] == 1) { + assert (top == numberOfStates); + top = state; + } + if (bottom != numberOfStates && top != numberOfStates) { + order = new Order(top, bottom, numberOfStates, &statesSorted); + } - for (auto state : *(order->statesSorted)) { - if (state != bottom && state != top) { + } else { assert (order != nullptr); auto successors = stateMap[state]; - if (successors->size() > 1) { + if (successors->getNumberOfSetBits() == 1) { + auto succ = successors->getNextSetIndex(0); + if (succ != state) { + if (!order->contains(succ)) { + order->add(succ); + } + order->addToNode(state, order->getNode(succ)); + } + } else if (successors->getNumberOfSetBits() > 1) { uint_fast64_t min = numberOfStates; uint_fast64_t max = numberOfStates; bool allSorted = true; @@ -178,9 +199,9 @@ namespace storm { min = succ; max = succ; } else { - if (minValues[succ] > maxValues[max]) { + if (minValues[numberOfStates - 1 - succ] > maxValues[numberOfStates - 1 - max]) { max = succ; - } else if (maxValues[succ] < minValues[min]) { + } else if (maxValues[numberOfStates - 1 - succ] < minValues[numberOfStates - 1 - min]) { min = succ; } else { allSorted = false; @@ -214,6 +235,8 @@ namespace storm { } } + assert (order != nullptr); + // Handle sccs auto addedStates = order->getAddedStates(); for (auto scc : sccs) { @@ -368,8 +391,6 @@ namespace storm { handleAssumption(order, assumption); } - auto statesSorted = order->statesSorted; - auto oldNumberSet = numberOfStates; while (oldNumberSet != order->getAddedStates()->getNumberOfSetBits()) { oldNumberSet = order->getAddedStates()->getNumberOfSetBits(); @@ -390,9 +411,8 @@ namespace storm { if (!order->contains(succ1)) { order->addToNode(succ1, order->getNode(stateNumber)); statesToHandle->set(succ1, true); - auto itr = std::find(statesSorted->begin(), statesSorted->end(), succ1); - if (itr != statesSorted->end()) { - statesSorted->erase(itr); + if (order->containsStatesSorted(succ1)) { + order->removeStatesSorted(succ1); } } statesToHandle->set(stateNumber, false); @@ -407,18 +427,16 @@ namespace storm { auto compare = order->compare(stateNumber, succ1); if (compare == Order::ABOVE) { - auto itr = std::find(statesSorted->begin(), statesSorted->end(), succ2); - if (itr != statesSorted->end()) { - statesSorted->erase(itr); + if (order->containsStatesSorted(succ2)) { + order->removeStatesSorted(succ2); } order->addBetween(succ2, order->getTop(), order->getNode(stateNumber)); statesToHandle->set(succ2); statesToHandle->set(stateNumber, false); stateNumber = statesToHandle->getNextSetIndex(0); } else if (compare == Order::BELOW) { - auto itr = std::find(statesSorted->begin(), statesSorted->end(), succ2); - if (itr != statesSorted->end()) { - statesSorted->erase(itr); + if (order->containsStatesSorted(succ2)) { + order->removeStatesSorted(succ2); } order->addBetween(succ2, order->getNode(stateNumber), order->getBottom()); statesToHandle->set(succ2); @@ -442,39 +460,36 @@ namespace storm { } // Normal backwardreasoning - if (statesSorted->size() > 0) { - auto stateNumber = *(statesSorted->begin()); - while (order->contains(stateNumber) && statesSorted->size() > 1) { - // states.size()>1 such that there is at least one state left after erase - statesSorted->erase(statesSorted->begin()); - stateNumber = *(statesSorted->begin()); - - if (order->contains(stateNumber)) { - auto resAllAdded = allSuccAdded(order, stateNumber); - if (!std::get<0>(resAllAdded)) { - return std::make_tuple(order, std::get<1>(resAllAdded), std::get<2>(resAllAdded)); - } + auto stateNumber = order->getNextSortedState(); + while (stateNumber != numberOfStates && order->contains(stateNumber)) { + order->removeFirstStatesSorted(); + stateNumber = order->getNextSortedState(); + + if (stateNumber != numberOfStates && order->contains(stateNumber)) { + auto resAllAdded = allSuccAdded(order, stateNumber); + if (!std::get<0>(resAllAdded)) { + return std::make_tuple(order, std::get<1>(resAllAdded), std::get<2>(resAllAdded)); } } + } - if (!order->contains(stateNumber)) { - auto successors = stateMap[stateNumber]; - - auto result = extendAllSuccAdded(order, stateNumber, successors); - if (std::get<1>(result) != numberOfStates) { - // So we don't know the relation between all successor states - return result; - } else { - assert (order->getNode(stateNumber) != nullptr); - if (!acyclic) { - order->statesToHandle->set(stateNumber); - } - statesSorted->erase(statesSorted->begin()); + if (stateNumber != numberOfStates && !order->contains(stateNumber)) { + auto successors = stateMap[stateNumber]; + + auto result = extendAllSuccAdded(order, stateNumber, successors); + if (std::get<1>(result) != numberOfStates) { + // So we don't know the relation between all successor states + return result; + } else { + assert (order->getNode(stateNumber) != nullptr); + if (!acyclic) { + order->statesToHandle->set(stateNumber); } + order->removeFirstStatesSorted(); } - assert (order->getNode(stateNumber) != nullptr); - assert (order->contains(stateNumber)); } + assert (stateNumber == numberOfStates || order->getNode(stateNumber) != nullptr); + assert (stateNumber == numberOfStates || order->contains(stateNumber)); } assert (order->getAddedStates()->getNumberOfSetBits() == numberOfStates); From b308f4e1d08d4edb841c3c157f2dd4bd6cfb05c3 Mon Sep 17 00:00:00 2001 From: Jip Spel Date: Fri, 26 Jul 2019 11:47:40 +0200 Subject: [PATCH 170/178] Initialize region before creating sample points --- .../analysis/MonotonicityChecker.cpp | 54 ++++++++++--------- 1 file changed, 28 insertions(+), 26 deletions(-) diff --git a/src/storm-pars/analysis/MonotonicityChecker.cpp b/src/storm-pars/analysis/MonotonicityChecker.cpp index 47bc27b69..6c3518acf 100644 --- a/src/storm-pars/analysis/MonotonicityChecker.cpp +++ b/src/storm-pars/analysis/MonotonicityChecker.cpp @@ -29,26 +29,10 @@ namespace storm { this->formulas = formulas; this->validate = validate; this->precision = precision; - - if (numberOfSamples > 0) { - // sampling - if (model->isOfType(storm::models::ModelType::Dtmc)) { - this->resultCheckOnSamples = std::map::type, std::pair>( - checkOnSamples(model->as>(), numberOfSamples)); - } else if (model->isOfType(storm::models::ModelType::Mdp)) { - this->resultCheckOnSamples = std::map::type, std::pair>( - checkOnSamples(model->as>(), numberOfSamples)); - - } - checkSamples= true; - } else { - checkSamples= false; - } - std::shared_ptr> sparseModel = model->as>(); if (regions.size() == 1) { - region = *(regions.begin()); + this->region = *(regions.begin()); } else { assert (regions.size() == 0); typename storm::storage::ParameterRegion::Valuation lowerBoundaries; @@ -61,7 +45,22 @@ namespace storm { lowerBoundaries.insert(std::make_pair(var, lb)); upperBoundaries.insert(std::make_pair(var, ub)); } - region = storm::storage::ParameterRegion(std::move(lowerBoundaries), std::move(upperBoundaries)); + this->region = storm::storage::ParameterRegion(std::move(lowerBoundaries), std::move(upperBoundaries)); + } + + if (numberOfSamples > 0) { + // sampling + if (model->isOfType(storm::models::ModelType::Dtmc)) { + this->resultCheckOnSamples = std::map::type, std::pair>( + checkOnSamples(model->as>(), numberOfSamples)); + } else if (model->isOfType(storm::models::ModelType::Mdp)) { + this->resultCheckOnSamples = std::map::type, std::pair>( + checkOnSamples(model->as>(), numberOfSamples)); + + } + checkSamples= true; + } else { + checkSamples= false; } this->extender = new storm::analysis::OrderExtender(sparseModel); @@ -561,17 +560,20 @@ namespace storm { for (auto itr2 = variables.begin(); itr2 != variables.end(); ++itr2) { // Only change value for current variable if ((*itr) == (*itr2)) { - auto val = std::pair::type, typename utility::parametric::CoefficientType::type>( - (*itr2), storm::utility::convertNumber::type>( - boost::lexical_cast((i + 1) / (double(numberOfSamples + 1))))); + auto lb = region.getLowerBoundary(itr->name()); + auto ub = region.getUpperBoundary(itr->name()); + // Creates samples between lb and ub, that is: lb, lb + (ub-lb)/(#samples -1), lb + 2* (ub-lb)/(#samples -1), ..., ub + auto val = + std::pair::type, typename utility::parametric::CoefficientType::type> + (*itr,utility::convertNumber::type>(lb + i*(ub-lb)/(numberOfSamples-1))); valuation.insert(val); - assert (0 < val.second && val.second < 1); + } else { - auto val = std::pair::type, typename utility::parametric::CoefficientType::type>( - (*itr2), storm::utility::convertNumber::type>( - boost::lexical_cast((1) / (double(numberOfSamples + 1))))); + auto lb = region.getLowerBoundary(itr->name()); + auto val = + std::pair::type, typename utility::parametric::CoefficientType::type> + (*itr,utility::convertNumber::type>(lb)); valuation.insert(val); - assert (0 < val.second && val.second < 1); } } storm::models::sparse::Dtmc sampleModel = instantiator.instantiate(valuation); From f98250968c4ee53cb0f5ae507b27ca97c0b29099 Mon Sep 17 00:00:00 2001 From: Jip Spel Date: Tue, 15 Oct 2019 14:38:48 +0200 Subject: [PATCH 171/178] Fix checking monotonicity on samples --- .../analysis/MonotonicityChecker.cpp | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/src/storm-pars/analysis/MonotonicityChecker.cpp b/src/storm-pars/analysis/MonotonicityChecker.cpp index 6c3518acf..8687a0566 100644 --- a/src/storm-pars/analysis/MonotonicityChecker.cpp +++ b/src/storm-pars/analysis/MonotonicityChecker.cpp @@ -550,12 +550,16 @@ namespace storm { auto matrix = model->getTransitionMatrix(); std::set::type> variables = storm::models::sparse::getProbabilityParameters(*model); + // For each of the variables create a model in which we only change the value for this specific variable for (auto itr = variables.begin(); itr != variables.end(); ++itr) { double previous = -1; bool monDecr = true; bool monIncr = true; + // Check monotonicity in variable (*itr) by instantiating the model + // all other variables fixed on lb, only increasing (*itr) for (auto i = 0; (monDecr || monIncr) && i < numberOfSamples; ++i) { + // Create valuation auto valuation = storm::utility::parametric::Valuation(); for (auto itr2 = variables.begin(); itr2 != variables.end(); ++itr2) { // Only change value for current variable @@ -563,19 +567,14 @@ namespace storm { auto lb = region.getLowerBoundary(itr->name()); auto ub = region.getUpperBoundary(itr->name()); // Creates samples between lb and ub, that is: lb, lb + (ub-lb)/(#samples -1), lb + 2* (ub-lb)/(#samples -1), ..., ub - auto val = - std::pair::type, typename utility::parametric::CoefficientType::type> - (*itr,utility::convertNumber::type>(lb + i*(ub-lb)/(numberOfSamples-1))); - valuation.insert(val); - + valuation[*itr2] = utility::convertNumber::type>(lb + i*(ub-lb)/(numberOfSamples-1)); } else { auto lb = region.getLowerBoundary(itr->name()); - auto val = - std::pair::type, typename utility::parametric::CoefficientType::type> - (*itr,utility::convertNumber::type>(lb)); - valuation.insert(val); + valuation[*itr2] = utility::convertNumber::type>(lb); } } + + // Instantiate model and get result storm::models::sparse::Dtmc sampleModel = instantiator.instantiate(valuation); auto checker = storm::modelchecker::SparseDtmcPrctlModelChecker>(sampleModel); std::unique_ptr checkResult; @@ -598,9 +597,11 @@ namespace storm { std::vector values = quantitativeResult.getValueVector(); auto initialStates = model->getInitialStates(); double initial = 0; + // Get total probability from initial states for (auto j = initialStates.getNextSetIndex(0); j < model->getNumberOfStates(); j = initialStates.getNextSetIndex(j+1)) { initial += values[j]; } + // Calculate difference with result for previous valuation assert (initial >= 0-precision && initial <= 1+precision); double diff = previous - initial; assert (previous == -1 || diff >= -1-precision && diff <= 1 + precision); From a39f297b8c3f0dc26daecb1157b272ad2a769236 Mon Sep 17 00:00:00 2001 From: Jip Spel Date: Tue, 15 Oct 2019 14:47:41 +0200 Subject: [PATCH 172/178] Fix OrderTest and add assert in Order --- src/storm-pars/analysis/Order.cpp | 1 + src/test/storm-pars/analysis/OrderTest.cpp | 9 ++++++--- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/storm-pars/analysis/Order.cpp b/src/storm-pars/analysis/Order.cpp index 476a9e058..3c16f750f 100644 --- a/src/storm-pars/analysis/Order.cpp +++ b/src/storm-pars/analysis/Order.cpp @@ -14,6 +14,7 @@ namespace storm { this->numberOfStates = numberOfStates; this->addedStates = new storm::storage::BitVector(numberOfStates); this->doneBuilding = false; + assert (statesSorted != nullptr); this->statesSorted = *statesSorted; this->statesToHandle = initialMiddleStates; diff --git a/src/test/storm-pars/analysis/OrderTest.cpp b/src/test/storm-pars/analysis/OrderTest.cpp index 8b712508b..fc5d78709 100644 --- a/src/test/storm-pars/analysis/OrderTest.cpp +++ b/src/test/storm-pars/analysis/OrderTest.cpp @@ -11,8 +11,9 @@ TEST(OrderTest, Simple) { auto below = storm::storage::BitVector(numberOfStates); below.set(1); auto initialMiddle = storm::storage::BitVector(numberOfStates); + std::vector statesSorted; - auto order = storm::analysis::Order(&above, &below, &initialMiddle, numberOfStates, nullptr); + auto order = storm::analysis::Order(&above, &below, &initialMiddle, numberOfStates, &statesSorted); EXPECT_EQ(storm::analysis::Order::NodeComparison::ABOVE, order.compare(0,1)); EXPECT_EQ(storm::analysis::Order::NodeComparison::BELOW, order.compare(1,0)); EXPECT_EQ(nullptr, order.getNode(2)); @@ -77,8 +78,9 @@ TEST(OrderTest, copy_order) { auto below = storm::storage::BitVector(numberOfStates); below.set(1); auto initialMiddle = storm::storage::BitVector(numberOfStates); + std::vector statesSorted; - auto order = storm::analysis::Order(&above, &below, &initialMiddle, numberOfStates, nullptr); + auto order = storm::analysis::Order(&above, &below, &initialMiddle, numberOfStates, &statesSorted); order.add(2); order.add(3); order.addToNode(4, order.getNode(2)); @@ -142,8 +144,9 @@ TEST(OrderTest, merge_nodes) { auto below = storm::storage::BitVector(numberOfStates); below.set(1); auto initialMiddle = storm::storage::BitVector(numberOfStates); + std::vector statesSorted; - auto order = storm::analysis::Order(&above, &below, &initialMiddle, numberOfStates, nullptr); + auto order = storm::analysis::Order(&above, &below, &initialMiddle, numberOfStates, &statesSorted); order.add(2); order.add(3); order.addToNode(4, order.getNode(2)); From ed3fa3f82b7d252e3629a3c13855aa1cf94a619e Mon Sep 17 00:00:00 2001 From: Jip Spel Date: Thu, 17 Oct 2019 11:14:31 +0200 Subject: [PATCH 173/178] Fix TODOs --- src/storm-pars-cli/storm-pars.cpp | 110 +++++++++--------- src/storm-pars/analysis/AssumptionChecker.cpp | 2 - .../analysis/MonotonicityChecker.cpp | 5 - src/storm-pars/analysis/OrderExtender.cpp | 29 ----- src/storm-pars/api/region.h | 30 ----- 5 files changed, 58 insertions(+), 118 deletions(-) diff --git a/src/storm-pars-cli/storm-pars.cpp b/src/storm-pars-cli/storm-pars.cpp index 79c2284f2..c2679770d 100644 --- a/src/storm-pars-cli/storm-pars.cpp +++ b/src/storm-pars-cli/storm-pars.cpp @@ -668,66 +668,72 @@ namespace storm { if (model && monSettings.isSccEliminationSet()) { storm::utility::Stopwatch eliminationWatch(true); - // TODO: check for correct Model type - STORM_PRINT("Applying scc elimination" << std::endl); - auto sparseModel = model->as>(); - auto matrix = sparseModel->getTransitionMatrix(); - auto backwardsTransitionMatrix = matrix.transpose(); - - storm::storage::StronglyConnectedComponentDecompositionOptions const options; - auto decomposition = storm::storage::StronglyConnectedComponentDecomposition(matrix, options); - - storm::storage::BitVector selectedStates(matrix.getRowCount()); - storm::storage::BitVector selfLoopStates(matrix.getRowCount()); - for (auto i = 0; i < decomposition.size(); ++i) { - auto scc = decomposition.getBlock(i); - if (scc.size() > 1) { - auto nrInitial = 0; - auto statesScc = scc.getStates(); - std::vector entryStates; - for (auto state : statesScc) { - auto row = backwardsTransitionMatrix.getRow(state); - bool found = false; - for (auto backState : row) { - if (!scc.containsState(backState.getColumn())) { - found = true; + if (model->isOfType(storm::models::ModelType::Dtmc)) { + STORM_PRINT("Applying scc elimination" << std::endl); + auto sparseModel = model->as>(); + auto matrix = sparseModel->getTransitionMatrix(); + auto backwardsTransitionMatrix = matrix.transpose(); + + storm::storage::StronglyConnectedComponentDecompositionOptions const options; + auto decomposition = storm::storage::StronglyConnectedComponentDecomposition(matrix, options); + + storm::storage::BitVector selectedStates(matrix.getRowCount()); + storm::storage::BitVector selfLoopStates(matrix.getRowCount()); + for (auto i = 0; i < decomposition.size(); ++i) { + auto scc = decomposition.getBlock(i); + if (scc.size() > 1) { + auto nrInitial = 0; + auto statesScc = scc.getStates(); + std::vector entryStates; + for (auto state : statesScc) { + auto row = backwardsTransitionMatrix.getRow(state); + bool found = false; + for (auto backState : row) { + if (!scc.containsState(backState.getColumn())) { + found = true; + } + } + if (found) { + entryStates.push_back(state); + selfLoopStates.set(state); + } else { + selectedStates.set(state); } } - if (found) { - entryStates.push_back(state); - selfLoopStates.set(state); - } else { - selectedStates.set(state); + + if (entryStates.size() != 1) { + STORM_LOG_THROW(entryStates.size() > 1, storm::exceptions::NotImplementedException, + "state elimination not implemented for scc with more than 1 entry points"); } } + } - if (entryStates.size() != 1) { - STORM_LOG_THROW(entryStates.size() > 1, storm::exceptions::NotImplementedException, - "state elimination not implemented for scc with more than 1 entry points"); - } + storm::storage::FlexibleSparseMatrix flexibleMatrix(matrix); + storm::storage::FlexibleSparseMatrix flexibleBackwardTransitions(backwardsTransitionMatrix, true); + auto actionRewards = std::vector(matrix.getRowCount(), storm::utility::zero()); + storm::solver::stateelimination::NondeterministicModelStateEliminator stateEliminator(flexibleMatrix, flexibleBackwardTransitions, actionRewards); + for(auto state : selectedStates) { + stateEliminator.eliminateState(state, true); + } + for (auto state : selfLoopStates) { + auto row = flexibleMatrix.getRow(state); + stateEliminator.eliminateLoop(state); } + selectedStates.complement(); + auto keptRows = matrix.getRowFilter(selectedStates); + storm::storage::SparseMatrix newTransitionMatrix = flexibleMatrix.createSparseMatrix(keptRows, selectedStates); + // TODO: note that rewards get lost + model = std::make_shared>(std::move(newTransitionMatrix), sparseModel->getStateLabeling().getSubLabeling(selectedStates)); + + eliminationWatch.stop(); + STORM_PRINT(std::endl << "Time for scc elimination: " << eliminationWatch << "." << std::endl << std::endl); + model->printModelInformationToStream(std::cout); + } else if (model->isOfType(storm::models::ModelType::Mdp)) { + STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "Unable to perform SCC elimination for monotonicity analysis on MDP: Not mplemented"); + } else { + STORM_LOG_THROW(false, storm::exceptions::InvalidOperationException, "Unable to perform monotonicity analysis on the provided model type."); } - storm::storage::FlexibleSparseMatrix flexibleMatrix(matrix); - storm::storage::FlexibleSparseMatrix flexibleBackwardTransitions(backwardsTransitionMatrix, true); - auto actionRewards = std::vector(matrix.getRowCount(), storm::utility::zero()); - storm::solver::stateelimination::NondeterministicModelStateEliminator stateEliminator(flexibleMatrix, flexibleBackwardTransitions, actionRewards); - for(auto state : selectedStates) { - stateEliminator.eliminateState(state, true); - } - for (auto state : selfLoopStates) { - auto row = flexibleMatrix.getRow(state); - stateEliminator.eliminateLoop(state); - } - selectedStates.complement(); - auto keptRows = matrix.getRowFilter(selectedStates); - storm::storage::SparseMatrix newTransitionMatrix = flexibleMatrix.createSparseMatrix(keptRows, selectedStates); - // TODO: rewards get lost - model = std::make_shared>(std::move(newTransitionMatrix), sparseModel->getStateLabeling().getSubLabeling(selectedStates)); - - eliminationWatch.stop(); - STORM_PRINT(std::endl << "Time for scc elimination: " << eliminationWatch << "." << std::endl << std::endl); - model->printModelInformationToStream(std::cout); } std::vector> regions = parseRegions(model); diff --git a/src/storm-pars/analysis/AssumptionChecker.cpp b/src/storm-pars/analysis/AssumptionChecker.cpp index 43d0e75e4..e90b8e913 100644 --- a/src/storm-pars/analysis/AssumptionChecker.cpp +++ b/src/storm-pars/analysis/AssumptionChecker.cpp @@ -32,9 +32,7 @@ namespace storm { for (auto i = 0; i < numberOfSamples; ++i) { auto valuation = utility::parametric::Valuation(); - // TODO: samplen over de region for (auto var: variables) { - auto lb = region.getLowerBoundary(var.name()); auto ub = region.getUpperBoundary(var.name()); // Creates samples between lb and ub, that is: lb, lb + (ub-lb)/(#samples -1), lb + 2* (ub-lb)/(#samples -1), ..., ub diff --git a/src/storm-pars/analysis/MonotonicityChecker.cpp b/src/storm-pars/analysis/MonotonicityChecker.cpp index 8687a0566..62bbc02e2 100644 --- a/src/storm-pars/analysis/MonotonicityChecker.cpp +++ b/src/storm-pars/analysis/MonotonicityChecker.cpp @@ -194,13 +194,8 @@ namespace storm { std::vector minValues = minRes.getValueVector(); std::vector maxValues = maxRes.getValueVector(); - // TODO: zijn de value vectors nu precies omgedraaid? - // Create initial order std::tuple criticalTuple = extender->toOrder(formulas, minValues, maxValues); -// std::tuple criticalTuple = extender->toOrder(formulas); - - // Continue based on not (yet) sorted states std::map>> result; diff --git a/src/storm-pars/analysis/OrderExtender.cpp b/src/storm-pars/analysis/OrderExtender.cpp index 991f88f35..d9f109777 100644 --- a/src/storm-pars/analysis/OrderExtender.cpp +++ b/src/storm-pars/analysis/OrderExtender.cpp @@ -38,10 +38,8 @@ namespace storm { uint_fast64_t numberOfStates = this->model->getNumberOfStates(); // Build stateMap - // TODO: is dit wel nodig for (uint_fast64_t i = 0; i < numberOfStates; ++i) { stateMap[i] = new storm::storage::BitVector(numberOfStates, false); - auto row = matrix.getRow(i); for (auto rowItr = row.begin(); rowItr != row.end(); ++rowItr) { // ignore self-loops when there are more transitions @@ -129,33 +127,6 @@ namespace storm { template std::tuple OrderExtender::toOrder(std::vector> formulas, std::vector minValues, std::vector maxValues) { uint_fast64_t numberOfStates = this->model->getNumberOfStates(); -// -// // Compare min/max for all states -// STORM_LOG_THROW((++formulas.begin()) == formulas.end(), storm::exceptions::NotSupportedException, "Only one formula allowed for monotonicity analysis"); -// STORM_LOG_THROW((*(formulas[0])).isProbabilityOperatorFormula() -// && ((*(formulas[0])).asProbabilityOperatorFormula().getSubformula().isUntilFormula() -// || (*(formulas[0])).asProbabilityOperatorFormula().getSubformula().isEventuallyFormula()), storm::exceptions::NotSupportedException, "Expecting until or eventually formula"); -// -// // TODO: dit moet anders kunnen -// storm::modelchecker::SparsePropositionalModelChecker> propositionalChecker(*model); -// storm::storage::BitVector phiStates; -// storm::storage::BitVector psiStates; -// if ((*(formulas[0])).asProbabilityOperatorFormula().getSubformula().isUntilFormula()) { -// phiStates = propositionalChecker.check((*(formulas[0])).asProbabilityOperatorFormula().getSubformula().asUntilFormula().getLeftSubformula())->asExplicitQualitativeCheckResult().getTruthValuesVector(); -// psiStates = propositionalChecker.check((*(formulas[0])).asProbabilityOperatorFormula().getSubformula().asUntilFormula().getRightSubformula())->asExplicitQualitativeCheckResult().getTruthValuesVector(); -// } else { -// phiStates = storm::storage::BitVector(numberOfStates, true); -// psiStates = propositionalChecker.check((*(formulas[0])).asProbabilityOperatorFormula().getSubformula().asEventuallyFormula().getSubformula())->asExplicitQualitativeCheckResult().getTruthValuesVector(); -// } -// -// // Get the maybeStates -// std::pair statesWithProbability01 = storm::utility::graph::performProb01(this->model->getBackwardTransitions(), phiStates, psiStates); -// storm::storage::BitVector topStates = statesWithProbability01.second; -// storm::storage::BitVector bottomStates = statesWithProbability01.first; -// -// STORM_LOG_THROW(topStates.begin() != topStates.end(), storm::exceptions::NotImplementedException, "Formula yields to no 1 states"); -// STORM_LOG_THROW(bottomStates.begin() != bottomStates.end(), storm::exceptions::NotImplementedException, "Formula yields to no zero states"); -// uint_fast64_t bottom = numberOfStates; uint_fast64_t top = numberOfStates; std::vector statesSorted = storm::utility::graph::getTopologicalSort(matrix); diff --git a/src/storm-pars/api/region.h b/src/storm-pars/api/region.h index f0315f45d..0ee310b39 100644 --- a/src/storm-pars/api/region.h +++ b/src/storm-pars/api/region.h @@ -110,36 +110,6 @@ namespace storm { return checker; } - // TODO: make more generic - template - std::shared_ptr, ConstantType>> initializeParameterLiftingDtmcModelChecker(Environment const& env, std::shared_ptr> const& model, storm::modelchecker::CheckTask const& task, bool generateSplitEstimates = false, bool allowModelSimplification = true) { - - STORM_LOG_WARN_COND(storm::utility::parameterlifting::validateParameterLiftingSound(*model, task.getFormula()), "Could not validate whether parameter lifting is applicable. Please validate manually..."); - - std::shared_ptr> consideredModel = model; - - // Treat continuous time models - if (consideredModel->isOfType(storm::models::ModelType::Ctmc) || consideredModel->isOfType(storm::models::ModelType::MarkovAutomaton)) { - STORM_LOG_WARN("Parameter lifting not supported for continuous time models. Transforming continuous model to discrete model..."); - std::vector> taskFormulaAsVector { task.getFormula().asSharedPointer() }; - consideredModel = storm::api::transformContinuousToDiscreteTimeSparseModel(consideredModel, taskFormulaAsVector).first; - STORM_LOG_THROW(consideredModel->isOfType(storm::models::ModelType::Dtmc) || consideredModel->isOfType(storm::models::ModelType::Mdp), storm::exceptions::UnexpectedException, "Transformation to discrete time model has failed."); - } - - // Obtain the region model checker - std::shared_ptr, ConstantType>> checker; - if (consideredModel->isOfType(storm::models::ModelType::Dtmc)) { - checker = std::make_shared, ConstantType>>(); - } else { - STORM_LOG_THROW(false, storm::exceptions::InvalidOperationException, "Unable to perform parameterLifting on the provided model type."); - } - - checker->specify(env, consideredModel, task, generateSplitEstimates, allowModelSimplification); - - return checker; - } - - template std::shared_ptr> initializeValidatingRegionModelChecker(Environment const& env, std::shared_ptr> const& model, storm::modelchecker::CheckTask const& task, bool generateSplitEstimates = false, bool allowModelSimplification = true) { From 5c1d597292a0968eb857ff197f39d6363b5b5a64 Mon Sep 17 00:00:00 2001 From: Jip Spel Date: Mon, 21 Oct 2019 13:48:31 +0200 Subject: [PATCH 174/178] Add line for changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 52bebe6e8..27eddbf03 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,6 +25,7 @@ Version 1.3.x - Fixed linking with Mathsat on macOS - Fixed compilation for macOS mojave - Support for export of MTBDDs from storm +- Support for monotonicity checking of pMCs using the --monotonicity-analysis option. Use --help monotonicity for all options. ### Version 1.3.0 (2018/12) - Slightly improved scheduler extraction From e89b743f6562bb9f09da64d906e50d4b2f15f6cb Mon Sep 17 00:00:00 2001 From: Jip Spel Date: Mon, 21 Oct 2019 16:41:03 +0200 Subject: [PATCH 175/178] Update changelog --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 27eddbf03..b05097073 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,7 +25,7 @@ Version 1.3.x - Fixed linking with Mathsat on macOS - Fixed compilation for macOS mojave - Support for export of MTBDDs from storm -- Support for monotonicity checking of pMCs using the --monotonicity-analysis option. Use --help monotonicity for all options. +- Support for monotonicity checking of pMCs using the `--monotonicity-analysis` option. Use `--help monotonicity` for all options. ### Version 1.3.0 (2018/12) - Slightly improved scheduler extraction From 179c46570b27c60b4da89eef595e94f83e33acbe Mon Sep 17 00:00:00 2001 From: Jip Spel Date: Tue, 22 Oct 2019 11:14:25 +0200 Subject: [PATCH 176/178] Added missing file --- resources/examples/testfiles/pdtmc/simple4.pm | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 resources/examples/testfiles/pdtmc/simple4.pm diff --git a/resources/examples/testfiles/pdtmc/simple4.pm b/resources/examples/testfiles/pdtmc/simple4.pm new file mode 100644 index 000000000..1bdc3e004 --- /dev/null +++ b/resources/examples/testfiles/pdtmc/simple4.pm @@ -0,0 +1,17 @@ +dtmc + +const double p; + +module test + + // local state + s : [0..4] init 0; + + [] s=0 -> p*(1-p) : (s'=1) + (1-p*(1-p)) : (s'=2); + [] s=1 -> p : (s'=3) + (1-p) : (s'=4); + [] s=2 -> (1-p) : (s'=3) + (p) : (s'=4); + [] s=3 -> 1 : (s'=3); + [] s=4 -> 1 : (s'=4); + +endmodule + From 4c1958c2453278ace0a4406db7c95f097df9d456 Mon Sep 17 00:00:00 2001 From: Matthias Volk Date: Tue, 22 Oct 2019 11:19:54 +0200 Subject: [PATCH 177/178] Fixed some compiler warnings --- src/storm-pars-cli/storm-pars.cpp | 3 +-- src/storm-pars/analysis/AssumptionChecker.cpp | 2 +- src/storm-pars/analysis/MonotonicityChecker.cpp | 6 +++--- src/storm-pars/analysis/Order.cpp | 12 ++++-------- src/storm-pars/analysis/OrderExtender.cpp | 10 +++------- .../analysis/AssumptionCheckerTest.cpp | 16 ++++++++-------- .../analysis/MonotonicityCheckerTest.cpp | 8 ++++---- .../storm-pars/analysis/OrderExtenderTest.cpp | 6 +++--- 8 files changed, 27 insertions(+), 36 deletions(-) diff --git a/src/storm-pars-cli/storm-pars.cpp b/src/storm-pars-cli/storm-pars.cpp index c2679770d..75dba4492 100644 --- a/src/storm-pars-cli/storm-pars.cpp +++ b/src/storm-pars-cli/storm-pars.cpp @@ -679,10 +679,9 @@ namespace storm { storm::storage::BitVector selectedStates(matrix.getRowCount()); storm::storage::BitVector selfLoopStates(matrix.getRowCount()); - for (auto i = 0; i < decomposition.size(); ++i) { + for (size_t i = 0; i < decomposition.size(); ++i) { auto scc = decomposition.getBlock(i); if (scc.size() > 1) { - auto nrInitial = 0; auto statesScc = scc.getStates(); std::vector entryStates; for (auto state : statesScc) { diff --git a/src/storm-pars/analysis/AssumptionChecker.cpp b/src/storm-pars/analysis/AssumptionChecker.cpp index e90b8e913..fce4596ab 100644 --- a/src/storm-pars/analysis/AssumptionChecker.cpp +++ b/src/storm-pars/analysis/AssumptionChecker.cpp @@ -30,7 +30,7 @@ namespace storm { auto matrix = model->getTransitionMatrix(); std::set::type> variables = models::sparse::getProbabilityParameters(*model); - for (auto i = 0; i < numberOfSamples; ++i) { + for (uint_fast64_t i = 0; i < numberOfSamples; ++i) { auto valuation = utility::parametric::Valuation(); for (auto var: variables) { auto lb = region.getLowerBoundary(var.name()); diff --git a/src/storm-pars/analysis/MonotonicityChecker.cpp b/src/storm-pars/analysis/MonotonicityChecker.cpp index 62bbc02e2..c53609220 100644 --- a/src/storm-pars/analysis/MonotonicityChecker.cpp +++ b/src/storm-pars/analysis/MonotonicityChecker.cpp @@ -104,7 +104,7 @@ namespace storm { } } else { - auto i = 0; + size_t i = 0; for (auto itr = map.begin(); i < map.size() && itr != map.end(); ++itr) { auto order = itr->first; @@ -553,7 +553,7 @@ namespace storm { // Check monotonicity in variable (*itr) by instantiating the model // all other variables fixed on lb, only increasing (*itr) - for (auto i = 0; (monDecr || monIncr) && i < numberOfSamples; ++i) { + for (uint_fast64_t i = 0; (monDecr || monIncr) && i < numberOfSamples; ++i) { // Create valuation auto valuation = storm::utility::parametric::Valuation(); for (auto itr2 = variables.begin(); itr2 != variables.end(); ++itr2) { @@ -629,7 +629,7 @@ namespace storm { bool monDecr = true; bool monIncr = true; - for (auto i = 0; i < numberOfSamples; ++i) { + for (uint_fast64_t i = 0; i < numberOfSamples; ++i) { auto valuation = storm::utility::parametric::Valuation(); for (auto itr2 = variables.begin(); itr2 != variables.end(); ++itr2) { // Only change value for current variable diff --git a/src/storm-pars/analysis/Order.cpp b/src/storm-pars/analysis/Order.cpp index 3c16f750f..350cffa29 100644 --- a/src/storm-pars/analysis/Order.cpp +++ b/src/storm-pars/analysis/Order.cpp @@ -231,14 +231,14 @@ namespace storm { } std::vector Order::sortStates(storm::storage::BitVector* states) { - auto numberOfSetBits = states->getNumberOfSetBits(); + uint_fast64_t numberOfSetBits = states->getNumberOfSetBits(); auto stateSize = states->size(); auto result = std::vector(numberOfSetBits, stateSize); for (auto state : *states) { if (result[0] == stateSize) { result[0] = state; } else { - auto i = 0; + uint_fast64_t i = 0; bool added = false; while (i < numberOfSetBits && !added) { if (result[i] == stateSize) { @@ -249,7 +249,7 @@ namespace storm { if (compareRes == ABOVE) { auto temp = result[i]; result[i] = state; - for (auto j = i + 1; j < numberOfSetBits && result[j + 1] != stateSize; j++) { + for (uint_fast64_t j = i + 1; j < numberOfSetBits && result[j + 1] != stateSize; j++) { auto temp2 = result[j]; result[j] = temp; temp = temp2; @@ -261,7 +261,7 @@ namespace storm { ++i; auto temp = result[i]; result[i] = state; - for (auto j = i + 1; j < numberOfSetBits && result[j + 1] != stateSize; j++) { + for (uint_fast64_t j = i + 1; j < numberOfSetBits && result[j + 1] != stateSize; j++) { auto temp2 = result[j]; result[j] = temp; temp = temp2; @@ -277,10 +277,6 @@ namespace storm { return result; } - void Order::toString(std::ostream &out) { - - } - bool Order::above(Node *node1, Node *node2) { bool found = false; for (auto const& state : node1->states) { diff --git a/src/storm-pars/analysis/OrderExtender.cpp b/src/storm-pars/analysis/OrderExtender.cpp index d9f109777..636dd8913 100644 --- a/src/storm-pars/analysis/OrderExtender.cpp +++ b/src/storm-pars/analysis/OrderExtender.cpp @@ -53,7 +53,7 @@ namespace storm { storm::storage::StronglyConnectedComponentDecompositionOptions const options; this->sccs = storm::storage::StronglyConnectedComponentDecomposition(matrix, options); acyclic = true; - for (auto i = 0; acyclic && i < sccs.size(); ++i) { + for (size_t i = 0; acyclic && i < sccs.size(); ++i) { acyclic &= sccs.getBlock(i).size() <= 1; } } @@ -91,13 +91,9 @@ namespace storm { auto matrix = this->model->getTransitionMatrix(); auto initialMiddleStates = storm::storage::BitVector(numberOfStates); - // Check if MC contains cycles - storm::storage::StronglyConnectedComponentDecompositionOptions const options; - - // Create the Order - + // Add possible cycle breaking states if (!acyclic) { - for (auto i = 0; i < sccs.size(); ++i) { + for (size_t i = 0; i < sccs.size(); ++i) { auto scc = sccs.getBlock(i); if (scc.size() > 1) { auto states = scc.getStates(); diff --git a/src/test/storm-pars/analysis/AssumptionCheckerTest.cpp b/src/test/storm-pars/analysis/AssumptionCheckerTest.cpp index e08e4287e..fd5e31a85 100644 --- a/src/test/storm-pars/analysis/AssumptionCheckerTest.cpp +++ b/src/test/storm-pars/analysis/AssumptionCheckerTest.cpp @@ -131,8 +131,8 @@ TEST(AssumptionCheckerTest, Simple1) { model = simplifier.getSimplifiedModel(); dtmc = model->as>(); - ASSERT_EQ(dtmc->getNumberOfStates(), 5); - ASSERT_EQ(dtmc->getNumberOfTransitions(), 8); + ASSERT_EQ(dtmc->getNumberOfStates(), 5ul); + ASSERT_EQ(dtmc->getNumberOfTransitions(), 8ul); // Create the region auto vars = storm::models::sparse::getProbabilityParameters(*dtmc); @@ -183,8 +183,8 @@ TEST(AssumptionCheckerTest, Simple2) { model = simplifier.getSimplifiedModel(); dtmc = model->as>(); - ASSERT_EQ(dtmc->getNumberOfStates(), 5); - ASSERT_EQ(dtmc->getNumberOfTransitions(), 8); + ASSERT_EQ(dtmc->getNumberOfStates(), 5ul); + ASSERT_EQ(dtmc->getNumberOfTransitions(), 8ul); // Create the region auto vars = storm::models::sparse::getProbabilityParameters(*dtmc); @@ -249,8 +249,8 @@ TEST(AssumptionCheckerTest, Simple3) { model = simplifier.getSimplifiedModel(); dtmc = model->as>(); - ASSERT_EQ(6, dtmc->getNumberOfStates()); - ASSERT_EQ(12, dtmc->getNumberOfTransitions()); + ASSERT_EQ(6ul, dtmc->getNumberOfStates()); + ASSERT_EQ(12ul, dtmc->getNumberOfTransitions()); // Create the region auto vars = storm::models::sparse::getProbabilityParameters(*dtmc); @@ -318,8 +318,8 @@ TEST(AssumptionCheckerTest, Simple4) { model = simplifier.getSimplifiedModel(); dtmc = model->as>(); - ASSERT_EQ(dtmc->getNumberOfStates(), 5); - ASSERT_EQ(dtmc->getNumberOfTransitions(), 8); + ASSERT_EQ(dtmc->getNumberOfStates(), 5ul); + ASSERT_EQ(dtmc->getNumberOfTransitions(), 8ul); // Create the region auto vars = storm::models::sparse::getProbabilityParameters(*dtmc); diff --git a/src/test/storm-pars/analysis/MonotonicityCheckerTest.cpp b/src/test/storm-pars/analysis/MonotonicityCheckerTest.cpp index 3f1afd50c..c83d436b4 100644 --- a/src/test/storm-pars/analysis/MonotonicityCheckerTest.cpp +++ b/src/test/storm-pars/analysis/MonotonicityCheckerTest.cpp @@ -150,8 +150,8 @@ std::vector> regions = storm::analysis::MonotonicityChecker monotonicityChecker = storm::analysis::MonotonicityChecker(dtmc, formulas, regions, true); auto result = monotonicityChecker.checkMonotonicity(); - EXPECT_EQ(1, result.size()); - EXPECT_EQ(2, result.begin()->second.size()); + EXPECT_EQ(1ul, result.size()); + EXPECT_EQ(2ul, result.begin()->second.size()); auto monotone = result.begin()->second.begin(); EXPECT_EQ(true, monotone->second.first); EXPECT_EQ(false, monotone->second.second); @@ -198,8 +198,8 @@ TEST(MonotonicityCheckerTest, Brp_with_bisimulation_samples) { auto monotonicityChecker = storm::analysis::MonotonicityChecker(dtmc, formulas, regions, true, 50); auto result = monotonicityChecker.checkMonotonicity(); - EXPECT_EQ(1, result.size()); - EXPECT_EQ(2, result.begin()->second.size()); + EXPECT_EQ(1ul, result.size()); + EXPECT_EQ(2ul, result.begin()->second.size()); auto monotone = result.begin()->second.begin(); EXPECT_EQ(true, monotone->second.first); EXPECT_EQ(false, monotone->second.second); diff --git a/src/test/storm-pars/analysis/OrderExtenderTest.cpp b/src/test/storm-pars/analysis/OrderExtenderTest.cpp index e9c0c2115..50b916b71 100644 --- a/src/test/storm-pars/analysis/OrderExtenderTest.cpp +++ b/src/test/storm-pars/analysis/OrderExtenderTest.cpp @@ -53,7 +53,7 @@ TEST(OrderExtenderTest, Brp_with_bisimulation) { EXPECT_EQ(dtmc->getNumberOfStates(), std::get<2>(criticalTuple)); auto order = std::get<0>(criticalTuple); - for (auto i = 0; i < dtmc->getNumberOfStates(); ++i) { + for (uint_fast64_t i = 0; i < dtmc->getNumberOfStates(); ++i) { EXPECT_TRUE((*order->getAddedStates())[i]); } @@ -86,8 +86,8 @@ TEST(OrderExtenderTest, Brp_without_bisimulation) { auto *extender = new storm::analysis::OrderExtender(dtmc); auto criticalTuple = extender->toOrder(formulas); - EXPECT_EQ(183, std::get<1>(criticalTuple)); - EXPECT_EQ(186, std::get<2>(criticalTuple)); + EXPECT_EQ(183ul, std::get<1>(criticalTuple)); + EXPECT_EQ(186ul, std::get<2>(criticalTuple)); } From 9438d56ab308423077bd489cef7a18cb36975519 Mon Sep 17 00:00:00 2001 From: TimQu Date: Wed, 23 Oct 2019 21:02:18 +0200 Subject: [PATCH 178/178] added cli option for transforming continuous time models to discrete time. --- src/storm-cli-utilities/model-handling.h | 17 ++++++++++++++++- src/storm/api/transformation.h | 12 ++++++++++++ src/storm/settings/modules/IOSettings.cpp | 6 ------ src/storm/settings/modules/IOSettings.h | 6 ------ .../settings/modules/TransformationSettings.cpp | 11 +++++++++++ .../settings/modules/TransformationSettings.h | 11 +++++++++++ 6 files changed, 50 insertions(+), 13 deletions(-) diff --git a/src/storm-cli-utilities/model-handling.h b/src/storm-cli-utilities/model-handling.h index 47d33c0a1..6613030a2 100644 --- a/src/storm-cli-utilities/model-handling.h +++ b/src/storm-cli-utilities/model-handling.h @@ -371,7 +371,14 @@ namespace storm { result.second = true; } - if (ioSettings.isToNondeterministicModelSet()) { + if (transformationSettings.isToDiscreteTimeModelSet()) { + // TODO: we should also transform the properties at this point. + STORM_LOG_WARN_COND(!model->hasRewardModel("_time"), "Scheduled transformation to discrete time model, but a reward model named '_time' is already present in this model. We might take the wrong reward model later."); + result.first = storm::api::transformContinuousToDiscreteTimeSparseModel(std::move(*result.first), storm::api::extractFormulasFromProperties(input.properties)).first; + result.second = true; + } + + if (transformationSettings.isToNondeterministicModelSet()) { result.first = storm::api::transformToNondeterministicModel(std::move(*result.first)); result.second = true; } @@ -658,6 +665,14 @@ namespace storm { !storm::transformer::NonMarkovianChainTransformer::preservesFormula(*rawFormula)) { STORM_LOG_WARN("Property is not preserved by elimination of non-markovian states."); ignored = true; + } else if (transformationSettings.isToDiscreteTimeModelSet()) { + auto propertyFormula = storm::api::checkAndTransformContinuousToDiscreteTimeFormula(*property.getRawFormula()); + auto filterFormula = storm::api::checkAndTransformContinuousToDiscreteTimeFormula(*property.getFilter().getStatesFormula()); + if (propertyFormula && filterFormula) { + result = verificationCallback(propertyFormula, filterFormula); + } else { + ignored = true; + } } else { result = verificationCallback(property.getRawFormula(), property.getFilter().getStatesFormula()); diff --git a/src/storm/api/transformation.h b/src/storm/api/transformation.h index 4dcaf7f61..521aecb75 100644 --- a/src/storm/api/transformation.h +++ b/src/storm/api/transformation.h @@ -89,6 +89,18 @@ namespace storm { } + template + std::shared_ptr checkAndTransformContinuousToDiscreteTimeFormula(storm::logic::Formula const& formula, std::string const& timeRewardName = "_time") { + storm::transformer::ContinuousToDiscreteTimeModelTransformer transformer; + if (transformer.preservesFormula(formula)) { + return transformer.checkAndTransformFormulas({formula.asSharedPointer()}, timeRewardName).front(); + } else { + STORM_LOG_ERROR("Unable to transform formula " << formula << " to discrete time."); + } + return nullptr; + } + + /*! * Transforms the given symbolic model to a sparse model. */ diff --git a/src/storm/settings/modules/IOSettings.cpp b/src/storm/settings/modules/IOSettings.cpp index 04c7d4256..583f37c7f 100644 --- a/src/storm/settings/modules/IOSettings.cpp +++ b/src/storm/settings/modules/IOSettings.cpp @@ -44,7 +44,6 @@ namespace storm { const std::string IOSettings::janiPropertyOptionShortName = "jprop"; const std::string IOSettings::propertyOptionName = "prop"; const std::string IOSettings::propertyOptionShortName = "prop"; - const std::string IOSettings::toNondetOptionName = "to-nondet"; const std::string IOSettings::qvbsInputOptionName = "qvbs"; const std::string IOSettings::qvbsInputOptionShortName = "qvbs"; @@ -90,7 +89,6 @@ namespace storm { .addArgument(storm::settings::ArgumentBuilder::createStringArgument("values", "A comma separated list of constants and their value, e.g. a=1,b=2,c=3.").setDefaultValueString("").build()).build()); this->addOption(storm::settings::OptionBuilder(moduleName, janiPropertyOptionName, false, "Specifies the properties from the jani model (given by --" + janiInputOptionName + ") to be checked.").setShortName(janiPropertyOptionShortName) .addArgument(storm::settings::ArgumentBuilder::createStringArgument("values", "A comma separated list of properties to be checked").setDefaultValueString("").build()).build()); - this->addOption(storm::settings::OptionBuilder(moduleName, toNondetOptionName, false, "If set, DTMCs/CTMCs are converted to MDPs/MAs (without actual nondeterminism) before model checking.").setIsAdvanced().build()); this->addOption(storm::settings::OptionBuilder(moduleName, qvbsInputOptionName, false, "Selects a model from the Quantitative Verification Benchmark Set.").setShortName(qvbsInputOptionShortName) .addArgument(storm::settings::ArgumentBuilder::createStringArgument("model", "The short model name as in the benchmark set.").build()) @@ -266,10 +264,6 @@ namespace storm { return this->getOption(propertyOptionName).getArgumentByName("filter").getValueAsString(); } - bool IOSettings::isToNondeterministicModelSet() const { - return this->getOption(toNondetOptionName).getHasOptionBeenSet(); - } - bool IOSettings::isQvbsInputSet() const { return this->getOption(qvbsInputOptionName).getHasOptionBeenSet(); } diff --git a/src/storm/settings/modules/IOSettings.h b/src/storm/settings/modules/IOSettings.h index 96b419b67..9731a272c 100644 --- a/src/storm/settings/modules/IOSettings.h +++ b/src/storm/settings/modules/IOSettings.h @@ -290,11 +290,6 @@ namespace storm { * @return The property filter. */ std::string getPropertyFilter() const; - - /*! - * Retrieves whether a DTMC/CTMC should be converted to an MDP/MA - */ - bool isToNondeterministicModelSet() const; /*! * Retrieves whether the input model is to be read from the quantitative verification benchmark set (QVBS) @@ -354,7 +349,6 @@ namespace storm { static const std::string janiPropertyOptionShortName; static const std::string propertyOptionName; static const std::string propertyOptionShortName; - static const std::string toNondetOptionName; static const std::string qvbsInputOptionName; static const std::string qvbsInputOptionShortName; static const std::string qvbsRootOptionName; diff --git a/src/storm/settings/modules/TransformationSettings.cpp b/src/storm/settings/modules/TransformationSettings.cpp index 75b1c3daf..d948a48d9 100644 --- a/src/storm/settings/modules/TransformationSettings.cpp +++ b/src/storm/settings/modules/TransformationSettings.cpp @@ -12,6 +12,8 @@ namespace storm { const std::string TransformationSettings::chainEliminationOptionName = "eliminate-chains"; const std::string TransformationSettings::ignoreLabelingOptionName = "ec-ignore-labeling"; + const std::string TransformationSettings::toNondetOptionName = "to-nondet"; + const std::string TransformationSettings::toDiscreteTimeOptionName = "to-discrete"; TransformationSettings::TransformationSettings() : ModuleSettings(moduleName) { @@ -19,6 +21,8 @@ namespace storm { "If set, chains of non-Markovian states are eliminated if the resulting model is a Markov Automaton.").build()); this->addOption(storm::settings::OptionBuilder(moduleName, ignoreLabelingOptionName, false, "If set, the elimination of chains ignores the labels for all non-Markovian states. This may cause wrong results.").build()); + this->addOption(storm::settings::OptionBuilder(moduleName, toNondetOptionName, false, "If set, DTMCs/CTMCs are converted to MDPs/MAs (without actual nondeterminism) before model checking.").setIsAdvanced().build()); + this->addOption(storm::settings::OptionBuilder(moduleName, toDiscreteTimeOptionName, false, "If set, CTMCs/MAs are converted to DTMCs/MDPs (which might or might not preserve the provided properties).").setIsAdvanced().build()); } bool TransformationSettings::isChainEliminationSet() const { @@ -29,6 +33,13 @@ namespace storm { return this->getOption(ignoreLabelingOptionName).getHasOptionBeenSet(); } + bool TransformationSettings::isToNondeterministicModelSet() const { + return this->getOption(toNondetOptionName).getHasOptionBeenSet(); + } + + bool TransformationSettings::isToDiscreteTimeModelSet() const { + return this->getOption(toDiscreteTimeOptionName).getHasOptionBeenSet(); + } bool TransformationSettings::check() const { // Ensure that labeling preservation is only set if chain elimination is set diff --git a/src/storm/settings/modules/TransformationSettings.h b/src/storm/settings/modules/TransformationSettings.h index ba646c763..00642e5fb 100644 --- a/src/storm/settings/modules/TransformationSettings.h +++ b/src/storm/settings/modules/TransformationSettings.h @@ -34,6 +34,15 @@ namespace storm { */ bool isIgnoreLabelingSet() const; + /*! + * Retrieves whether a DTMC/CTMC should be converted to an MDP/MA + */ + bool isToNondeterministicModelSet() const; + + /*! + * Retrieves whether a CTMC/MA should be converted to a DTMC/MDP + */ + bool isToDiscreteTimeModelSet() const; bool check() const override; @@ -46,6 +55,8 @@ namespace storm { // Define the string names of the options as constants. static const std::string chainEliminationOptionName; static const std::string ignoreLabelingOptionName; + static const std::string toNondetOptionName; + static const std::string toDiscreteTimeOptionName; };