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.
443 lines
22 KiB
443 lines
22 KiB
#include <cstring>
|
|
#include <algorithm>
|
|
|
|
#include "src/storage/dd/CuddDd.h"
|
|
#include "src/storage/dd/CuddDdManager.h"
|
|
|
|
#include "src/exceptions/InvalidArgumentException.h"
|
|
|
|
namespace storm {
|
|
namespace dd {
|
|
Dd<DdType::CUDD>::Dd(std::shared_ptr<DdManager<DdType::CUDD>> ddManager, ADD cuddAdd, std::set<std::string> const& containedMetaVariableNames) : ddManager(ddManager), cuddAdd(cuddAdd), containedMetaVariableNames(containedMetaVariableNames) {
|
|
// Intentionally left empty.
|
|
}
|
|
|
|
bool Dd<DdType::CUDD>::operator==(Dd<DdType::CUDD> const& other) const {
|
|
return this->cuddAdd == other.getCuddAdd();
|
|
}
|
|
|
|
bool Dd<DdType::CUDD>::operator!=(Dd<DdType::CUDD> const& other) const {
|
|
return this->cuddAdd != other.getCuddAdd();
|
|
}
|
|
|
|
Dd<DdType::CUDD> Dd<DdType::CUDD>::operator+(Dd<DdType::CUDD> const& other) const {
|
|
Dd<DdType::CUDD> result(*this);
|
|
result += other;
|
|
return result;
|
|
}
|
|
|
|
Dd<DdType::CUDD>& Dd<DdType::CUDD>::operator+=(Dd<DdType::CUDD> const& other) {
|
|
this->cuddAdd += other.getCuddAdd();
|
|
|
|
// Join the variable sets of the two participating DDs.
|
|
this->getContainedMetaVariableNames().insert(other.getContainedMetaVariableNames().begin(), other.getContainedMetaVariableNames().end());
|
|
|
|
return *this;
|
|
}
|
|
|
|
Dd<DdType::CUDD> Dd<DdType::CUDD>::operator*(Dd<DdType::CUDD> const& other) const {
|
|
Dd<DdType::CUDD> result(*this);
|
|
result *= other;
|
|
return result;
|
|
}
|
|
|
|
Dd<DdType::CUDD>& Dd<DdType::CUDD>::operator*=(Dd<DdType::CUDD> const& other) {
|
|
this->cuddAdd *= other.getCuddAdd();
|
|
|
|
// Join the variable sets of the two participating DDs.
|
|
this->getContainedMetaVariableNames().insert(other.getContainedMetaVariableNames().begin(), other.getContainedMetaVariableNames().end());
|
|
|
|
return *this;
|
|
}
|
|
|
|
Dd<DdType::CUDD> Dd<DdType::CUDD>::operator-(Dd<DdType::CUDD> const& other) const {
|
|
Dd<DdType::CUDD> result(*this);
|
|
result -= other;
|
|
return result;
|
|
}
|
|
|
|
Dd<DdType::CUDD> Dd<DdType::CUDD>::operator-() const {
|
|
return this->getDdManager()->getZero() - *this;
|
|
}
|
|
|
|
Dd<DdType::CUDD>& Dd<DdType::CUDD>::operator-=(Dd<DdType::CUDD> const& other) {
|
|
this->cuddAdd -= other.getCuddAdd();
|
|
|
|
// Join the variable sets of the two participating DDs.
|
|
this->getContainedMetaVariableNames().insert(other.getContainedMetaVariableNames().begin(), other.getContainedMetaVariableNames().end());
|
|
|
|
return *this;
|
|
}
|
|
|
|
Dd<DdType::CUDD> Dd<DdType::CUDD>::operator/(Dd<DdType::CUDD> const& other) const {
|
|
Dd<DdType::CUDD> result(*this);
|
|
result /= other;
|
|
return result;
|
|
}
|
|
|
|
Dd<DdType::CUDD>& Dd<DdType::CUDD>::operator/=(Dd<DdType::CUDD> const& other) {
|
|
this->cuddAdd = this->cuddAdd.Divide(other.getCuddAdd());
|
|
|
|
// Join the variable sets of the two participating DDs.
|
|
this->getContainedMetaVariableNames().insert(other.getContainedMetaVariableNames().begin(), other.getContainedMetaVariableNames().end());
|
|
|
|
return *this;
|
|
}
|
|
|
|
Dd<DdType::CUDD> Dd<DdType::CUDD>::operator!() const {
|
|
Dd<DdType::CUDD> result(*this);
|
|
result.complement();
|
|
return result;
|
|
}
|
|
|
|
Dd<DdType::CUDD> Dd<DdType::CUDD>::operator&&(Dd<DdType::CUDD> const& other) const {
|
|
std::set<std::string> metaVariableNames(this->getContainedMetaVariableNames());
|
|
metaVariableNames.insert(other.getContainedMetaVariableNames().begin(), other.getContainedMetaVariableNames().end());
|
|
|
|
// Rewrite a and b to not((not a) or (not b)).
|
|
return Dd<DdType::CUDD>(this->getDdManager(), ~(~this->getCuddAdd()).Or(~other.getCuddAdd()), metaVariableNames);
|
|
}
|
|
|
|
Dd<DdType::CUDD> Dd<DdType::CUDD>::operator||(Dd<DdType::CUDD> const& other) const {
|
|
std::set<std::string> metaVariableNames(this->getContainedMetaVariableNames());
|
|
metaVariableNames.insert(other.getContainedMetaVariableNames().begin(), other.getContainedMetaVariableNames().end());
|
|
return Dd<DdType::CUDD>(this->getDdManager(), this->getCuddAdd().Or(other.getCuddAdd()), metaVariableNames);
|
|
}
|
|
|
|
Dd<DdType::CUDD>& Dd<DdType::CUDD>::complement() {
|
|
this->cuddAdd = ~this->cuddAdd;
|
|
return *this;
|
|
}
|
|
|
|
Dd<DdType::CUDD> Dd<DdType::CUDD>::equals(Dd<DdType::CUDD> const& other) const {
|
|
Dd<DdType::CUDD> result(*this);
|
|
result.cuddAdd = result.cuddAdd.Equals(other.getCuddAdd());
|
|
return result;
|
|
}
|
|
|
|
Dd<DdType::CUDD> Dd<DdType::CUDD>::notEquals(Dd<DdType::CUDD> const& other) const {
|
|
Dd<DdType::CUDD> result(*this);
|
|
result.cuddAdd = result.cuddAdd.NotEquals(other.getCuddAdd());
|
|
return result;
|
|
}
|
|
|
|
Dd<DdType::CUDD> Dd<DdType::CUDD>::less(Dd<DdType::CUDD> const& other) const {
|
|
Dd<DdType::CUDD> result(*this);
|
|
result.cuddAdd = result.cuddAdd.LessThan(other.getCuddAdd());
|
|
return result;
|
|
}
|
|
|
|
Dd<DdType::CUDD> Dd<DdType::CUDD>::lessOrEqual(Dd<DdType::CUDD> const& other) const {
|
|
Dd<DdType::CUDD> result(*this);
|
|
result.cuddAdd = result.cuddAdd.LessThanOrEqual(other.getCuddAdd());
|
|
return result;
|
|
}
|
|
|
|
Dd<DdType::CUDD> Dd<DdType::CUDD>::greater(Dd<DdType::CUDD> const& other) const {
|
|
Dd<DdType::CUDD> result(*this);
|
|
result.cuddAdd = result.cuddAdd.GreaterThan(other.getCuddAdd());
|
|
return result;
|
|
}
|
|
|
|
Dd<DdType::CUDD> Dd<DdType::CUDD>::greaterOrEqual(Dd<DdType::CUDD> const& other) const {
|
|
Dd<DdType::CUDD> result(*this);
|
|
result.cuddAdd = result.cuddAdd.GreaterThanOrEqual(other.getCuddAdd());
|
|
return result;
|
|
}
|
|
|
|
void Dd<DdType::CUDD>::existsAbstract(std::set<std::string> const& metaVariableNames) {
|
|
Dd<DdType::CUDD> cubeDd(this->getDdManager()->getOne());
|
|
|
|
for (auto const& metaVariableName : metaVariableNames) {
|
|
// First check whether the DD contains the meta variable and erase it, if this is the case.
|
|
if (!this->containsMetaVariable(metaVariableName)) {
|
|
throw storm::exceptions::InvalidArgumentException() << "Cannot abstract from meta variable that is not present in the DD.";
|
|
}
|
|
this->getContainedMetaVariableNames().erase(metaVariableName);
|
|
|
|
DdMetaVariable<DdType::CUDD> const& metaVariable = this->getDdManager()->getMetaVariable(metaVariableName);
|
|
cubeDd *= metaVariable.getCube();
|
|
}
|
|
|
|
this->cuddAdd = this->cuddAdd.OrAbstract(cubeDd.getCuddAdd());
|
|
}
|
|
|
|
void Dd<DdType::CUDD>::sumAbstract(std::set<std::string> const& metaVariableNames) {
|
|
Dd<DdType::CUDD> cubeDd(this->getDdManager()->getOne());
|
|
|
|
for (auto const& metaVariableName : metaVariableNames) {
|
|
// First check whether the DD contains the meta variable and erase it, if this is the case.
|
|
if (!this->containsMetaVariable(metaVariableName)) {
|
|
throw storm::exceptions::InvalidArgumentException() << "Cannot abstract from meta variable that is not present in the DD.";
|
|
}
|
|
this->getContainedMetaVariableNames().erase(metaVariableName);
|
|
|
|
DdMetaVariable<DdType::CUDD> const& metaVariable = this->getDdManager()->getMetaVariable(metaVariableName);
|
|
cubeDd *= metaVariable.getCube();
|
|
}
|
|
|
|
this->cuddAdd = this->cuddAdd.ExistAbstract(cubeDd.getCuddAdd());
|
|
}
|
|
|
|
void Dd<DdType::CUDD>::minAbstract(std::set<std::string> const& metaVariableNames) {
|
|
Dd<DdType::CUDD> cubeDd(this->getDdManager()->getOne());
|
|
|
|
for (auto const& metaVariableName : metaVariableNames) {
|
|
// First check whether the DD contains the meta variable and erase it, if this is the case.
|
|
if (!this->containsMetaVariable(metaVariableName)) {
|
|
throw storm::exceptions::InvalidArgumentException() << "Cannot abstract from meta variable that is not present in the DD.";
|
|
}
|
|
this->getContainedMetaVariableNames().erase(metaVariableName);
|
|
|
|
DdMetaVariable<DdType::CUDD> const& metaVariable = this->getDdManager()->getMetaVariable(metaVariableName);
|
|
cubeDd *= metaVariable.getCube();
|
|
}
|
|
|
|
this->cuddAdd = this->cuddAdd.MinAbstract(cubeDd.getCuddAdd());
|
|
}
|
|
|
|
void Dd<DdType::CUDD>::maxAbstract(std::set<std::string> const& metaVariableNames) {
|
|
Dd<DdType::CUDD> cubeDd(this->getDdManager()->getOne());
|
|
|
|
for (auto const& metaVariableName : metaVariableNames) {
|
|
// First check whether the DD contains the meta variable and erase it, if this is the case.
|
|
if (!this->containsMetaVariable(metaVariableName)) {
|
|
throw storm::exceptions::InvalidArgumentException() << "Cannot abstract from meta variable that is not present in the DD.";
|
|
}
|
|
this->getContainedMetaVariableNames().erase(metaVariableName);
|
|
|
|
DdMetaVariable<DdType::CUDD> const& metaVariable = this->getDdManager()->getMetaVariable(metaVariableName);
|
|
cubeDd *= metaVariable.getCube();
|
|
}
|
|
|
|
this->cuddAdd = this->cuddAdd.MaxAbstract(cubeDd.getCuddAdd());
|
|
}
|
|
|
|
bool Dd<DdType::CUDD>::equalModuloPrecision(Dd<DdType::CUDD> const& other, double precision, bool relative) const {
|
|
if (relative) {
|
|
return this->getCuddAdd().EqualSupNormRel(other.getCuddAdd(), precision);
|
|
} else {
|
|
return this->getCuddAdd().EqualSupNorm(other.getCuddAdd(), precision);
|
|
}
|
|
}
|
|
|
|
void Dd<DdType::CUDD>::swapVariables(std::vector<std::pair<std::string, std::string>> const& metaVariablePairs) {
|
|
std::vector<ADD> from;
|
|
std::vector<ADD> to;
|
|
for (auto const& metaVariablePair : metaVariablePairs) {
|
|
DdMetaVariable<DdType::CUDD> const& variable1 = this->getDdManager()->getMetaVariable(metaVariablePair.first);
|
|
DdMetaVariable<DdType::CUDD> const& variable2 = this->getDdManager()->getMetaVariable(metaVariablePair.second);
|
|
|
|
// Check if it's legal so swap the meta variables.
|
|
if (variable1.getNumberOfDdVariables() != variable2.getNumberOfDdVariables()) {
|
|
throw storm::exceptions::InvalidArgumentException() << "Unable to swap meta variables with different size.";
|
|
}
|
|
|
|
// Keep track of the contained meta variables in the DD.
|
|
bool containsVariable1 = this->containsMetaVariable(metaVariablePair.first);
|
|
bool containsVariable2 = this->containsMetaVariable(metaVariablePair.second);
|
|
if (containsVariable1 && !containsVariable2) {
|
|
this->removeContainedMetaVariable(metaVariablePair.first);
|
|
this->addContainedMetaVariable(metaVariablePair.second);
|
|
} else if (!containsVariable1 && containsVariable2) {
|
|
this->removeContainedMetaVariable(metaVariablePair.second);
|
|
this->addContainedMetaVariable(metaVariablePair.first);
|
|
}
|
|
|
|
// Add the variables to swap to the corresponding vectors.
|
|
for (auto const& ddVariable : variable1.getDdVariables()) {
|
|
from.push_back(ddVariable.getCuddAdd());
|
|
}
|
|
for (auto const& ddVariable : variable2.getDdVariables()) {
|
|
to.push_back(ddVariable.getCuddAdd());
|
|
}
|
|
}
|
|
|
|
// Finally, call CUDD to swap the variables.
|
|
this->cuddAdd = this->cuddAdd.SwapVariables(from, to);
|
|
}
|
|
|
|
Dd<DdType::CUDD> Dd<DdType::CUDD>::multiplyMatrix(Dd<DdType::CUDD> const& otherMatrix, std::set<std::string> const& summationMetaVariableNames) const {
|
|
std::vector<ADD> summationDdVariables;
|
|
|
|
// Create the CUDD summation variables.
|
|
for (auto const& metaVariableName : summationMetaVariableNames) {
|
|
for (auto const& ddVariable : this->getDdManager()->getMetaVariable(metaVariableName).getDdVariables()) {
|
|
summationDdVariables.push_back(ddVariable.getCuddAdd());
|
|
}
|
|
}
|
|
|
|
std::set<std::string> unionOfMetaVariableNames;
|
|
std::set_union(this->getContainedMetaVariableNames().begin(), this->getContainedMetaVariableNames().end(), otherMatrix.getContainedMetaVariableNames().begin(), otherMatrix.getContainedMetaVariableNames().end(), std::inserter(unionOfMetaVariableNames, unionOfMetaVariableNames.begin()));
|
|
std::set<std::string> containedMetaVariableNames;
|
|
std::set_difference(unionOfMetaVariableNames.begin(), unionOfMetaVariableNames.end(), summationMetaVariableNames.begin(), summationMetaVariableNames.end(), std::inserter(containedMetaVariableNames, containedMetaVariableNames.begin()));
|
|
|
|
return Dd<DdType::CUDD>(this->getDdManager(), this->cuddAdd.MatrixMultiply(otherMatrix.getCuddAdd(), summationDdVariables), containedMetaVariableNames);
|
|
}
|
|
|
|
uint_fast64_t Dd<DdType::CUDD>::getNonZeroCount() const {
|
|
std::size_t numberOfDdVariables = 0;
|
|
for (auto const& metaVariableName : this->containedMetaVariableNames) {
|
|
numberOfDdVariables += this->getDdManager()->getMetaVariable(metaVariableName).getNumberOfDdVariables();
|
|
}
|
|
return static_cast<uint_fast64_t>(this->cuddAdd.CountMinterm(static_cast<int>(numberOfDdVariables)));
|
|
}
|
|
|
|
uint_fast64_t Dd<DdType::CUDD>::getLeafCount() const {
|
|
return static_cast<uint_fast64_t>(this->cuddAdd.CountLeaves());
|
|
}
|
|
|
|
uint_fast64_t Dd<DdType::CUDD>::getNodeCount() const {
|
|
return static_cast<uint_fast64_t>(this->cuddAdd.nodeCount());
|
|
}
|
|
|
|
double Dd<DdType::CUDD>::getMin() const {
|
|
ADD constantMinAdd = this->cuddAdd.FindMin();
|
|
return static_cast<double>(Cudd_V(constantMinAdd.getNode()));
|
|
}
|
|
|
|
double Dd<DdType::CUDD>::getMax() const {
|
|
ADD constantMaxAdd = this->cuddAdd.FindMax();
|
|
return static_cast<double>(Cudd_V(constantMaxAdd.getNode()));
|
|
}
|
|
|
|
void Dd<DdType::CUDD>::setValue(std::string const& metaVariableName, int_fast64_t variableValue, double targetValue) {
|
|
std::map<std::string, int_fast64_t> metaVariableNameToValueMap;
|
|
metaVariableNameToValueMap.emplace(metaVariableName, variableValue);
|
|
this->setValue(metaVariableNameToValueMap, targetValue);
|
|
}
|
|
|
|
void Dd<DdType::CUDD>::setValue(std::string const& metaVariableName1, int_fast64_t variableValue1, std::string const& metaVariableName2, int_fast64_t variableValue2, double targetValue) {
|
|
std::map<std::string, int_fast64_t> metaVariableNameToValueMap;
|
|
metaVariableNameToValueMap.emplace(metaVariableName1, variableValue1);
|
|
metaVariableNameToValueMap.emplace(metaVariableName2, variableValue2);
|
|
this->setValue(metaVariableNameToValueMap, targetValue);
|
|
}
|
|
|
|
void Dd<DdType::CUDD>::setValue(std::map<std::string, int_fast64_t> const& metaVariableNameToValueMap, double targetValue) {
|
|
Dd<DdType::CUDD> valueEncoding(this->getDdManager()->getOne());
|
|
for (auto const& nameValuePair : metaVariableNameToValueMap) {
|
|
valueEncoding *= this->getDdManager()->getEncoding(nameValuePair.first, nameValuePair.second);
|
|
// Also record that the DD now contains the meta variable.
|
|
this->addContainedMetaVariable(nameValuePair.first);
|
|
}
|
|
|
|
this->cuddAdd = valueEncoding.getCuddAdd().Ite(this->getDdManager()->getConstant(targetValue).getCuddAdd(), this->cuddAdd);
|
|
}
|
|
|
|
double Dd<DdType::CUDD>::getValue(std::map<std::string, int_fast64_t> const& metaVariableNameToValueMap) const {
|
|
std::set<std::string> remainingMetaVariables(this->getContainedMetaVariableNames());
|
|
Dd<DdType::CUDD> valueEncoding(this->getDdManager()->getOne());
|
|
for (auto const& nameValuePair : metaVariableNameToValueMap) {
|
|
valueEncoding *= this->getDdManager()->getEncoding(nameValuePair.first, nameValuePair.second);
|
|
if (this->containsMetaVariable(nameValuePair.first)) {
|
|
remainingMetaVariables.erase(nameValuePair.first);
|
|
}
|
|
}
|
|
|
|
if (!remainingMetaVariables.empty()) {
|
|
throw storm::exceptions::InvalidArgumentException() << "Cannot evaluate function for which not all inputs were given.";
|
|
}
|
|
|
|
Dd<DdType::CUDD> value = *this * valueEncoding;
|
|
value.sumAbstract(this->getContainedMetaVariableNames());
|
|
return static_cast<double>(Cudd_V(value.getCuddAdd().getNode()));
|
|
}
|
|
|
|
bool Dd<DdType::CUDD>::isOne() const {
|
|
return *this == this->getDdManager()->getOne();
|
|
}
|
|
|
|
bool Dd<DdType::CUDD>::isZero() const {
|
|
return *this == this->getDdManager()->getZero();
|
|
}
|
|
|
|
bool Dd<DdType::CUDD>::isConstant() const {
|
|
return Cudd_IsConstant(this->cuddAdd.getNode());
|
|
}
|
|
|
|
bool Dd<DdType::CUDD>::containsMetaVariable(std::string const& metaVariableName) const {
|
|
auto const& metaVariable = containedMetaVariableNames.find(metaVariableName);
|
|
return metaVariable != containedMetaVariableNames.end();
|
|
}
|
|
|
|
bool Dd<DdType::CUDD>::containsMetaVariables(std::set<std::string> metaVariableNames) const {
|
|
for (auto const& metaVariableName : metaVariableNames) {
|
|
auto const& metaVariable = containedMetaVariableNames.find(metaVariableName);
|
|
|
|
if (metaVariable == containedMetaVariableNames.end()) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
std::set<std::string> const& Dd<DdType::CUDD>::getContainedMetaVariableNames() const {
|
|
return this->containedMetaVariableNames;
|
|
}
|
|
|
|
std::set<std::string>& Dd<DdType::CUDD>::getContainedMetaVariableNames() {
|
|
return this->containedMetaVariableNames;
|
|
}
|
|
|
|
void Dd<DdType::CUDD>::exportToDot(std::string const& filename) const {
|
|
std::vector<ADD> cuddAddVector = { this->cuddAdd };
|
|
if (filename.empty()) {
|
|
this->getDdManager()->getCuddManager().DumpDot(cuddAddVector);
|
|
} else {
|
|
// Build the name input of the DD.
|
|
std::vector<char*> ddNames;
|
|
std::string ddName("f");
|
|
ddNames.push_back(new char[ddName.size() + 1]);
|
|
memcpy(ddNames.back(), ddName.c_str(), 2);
|
|
|
|
// Now build the variables names.
|
|
std::vector<std::string> ddVariableNamesAsStrings = this->getDdManager()->getDdVariableNames();
|
|
std::vector<char*> ddVariableNames;
|
|
for (auto const& element : ddVariableNamesAsStrings) {
|
|
ddVariableNames.push_back(new char[element.size() + 1]);
|
|
memcpy(ddVariableNames.back(), element.c_str(), element.size() + 1);
|
|
}
|
|
|
|
// Open the file, dump the DD and close it again.
|
|
FILE* filePointer = fopen(filename.c_str() , "w");
|
|
this->getDdManager()->getCuddManager().DumpDot(cuddAddVector, &ddVariableNames[0], &ddNames[0], filePointer);
|
|
fclose(filePointer);
|
|
|
|
// Finally, delete the names.
|
|
for (char* element : ddNames) {
|
|
delete element;
|
|
}
|
|
for (char* element : ddVariableNames) {
|
|
delete element;
|
|
}
|
|
}
|
|
}
|
|
|
|
ADD Dd<DdType::CUDD>::getCuddAdd() {
|
|
return this->cuddAdd;
|
|
}
|
|
|
|
ADD const& Dd<DdType::CUDD>::getCuddAdd() const {
|
|
return this->cuddAdd;
|
|
}
|
|
|
|
void Dd<DdType::CUDD>::addContainedMetaVariable(std::string const& metaVariableName) {
|
|
this->getContainedMetaVariableNames().insert(metaVariableName);
|
|
}
|
|
|
|
void Dd<DdType::CUDD>::removeContainedMetaVariable(std::string const& metaVariableName) {
|
|
this->getContainedMetaVariableNames().erase(metaVariableName);
|
|
}
|
|
|
|
std::shared_ptr<DdManager<DdType::CUDD>> Dd<DdType::CUDD>::getDdManager() const {
|
|
return this->ddManager;
|
|
}
|
|
|
|
std::ostream & operator<<(std::ostream& out, const Dd<DdType::CUDD>& dd) {
|
|
dd.exportToDot();
|
|
return out;
|
|
}
|
|
|
|
}
|
|
}
|