18template<
typename ValueType>
 
   20    : lpSolverFactory(
std::move(lpSolverFactory)) {
 
 
   24template<
typename ValueType>
 
   31template<
typename ValueType>
 
   38template<
typename ValueType>
 
   40                                                                     std::vector<ValueType> 
const& b)
 const {
 
   42        return solveEquationsLp(env, dir, x, b);
 
   45                        "This min max solver does not support the selected technique.");
 
   46        return solveEquationsViToLp(env, dir, x, b);
 
 
   50template<
typename ValueType>
 
   52                                                                   std::vector<ValueType> 
const& b)
 const {
 
   54    STORM_LOG_THROW(!this->choiceFixedForRowGroup, storm::exceptions::NotImplementedException, 
"Fixed choices not implemented for this solution method.");
 
   56        auto viOperator = std::make_shared<helper::ValueIterationOperator<double, false>>();
 
   57        if constexpr (std::is_same_v<ValueType, double>) {
 
   58            viOperator->setMatrixBackwards(*this->A);
 
   60            viOperator->setMatrixBackwards(this->A->template toValueType<double>(), &this->A->getRowGroupIndices());
 
   63        uint64_t numIterations{0};
 
   65            this->showProgressIterative(numIterations);
 
   69            this->createUpperBoundsVector(x);
 
   71            this->createLowerBoundsVector(x);
 
   73        this->startMeasureProgress();
 
   74        if constexpr (std::is_same_v<ValueType, double>) {
 
   79            auto xVi = storm::utility::vector::convertNumericVector<double>(x);
 
   80            auto bVi = storm::utility::vector::convertNumericVector<double>(b);
 
   83            viHelper.VI(xVi, bVi, numIterations, relative, precision, dir, viCallback);
 
   84            auto xIt = xVi.cbegin();
 
   86                xi = storm::utility::convertNumber<ValueType>(*xIt);
 
   91    STORM_LOG_DEBUG(
"Found initial values using Value Iteration. Starting LP solving now.");
 
   94        res = solveEquationsLp(env, dir, x, b, 
nullptr, &x);  
 
   96        res = solveEquationsLp(env, dir, x, b, &x, 
nullptr);  
 
  105        for (uint64_t rowGroup = 0; rowGroup < this->A->getRowGroupCount(); ++rowGroup) {
 
  106            uint64_t row = this->A->getRowGroupIndices()[rowGroup];
 
  107            ValueType optimalGroupValue = this->A->multiplyRowWithVector(row, x) + b[row];
 
  108            for (++row; row < this->A->getRowGroupIndices()[rowGroup + 1]; ++row) {
 
  109                ValueType rowValue = this->A->multiplyRowWithVector(row, x) + b[row];
 
  110                if ((
minimize(dir) && rowValue < optimalGroupValue) || (
maximize(dir) && rowValue > optimalGroupValue)) {
 
  111                    optimalGroupValue = rowValue;
 
  114            if (x[rowGroup] != optimalGroupValue) {
 
  115                STORM_LOG_WARN(
"LP with provided bounds is incorrect. Restarting without bounds.");
 
  116                return solveEquationsLp(env, dir, x, b);  
 
  124template<
typename ValueType>
 
  125bool LpMinMaxLinearEquationSolver<ValueType>::solveEquationsLp(Environment 
const& env, 
OptimizationDirection dir, std::vector<ValueType>& x,
 
  126                                                               std::vector<ValueType> 
const& b, std::vector<ValueType> 
const* lowerBounds,
 
  127                                                               std::vector<ValueType> 
const* upperBounds)
 const {
 
  131    bool const optimizeOnlyRelevant = this->hasRelevantValues() && env.solver().minMax().lp().getOptimizeOnlyForInitialState();
 
  132    STORM_LOG_DEBUG(
"Optimize only for relevant state requested:" << env.solver().minMax().lp().getOptimizeOnlyForInitialState());
 
  133    if (optimizeOnlyRelevant) {
 
  135    } 
else if (!this->hasRelevantValues()) {
 
  136        STORM_LOG_DEBUG(
"No relevant values set! Optimizing over all states.");
 
  140    std::function<
ValueType(uint64_t 
const&)> lower, upper;
 
  141    if (this->hasLowerBound() && lowerBounds == 
nullptr) {
 
  142        lower = [
this](uint64_t 
const& 
i) { 
return this->getLowerBound(i); };
 
  143    } 
else if (!this->hasLowerBound() && lowerBounds != 
nullptr) {
 
  144        STORM_LOG_ASSERT(lowerBounds->size() == x.size(), 
"lower bounds vector has invalid size.");
 
  145        lower = [&lowerBounds](uint64_t 
const& 
i) { 
return (*lowerBounds)[
i]; };
 
  146    } 
else if (this->hasLowerBound() && lowerBounds != 
nullptr) {
 
  147        STORM_LOG_ASSERT(lowerBounds->size() == x.size(), 
"lower bounds vector has invalid size.");
 
  148        lower = [&lowerBounds, 
this](uint64_t 
const& 
i) { 
return std::max(this->getLowerBound(i), (*lowerBounds)[i]); };
 
  150    if (this->hasUpperBound() && upperBounds == 
nullptr) {
 
  151        upper = [
this](uint64_t 
const& 
i) { 
return this->getUpperBound(i); };
 
  152    } 
else if (!this->hasUpperBound() && upperBounds != 
nullptr) {
 
  153        STORM_LOG_ASSERT(upperBounds->size() == x.size(), 
"upper bounds vector has invalid size.");
 
  154        upper = [&upperBounds](uint64_t 
const& 
i) { 
return (*upperBounds)[
i]; };
 
  155    } 
else if (this->hasUpperBound() && upperBounds != 
nullptr) {
 
  156        STORM_LOG_ASSERT(upperBounds->size() == x.size(), 
"upper bounds vector has invalid size.");
 
  157        upper = [&upperBounds, 
this](uint64_t 
const& 
i) { 
return std::min(this->getUpperBound(i), (*upperBounds)[i]); };
 
  159    bool const useBounds = lower || upper;
 
  162    auto solver = lpSolverFactory->createRaw(
"");
 
  163    solver->setOptimizationDirection(
invert(dir));
 
  165    std::map<VariableIndex, ValueType> constantRowGroups;  
 
  168    for (uint64_t rowGroup = 0; rowGroup < this->A->getRowGroupCount(); ++rowGroup) {
 
  170            (optimizeOnlyRelevant && !this->getRelevantValues().get(rowGroup)) ? storm::utility::zero<ValueType>() : storm::utility::one<ValueType>();
 
  171        std::optional<ValueType> lowerBound, upperBound;
 
  174                lowerBound = lower(rowGroup);
 
  177                upperBound = upper(rowGroup);
 
  179                    STORM_LOG_ASSERT(*lowerBound <= *upperBound, 
"Lower Bound at row group " << rowGroup << 
" is " << *lowerBound
 
  180                                                                                             << 
" which exceeds the upper bound " << *upperBound << 
".");
 
  181                    if (*lowerBound == *upperBound) {
 
  184                        constantRowGroups.emplace(rowGroup, *lowerBound);
 
  186                        solver->addContinuousVariable(
"dummy" + std::to_string(rowGroup));
 
  192        solver->addContinuousVariable(
"x" + std::to_string(rowGroup), lowerBound, upperBound, objValue);
 
  195    STORM_LOG_DEBUG(
"Use eq if there is a single action: " << env.solver().minMax().lp().getUseEqualityForSingleActions());
 
  196    bool const useEqualityForSingleAction = env.solver().minMax().lp().getUseEqualityForSingleActions();
 
  200    for (uint64_t rowGroup = 0; rowGroup < this->A->getRowGroupCount(); ++rowGroup) {
 
  202        uint64_t rowIndex, rowGroupEnd;
 
  203        if (this->choiceFixedForRowGroup && this->choiceFixedForRowGroup.get()[rowGroup]) {
 
  204            rowIndex = this->A->getRowGroupIndices()[rowGroup] + this->getInitialScheduler()[rowGroup];
 
  205            rowGroupEnd = rowIndex + 1;
 
  207            rowIndex = this->A->getRowGroupIndices()[rowGroup];
 
  208            rowGroupEnd = this->A->getRowGroupIndices()[rowGroup + 1];
 
  210        bool const singleAction = (rowIndex + 1 == rowGroupEnd);
 
  213        for (; rowIndex < rowGroupEnd; ++rowIndex) {
 
  214            auto row = this->A->getRow(rowIndex);
 
  215            RawLpConstraint<ValueType> constraint(relationType, -b[rowIndex], row.getNumberOfEntries());
 
  216            auto addToConstraint = [&constraint, &constantRowGroups](VariableIndex 
const& var, 
ValueType const& val) {
 
  217                if (
auto findRes = constantRowGroups.find(var); findRes != constantRowGroups.end()) {
 
  218                    constraint.rhs -= findRes->second * val;
 
  220                    constraint.addToLhs(var, val);
 
  223            auto entryIt = row.begin();
 
  224            auto const entryItEnd = row.end();
 
  225            for (; entryIt != entryItEnd && entryIt->getColumn() < rowGroup; ++entryIt) {
 
  226                addToConstraint(entryIt->getColumn(), entryIt->getValue());
 
  228            ValueType diagVal = -storm::utility::one<ValueType>();
 
  229            if (entryIt != entryItEnd && entryIt->getColumn() == rowGroup) {
 
  230                diagVal += entryIt->getValue();
 
  233            addToConstraint(rowGroup, diagVal);
 
  234            for (; entryIt != entryItEnd; ++entryIt) {
 
  235                addToConstraint(entryIt->getColumn(), entryIt->getValue());
 
  237            solver->addConstraint(
"", constraint);
 
  246    bool const infeasible = solver->isInfeasible();
 
  247    if (infeasible && (lowerBounds || upperBounds)) {
 
  249        STORM_LOG_WARN(
"LP with provided bounds is infeasible. Restarting without bounds.");
 
  250        return solveEquationsLp(env, dir, x, b);
 
  252    STORM_LOG_THROW(!infeasible, storm::exceptions::UnexpectedException, 
"The MinMax equation system is infeasible.");
 
  253    STORM_LOG_THROW(!solver->isUnbounded(), storm::exceptions::UnexpectedException, 
"The MinMax equation system is unbounded.");
 
  254    STORM_LOG_THROW(solver->isOptimal(), storm::exceptions::UnexpectedException, 
"Unable to find optimal solution for MinMax equation system.");
 
  257    auto xIt = x.begin();
 
  259    for (; xIt != x.end(); ++xIt, ++
i) {
 
  260        if (
auto findRes = constantRowGroups.find(i); findRes != constantRowGroups.end()) {
 
  261            *xIt = findRes->second;
 
  263            *xIt = solver->getContinuousValue(i);
 
  268    if (this->isTrackSchedulerSet()) {
 
  269        this->schedulerChoices = std::vector<uint_fast64_t>(this->A->getRowGroupCount());
 
  270        for (uint64_t rowGroup = 0; rowGroup < this->A->getRowGroupCount(); ++rowGroup) {
 
  271            if (!this->choiceFixedForRowGroup || !this->choiceFixedForRowGroup.get()[rowGroup]) {
 
  273                uint64_t row = this->A->getRowGroupIndices()[rowGroup];
 
  274                uint64_t optimalChoiceIndex = 0;
 
  275                uint64_t currChoice = 0;
 
  276                ValueType optimalGroupValue = this->A->multiplyRowWithVector(row, x) + b[row];
 
  277                for (++row, ++currChoice; row < this->A->getRowGroupIndices()[rowGroup + 1]; ++row, ++currChoice) {
 
  278                    ValueType rowValue = this->A->multiplyRowWithVector(row, x) + b[row];
 
  279                    if ((
minimize(dir) && rowValue < optimalGroupValue) || (
maximize(dir) && rowValue > optimalGroupValue)) {
 
  280                        optimalGroupValue = rowValue;
 
  281                        optimalChoiceIndex = currChoice;
 
  284                this->schedulerChoices.get()[rowGroup] = optimalChoiceIndex;
 
  292template<
typename ValueType>
 
  297template<
typename ValueType>
 
  299    Environment const& env, boost::optional<storm::solver::OptimizationDirection> 
const& direction, 
bool const& hasInitialScheduler)
 const {
 
 
  327#ifdef STORM_HAVE_CARL 
SolverEnvironment & solver()
 
bool getUseNonTrivialBounds() const
 
uint64_t const & getMaximalNumberOfIterations() const
 
MinMaxLpSolverEnvironment const & lp() const
 
storm::RationalNumber const & getPrecision() const
 
storm::solver::MinMaxMethod const & getMethod() const
 
bool isForceRequireUnique() const
 
bool const & getRelativeTerminationCriterion() const
 
MinMaxSolverEnvironment & minMax()
 
Solves a MinMaxLinearEquationSystem using a linear programming solver.
 
LpMinMaxLinearEquationSolver(std::unique_ptr< storm::utility::solver::LpSolverFactory< ValueType > > &&lpSolverFactory)
 
virtual bool internalSolveEquations(Environment const &env, OptimizationDirection dir, std::vector< ValueType > &x, std::vector< ValueType > const &b) const override
 
virtual MinMaxLinearEquationSolverRequirements getRequirements(Environment const &env, boost::optional< storm::solver::OptimizationDirection > const &direction=boost::none, bool const &hasInitialScheduler=false) const override
Retrieves the requirements of this solver for solving equations with the current settings.
 
virtual void clearCache() const override
Clears the currently cached data that has been stored during previous calls of the solver.
 
std::conditional_t< RawMode, typename RawLpConstraint< ValueType >::VariableIndexType, storm::expressions::Variable > Variable
 
virtual void clearCache() const
Clears the currently cached data that has been stored during previous calls of the solver.
 
MinMaxLinearEquationSolverRequirements & requireBounds(bool critical=true)
 
MinMaxLinearEquationSolverRequirements & requireUniqueSolution(bool critical=true)
 
MinMaxLinearEquationSolverRequirements & requireLowerBounds(bool critical=true)
 
MinMaxLinearEquationSolverRequirements & requireUpperBounds(bool critical=true)
 
A class that holds a possibly non-square matrix in the compressed row storage format.
 
#define STORM_LOG_WARN(message)
 
#define STORM_LOG_DEBUG(message)
 
#define STORM_LOG_TRACE(message)
 
#define STORM_LOG_ASSERT(cond, message)
 
#define STORM_LOG_THROW(cond, exception, message)
 
SFTBDDChecker::ValueType ValueType
 
bool constexpr maximize(OptimizationDirection d)
 
OptimizationDirection constexpr invert(OptimizationDirection d)
 
bool constexpr minimize(OptimizationDirection d)