Skip to content

Multiobjective exportschedulers #328

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 18 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
f0d6c45
explicit pareto curve check result stores mapping from pareto point t…
UlisesTorrella Feb 13, 2023
1a9cff8
scheduler expose number of choices
UlisesTorrella Feb 13, 2023
6e22da3
multiobjective postprocessing schedulers
UlisesTorrella Feb 13, 2023
77d5008
return schedulers for each point during pcaa
UlisesTorrella Feb 13, 2023
97a2bfc
make format
UlisesTorrella Feb 13, 2023
c8b1154
storm-cli to allow scheduler exporting in multiobjective analysis
UlisesTorrella Feb 13, 2023
22635c9
avoid recomputing scheduler if point is already stored
UlisesTorrella Feb 13, 2023
651cd2c
fix compute original scheduler
UlisesTorrella Feb 13, 2023
199e49f
pcaa scheduler to original consider non trivial schedulers
UlisesTorrella Feb 13, 2023
fce5e60
transforming schedulers from incorporated memory models to schedulers…
UlisesTorrella Feb 15, 2023
cf52103
flag to compute schedulers only when exportScheduler is needed in mul…
UlisesTorrella Feb 15, 2023
6770306
make format
UlisesTorrella Feb 15, 2023
186f4a4
standard pcaa vector checker only stores needed information from merg…
UlisesTorrella Feb 16, 2023
59de157
multiobjective scheduler postprocessing set dont care to irrelevant s…
UlisesTorrella Feb 16, 2023
fe39c84
fixed bug only happening on release build
UlisesTorrella Feb 20, 2023
423d01d
optimizations and improvements for scheduler export in multiobjective…
UlisesTorrella Feb 21, 2023
8e0a4c1
remove leftover comments
UlisesTorrella Mar 10, 2023
e186866
fix format
UlisesTorrella Mar 10, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 17 additions & 1 deletion src/storm-cli-utilities/model-handling.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@

#include "storm/exceptions/OptionParserException.h"

#include "storm/modelchecker/results/CheckResult.h"
#include "storm/modelchecker/results/ExplicitParetoCurveCheckResult.h"
#include "storm/modelchecker/results/SymbolicQualitativeCheckResult.h"

#include "storm/models/sparse/StandardRewardModel.h"
Expand Down Expand Up @@ -1141,7 +1143,21 @@ void verifyWithSparseEngine(std::shared_ptr<storm::models::ModelBase> const& mod
STORM_LOG_ERROR("Scheduler requested but could not be generated.");
}
} else {
STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Scheduler export not supported for this property.");
if (result->isExplicitParetoCurveCheckResult()) {
if (result->template asExplicitParetoCurveCheckResult<ValueType>().hasScheduler()) {
auto schedulers = result->template asExplicitParetoCurveCheckResult<ValueType>().getSchedulers();
for (auto const& scheduler : schedulers) {
storm::api::exportScheduler(sparseModel, *scheduler.second.get(),
(exportCount == 0 ? std::string("") : std::to_string(exportCount)) +
ioSettings.getExportSchedulerFilename() + "-" +
storm::utility::vector::toStringNoVerbose(scheduler.first));
}
} else {
STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Scheduler export not supported for this property.");
}
} else {
STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Scheduler export not supported for this property.");
}
}
}
if (ioSettings.isExportCheckResultSet()) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
#include "storm/modelchecker/multiobjective/MultiObjectivePostprocessing.h"

#include "storm/adapters/RationalNumberAdapter.h"
#include "storm/models/sparse/MarkovAutomaton.h"
#include "storm/models/sparse/Mdp.h"
#include "storm/storage/Scheduler.h"
#include "storm/storage/memorystructure/SparseModelMemoryProductReverseData.h"

