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.
138 lines
7.4 KiB
138 lines
7.4 KiB
#include "storm/storage/geometry/ReduceVertexCloud.h"
|
|
#include "storm/utility/Stopwatch.h"
|
|
#undef _DEBUG_REDUCE_VERTEX_CLOUD
|
|
|
|
|
|
namespace storm {
|
|
namespace storage {
|
|
namespace geometry {
|
|
|
|
template<typename ValueType>
|
|
std::string toString(std::map<uint64_t, ValueType> const& point) {
|
|
std::stringstream sstr;
|
|
bool first = true;
|
|
for (auto const& entry : point) {
|
|
if (first) {
|
|
first = false;
|
|
} else {
|
|
sstr << ", ";
|
|
}
|
|
sstr << entry.first << " : " << entry.second;
|
|
}
|
|
return sstr.str();
|
|
}
|
|
|
|
template<typename ValueType>
|
|
std::pair<storm::storage::BitVector, bool> ReduceVertexCloud<ValueType>::eliminate(std::vector<std::map<uint64_t, ValueType>> const& input, uint64_t maxdimension) {
|
|
std::shared_ptr<storm::expressions::ExpressionManager> expressionManager = std::make_shared<storm::expressions::ExpressionManager>();
|
|
std::vector<storm::storage::BitVector> supports;
|
|
std::vector<storm::expressions::Variable> weightVariables;
|
|
std::vector<storm::expressions::Expression> weightVariableExpressions;
|
|
|
|
for (uint64_t pointIndex = 0; pointIndex < input.size(); ++pointIndex) {
|
|
|
|
// Compute the support vectors to quickly determine which input points could be relevant.
|
|
supports.push_back(storm::storage::BitVector(maxdimension));
|
|
for (auto const& entry : input[pointIndex]) {
|
|
supports.back().set(entry.first, true);
|
|
}
|
|
// Add a weight variable for each input point
|
|
weightVariables.push_back(expressionManager->declareRationalVariable("w_"+ std::to_string(pointIndex)));
|
|
// For convenience and performance, obtain the expression.
|
|
weightVariableExpressions.push_back(weightVariables.back().getExpression());
|
|
}
|
|
|
|
std::unique_ptr<storm::solver::SmtSolver> smtSolver = smtSolverFactory->create(*expressionManager);
|
|
for (auto const& weightVariableExpr : weightVariableExpressions) {
|
|
//smtSolver->add((weightVariableExpr == expressionManager->rational(0.0)) || (weightVariableExpr > expressionManager->rational(0.00001)));
|
|
smtSolver->add((weightVariableExpr >= expressionManager->rational(0.0)));
|
|
smtSolver->add(weightVariableExpr < expressionManager->rational(1.0));
|
|
}
|
|
if (storm::utility::isZero(wiggle)) {
|
|
smtSolver->add(storm::expressions::sum(weightVariableExpressions) <=
|
|
expressionManager->rational(1));
|
|
} else {
|
|
smtSolver->add(storm::expressions::sum(weightVariableExpressions) <=
|
|
expressionManager->rational(1.0 + wiggle));
|
|
smtSolver->add(storm::expressions::sum(weightVariableExpressions) >=
|
|
expressionManager->rational(1 - wiggle));
|
|
}
|
|
|
|
storm::utility::Stopwatch solverTime;
|
|
storm::utility::Stopwatch totalTime(true);
|
|
storm::storage::BitVector vertices(input.size());
|
|
for (uint64_t pointIndex = 0; pointIndex < input.size(); ++pointIndex) {
|
|
#ifdef _DEBUG_REUCE_VERTEX_CLOUD
|
|
std::cout << pointIndex << " out of " << input.size() << std::endl;
|
|
#endif
|
|
smtSolver->push();
|
|
std::map<uint64_t, std::vector<storm::expressions::Expression>> dimensionTerms;
|
|
for (auto const& entry : input[pointIndex]) {
|
|
dimensionTerms[entry.first] = {expressionManager->rational(-entry.second)};
|
|
}
|
|
for (uint64_t potentialSupport = 0; potentialSupport < input.size(); ++potentialSupport) {
|
|
if (pointIndex == potentialSupport) {
|
|
smtSolver->add(weightVariableExpressions[potentialSupport] == expressionManager->rational(0.0));
|
|
} else if (potentialSupport < pointIndex && !vertices.get(potentialSupport)) {
|
|
smtSolver->add(weightVariableExpressions[potentialSupport] == expressionManager->rational(0.0));
|
|
} else if (supports[potentialSupport].isSubsetOf(supports[pointIndex])) {
|
|
for (auto const& entry : input[potentialSupport]) {
|
|
dimensionTerms[entry.first].push_back(weightVariableExpressions[potentialSupport] * expressionManager->rational(entry.second));
|
|
}
|
|
} else {
|
|
smtSolver->add(weightVariableExpressions[potentialSupport] == expressionManager->rational(0.0));
|
|
}
|
|
}
|
|
for (auto const& entry : dimensionTerms) {
|
|
smtSolver->add(storm::expressions::sum(entry.second) == expressionManager->rational(0.0));
|
|
}
|
|
|
|
solverTime.start();
|
|
auto result = smtSolver->check();
|
|
solverTime.stop();
|
|
if (result == storm::solver::SmtSolver::CheckResult::Unsat) {
|
|
#ifdef _DEBUG_REDUCE_VERTEX_CLOUD
|
|
if (input[pointIndex].size() == 2) {
|
|
std::cout << "point " << toString(input[pointIndex]) << " is a vertex:";
|
|
std::cout << smtSolver->getSmtLibString() << std::endl;
|
|
}
|
|
#endif
|
|
vertices.set(pointIndex, true);
|
|
}
|
|
#ifdef _DEBUG_REDUCE_VERTEX_CLOUD
|
|
else
|
|
{
|
|
std::cout << "point " << toString(input[pointIndex]) << " is a convex combination of ";
|
|
auto val = smtSolver->getModelAsValuation();
|
|
uint64_t varIndex = 0;
|
|
for (auto const& wvar : weightVariables) {
|
|
if (!storm::utility::isZero(val.getRationalValue(wvar))) {
|
|
std::cout << toString(input[varIndex]) << " (weight: " << val.getRationalValue(wvar) << ")";
|
|
}
|
|
varIndex++;
|
|
}
|
|
std::cout << std::endl;
|
|
}
|
|
if (timeOut > )
|
|
#endif
|
|
if (timeOut > 0 && static_cast<uint64_t>(totalTime.getTimeInMilliseconds()) > timeOut) {
|
|
for (uint64_t remainingPoint = pointIndex + 1; remainingPoint < input.size(); ++remainingPoint) {
|
|
vertices.set(remainingPoint);
|
|
}
|
|
return {vertices, true};
|
|
}
|
|
smtSolver->pop();
|
|
#ifdef _DEBUG_REDUCE_VERTEX_CLOUD
|
|
std::cout << "Solver time " << solverTime.getTimeInMilliseconds() << std::endl;
|
|
std::cout << "Total time " << totalTime.getTimeInMilliseconds() << std::endl;
|
|
#endif
|
|
}
|
|
return {vertices, false};
|
|
|
|
}
|
|
|
|
template class ReduceVertexCloud<double>;
|
|
template class ReduceVertexCloud<storm::RationalNumber>;
|
|
}
|
|
}
|
|
}
|