305 lines
17 KiB

#include "src/models/sparse/Model.h"
#include <boost/algorithm/string/join.hpp>
#include "src/utility/vector.h"
#include "src/adapters/CarlAdapter.h"
#include "src/exceptions/IllegalArgumentException.h"
#include "src/exceptions/IllegalFunctionCallException.h"
namespace storm {
namespace models {
namespace sparse {
template<typename ValueType, typename RewardModelType>
Model<ValueType, RewardModelType>::Model(storm::models::ModelType const& modelType,
storm::storage::SparseMatrix<ValueType> const& transitionMatrix,
storm::models::sparse::StateLabeling const& stateLabeling,
std::unordered_map<std::string, RewardModelType> const& rewardModels,
boost::optional<std::vector<LabelSet>> const& optionalChoiceLabeling)
: ModelBase(modelType), transitionMatrix(transitionMatrix), stateLabeling(stateLabeling),
rewardModels(rewardModels), choiceLabeling(optionalChoiceLabeling) {
for (auto const& rewardModel : this->getRewardModels()) {
STORM_LOG_THROW(!rewardModel.second.hasTransitionRewards() || rewardModel.second.getTransitionRewardMatrix().isSubmatrixOf(this->getTransitionMatrix()), storm::exceptions::IllegalArgumentException, "The transition reward matrix is not a submatrix of the transition matrix, i.e. there are rewards for transitions that do not exist.");
}
}
template<typename ValueType, typename RewardModelType>
Model<ValueType, RewardModelType>::Model(storm::models::ModelType const& modelType,
storm::storage::SparseMatrix<ValueType>&& transitionMatrix,
storm::models::sparse::StateLabeling&& stateLabeling,
std::unordered_map<std::string, RewardModelType>&& rewardModels,
boost::optional<std::vector<LabelSet>>&& optionalChoiceLabeling)
: ModelBase(modelType), transitionMatrix(std::move(transitionMatrix)), stateLabeling(std::move(stateLabeling)),
rewardModels(std::move(rewardModels)), choiceLabeling(std::move(optionalChoiceLabeling)) {
for (auto const& rewardModel : this->getRewardModels()) {
STORM_LOG_THROW(!rewardModel.second.hasTransitionRewards() || rewardModel.second.getTransitionRewardMatrix().isSubmatrixOf(this->getTransitionMatrix()), storm::exceptions::IllegalArgumentException, "The transition reward matrix is not a submatrix of the transition matrix, i.e. there are rewards for transitions that do not exist.");
}
}
template<typename ValueType, typename RewardModelType>
storm::storage::SparseMatrix<ValueType> Model<ValueType, RewardModelType>::getBackwardTransitions() const {
return this->getTransitionMatrix().transpose(true);
}
template<typename ValueType, typename RewardModelType>
typename storm::storage::SparseMatrix<ValueType>::const_rows Model<ValueType, RewardModelType>::getRows(storm::storage::sparse::state_type state) const {
return this->getTransitionMatrix().getRowGroup(state);
}
template<typename ValueType, typename RewardModelType>
uint_fast64_t Model<ValueType, RewardModelType>::getNumberOfStates() const {
return this->getTransitionMatrix().getColumnCount();
}
template<typename ValueType, typename RewardModelType>
uint_fast64_t Model<ValueType, RewardModelType>::getNumberOfTransitions() const {
return this->getTransitionMatrix().getNonzeroEntryCount();
}
template<typename ValueType, typename RewardModelType>
storm::storage::BitVector const& Model<ValueType, RewardModelType>::getInitialStates() const {
return this->getStates("init");
}
template<typename ValueType, typename RewardModelType>
storm::storage::BitVector const& Model<ValueType, RewardModelType>::getStates(std::string const& label) const {
return stateLabeling.getStates(label);
}
template<typename ValueType, typename RewardModelType>
bool Model<ValueType, RewardModelType>::hasLabel(std::string const& label) const {
return stateLabeling.containsLabel(label);
}
template<typename ValueType, typename RewardModelType>
storm::storage::SparseMatrix<ValueType> const& Model<ValueType, RewardModelType>::getTransitionMatrix() const {
return transitionMatrix;
}
template<typename ValueType, typename RewardModelType>
storm::storage::SparseMatrix<ValueType>& Model<ValueType, RewardModelType>::getTransitionMatrix() {
return transitionMatrix;
}
template<typename ValueType, typename RewardModelType>
bool Model<ValueType, RewardModelType>::hasRewardModel(std::string const& rewardModelName) const {
return this->rewardModels.find(rewardModelName) != this->rewardModels.end();
}
template<typename ValueType, typename RewardModelType>
RewardModelType const& Model<ValueType, RewardModelType>::getRewardModel(std::string const& rewardModelName) const {
auto it = this->rewardModels.find(rewardModelName);
if (it == this->rewardModels.end()) {
if (rewardModelName.empty()) {
if (this->hasUniqueRewardModel()) {
return this->getUniqueRewardModel()->second;
} else {
STORM_LOG_THROW(false, storm::exceptions::IllegalArgumentException, "Unable to refer to default reward model, because there is no default model or it is not unique.");
}
} else {
STORM_LOG_THROW(false, storm::exceptions::IllegalArgumentException, "The requested reward model '" << rewardModelName << "' does not exist.");
}
}
return it->second;
}
template<typename ValueType, typename RewardModelType>
bool Model<ValueType, RewardModelType>::hasUniqueRewardModel() const {
return this->getNumberOfRewardModels() == 1;
}
template<typename ValueType, typename RewardModelType>
bool Model<ValueType, RewardModelType>::hasRewardModel() const {
return !this->rewardModels.empty();
}
template<typename ValueType, typename RewardModelType>
typename std::unordered_map<std::string, RewardModelType>::const_iterator Model<ValueType, RewardModelType>::getUniqueRewardModel() const {
STORM_LOG_THROW(this->getNumberOfRewardModels() == 1, storm::exceptions::IllegalFunctionCallException, "The reward model is not unique.");
return this->rewardModels.cbegin();
}
template<typename ValueType, typename RewardModelType>
uint_fast64_t Model<ValueType, RewardModelType>::getNumberOfRewardModels() const {
return this->rewardModels.size();
}
template<typename ValueType, typename RewardModelType>
std::vector<LabelSet> const& Model<ValueType, RewardModelType>::getChoiceLabeling() const {
return choiceLabeling.get();
}
template<typename ValueType, typename RewardModelType>
boost::optional<std::vector<LabelSet>> const& Model<ValueType, RewardModelType>::getOptionalChoiceLabeling() const {
return choiceLabeling;
}
template<typename ValueType, typename RewardModelType>
storm::models::sparse::StateLabeling const& Model<ValueType, RewardModelType>::getStateLabeling() const {
return stateLabeling;
}
template<typename ValueType, typename RewardModelType>
storm::models::sparse::StateLabeling& Model<ValueType, RewardModelType>::getStateLabeling() {
return stateLabeling;
}
template<typename ValueType, typename RewardModelType>
bool Model<ValueType, RewardModelType>::hasChoiceLabeling() const {
return static_cast<bool>(choiceLabeling);
}
template<typename ValueType, typename RewardModelType>
std::size_t Model<ValueType, RewardModelType>::getSizeInBytes() const {
std::size_t result = transitionMatrix.getSizeInBytes() + stateLabeling.getSizeInBytes();
for (auto const& rewardModel : this->rewardModels) {
result += rewardModel.second.getSizeInBytes();
}
if (hasChoiceLabeling()) {
result += getChoiceLabeling().size() * sizeof(LabelSet);
}
return result;
}
template<typename ValueType, typename RewardModelType>
void Model<ValueType, RewardModelType>::printModelInformationToStream(std::ostream& out) const {
this->printModelInformationHeaderToStream(out);
this->printModelInformationFooterToStream(out);
}
template<typename ValueType, typename RewardModelType>
void Model<ValueType, RewardModelType>::printModelInformationHeaderToStream(std::ostream& out) const {
out << "-------------------------------------------------------------- " << std::endl;
out << "Model type: \t" << this->getType() << " (sparse)" << std::endl;
out << "States: \t" << this->getNumberOfStates() << std::endl;
out << "Transitions: \t" << this->getNumberOfTransitions() << std::endl;
}
template<typename ValueType, typename RewardModelType>
void Model<ValueType, RewardModelType>::printModelInformationFooterToStream(std::ostream& out) const {
this->printRewardModelsInformationToStream(out);
this->getStateLabeling().printLabelingInformationToStream(out);
out << "Size in memory: \t" << (this->getSizeInBytes())/1024 << " kbytes" << std::endl;
out << "-------------------------------------------------------------- " << std::endl;
}
template<typename ValueType, typename RewardModelType>
void Model<ValueType, RewardModelType>::printRewardModelsInformationToStream(std::ostream& out) const {
if (this->rewardModels.size()) {
std::vector<std::string> rewardModelNames;
std::for_each(this->rewardModels.cbegin(), this->rewardModels.cend(),
[&rewardModelNames] (typename std::pair<std::string, RewardModelType> const& nameRewardModelPair) {
if (nameRewardModelPair.first.empty()) { rewardModelNames.push_back("(default)"); } else { rewardModelNames.push_back(nameRewardModelPair.first); }
});
out << "Reward Models: " << boost::join(rewardModelNames, ", ") << std::endl;
} else {
out << "Reward Models: none" << std::endl;
}
}
template<typename ValueType, typename RewardModelType>
void Model<ValueType, RewardModelType>::writeDotToStream(std::ostream& outStream, bool includeLabeling, storm::storage::BitVector const* subsystem, std::vector<ValueType> const* firstValue, std::vector<ValueType> const* secondValue, std::vector<uint_fast64_t> const* stateColoring, std::vector<std::string> const* colors, std::vector<uint_fast64_t>* scheduler, bool finalizeOutput) const {
outStream << "digraph model {" << std::endl;
// Write all states to the stream.
for (uint_fast64_t state = 0, highestStateIndex = this->getNumberOfStates() - 1; state <= highestStateIndex; ++state) {
if (subsystem == nullptr || subsystem->get(state)) {
outStream << "\t" << state;
if (includeLabeling || firstValue != nullptr || secondValue != nullptr || stateColoring != nullptr) {
outStream << " [ ";
// If we need to print some extra information, do so now.
if (includeLabeling || firstValue != nullptr || secondValue != nullptr) {
outStream << "label = \"" << state << ": ";
// Now print the state labeling to the stream if requested.
if (includeLabeling) {
outStream << "{";
bool includeComma = false;
for (std::string const& label : this->getLabelsOfState(state)) {
if (includeComma) {
outStream << ", ";
} else {
includeComma = true;
}
outStream << label;
}
outStream << "}";
}
// If we are to include some values for the state as well, we do so now.
if (firstValue != nullptr || secondValue != nullptr) {
outStream << " [";
if (firstValue != nullptr) {
outStream << (*firstValue)[state];
if (secondValue != nullptr) {
outStream << ", ";
}
}
if (secondValue != nullptr) {
outStream << (*secondValue)[state];
}
outStream << "]";
}
outStream << "\"";
// Now, we color the states if there were colors given.
if (stateColoring != nullptr && colors != nullptr) {
outStream << ", ";
outStream << " style = filled, fillcolor = " << (*colors)[(*stateColoring)[state]];
}
}
outStream << " ]";
}
outStream << ";" << std::endl;
}
}
// If this methods has not been called from a derived class, we want to close the digraph here.
if (finalizeOutput) {
outStream << "}" << std::endl;
}
}
template<typename ValueType, typename RewardModelType>
std::set<std::string> Model<ValueType, RewardModelType>::getLabelsOfState(storm::storage::sparse::state_type state) const {
return this->stateLabeling.getLabelsOfState(state);
}
template<typename ValueType, typename RewardModelType>
void Model<ValueType, RewardModelType>::setTransitionMatrix(storm::storage::SparseMatrix<ValueType> const& transitionMatrix) {
this->transitionMatrix = transitionMatrix;
}
template<typename ValueType, typename RewardModelType>
void Model<ValueType, RewardModelType>::setTransitionMatrix(storm::storage::SparseMatrix<ValueType>&& transitionMatrix) {
this->transitionMatrix = std::move(transitionMatrix);
}
template<typename ValueType, typename RewardModelType>
bool Model<ValueType, RewardModelType>::isSparseModel() const {
return true;
}
template<typename ValueType, typename RewardModelType>
std::unordered_map<std::string, RewardModelType>& Model<ValueType, RewardModelType>::getRewardModels() {
return this->rewardModels;
}
template<typename ValueType, typename RewardModelType>
std::unordered_map<std::string, RewardModelType> const& Model<ValueType, RewardModelType>::getRewardModels() const {
return this->rewardModels;
}
template class Model<double>;
template class Model<float>;
#ifdef STORM_HAVE_CARL
template class Model<storm::RationalFunction>;
#endif
}
}
}