namespace storm {
namespace modelchecker {
Expand Down Expand Up @@ -66,6 +70,41 @@ std::shared_ptr<storm::storage::geometry::Polytope<GeometryValueType>> transform
return polytope->affineTransformation(transformationMatrix, transformationVector);
}

/*
* This function is only responsible to reverse changes to the model made in the preprocessor
* (not the ones done by specific checkers)
*/
template<typename ValueType, typename SparseModelType>
void transformObjectiveSchedulersToOriginal(storm::storage::SparseModelMemoryProductReverseData const& reverseData,
std::shared_ptr<SparseModelType> const& originalModel,
std::map<std::vector<ValueType>, std::shared_ptr<storm::storage::Scheduler<ValueType>>> schedulers) {
auto memoryStateCount = reverseData.memory.getNumberOfStates();
auto originalModelStates = originalModel->getNumberOfStates();
for (auto it = schedulers.begin(); it != schedulers.end(); ++it) {
std::shared_ptr<storm::storage::Scheduler<ValueType>> scheduler = it->second;
auto point = it->first;
storm::storage::Scheduler<ValueType> result(originalModelStates, reverseData.memory);
auto currSchedulerModelStates = scheduler->getNumberOfModelStates();
for (int state = 0; state < originalModelStates; state++) {
for (int memState = 0; memState < memoryStateCount; memState++) {
auto const& productState = reverseData.toResultStateMapping[state * memoryStateCount + memState];
if (productState != -1) {
// if it's -1 it's unreachable
if (productState >= currSchedulerModelStates) {
// means it's been deleted as irrelevant state
result.setDontCare(productState, memState, true);
} else {
auto choice = scheduler->getChoice(productState);
result.setChoice(choice, state, memState);
}
}
}
}
scheduler.reset();
schedulers[point] = std::move(std::make_shared<storm::storage::Scheduler<ValueType>>(result));
}
}

template std::vector<storm::RationalNumber> transformObjectiveValuesToOriginal(std::vector<Objective<double>> objectives,
std::vector<storm::RationalNumber> const& point);
template std::shared_ptr<storm::storage::geometry::Polytope<storm::RationalNumber>> transformObjectivePolytopeToOriginal(
Expand All @@ -74,6 +113,25 @@ template std::vector<storm::RationalNumber> transformObjectiveValuesToOriginal(s
std::vector<storm::RationalNumber> const& point);
template std::shared_ptr<storm::storage::geometry::Polytope<storm::RationalNumber>> transformObjectivePolytopeToOriginal(
std::vector<Objective<storm::RationalNumber>> objectives, std::shared_ptr<storm::storage::geometry::Polytope<storm::RationalNumber>> const& polytope);

template void transformObjectiveSchedulersToOriginal(
storm::storage::SparseModelMemoryProductReverseData const& reverseData,
std::shared_ptr<storm::models::sparse::Mdp<storm::RationalNumber>> const& originalModel,
std::map<std::vector<storm::RationalNumber>, std::shared_ptr<storm::storage::Scheduler<storm::RationalNumber>>> schedulers);

template void transformObjectiveSchedulersToOriginal(storm::storage::SparseModelMemoryProductReverseData const& reverseData,
std::shared_ptr<storm::models::sparse::Mdp<double>> const& originalModel,
std::map<std::vector<double>, std::shared_ptr<storm::storage::Scheduler<double>>> schedulers);

template void transformObjectiveSchedulersToOriginal(
storm::storage::SparseModelMemoryProductReverseData const& reverseData,
std::shared_ptr<storm::models::sparse::MarkovAutomaton<storm::RationalNumber>> const& originalModel,
std::map<std::vector<storm::RationalNumber>, std::shared_ptr<storm::storage::Scheduler<storm::RationalNumber>>> schedulers);

template void transformObjectiveSchedulersToOriginal(storm::storage::SparseModelMemoryProductReverseData const& reverseData,
std::shared_ptr<storm::models::sparse::MarkovAutomaton<double>> const& originalModel,
std::map<std::vector<double>, std::shared_ptr<storm::storage::Scheduler<double>>> schedulers);

} // namespace multiobjective
} // namespace modelchecker
} // namespace storm
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@
#include <vector>

#include "storm/modelchecker/multiobjective/Objective.h"
#include "storm/storage/Scheduler.h"
#include "storm/storage/geometry/Polytope.h"
#include "storm/storage/memorystructure/SparseModelMemoryProductReverseData.h"

namespace storm {
namespace modelchecker {
Expand All @@ -17,6 +19,15 @@ template<typename ValueType, typename GeometryValueType>
std::shared_ptr<storm::storage::geometry::Polytope<GeometryValueType>> transformObjectivePolytopeToOriginal(
std::vector<Objective<ValueType>> objectives, std::shared_ptr<storm::storage::geometry::Polytope<GeometryValueType>> const& polytope);

/*
* Uses the information from reverse data to edit the objective schedulers in 'schedulers' to ones
* apt for the target model.
*/
template<typename ValueType, typename SparseModelType>
void transformObjectiveSchedulersToOriginal(storm::storage::SparseModelMemoryProductReverseData const& reverseData,
std::shared_ptr<SparseModelType> const& originalModel,
std::map<std::vector<ValueType>, std::shared_ptr<storm::storage::Scheduler<ValueType>>> schedulers);

} // namespace multiobjective
} // namespace modelchecker
} // namespace storm
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
#include "storm/modelchecker/multiobjective/multiObjectiveModelChecking.h"

