Storm 1.11.1.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::RationalFunction>) {
76 os << "parametric";
77 } else {
78 STORM_LOG_ASSERT(false, "Unhandled value type");
79 }
80 os << '\n';
81 os << "@parameters\n";
82 if (parameters.empty()) {
83 for (std::string const& parameter : getParameters(sparseModel)) {
84 os << parameter << " ";
85 }
86 } else {
87 for (std::string const& parameter : parameters) {
88 os << parameter << " ";
89 }
90 }
91 os << '\n';
92
93 // Optionally write placeholders which only need to be parsed once
94 // This is used to reduce the parsing effort for rational functions
95 // Placeholders begin with the dollar symbol $
96 std::unordered_map<ValueType, std::string> placeholders;
97 if (options.allowPlaceholders) {
98 placeholders = generatePlaceholders(sparseModel, exitRates);
99 }
100 if (!placeholders.empty()) {
101 os << "@placeholders\n";
102 for (auto const& entry : placeholders) {
103 os << "$" << entry.second << " : " << entry.first << '\n';
104 }
105 }
106
107 os << "@reward_models\n";
108 for (auto const& rewardModel : sparseModel->getRewardModels()) {
109 os << rewardModel.first << " ";
110 }
111 os << '\n';
112 os << "@nr_states\n" << sparseModel->getNumberOfStates() << '\n';
113 os << "@nr_choices\n" << sparseModel->getNumberOfChoices() << '\n';
114 os << "@model\n";
115
116 storm::storage::SparseMatrix<ValueType> const& matrix = sparseModel->getTransitionMatrix();
117
118 // Iterate over states and export state information and outgoing transitions
119 for (typename storm::storage::SparseMatrix<ValueType>::index_type group = 0; group < matrix.getRowGroupCount(); ++group) {
120 os << "state " << group;
121
122 // Write exit rates for CTMCs and MAs
123 if (!exitRates.empty()) {
124 os << " !";
125 writeValue(os, exitRates.at(group), placeholders);
126 }
127
128 if (sparseModel->getType() == storm::models::ModelType::Pomdp) {
129 os << " {" << sparseModel->template as<storm::models::sparse::Pomdp<ValueType>>()->getObservation(group) << "}";
130 }
131
132 // Write state rewards
133 bool first = true;
134 for (auto const& rewardModelEntry : sparseModel->getRewardModels()) {
135 if (first) {
136 os << " [";
137 first = false;
138 } else {
139 os << ", ";
140 }
141
142 if (rewardModelEntry.second.hasStateRewards()) {
143 writeValue(os, rewardModelEntry.second.getStateRewardVector().at(group), placeholders);
144 } else {
145 os << "0";
146 }
147 }
148
149 if (!first) {
150 os << "]";
151 }
152
153 // Write labels. Only labels with a whitespace are put in (double) quotation marks.
154 for (auto const& label : sparseModel->getStateLabeling().getLabelsOfState(group)) {
155 STORM_LOG_THROW(std::count(label.begin(), label.end(), '\"') == 0, storm::exceptions::NotSupportedException,
156 "Labels with quotation marks are not supported in the DRN format and therefore may not be exported.");
157 // TODO consider escaping the quotation marks. Not sure whether that is a good idea.
158 if (std::count_if(label.begin(), label.end(), isspace) > 0) {
159 os << " \"" << label << "\"";
160 } else {
161 os << " " << label;
162 }
163 }
164 os << '\n';
165 // Write state valuations as comments
166 if (sparseModel->hasStateValuations()) {
167 os << "//" << sparseModel->getStateValuations().getStateInfo(group) << '\n';
168 }
169
170 // Write probabilities
171 typename storm::storage::SparseMatrix<ValueType>::index_type start = matrix.hasTrivialRowGrouping() ? group : matrix.getRowGroupIndices()[group];
172 typename storm::storage::SparseMatrix<ValueType>::index_type end = matrix.hasTrivialRowGrouping() ? group + 1 : matrix.getRowGroupIndices()[group + 1];
173
174 // Iterate over all actions
175 for (typename storm::storage::SparseMatrix<ValueType>::index_type row = start; row < end; ++row) {
176 // Write choice
177 if (sparseModel->hasChoiceLabeling()) {
178 os << "\taction ";
179 bool lfirst = true;
180 if (sparseModel->getChoiceLabeling().getLabelsOfChoice(row).empty()) {
181 os << "__NOLABEL__";
182 }
183 for (auto const& label : sparseModel->getChoiceLabeling().getLabelsOfChoice(row)) {
184 if (!lfirst) {
185 os << "_";
186 lfirst = false;
187 }
188 os << label;
189 }
190 } else {
191 os << "\taction " << row - start;
192 }
193
194 // Write action rewards
195 bool first = true;
196 for (auto const& rewardModelEntry : sparseModel->getRewardModels()) {
197 if (first) {
198 os << " [";
199 first = false;
200 } else {
201 os << ", ";
202 }
203
204 if (rewardModelEntry.second.hasStateActionRewards()) {
205 writeValue(os, rewardModelEntry.second.getStateActionRewardVector().at(row), placeholders);
206 } else {
207 os << "0";
208 }
209 }
210 if (!first) {
211 os << "]";
212 }
213 os << '\n';
214
215 // Write transitions
216 for (auto it = matrix.begin(row); it != matrix.end(row); ++it) {
217 ValueType prob = it->getValue();
218 os << "\t\t" << it->getColumn() << " : ";
219 writeValue(os, prob, placeholders);
220 os << '\n';
221 }
222 }
223 } // end state iteration
224}
225
226template<typename ValueType>
227std::vector<std::string> getParameters(std::shared_ptr<storm::models::sparse::Model<ValueType>>) {
228 return {};
229}
230
231template<>
232std::vector<std::string> getParameters(std::shared_ptr<storm::models::sparse::Model<storm::RationalFunction>> sparseModel) {
233 std::vector<std::string> parameters;
234 std::set<storm::RationalFunctionVariable> parametersProb = storm::models::sparse::getProbabilityParameters(*sparseModel);
235 std::set<storm::RationalFunctionVariable> parametersReward = storm::models::sparse::getRewardParameters(*sparseModel);
236 parametersProb.insert(parametersReward.begin(), parametersReward.end());
237 for (auto const& parameter : parametersProb) {
238 std::stringstream stream;
239 stream << parameter;
240 parameters.push_back(stream.str());
241 }
242 return parameters;
243}
244
245template<typename ValueType>
246std::unordered_map<ValueType, std::string> generatePlaceholders(std::shared_ptr<storm::models::sparse::Model<ValueType>>, std::vector<ValueType>) {
247 return {};
248}
249
258void createPlaceholder(std::unordered_map<storm::RationalFunction, std::string>& placeholders, storm::RationalFunction const& value, size_t& i) {
259 if (!storm::utility::isConstant(value)) {
260 auto ret = placeholders.insert(std::make_pair(value, std::to_string(i)));
261 if (ret.second) {
262 // New element was inserted
263 ++i;
264 }
265 }
266}
267
268template<>
269std::unordered_map<storm::RationalFunction, std::string> generatePlaceholders(
270 std::shared_ptr<storm::models::sparse::Model<storm::RationalFunction>> sparseModel, std::vector<storm::RationalFunction> exitRates) {
271 std::unordered_map<storm::RationalFunction, std::string> placeholders;
272 size_t i = 0;
273
274 // Exit rates
275 for (auto const& exitRate : exitRates) {
276 createPlaceholder(placeholders, exitRate, i);
277 }
278
279 // Rewards
280 for (auto const& rewardModelEntry : sparseModel->getRewardModels()) {
281 if (rewardModelEntry.second.hasStateRewards()) {
282 for (auto const& reward : rewardModelEntry.second.getStateRewardVector()) {
283 createPlaceholder(placeholders, reward, i);
284 }
285 }
286 if (rewardModelEntry.second.hasStateActionRewards()) {
287 for (auto const& reward : rewardModelEntry.second.getStateActionRewardVector()) {
288 createPlaceholder(placeholders, reward, i);
289 }
290 }
291 }
292
293 // Transition probabilities
294 for (auto const& entry : sparseModel->getTransitionMatrix()) {
295 createPlaceholder(placeholders, entry.getValue(), i);
296 }
297
298 return placeholders;
299}
300
301template<typename ValueType>
302void writeValue(std::ostream& os, ValueType value, std::unordered_map<ValueType, std::string> const& placeholders) {
303 if (storm::utility::isConstant(value)) {
304 os << value;
305 return;
306 }
307
308 // Try to use placeholder
309 auto it = placeholders.find(value);
310 if (it != placeholders.end()) {
311 // Use placeholder
312 os << "$" << it->second;
313 } else {
314 os << value;
315 }
316}
317
318// Template instantiations
319template void explicitExportSparseModel<double>(std::filesystem::path const& os, std::shared_ptr<storm::models::sparse::Model<double>> sparseModel,
320 std::vector<std::string> const& parameters, DirectEncodingExporterOptions const& options);
321template void explicitExportSparseModel<storm::RationalNumber>(std::filesystem::path const& os,
322 std::shared_ptr<storm::models::sparse::Model<storm::RationalNumber>> sparseModel,
323 std::vector<std::string> const& parameters, DirectEncodingExporterOptions const& options);
324template void explicitExportSparseModel<storm::RationalFunction>(std::filesystem::path const& os,
326 std::vector<std::string> const& parameters, DirectEncodingExporterOptions const& options);
327template void explicitExportSparseModel<storm::Interval>(std::filesystem::path const& os,
328 std::shared_ptr<storm::models::sparse::Model<storm::Interval>> sparseModel,
329 std::vector<std::string> const& parameters, DirectEncodingExporterOptions const& options);
330
331template void explicitExportSparseModel<double>(std::ostream& os, std::shared_ptr<storm::models::sparse::Model<double>> sparseModel,
332 std::vector<std::string> const& parameters, DirectEncodingExporterOptions const& options);
334 std::shared_ptr<storm::models::sparse::Model<storm::RationalNumber>> sparseModel,
335 std::vector<std::string> const& parameters, DirectEncodingExporterOptions const& options);
338 std::vector<std::string> const& parameters, DirectEncodingExporterOptions const& options);
339template void explicitExportSparseModel<storm::Interval>(std::ostream& os, std::shared_ptr<storm::models::sparse::Model<storm::Interval>> sparseModel,
340 std::vector<std::string> const& parameters, DirectEncodingExporterOptions const& options);
341} // namespace io
342} // 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:32
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::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:699
std::set< storm::RationalFunctionVariable > getProbabilityParameters(Model< storm::RationalFunction > const &model)
Get all probability parameters occurring on transitions.
Definition Model.cpp:695
bool isConstant(ValueType const &)
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 ...