#include "storm/storage/geometry/ReduceVertexCloud.h" #include "storm/utility/Stopwatch.h" #undef _DEBUG_REDUCE_VERTEX_CLOUD namespace storm { namespace storage { namespace geometry { template std::string toString(std::map 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 std::pair ReduceVertexCloud::eliminate(std::vector> const& input, uint64_t maxdimension) { std::shared_ptr expressionManager = std::make_shared(); std::vector supports; std::vector weightVariables; std::vector 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 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> 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(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; template class ReduceVertexCloud; } } }