#include "storm/environment/modelchecker/MultiObjectiveModelCheckerEnvironment.h"
#include "storm/modelchecker/multiobjective/MultiObjectivePostprocessing.h"
#include "storm/modelchecker/multiobjective/constraintbased/SparseCbAchievabilityQuery.h"
#include "storm/modelchecker/multiobjective/deterministicScheds/DeterministicSchedsParetoExplorer.h"
#include "storm/modelchecker/multiobjective/pcaa/SparsePcaaAchievabilityQuery.h"
#include "storm/modelchecker/multiobjective/pcaa/SparsePcaaParetoQuery.h"
#include "storm/modelchecker/multiobjective/pcaa/SparsePcaaQuantitativeQuery.h"
#include "storm/modelchecker/multiobjective/preprocessing/SparseMultiObjectivePreprocessor.h"
#include "storm/modelchecker/results/CheckResult.h"
#include "storm/modelchecker/results/ExplicitParetoCurveCheckResult.h"
#include "storm/models/sparse/MarkovAutomaton.h"
#include "storm/models/sparse/Mdp.h"
#include "storm/models/sparse/StandardRewardModel.h"
Expand Down Expand Up @@ -83,6 +86,13 @@ std::unique_ptr<CheckResult> performMultiObjectiveModelChecking(Environment cons
}

result = query->check(env);
if (preprocessorResult.memoryIncorporationReverseData && result->isExplicitParetoCurveCheckResult() &&
result->template asExplicitParetoCurveCheckResult<typename SparseModelType::ValueType>().hasScheduler()) {
// we have information to post-process schedulers
auto schedulers = result->template asExplicitParetoCurveCheckResult<typename SparseModelType::ValueType>().getSchedulers();
transformObjectiveSchedulersToOriginal(std::move(preprocessorResult.memoryIncorporationReverseData.value()),
std::make_shared<SparseModelType>(model), schedulers);
}

