You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
323 lines
15 KiB
323 lines
15 KiB
#include "storm/storage/jani/OrderedAssignments.h"
|
|
|
|
#include "storm/utility/macros.h"
|
|
#include "storm/exceptions/InvalidArgumentException.h"
|
|
#include "storm/storage/jani/VariableSet.h"
|
|
|
|
namespace storm {
|
|
namespace jani {
|
|
|
|
OrderedAssignments::OrderedAssignments(std::vector<Assignment> const& assignments) {
|
|
for (auto const& assignment : assignments) {
|
|
add(assignment);
|
|
}
|
|
}
|
|
|
|
OrderedAssignments::OrderedAssignments(Assignment const& assignment) {
|
|
add(assignment);
|
|
}
|
|
|
|
OrderedAssignments OrderedAssignments::clone() const {
|
|
OrderedAssignments result;
|
|
for (auto const& assignment : allAssignments) {
|
|
result.add(Assignment(*assignment));
|
|
}
|
|
return result;
|
|
}
|
|
|
|
bool OrderedAssignments::add(Assignment const& assignment, bool addToExisting) {
|
|
// If the element is contained in this set of assignment, nothing needs to be added.
|
|
if (!addToExisting && this->contains(assignment)) {
|
|
return false;
|
|
}
|
|
|
|
// Otherwise, we find the spot to insert it.
|
|
auto it = lowerBound(assignment, allAssignments);
|
|
|
|
// Check if an assignment to this variable is already present
|
|
if (it != allAssignments.end() && assignment.getLValue() == (*it)->getLValue()) {
|
|
STORM_LOG_THROW(addToExisting && assignment.getLValue().isVariable() && assignment.getExpressionVariable().hasNumericalType(), storm::exceptions::InvalidArgumentException, "Cannot add assignment ('" << assignment.getAssignedExpression() << "') as an assignment ('" << (*it)->getAssignedExpression() << "') to LValue '" << (*it)->getLValue() << "' already exists.");
|
|
(*it)->setAssignedExpression((*it)->getAssignedExpression() + assignment.getAssignedExpression());
|
|
} else {
|
|
// Finally, insert the new element in the correct vectors.
|
|
auto elementToInsert = std::make_shared<Assignment>(assignment);
|
|
allAssignments.emplace(it, elementToInsert);
|
|
if (assignment.isTransient()) {
|
|
auto transientIt = lowerBound(assignment, transientAssignments);
|
|
transientAssignments.emplace(transientIt, elementToInsert);
|
|
} else {
|
|
auto nonTransientIt = lowerBound(assignment, nonTransientAssignments);
|
|
nonTransientAssignments.emplace(nonTransientIt, elementToInsert);
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool OrderedAssignments::remove(Assignment const& assignment) {
|
|
// If the element is contained in this set of assignment, nothing needs to be removed.
|
|
if (!this->contains(assignment)) {
|
|
return false;
|
|
}
|
|
|
|
// Otherwise, we find the element to delete.
|
|
auto it = lowerBound(assignment, allAssignments);
|
|
STORM_LOG_ASSERT(it != allAssignments.end(), "Invalid iterator, expected existing element.");
|
|
STORM_LOG_ASSERT(assignment == **it, "Wrong iterator position.");
|
|
allAssignments.erase(it);
|
|
|
|
if (assignment.isTransient()) {
|
|
auto transientIt = lowerBound(assignment, transientAssignments);
|
|
STORM_LOG_ASSERT(transientIt != transientAssignments.end(), "Invalid iterator, expected existing element.");
|
|
STORM_LOG_ASSERT(assignment == **transientIt, "Wrong iterator position.");
|
|
transientAssignments.erase(transientIt);
|
|
} else {
|
|
auto nonTransientIt = lowerBound(assignment, nonTransientAssignments);
|
|
STORM_LOG_ASSERT(nonTransientIt != nonTransientAssignments.end(), "Invalid iterator, expected existing element.");
|
|
STORM_LOG_ASSERT(assignment == **nonTransientIt, "Wrong iterator position.");
|
|
nonTransientAssignments.erase(nonTransientIt);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool OrderedAssignments::hasMultipleLevels(bool onlyTransient) const {
|
|
if ((onlyTransient ? transientAssignments : allAssignments).empty()) {
|
|
return false;
|
|
}
|
|
return getLowestLevel(onlyTransient) != 0 || getHighestLevel(onlyTransient) != 0;
|
|
}
|
|
|
|
bool OrderedAssignments::empty() const {
|
|
return allAssignments.empty();
|
|
}
|
|
|
|
void OrderedAssignments::clear() {
|
|
allAssignments.clear();
|
|
transientAssignments.clear();
|
|
nonTransientAssignments.clear();
|
|
}
|
|
|
|
std::size_t OrderedAssignments::getNumberOfAssignments() const {
|
|
return allAssignments.size();
|
|
}
|
|
|
|
int64_t OrderedAssignments::getLowestLevel(bool onlyTransient) const {
|
|
auto const& as = onlyTransient ? transientAssignments : allAssignments;
|
|
assert(!as.empty());
|
|
return as.front()->getLevel();
|
|
}
|
|
|
|
int64_t OrderedAssignments::getHighestLevel(bool onlyTransient) const {
|
|
auto const& as = onlyTransient ? transientAssignments : allAssignments;
|
|
assert(!as.empty());
|
|
return as.back()->getLevel();
|
|
}
|
|
|
|
bool OrderedAssignments::contains(Assignment const& assignment) const {
|
|
auto it = lowerBound(assignment, allAssignments);
|
|
if (it != allAssignments.end() && assignment == **it) {
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
OrderedAssignments OrderedAssignments::simplifyLevels(bool synchronous, VariableSet const& localVars, bool first) const {
|
|
bool changed = false;
|
|
if (first) {
|
|
std::vector<Assignment> newAssignments;
|
|
for (uint64_t i = 0; i < allAssignments.size(); ++i) {
|
|
auto const& iLValue = allAssignments.at(i)->getLValue();
|
|
if (synchronous && !localVars.hasVariable(iLValue.isVariable() ? iLValue.getVariable() : iLValue.getArray())) {
|
|
newAssignments.push_back(*(allAssignments.at(i)));
|
|
continue;
|
|
}
|
|
bool readBeforeWrite = true;
|
|
for (uint64_t j = i + 1; j < allAssignments.size(); ++j) {
|
|
if (allAssignments.at(j)->getAssignedExpression().containsVariable(
|
|
{iLValue.isVariable() ? iLValue.getVariable().getExpressionVariable() : iLValue.getArray().getExpressionVariable()})) {
|
|
// is read.
|
|
break;
|
|
}
|
|
if (iLValue == allAssignments.at(j)->getLValue()) {
|
|
// is written, has not been read before
|
|
readBeforeWrite = false;
|
|
break;
|
|
}
|
|
|
|
}
|
|
if (readBeforeWrite) {
|
|
newAssignments.push_back(*(allAssignments.at(i)));
|
|
} else {
|
|
changed = true;
|
|
}
|
|
}
|
|
if (changed) {
|
|
return OrderedAssignments(newAssignments).simplifyLevels(synchronous, localVars, false);
|
|
}
|
|
}
|
|
|
|
|
|
std::vector<Assignment> newAssignments;
|
|
for (auto const& assignment : allAssignments) {
|
|
newAssignments.push_back(*assignment);
|
|
if (assignment->isTransient() && !assignment->getAssignedExpression().containsVariables()) {
|
|
// Since we do not support
|
|
}
|
|
if (synchronous && !localVars.hasVariable(assignment->getLValue().isVariable() ? assignment->getLValue().getVariable() : assignment->getLValue().getArray())) {
|
|
continue;
|
|
}
|
|
if (assignment->getLevel() == 0) {
|
|
continue;
|
|
}
|
|
uint64_t assNr = upperBound(assignment->getLevel() - 1);
|
|
if (assNr == isWrittenBeforeAssignment(assignment->getLValue(), assNr)) {
|
|
if (assNr == isReadBeforeAssignment(assignment->getLValue(), assNr)) {
|
|
newAssignments.back().setLevel(0);
|
|
changed = true;
|
|
}
|
|
}
|
|
}
|
|
if (changed) {
|
|
return OrderedAssignments(newAssignments).simplifyLevels(synchronous, localVars, false);
|
|
} else {
|
|
return *this;
|
|
}
|
|
|
|
}
|
|
|
|
detail::ConstAssignments OrderedAssignments::getAllAssignments() const {
|
|
return detail::ConstAssignments(allAssignments.begin(), allAssignments.end());
|
|
}
|
|
|
|
detail::ConstAssignments OrderedAssignments::getTransientAssignments() const {
|
|
return detail::ConstAssignments(transientAssignments.begin(), transientAssignments.end());
|
|
}
|
|
|
|
detail::ConstAssignments OrderedAssignments::getNonTransientAssignments() const {
|
|
return detail::ConstAssignments(nonTransientAssignments.begin(), nonTransientAssignments.end());
|
|
}
|
|
|
|
struct AssignmentLevelToLevelComparator {
|
|
bool operator()(std::shared_ptr<Assignment> const& left, int64_t const& right) const {
|
|
return left->getLevel() < right;
|
|
}
|
|
bool operator()(int64_t const& left, std::shared_ptr<Assignment> const& right) const {
|
|
return left < right->getLevel();
|
|
}
|
|
};
|
|
|
|
detail::ConstAssignments OrderedAssignments::getTransientAssignments(int64_t assignmentLevel) const {
|
|
auto begin = std::lower_bound(transientAssignments.begin(), transientAssignments.end(), assignmentLevel, AssignmentLevelToLevelComparator());
|
|
auto end = std::upper_bound(begin, transientAssignments.end(), assignmentLevel, AssignmentLevelToLevelComparator());
|
|
return detail::ConstAssignments(begin, end);
|
|
}
|
|
|
|
detail::ConstAssignments OrderedAssignments::getNonTransientAssignments(int64_t assignmentLevel) const {
|
|
auto begin = std::lower_bound(nonTransientAssignments.begin(), nonTransientAssignments.end(), assignmentLevel, AssignmentLevelToLevelComparator());
|
|
auto end = std::upper_bound(begin, nonTransientAssignments.end(), assignmentLevel, AssignmentLevelToLevelComparator());
|
|
return detail::ConstAssignments(begin, end);
|
|
}
|
|
|
|
bool OrderedAssignments::hasTransientAssignment() const {
|
|
return !transientAssignments.empty();
|
|
}
|
|
|
|
detail::Assignments::iterator OrderedAssignments::begin() {
|
|
return detail::Assignments::make_iterator(allAssignments.begin());
|
|
}
|
|
|
|
detail::ConstAssignments::iterator OrderedAssignments::begin() const {
|
|
return detail::ConstAssignments::make_iterator(allAssignments.begin());
|
|
}
|
|
|
|
detail::Assignments::iterator OrderedAssignments::end() {
|
|
return detail::Assignments::make_iterator(allAssignments.end());
|
|
}
|
|
|
|
detail::ConstAssignments::iterator OrderedAssignments::end() const {
|
|
return detail::ConstAssignments::make_iterator(allAssignments.end());
|
|
}
|
|
|
|
void OrderedAssignments::substitute(std::map<storm::expressions::Variable, storm::expressions::Expression> const& substitution) {
|
|
for (auto& assignment : allAssignments) {
|
|
assignment->substitute(substitution);
|
|
}
|
|
}
|
|
|
|
void OrderedAssignments::changeAssignmentVariables(std::map<Variable const*, std::reference_wrapper<Variable const>> const& remapping) {
|
|
std::vector<Assignment> newAssignments;
|
|
for (auto& assignment : allAssignments) {
|
|
newAssignments.emplace_back(assignment->getLValue().changeAssignmentVariables(remapping), assignment->getAssignedExpression(), assignment->getLevel());
|
|
}
|
|
*this = OrderedAssignments(newAssignments);
|
|
}
|
|
|
|
std::vector<std::shared_ptr<Assignment>>::const_iterator OrderedAssignments::lowerBound(Assignment const& assignment, std::vector<std::shared_ptr<Assignment>> const& assignments) {
|
|
return std::lower_bound(assignments.begin(), assignments.end(), assignment, storm::jani::AssignmentPartialOrderByLevelAndLValue());
|
|
}
|
|
|
|
uint64_t OrderedAssignments::isReadBeforeAssignment(LValue const& lValue, uint64_t assignmentNumber, uint64_t start) const {
|
|
Variable const& var = lValue.isVariable() ? lValue.getVariable() : lValue.getArray();
|
|
// TODO: do this more carefully
|
|
STORM_LOG_WARN_COND(lValue.isVariable(), "Called a method that is not optimized for arrays.");
|
|
for (uint64_t i = start; i < assignmentNumber; i++) {
|
|
if (allAssignments.at(i)->getAssignedExpression().containsVariable({ var.getExpressionVariable() })) {
|
|
return i;
|
|
}
|
|
}
|
|
return assignmentNumber;
|
|
}
|
|
|
|
uint64_t OrderedAssignments::isWrittenBeforeAssignment(LValue const& lValue, uint64_t assignmentNumber, uint64_t start) const {
|
|
for (uint64_t i = start; i < assignmentNumber; i++) {
|
|
if (allAssignments.at(i)->getLValue() == lValue) {
|
|
return i;
|
|
}
|
|
}
|
|
return assignmentNumber;
|
|
}
|
|
|
|
uint64_t OrderedAssignments::upperBound(int64_t index) const {
|
|
uint64_t result = 0;
|
|
for(auto const& assignment : allAssignments) {
|
|
if(assignment->getLevel() > index) {
|
|
return result;
|
|
}
|
|
++result;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
bool OrderedAssignments::areLinear() const {
|
|
bool result = true;
|
|
for (auto const& assignment : getAllAssignments()) {
|
|
result &= assignment.isLinear();
|
|
}
|
|
return result;
|
|
}
|
|
|
|
bool OrderedAssignments::checkOrder() const {
|
|
for (std::vector<std::shared_ptr<Assignment>>::const_iterator it = allAssignments.cbegin(); it != allAssignments.cend(); ++it) {
|
|
if (it != lowerBound(**it, allAssignments)) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
std::ostream& operator<<(std::ostream& stream, OrderedAssignments const& assignments) {
|
|
stream << "[";
|
|
for(auto const& e : assignments.allAssignments) {
|
|
stream << *e;
|
|
if (e->getLevel() != 0) {
|
|
stream << " @" << e->getLevel();
|
|
}
|
|
stream << std::endl;
|
|
}
|
|
stream << "]";
|
|
return stream;
|
|
}
|
|
|
|
}
|
|
}
|