Storm 1.13.0.1
A Modern Probabilistic Model Checker
Loading...
Searching...
No Matches
DirectEncodingExporter.cpp
Go to the documentation of this file.
2
3#include <sstream>
4
10#include "storm/io/file.h"
18
19namespace storm {
20namespace io {
21
22template<typename ValueType>
23void explicitExportSparseModel(std::filesystem::path const& filename, std::shared_ptr<storm::models::sparse::Model<ValueType>> sparseModel,
24 std::vector<std::string> const& parameters, DirectEncodingExporterOptions const& options) {
25 auto const compression = (options.compression == CompressionMode::Default) ? getCompressionModeFromFileExtension(filename) : options.compression;
26 if (compression == CompressionMode::None) {
27 // No compression
28 std::ofstream stream;
29 storm::io::openFile(filename, stream);
30 storm::io::explicitExportSparseModel(stream, sparseModel, parameters, options);
32 } else {
33 // TODO: write directly to compressed file instead of having the entire file in memory first
34 std::stringstream stream;
35 storm::io::explicitExportSparseModel(stream, sparseModel, parameters, options);
36 auto nameInArchive = filename.filename();
38 // remove compression extension from filename (e.g. model.drn.gz -> model.drn)
39 nameInArchive.replace_extension();
40 }
41 storm::io::ArchiveWriter archiveWriter(filename, compression);
42 archiveWriter.addTextFile(nameInArchive, stream.str());
43 }
44}
45
46template<typename ValueType>
47void explicitExportSparseModel(std::ostream& os, std::shared_ptr<storm::models::sparse::Model<ValueType>> sparseModel,
48 std::vector<std::string> const& parameters, DirectEncodingExporterOptions const& options) {
49 // Handle output precision of doubles
50 if (options.outputPrecision) {
51 os.precision(*options.outputPrecision);
52 }
53
54 // Notice that for CTMCs we write the rate matrix instead of probabilities
55
56 // Initialize
57 std::vector<ValueType> exitRates; // Only for CTMCs and MAs.
58 if (sparseModel->getType() == storm::models::ModelType::Ctmc) {
59 exitRates = sparseModel->template as<storm::models::sparse::Ctmc<ValueType>>()->getExitRateVector();
60 } else if (sparseModel->getType() == storm::models::ModelType::MarkovAutomaton) {
61 exitRates = sparseModel->template as<storm::models::sparse::MarkovAutomaton<ValueType>>()->getExitRates();
62 }
63
64 // Write header
65 os << "// Exported by storm\n";
66 os << "// Original model type: " << sparseModel->getType() << '\n';
67 os << "@type: " << sparseModel->getType() << '\n';
68 os << "@value_type: ";
69 if constexpr (std::is_same_v<ValueType, double>) {
70 os << "double";
71 } else if constexpr (std::is_same_v<ValueType, storm::RationalNumber>) {
72 os << "rational";
73 } else if constexpr (std::is_same_v<ValueType, storm::Interval>) {
74 os << "double-interval";
75 } else if constexpr (std::is_same_v<ValueType, storm::RationalInterval>) {
76 os << "rational-interval";
77 } else if constexpr (std::is_same_v<ValueType, storm::RationalFunction>) {
78 os << "parametric";
79 } else {
80 STORM_LOG_ASSERT(false, "Unhandled value type");
81 }
82 os << '\n';
83 os << "@parameters\n";
84 if (parameters.empty()) {
85 for (std::string const& parameter : getParameters(sparseModel)) {
86 os << parameter << " ";
87 }
88 } else {
89 for (std::string const& parameter : parameters) {
90 os << parameter << " ";
91 }
92 }
93 os << '\n';
94
95 // Optionally write placeholders which only need to be parsed once
96 // This is used to reduce the parsing effort for rational functions
97 // Placeholders begin with the dollar symbol $
98 std::unordered_map<ValueType, std::string> placeholders;
99 if (options.allowPlaceholders) {
100 placeholders = generatePlaceholders(sparseModel, exitRates);
101 }
102 if (!placeholders.empty()) {
103 os << "@placeholders\n";
104 for (auto const& entry : placeholders) {
105 os << "$" << entry.second << " : " << entry.first << '\n';
106 }
107 }
108
109 os << "@reward_models\n";
110 for (auto const& rewardModel : sparseModel->getRewardModels()) {
111 os << rewardModel.first << " ";
112 }
113 os << '\n';
114 os << "@nr_states\n" << sparseModel->getNumberOfStates() << '\n';
115 os << "@nr_choices\n" << sparseModel->getNumberOfChoices() << '\n';
116 os << "@model\n";
117
118 storm::storage::SparseMatrix<ValueType> const& matrix = sparseModel->getTransitionMatrix();
119
120 // Iterate over states and export state information and outgoing transitions
121 for (typename storm::storage::SparseMatrix<ValueType>::index_type group = 0; group < matrix.getRowGroupCount(); ++group) {
122 os << "state " << group;
123
124 // Write exit rates for CTMCs and MAs
125 if (!exitRates.empty()) {
126 os << " !";
127 writeValue(os, exitRates.at(group), placeholders);
128 }
129
130 if (sparseModel->getType() == storm::models::ModelType::Pomdp) {
131 os << " {" << sparseModel->template as<storm::models::sparse::Pomdp<ValueType>>()->getObservation(group) << "}";
132 }
133
134 // Write state rewards
135 bool first = true;
136 for (auto const& rewardModelEntry : sparseModel->getRewardModels()) {
137 if (first) {
138 os << " [";
139 first = false;
140 } else {
141 os << ", ";
142 }
143
144 if (rewardModelEntry.second.hasStateRewards()) {
145 writeValue(os, rewardModelEntry.second.getStateRewardVector().at(group), placeholders);
146 } else {
147 os << "0";
148 }
149 }
150
151 if (!first) {
152 os << "]";
153 }
154
155 // Write labels. Only labels with a whitespace are put in (double) quotation marks.
156 for (auto const& label : sparseModel->getStateLabeling().getLabelsOfState(group)) {
157 STORM_LOG_THROW(std::count(label.begin(), label.end(), '\"') == 0, storm::exceptions::NotSupportedException,
158 "Labels with quotation marks are not supported in the DRN format and therefore may not be exported.");
159 // TODO consider escaping the quotation marks. Not sure whether that is a good idea.
160 if (std::count_if(label.begin(), label.end(), isspace) > 0) {
161 os << " \"" << label << "\"";
162 } else {
163 os << " " << label;
164 }
165 }
166 os << '\n';
167 // Write state valuations as comments
168 if (sparseModel->hasStateValuations()) {
169 os << "//" << sparseModel->getStateValuations().getStateInfo(group) << '\n';
170 }
171
172 // Write probabilities
173 typename storm::storage::SparseMatrix<ValueType>::index_type start = matrix.hasTrivialRowGrouping() ? group : matrix.getRowGroupIndices()[group];
174 typename storm::storage::SparseMatrix<ValueType>::index_type end = matrix.hasTrivialRowGrouping() ? group + 1 : matrix.getRowGroupIndices()[group + 1];
175
176 // Iterate over all actions
177 for (typename storm::storage::SparseMatrix<ValueType>::index_type row = start; row < end; ++row) {
178 // Write choice
179 if (sparseModel->hasChoiceLabeling()) {
180 os << "\taction ";
181 bool lfirst = true;
182 if (sparseModel->getChoiceLabeling().getLabelsOfChoice(row).empty()) {
183 os << "__NOLABEL__";
184 }
185 for (auto const& label : sparseModel->getChoiceLabeling().getLabelsOfChoice(row)) {
186 if (!lfirst) {
187 os << "_";
188 lfirst = false;
189 }
190 os << label;
191 }
192 } else {
193 os << "\taction " << row - start;
194 }
195
196 // Write action rewards
197 bool first = true;
198 for (auto const& rewardModelEntry : sparseModel->getRewardModels()) {
199 if (first) {
200 os << " [";
201 first = false;
202 } else {
203 os << ", ";
204 }
205
206 if (rewardModelEntry.second.hasStateActionRewards()) {
207 writeValue(os, rewardModelEntry.second.getStateActionRewardVector().at(row), placeholders);
208 } else {
209 os << "0";
210 }
211 }
212 if (!first) {
213 os << "]";
214 }
215 os << '\n';
216
217 // Write transitions
218 for (auto it = matrix.begin(row); it != matrix.end(row); ++it) {
219 ValueType prob = it->getValue();
220 os << "\t\t" << it->getColumn() << " : ";
221 writeValue(os, prob, placeholders);
222 os << '\n';
223 }
224 }
225 } // end state iteration
226}
227
228template<typename ValueType>
229std::vector<std::string> getParameters(std::shared_ptr<storm::models::sparse::Model<ValueType>>) {
230 return {};
231}
232
233template<>
234std::vector<std::string> getParameters(std::shared_ptr<storm::models::sparse::Model<storm::RationalFunction>> sparseModel) {
235 std::vector<std::string> parameters;
236 std::set<storm::RationalFunctionVariable> parametersProb = storm::models::sparse::getProbabilityParameters(*sparseModel);
237 std::set<storm::RationalFunctionVariable> parametersReward = storm::models::sparse::getRewardParameters(*sparseModel);
238 parametersProb.insert(parametersReward.begin(), parametersReward.end());
239 for (auto const& parameter : parametersProb) {
240 std::stringstream stream;
241 stream << parameter;
242 parameters.push_back(stream.str());
243 }
244 return parameters;
245}
246
247template<typename ValueType>
248std::unordered_map<ValueType, std::string> generatePlaceholders(std::shared_ptr<storm::models::sparse::Model<ValueType>>, std::vector<ValueType>) {
249 return {};
250}
251
259
260void createPlaceholder(std::unordered_map<storm::RationalFunction, std::string>& placeholders, storm::RationalFunction const& value, size_t& i) {
261 if (!storm::utility::isConstant(value)) {
262 auto ret = placeholders.insert(std::make_pair(value, std::to_string(i)));
263 if (ret.second) {
264 // New element was inserted
265 ++i;
266 }
267 }
268}
269
270template<>
271std::unordered_map<storm::RationalFunction, std::string> generatePlaceholders(
272 std::shared_ptr<storm::models::sparse::Model<storm::RationalFunction>> sparseModel, std::vector<storm::RationalFunction> exitRates) {
273 std::unordered_map<storm::RationalFunction, std::string> placeholders;
274 size_t i = 0;
275
276 // Exit rates
277 for (auto const& exitRate : exitRates) {
278 createPlaceholder(placeholders, exitRate, i);
279 }
280
281 // Rewards
282 for (auto const& rewardModelEntry : sparseModel->getRewardModels()) {
283 if (rewardModelEntry.second.hasStateRewards()) {
284 for (auto const& reward : rewardModelEntry.second.getStateRewardVector()) {
285 createPlaceholder(placeholders, reward, i);
286 }
287 }
288 if (rewardModelEntry.second.hasStateActionRewards()) {
289 for (auto const& reward : rewardModelEntry.second.getStateActionRewardVector()) {
290 createPlaceholder(placeholders, reward, i);
291 }
292 }
293 }
294
295 // Transition probabilities
296 for (auto const& entry : sparseModel->getTransitionMatrix()) {
297 createPlaceholder(placeholders, entry.getValue(), i);
298 }
299
300 return placeholders;
301}
302
303template<typename ValueType>
304void writeValue(std::ostream& os, ValueType value, std::unordered_map<ValueType, std::string> const& placeholders) {
305 if (storm::utility::isConstant(value)) {
306 os << value;
307 return;
308 }
309
310 // Try to use placeholder
311 auto it = placeholders.find(value);
312 if (it != placeholders.end()) {
313 // Use placeholder
314 os << "$" << it->second;
315 } else {
316 os << value;
317 }
318}
319
320// Template instantiations
321template void explicitExportSparseModel<double>(std::filesystem::path const& os, std::shared_ptr<storm::models::sparse::Model<double>> sparseModel,
322 std::vector<std::string> const& parameters, DirectEncodingExporterOptions const& options);
323template void explicitExportSparseModel<storm::RationalNumber>(std::filesystem::path const& os,
324 std::shared_ptr<storm::models::sparse::Model<storm::RationalNumber>> sparseModel,
325 std::vector<std::string> const& parameters, DirectEncodingExporterOptions const& options);
326template void explicitExportSparseModel<storm::RationalFunction>(std::filesystem::path const& os,
328 std::vector<std::string> const& parameters, DirectEncodingExporterOptions const& options);
329template void explicitExportSparseModel<storm::Interval>(std::filesystem::path const& os,
330 std::shared_ptr<storm::models::sparse::Model<storm::Interval>> sparseModel,
331 std::vector<std::string> const& parameters, DirectEncodingExporterOptions const& options);
332template void explicitExportSparseModel<storm::RationalInterval>(std::filesystem::path const& os,
334 std::vector<std::string> const& parameters, DirectEncodingExporterOptions const& options);
335
336template void explicitExportSparseModel<double>(std::ostream& os, std::shared_ptr<storm::models::sparse::Model<double>> sparseModel,
337 std::vector<std::string> const& parameters, DirectEncodingExporterOptions const& options);
339 std::shared_ptr<storm::models::sparse::Model<storm::RationalNumber>> sparseModel,
340 std::vector<std::string> const& parameters, DirectEncodingExporterOptions const& options);
343 std::vector<std::string> const& parameters, DirectEncodingExporterOptions const& options);
344template void explicitExportSparseModel<storm::Interval>(std::ostream& os, std::shared_ptr<storm::models::sparse::Model<storm::Interval>> sparseModel,
345 std::vector<std::string> const& parameters, DirectEncodingExporterOptions const& options);
348 std::vector<std::string> const& parameters, DirectEncodingExporterOptions const& options);
349} // namespace io
350} // namespace storm
void addTextFile(std::filesystem::path const &archivePath, std::string const &data)
Add a text file to the archive.
Base class for all sparse models.
Definition Model.h:30
A class that holds a possibly non-square matrix in the compressed row storage format.
const_iterator begin(index_type row) const
Retrieves an iterator that points to the beginning of the given row.
const_iterator end(index_type row) const
Retrieves an iterator that points past the end of the given row.
index_type getRowGroupCount() const
Returns the number of row groups in the matrix.
bool hasTrivialRowGrouping() const
Retrieves whether the matrix has a trivial row grouping.
std::vector< index_type > const & getRowGroupIndices() const
Returns the grouping of rows of this matrix.
SparseMatrixIndexType index_type
#define STORM_LOG_ASSERT(cond, message)
Definition macros.h:11
#define STORM_LOG_THROW(cond, exception, message)
Definition macros.h:30
template void explicitExportSparseModel< double >(std::filesystem::path const &os, std::shared_ptr< storm::models::sparse::Model< double > > sparseModel, std::vector< std::string > const &parameters, DirectEncodingExporterOptions const &options)
void explicitExportSparseModel(std::filesystem::path const &filename, std::shared_ptr< storm::models::sparse::Model< ValueType > > sparseModel, std::vector< std::string > const &parameters, DirectEncodingExporterOptions const &options)
Exports a sparse model into the explicit DRN format.
CompressionMode getCompressionModeFromFileExtension(std::filesystem::path const &filename)
template void explicitExportSparseModel< storm::Interval >(std::filesystem::path const &os, std::shared_ptr< storm::models::sparse::Model< storm::Interval > > sparseModel, std::vector< std::string > const &parameters, DirectEncodingExporterOptions const &options)
void createPlaceholder(std::unordered_map< storm::RationalFunction, std::string > &placeholders, storm::RationalFunction const &value, size_t &i)
Helper function to create a possible placeholder.
template void explicitExportSparseModel< storm::RationalInterval >(std::filesystem::path const &os, std::shared_ptr< storm::models::sparse::Model< storm::RationalInterval > > sparseModel, std::vector< std::string > const &parameters, DirectEncodingExporterOptions const &options)
template void explicitExportSparseModel< storm::RationalNumber >(std::filesystem::path const &os, std::shared_ptr< storm::models::sparse::Model< storm::RationalNumber > > sparseModel, std::vector< std::string > const &parameters, DirectEncodingExporterOptions const &options)
void writeValue(std::ostream &os, ValueType value, std::unordered_map< ValueType, std::string > const &placeholders)
Write value to stream while using the placeholders.
void closeFile(std::ofstream &stream)
Close the given file after writing.
Definition file.h:47
void openFile(std::string const &filepath, std::ofstream &filestream, bool append=false, bool silent=false)
Open the given file for writing.
Definition file.h:18
std::vector< std::string > getParameters(std::shared_ptr< storm::models::sparse::Model< ValueType > >)
Accumulate parameters in the model.
std::unordered_map< ValueType, std::string > generatePlaceholders(std::shared_ptr< storm::models::sparse::Model< ValueType > >, std::vector< ValueType >)
Generate placeholders for rational functions in the model.
template void explicitExportSparseModel< storm::RationalFunction >(std::filesystem::path const &os, std::shared_ptr< storm::models::sparse::Model< storm::RationalFunction > > sparseModel, std::vector< std::string > const &parameters, DirectEncodingExporterOptions const &options)
std::set< storm::RationalFunctionVariable > getRewardParameters(Model< storm::RationalFunction > const &model)
Get all parameters occurring in rewards.
Definition Model.cpp:698
std::set< storm::RationalFunctionVariable > getProbabilityParameters(Model< storm::RationalFunction > const &model)
Get all probability parameters occurring on transitions.
Definition Model.cpp:694
bool isConstant(ValueType const &)
carl::RationalFunction< Polynomial, true > RationalFunction
bool allowPlaceholders
Allow placeholders for rational functions in the exported DRN file.
storm::io::CompressionMode compression
The type of compression used for the exported DRN file.
std::optional< std::size_t > outputPrecision
If set, the output precision for floating point numbers in the exported DRN file is set to the given ...