if (env.modelchecker().multi().isExportPlotSet()) {
query->exportPlotOfCurrentApproximation(env);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,14 @@ class PcaaWeightVectorChecker {
*/
virtual storm::storage::Scheduler<ValueType> computeScheduler() const;

/*!
* If changes has been made to the given model this function should inverse them to return a scheduler
* for the given model
*/
virtual storm::storage::Scheduler<ValueType> computeOriginalScheduler() const {
return computeScheduler();
}

protected:
/*!
* Computes the weighted lower or upper bounds for the provided set of objectives.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@
#include "storm/models/sparse/MarkovAutomaton.h"
#include "storm/models/sparse/Mdp.h"
#include "storm/models/sparse/StandardRewardModel.h"
#include "storm/settings/SettingsManager.h"
#include "storm/settings/modules/CoreSettings.h"
#include "storm/settings/modules/IOSettings.h"
#include "storm/storage/Scheduler.h"
#include "storm/utility/SignalHandler.h"
#include "storm/utility/constants.h"
#include "storm/utility/vector.h"
Expand Down Expand Up @@ -51,13 +55,24 @@ std::unique_ptr<CheckResult> SparsePcaaParetoQuery<SparseModelType, GeometryValu
storm::utility::vector::convertNumericVector<typename SparseModelType::ValueType>(transformObjectiveValuesToOriginal(this->objectives, vertex)));
}
return std::unique_ptr<CheckResult>(new ExplicitParetoCurveCheckResult<typename SparseModelType::ValueType>(
this->originalModel.getInitialStates().getNextSetIndex(0), std::move(paretoOptimalPoints),
this->originalModel.getInitialStates().getNextSetIndex(0), std::move(paretoOptimalPoints), std::move(schedulers),
transformObjectivePolytopeToOriginal(this->objectives, this->underApproximation)
->template convertNumberRepresentation<typename SparseModelType::ValueType>(),
transformObjectivePolytopeToOriginal(this->objectives, this->overApproximation)
->template convertNumberRepresentation<typename SparseModelType::ValueType>()));
}

template<class SparseModelType, typename GeometryValueType>
void SparsePcaaParetoQuery<SparseModelType, GeometryValueType>::updateSchedulers() {
if (storm::settings::getModule<storm::settings::modules::IOSettings>().isExportSchedulerSet()) {
std::vector<typename SparseModelType::ValueType> point = this->weightVectorChecker->getUnderApproximationOfInitialStateResults();
if (!this->schedulers.count(point)) {
this->schedulers[point] =
std::make_shared<storm::storage::Scheduler<typename SparseModelType::ValueType>>(this->weightVectorChecker->computeOriginalScheduler());
}
}
}

template<class SparseModelType, typename GeometryValueType>
void SparsePcaaParetoQuery<SparseModelType, GeometryValueType>::exploreSetOfAchievablePoints(Environment const& env) {
STORM_LOG_THROW(env.modelchecker().multi().getPrecisionType() == MultiObjectiveModelCheckerEnvironment::PrecisionType::Absolute,
Expand All @@ -68,6 +83,7 @@ void SparsePcaaParetoQuery<SparseModelType, GeometryValueType>::exploreSetOfAchi
WeightVector direction(this->objectives.size(), storm::utility::zero<GeometryValueType>());
direction[objIndex] = storm::utility::one<GeometryValueType>();
this->performRefinementStep(env, std::move(direction));
this->updateSchedulers();
if (storm::utility::resources::isTerminate()) {
break;
}
Expand Down Expand Up @@ -95,6 +111,7 @@ void SparsePcaaParetoQuery<SparseModelType, GeometryValueType>::exploreSetOfAchi
STORM_LOG_INFO("Current precision of the approximation of the pareto curve is ~" << storm::utility::convertNumber<double>(farestDistance));
WeightVector direction = underApproxHalfspaces[farestHalfspaceIndex].normalVector();
this->performRefinementStep(env, std::move(direction));
this->updateSchedulers();
}
STORM_LOG_ERROR("Could not reach the desired precision: Termination requested or maximum number of refinement steps exceeded.");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,20 @@ class SparsePcaaParetoQuery : public SparsePcaaQuery<SparseModelType, GeometryVa
*/
virtual std::unique_ptr<CheckResult> check(Environment const& env) override;

/*
* Compute the scheduler for current underaproximated point and store it
*/
void updateSchedulers();

private:
/*
* Performs refinement steps until the approximation is sufficiently precise
*/
void exploreSetOfAchievablePoints(Environment const& env);
/*
* Schedulers corresponding to the pareto optimal points
*/
std::map<std::vector<typename SparseModelType::ValueType>, std::shared_ptr<storm::storage::Scheduler<typename SparseModelType::ValueType>>> schedulers;
};

} // namespace multiobjective
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ void StandardPcaaWeightVectorChecker<SparseModelType>::initialize(
auto mergerResult =
merger.mergeTargetAndSinkStates(maybeStates, rewardAnalysis.reward0AStates, storm::storage::BitVector(maybeStates.size(), false),
std::vector<std::string>(relevantRewardModels.begin(), relevantRewardModels.end()), finiteTotalRewardChoices);

goalStateMergerIndexMapping = mergerResult.oldToNewStateIndexMapping;
// Initialize data specific for the considered model type
initializeModelTypeSpecificData(*mergerResult.model);

Expand Down Expand Up @@ -235,6 +235,18 @@ StandardPcaaWeightVectorChecker<SparseModelType>::computeScheduler() const {
return result;
}

template<class SparseModelType>
storm::storage::Scheduler<typename StandardPcaaWeightVectorChecker<SparseModelType>::ValueType>
StandardPcaaWeightVectorChecker<SparseModelType>::computeOriginalScheduler() const {
auto scheduler = this->computeScheduler();
storm::storage::Scheduler<ValueType> result(goalStateMergerIndexMapping.size());
auto numOfModelStates = result.getNumberOfModelStates();
for (int state = 0; state < numOfModelStates; state++) {
result.setChoice(scheduler.getChoice(goalStateMergerIndexMapping[state]), state);
}
return result;
}

template<typename ValueType>
void computeSchedulerProb1(storm::storage::SparseMatrix<ValueType> const& transitionMatrix, storm::storage::SparseMatrix<ValueType> const& backwardTransitions,
storm::storage::BitVector const& consideredStates, storm::storage::BitVector const& statesToReach, std::vector<uint64_t>& choices,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include "storm/storage/Scheduler.h"
#include "storm/storage/SparseMatrix.h"
#include "storm/transformer/EndComponentEliminator.h"
#include "storm/transformer/GoalStateMerger.h"
#include "storm/utility/vector.h"

namespace storm {
Expand Down Expand Up @@ -67,6 +68,12 @@ class StandardPcaaWeightVectorChecker : public PcaaWeightVectorChecker<SparseMod
*/
virtual storm::storage::Scheduler<ValueType> computeScheduler() const override;

/*!
* Use the "oldToNewStateIndexMapping" from the merge result to build a scheduler fit for the original scheduler
* from the calculated scheduler from "computerScheduler"
*/
virtual storm::storage::Scheduler<ValueType> computeOriginalScheduler() const override;

protected:
void initialize(preprocessing::SparseMultiObjectivePreprocessorResult<SparseModelType> const& preprocessorResult);
virtual void initializeModelTypeSpecificData(SparseModelType const& model) = 0;
Expand Down Expand Up @@ -173,6 +180,9 @@ class StandardPcaaWeightVectorChecker : public PcaaWeightVectorChecker<SparseMod
};
boost::optional<EcQuotient> ecQuotient;

// Merge results
std::vector<uint_fast64_t> goalStateMergerIndexMapping;

struct LraMecDecomposition {
storm::storage::MaximalEndComponentDecomposition<ValueType> mecs;
std::vector<ValueType> auxMecValues;
Expand Down
Loading