Storm 1.11.0.1
A Modern Probabilistic Model Checker
Loading...
Searching...
No Matches
JSONExporter.cpp
Go to the documentation of this file.
1#include "JSONExporter.h"
2
3#include <fstream>
4#include <iostream>
5#include <vector>
6
9#include "storm/io/file.h"
11
16
29
31
40
41namespace storm {
42namespace jani {
43
44ExportJsonType anyToJson(boost::any&& input) {
45 boost::any tmp(std::move(input));
46 ExportJsonType res = std::move(*boost::any_cast<ExportJsonType>(&tmp));
47 return res;
48}
49
50ExportJsonType buildExpression(storm::expressions::Expression const& exp, std::vector<storm::jani::Constant> const& constants,
51 VariableSet const& globalVariables = VariableSet(), VariableSet const& localVariables = VariableSet(),
52 std::unordered_set<std::string> const& auxiliaryVariables = {}) {
53 STORM_LOG_TRACE("Exporting " << exp);
54 return ExpressionToJson::translate(exp, constants, globalVariables, localVariables, auxiliaryVariables);
55}
56
58 public:
59 CompositionJsonExporter(bool allowRecursion) : allowRecursion(allowRecursion) {}
60
61 static ExportJsonType translate(storm::jani::Composition const& comp, bool allowRecursion = true) {
62 CompositionJsonExporter visitor(allowRecursion);
63 return anyToJson(comp.accept(visitor, boost::none));
64 }
65
66 virtual boost::any visit(AutomatonComposition const& composition, boost::any const&) {
67 ExportJsonType compDecl;
68 ExportJsonType autDecl;
69 autDecl["automaton"] = composition.getAutomatonName();
70 std::vector<ExportJsonType> elements;
71 elements.push_back(autDecl);
72 compDecl["elements"] = elements;
73 return compDecl;
74 }
75
76 virtual boost::any visit(ParallelComposition const& composition, boost::any const& data) {
77 ExportJsonType compDecl;
78
79 std::vector<ExportJsonType> elems;
80 for (auto const& subcomp : composition.getSubcompositions()) {
81 ExportJsonType elemDecl;
82 if (subcomp->isAutomatonComposition()) {
83 elemDecl["automaton"] = std::static_pointer_cast<AutomatonComposition>(subcomp)->getAutomatonName();
84 } else {
85 STORM_LOG_THROW(allowRecursion, storm::exceptions::InvalidJaniException, "Nesting composition " << *subcomp << " is not supported by JANI.");
86 elemDecl = anyToJson(subcomp->accept(*this, data));
87 }
88 elems.push_back(elemDecl);
89 }
90 compDecl["elements"] = elems;
91 std::vector<ExportJsonType> synElems;
92 for (auto const& syncs : composition.getSynchronizationVectors()) {
93 ExportJsonType syncDecl;
94 syncDecl["synchronise"] = std::vector<std::string>();
95 for (auto const& syncIn : syncs.getInput()) {
97 syncDecl["synchronise"].push_back(nullptr);
98 } else {
99 syncDecl["synchronise"].push_back(syncIn);
100 }
101 }
102 syncDecl["result"] = syncs.getOutput();
103 synElems.push_back(syncDecl);
104 }
105 if (!synElems.empty()) {
106 compDecl["syncs"] = synElems;
107 }
108
109 return compDecl;
110 }
111
112 private:
113 bool allowRecursion;
114};
115
117 switch (ct) {
119 return "<";
121 return "≤";
123 return ">";
125 return "≥";
126 }
127 STORM_LOG_THROW(false, storm::exceptions::IllegalArgumentException, "Unknown ComparisonType");
128}
129
130ExportJsonType FormulaToJaniJson::constructPropertyInterval(boost::optional<storm::expressions::Expression> const& lower,
131 boost::optional<bool> const& lowerExclusive,
132 boost::optional<storm::expressions::Expression> const& upper,
133 boost::optional<bool> const& upperExclusive) const {
134 STORM_LOG_THROW((lower.is_initialized() || upper.is_initialized()), storm::exceptions::InvalidJaniException,
135 "PropertyInterval needs either a lower or an upper bound, but none was given.");
136 STORM_LOG_THROW((lower.is_initialized() || !lowerExclusive.is_initialized()), storm::exceptions::InvalidJaniException,
137 "PropertyInterval defines wether the lower bound is exclusive but no lower bound is given.");
138 STORM_LOG_THROW((upper.is_initialized() || !upperExclusive.is_initialized()), storm::exceptions::InvalidJaniException,
139 "PropertyInterval defines wether the upper bound is exclusive but no upper bound is given.");
140
141 ExportJsonType iDecl;
142 if (lower) {
143 iDecl["lower"] = buildExpression(*lower, model.getConstants(), model.getGlobalVariables());
144 if (lowerExclusive) {
145 iDecl["lower-exclusive"] = *lowerExclusive;
146 }
147 }
148 if (upper) {
149 iDecl["upper"] = buildExpression(*upper, model.getConstants(), model.getGlobalVariables());
150 if (upperExclusive) {
151 iDecl["upper-exclusive"] = *upperExclusive;
152 }
153 }
154 return iDecl;
155}
156
157ExportJsonType FormulaToJaniJson::constructRewardAccumulation(storm::logic::RewardAccumulation const& rewardAccumulation,
158 std::string const& rewardModelName) const {
159 storm::jani::RewardModelInformation info(model, rewardModelName);
160
161 bool steps = rewardAccumulation.isStepsSet() && (info.hasActionRewards() || info.hasTransitionRewards());
162 bool time = rewardAccumulation.isTimeSet() && !model.isDiscreteTimeModel() && info.hasStateRewards();
163 bool exit = rewardAccumulation.isExitSet() && info.hasStateRewards();
164
165 return constructRewardAccumulation(storm::logic::RewardAccumulation(steps, time, exit));
166}
167
168ExportJsonType FormulaToJaniJson::constructRewardAccumulation(storm::logic::RewardAccumulation const& rewardAccumulation) const {
169 std::vector<std::string> res;
170 if (rewardAccumulation.isStepsSet()) {
171 res.push_back("steps");
172 }
173 if (rewardAccumulation.isTimeSet()) {
174 res.push_back("time");
175 }
176 if (rewardAccumulation.isExitSet()) {
177 stateExitRewards = true;
178 res.push_back("exit");
179 }
180 return res;
181}
182
183ExportJsonType FormulaToJaniJson::constructStandardRewardAccumulation(std::string const& rewardModelName) const {
184 if (model.isDiscreteTimeModel()) {
185 return constructRewardAccumulation(storm::logic::RewardAccumulation(true, false, true), rewardModelName);
186 } else {
187 return constructRewardAccumulation(storm::logic::RewardAccumulation(true, true, false), rewardModelName);
188 }
189}
190
192 FormulaToJaniJson translator(model);
193 auto result = anyToJson(formula.accept(translator));
194 if (translator.containsStateExitRewards()) {
196 }
197 return result;
198}
199
201 return stateExitRewards;
202}
203
204boost::any FormulaToJaniJson::visit(storm::logic::AtomicExpressionFormula const& f, boost::any const&) const {
205 return buildExpression(f.getExpression(), model.getConstants(), model.getGlobalVariables());
206}
207
208boost::any FormulaToJaniJson::visit(storm::logic::AtomicLabelFormula const& f, boost::any const&) const {
209 ExportJsonType opDecl(f.getLabel());
210 return opDecl;
211}
212boost::any FormulaToJaniJson::visit(storm::logic::BinaryBooleanStateFormula const& f, boost::any const& data) const {
213 ExportJsonType opDecl;
215 opDecl["op"] = op == storm::logic::BinaryBooleanStateFormula::OperatorType::And ? "∧" : "∨";
216 opDecl["left"] = anyToJson(f.getLeftSubformula().accept(*this, data));
217 opDecl["right"] = anyToJson(f.getRightSubformula().accept(*this, data));
218 return opDecl;
219}
220boost::any FormulaToJaniJson::visit(storm::logic::BinaryBooleanPathFormula const& f, boost::any const& data) const {
221 ExportJsonType opDecl;
223 opDecl["op"] = op == storm::logic::BinaryBooleanPathFormula::OperatorType::And ? "∧" : "∨";
224 opDecl["left"] = boost::any_cast<ExportJsonType>(f.getLeftSubformula().accept(*this, data));
225 opDecl["right"] = boost::any_cast<ExportJsonType>(f.getRightSubformula().accept(*this, data));
226 return opDecl;
227}
228boost::any FormulaToJaniJson::visit(storm::logic::BooleanLiteralFormula const& f, boost::any const&) const {
229 ExportJsonType opDecl(f.isTrueFormula() ? true : false);
230 return opDecl;
231}
232boost::any FormulaToJaniJson::visit(storm::logic::BoundedUntilFormula const& f, boost::any const& data) const {
233 STORM_LOG_THROW(!f.hasMultiDimensionalSubformulas(), storm::exceptions::NotSupportedException,
234 "Jani export of multi-dimensional bounded until formulas is not supported.");
235 ExportJsonType opDecl;
236 opDecl["op"] = "U";
237 opDecl["left"] = anyToJson(f.getLeftSubformula().accept(*this, data));
238 opDecl["right"] = anyToJson(f.getRightSubformula().accept(*this, data));
239
240 bool hasStepBounds(false), hasTimeBounds(false);
241 std::vector<ExportJsonType> rewardBounds;
242
243 for (uint64_t i = 0; i < f.getDimension(); ++i) {
244 boost::optional<storm::expressions::Expression> lower, upper;
245 boost::optional<bool> lowerExclusive, upperExclusive;
246 if (f.hasLowerBound(i)) {
247 lower = f.getLowerBound(i);
248 lowerExclusive = f.isLowerBoundStrict(i);
249 }
250 if (f.hasUpperBound(i)) {
251 upper = f.getUpperBound(i);
252 upperExclusive = f.isUpperBoundStrict(i);
253 }
254 ExportJsonType propertyInterval = constructPropertyInterval(lower, lowerExclusive, upper, upperExclusive);
255
256 auto tbr = f.getTimeBoundReference(i);
257 if (tbr.isStepBound() || (model.isDiscreteTimeModel() && tbr.isTimeBound())) {
258 STORM_LOG_THROW(!hasStepBounds, storm::exceptions::NotSupportedException,
259 "Jani export of until formulas with multiple step bounds is not supported.");
260 hasStepBounds = true;
261 opDecl["step-bounds"] = propertyInterval;
262 } else if (tbr.isRewardBound()) {
263 ExportJsonType rewbound;
264 rewbound["exp"] = buildExpression(model.getRewardModelExpression(tbr.getRewardName()), model.getConstants(), model.getGlobalVariables());
265 if (tbr.hasRewardAccumulation()) {
266 rewbound["accumulate"] = constructRewardAccumulation(tbr.getRewardAccumulation(), tbr.getRewardName());
267 } else {
268 rewbound["accumulate"] = constructStandardRewardAccumulation(tbr.getRewardName());
269 }
270 rewbound["bounds"] = propertyInterval;
271 rewardBounds.push_back(std::move(rewbound));
272 } else {
273 STORM_LOG_THROW(!hasTimeBounds, storm::exceptions::NotSupportedException,
274 "Jani export of until formulas with multiple time bounds is not supported.");
275 hasTimeBounds = true;
276 opDecl["time-bounds"] = propertyInterval;
277 }
278 }
279 if (!rewardBounds.empty()) {
280 opDecl["reward-bounds"] = ExportJsonType(rewardBounds);
281 }
282 return opDecl;
283}
284
285boost::any FormulaToJaniJson::visit(storm::logic::ConditionalFormula const&, boost::any const&) const {
286 STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Jani currently does not support conditional formulae");
287}
288
289boost::any FormulaToJaniJson::visit(storm::logic::CumulativeRewardFormula const&, boost::any const&) const {
290 STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Storm currently does not support translating cumulative reward formulae");
291}
292
293boost::any FormulaToJaniJson::visit(storm::logic::EventuallyFormula const& f, boost::any const& data) const {
294 ExportJsonType opDecl;
295 opDecl["op"] = "U";
296 opDecl["left"] = anyToJson(f.getTrueFormula()->accept(*this, data));
297 opDecl["right"] = anyToJson(f.getSubformula().accept(*this, data));
298 return opDecl;
299}
300
301boost::any FormulaToJaniJson::visit(storm::logic::TimeOperatorFormula const& f, boost::any const& data) const {
302 ExportJsonType opDecl;
303
304 // Create standard reward accumulation for time operator formulas.
308 }
309 auto rewAccJson = constructRewardAccumulation(rewAcc);
310
311 if (f.hasBound()) {
312 auto bound = f.getBound();
313 opDecl["op"] = comparisonTypeToJani(bound.comparisonType);
314 if (f.hasOptimalityType()) {
315 opDecl["left"]["op"] = f.getOptimalityType() == storm::solver::OptimizationDirection::Minimize ? "Emin" : "Emax";
317 opDecl["left"]["reach"] = anyToJson(f.getSubformula().asEventuallyFormula().getSubformula().accept(*this, data));
318 } else {
319 STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Unsupported subformula for time operator formula " << f);
320 }
321 } else {
322 opDecl["left"]["op"] =
323 (bound.comparisonType == storm::logic::ComparisonType::Less || bound.comparisonType == storm::logic::ComparisonType::LessEqual) ? "Emax"
324 : "Emin";
325 opDecl["left"]["reach"] = anyToJson(f.getSubformula().asEventuallyFormula().getSubformula().accept(*this, data));
326 }
327 opDecl["left"]["exp"] = ExportJsonType(1);
328 opDecl["left"]["accumulate"] = rewAccJson;
329 opDecl["right"] = buildExpression(bound.threshold, model.getConstants(), model.getGlobalVariables());
330 } else {
331 if (f.hasOptimalityType()) {
332 opDecl["op"] = f.getOptimalityType() == storm::solver::OptimizationDirection::Minimize ? "Emin" : "Emax";
334 opDecl["reach"] = anyToJson(f.getSubformula().asEventuallyFormula().getSubformula().accept(*this, data));
335 } else {
336 STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Unsupported subformula for time operator formula " << f);
337 }
338 } else {
339 // TODO add checks
340 opDecl["op"] = "Emin";
341 opDecl["reach"] = anyToJson(f.getSubformula().asEventuallyFormula().getSubformula().accept(*this, data));
342 }
343 opDecl["exp"] = ExportJsonType(1);
344 opDecl["accumulate"] = rewAccJson;
345 }
346 return opDecl;
347}
348
349boost::any FormulaToJaniJson::visit(storm::logic::GloballyFormula const& f, boost::any const& data) const {
350 ExportJsonType opDecl;
351 opDecl["op"] = "G";
352 opDecl["exp"] = anyToJson(f.getSubformula().accept(*this, data));
353 return opDecl;
354}
355
356boost::any FormulaToJaniJson::visit(storm::logic::GameFormula const&, boost::any const&) const {
357 STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "Conversion of game formulas to Jani is not supported.");
358}
359
360boost::any FormulaToJaniJson::visit(storm::logic::InstantaneousRewardFormula const&, boost::any const&) const {
361 STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "Jani currently does not support conversion of an instanteneous reward formula");
362}
363
364boost::any FormulaToJaniJson::visit(storm::logic::LongRunAverageOperatorFormula const& f, boost::any const& data) const {
365 ExportJsonType opDecl;
366 if (f.hasBound()) {
367 auto bound = f.getBound();
368 opDecl["op"] = comparisonTypeToJani(bound.comparisonType);
369 if (f.hasOptimalityType()) {
370 opDecl["left"]["op"] = f.getOptimalityType() == storm::solver::OptimizationDirection::Minimize ? "Smin" : "Smax";
371 opDecl["left"]["exp"] = anyToJson(f.getSubformula().accept(*this, data));
372 } else {
373 opDecl["left"]["op"] =
374 (bound.comparisonType == storm::logic::ComparisonType::Less || bound.comparisonType == storm::logic::ComparisonType::LessEqual) ? "Smax"
375 : "Smin";
376 opDecl["left"]["exp"] = anyToJson(f.getSubformula().accept(*this, data));
377 }
378 opDecl["right"] = buildExpression(bound.threshold, model.getConstants(), model.getGlobalVariables());
379 } else {
380 if (f.hasOptimalityType()) {
381 opDecl["op"] = f.getOptimalityType() == storm::solver::OptimizationDirection::Minimize ? "Smin" : "Smax";
382 opDecl["exp"] = anyToJson(f.getSubformula().accept(*this, data));
383
384 } else {
385 // TODO add checks
386 opDecl["op"] = "Smin";
387 opDecl["exp"] = anyToJson(f.getSubformula().accept(*this, data));
388 }
389 }
390 return opDecl;
391}
392
393boost::any FormulaToJaniJson::visit(storm::logic::LongRunAverageRewardFormula const&, boost::any const&) const {
394 // ExportJsonType opDecl;
395 // if(f.()) {
396 // auto bound = f.getBound();
397 // opDecl["op"] = comparisonTypeToJani(bound.comparisonType);
398 // if(f.hasOptimalityType()) {
399 // opDecl["left"]["op"] = f.getOptimalityType() == storm::solver::OptimizationDirection::Minimize ? "Smin" : "Smax";
400 // opDecl["left"]["exp"] = anyToJson(f.getSubformula().accept(*this, boost::none));
401 // } else {
402 // opDecl["left"]["op"] = (bound.comparisonType == storm::logic::ComparisonType::Less || bound.comparisonType ==
403 // storm::logic::ComparisonType::LessEqual) ? "Smax" : "Smin"; opDecl["left"]["exp"] = anyToJson(f.getSubformula().accept(*this,
404 // boost::none));
405 // }
406 // opDecl["right"] = ExpressionToJson::translate(bound.threshold);
407 // } else {
408 // if(f.hasOptimalityType()) {
409 // opDecl["op"] = f.getOptimalityType() == storm::solver::OptimizationDirection::Minimize ? "Smin" : "Smax";
410 // opDecl["exp"] = anyToJson(f.getSubformula().accept(*this, boost::none));
411 //
412 // } else {
413 // // TODO add checks
414 // opDecl["op"] = "Pmin";
415 // opDecl["exp"] = anyToJson(f.getSubformula().accept(*this, boost::none));
416 // }
417 // }
418 // return opDecl;
419
420 STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "Jani currently does not support conversion of an LRA reward formula");
421}
422
423boost::any FormulaToJaniJson::visit(storm::logic::MultiObjectiveFormula const&, boost::any const&) const {
424 STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "Jani currently does not support conversion of a multi-objective formula");
425}
426
427boost::any FormulaToJaniJson::visit(storm::logic::QuantileFormula const&, boost::any const&) const {
428 STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "Jani currently does not support conversion of a Quantile formula");
429}
430
431boost::any FormulaToJaniJson::visit(storm::logic::NextFormula const& f, boost::any const& data) const {
432 ExportJsonType opDecl;
433 opDecl["op"] = "U";
434 opDecl["left"] = anyToJson(f.getTrueFormula()->accept(*this, data));
435 opDecl["right"] = anyToJson(f.getSubformula().accept(*this, data));
436 auto intervalExpressionManager = std::make_shared<storm::expressions::ExpressionManager>();
437 opDecl["step-bounds"] = constructPropertyInterval(intervalExpressionManager->integer(1), false, intervalExpressionManager->integer(1), false);
438 return opDecl;
439}
440
441boost::any FormulaToJaniJson::visit(storm::logic::ProbabilityOperatorFormula const& f, boost::any const& data) const {
442 ExportJsonType opDecl;
443
444 if (f.hasBound()) {
445 auto bound = f.getBound();
446 opDecl["op"] = comparisonTypeToJani(bound.comparisonType);
447 if (f.hasOptimalityType()) {
448 opDecl["left"]["op"] = f.getOptimalityType() == storm::solver::OptimizationDirection::Minimize ? "Pmin" : "Pmax";
449 opDecl["left"]["exp"] = anyToJson(f.getSubformula().accept(*this, data));
450 } else {
451 opDecl["left"]["op"] =
452 (bound.comparisonType == storm::logic::ComparisonType::Less || bound.comparisonType == storm::logic::ComparisonType::LessEqual) ? "Pmax"
453 : "Pmin";
454 opDecl["left"]["exp"] = anyToJson(f.getSubformula().accept(*this, data));
455 }
456 opDecl["right"] = buildExpression(bound.threshold, model.getConstants(), model.getGlobalVariables());
457 } else {
458 if (f.hasOptimalityType()) {
459 opDecl["op"] = f.getOptimalityType() == storm::solver::OptimizationDirection::Minimize ? "Pmin" : "Pmax";
460 opDecl["exp"] = anyToJson(f.getSubformula().accept(*this, data));
461
462 } else {
463 // TODO add checks
464 opDecl["op"] = "Pmin";
465 opDecl["exp"] = anyToJson(f.getSubformula().accept(*this, data));
466 }
467 }
468 return opDecl;
469}
470
471boost::any FormulaToJaniJson::visit(storm::logic::RewardOperatorFormula const& f, boost::any const& data) const {
472 ExportJsonType opDecl;
473
474 std::string instantName;
475 if (model.isDiscreteTimeModel()) {
476 instantName = "step-instant";
477 } else {
478 instantName = "time-instant";
479 }
480
481 std::string rewardModelName;
482 if (f.hasRewardModelName()) {
483 rewardModelName = f.getRewardModelName();
484 } else {
486 for (auto const& variable : model.getGlobalVariables().getRealVariables()) {
487 if (variable.isTransient()) {
488 rewardModelName = variable.getName();
489 STORM_LOG_WARN("Reward model name was not given, assuming the only global real transient variable '" << rewardModelName
490 << "' to measure the reward.");
491 break;
492 }
493 }
494 }
495 }
496 STORM_LOG_THROW(!rewardModelName.empty(), storm::exceptions::NotSupportedException, "Reward name has to be specified for Jani-conversion");
497
498 std::string opString = "";
500 opString = "S";
501 } else {
502 opString = "E";
503 }
504 if (f.hasOptimalityType()) {
505 opString += storm::solver::minimize(f.getOptimalityType()) ? "min" : "max";
506 } else if (f.hasBound()) {
507 opString += storm::logic::isLowerBound(f.getBound().comparisonType) ? "min" : "max";
508 } else {
509 opString += "min";
510 }
511
512 opDecl["op"] = opString;
513
515 opDecl["reach"] = anyToJson(f.getSubformula().asEventuallyFormula().getSubformula().accept(*this, data));
517 opDecl["accumulate"] = constructRewardAccumulation(f.getSubformula().asEventuallyFormula().getRewardAccumulation(), rewardModelName);
518 } else {
519 opDecl["accumulate"] = constructStandardRewardAccumulation(rewardModelName);
520 }
521 } else if (f.getSubformula().isCumulativeRewardFormula()) {
522 // TODO: support for reward bounded formulas
524 "Export for cumulative reward formulas with reward instant currently unsupported.");
527 opDecl["accumulate"] = constructRewardAccumulation(f.getSubformula().asCumulativeRewardFormula().getRewardAccumulation(), rewardModelName);
528 } else {
529 opDecl["accumulate"] = constructStandardRewardAccumulation(rewardModelName);
530 }
535 opDecl["accumulate"] = constructRewardAccumulation(f.getSubformula().asLongRunAverageRewardFormula().getRewardAccumulation(), rewardModelName);
536 } else {
537 opDecl["accumulate"] = constructStandardRewardAccumulation(rewardModelName);
538 }
539 }
540 opDecl["exp"] = buildExpression(model.getRewardModelExpression(rewardModelName), model.getConstants(), model.getGlobalVariables());
541
542 if (f.hasBound()) {
543 ExportJsonType compDecl;
544 auto bound = f.getBound();
545 compDecl["op"] = comparisonTypeToJani(bound.comparisonType);
546 compDecl["left"] = std::move(opDecl);
547 compDecl["right"] = buildExpression(bound.threshold, model.getConstants(), model.getGlobalVariables());
548 return compDecl;
549 } else {
550 return opDecl;
551 }
552}
553
554boost::any FormulaToJaniJson::visit(storm::logic::TotalRewardFormula const&, boost::any const&) const {
555 STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "Jani currently does not support a total reward formula");
556}
557
558boost::any FormulaToJaniJson::visit(storm::logic::UnaryBooleanStateFormula const& f, boost::any const& data) const {
559 STORM_LOG_ASSERT(f.getOperator() == storm::logic::UnaryBooleanStateFormula::OperatorType::Not, "Unsupported operator");
560 ExportJsonType opDecl;
561 opDecl["op"] = "¬";
562 opDecl["exp"] = anyToJson(f.getSubformula().accept(*this, data));
563 return opDecl;
564}
565
566boost::any FormulaToJaniJson::visit(storm::logic::UnaryBooleanPathFormula const& f, boost::any const& data) const {
567 STORM_LOG_ASSERT(f.getOperator() == storm::logic::UnaryBooleanStateFormula::OperatorType::Not, "Unsupported operator");
568 ExportJsonType opDecl;
569 opDecl["op"] = "¬";
570 opDecl["exp"] = boost::any_cast<ExportJsonType>(f.getSubformula().accept(*this, data));
571 return opDecl;
572}
573
574boost::any FormulaToJaniJson::visit(storm::logic::UntilFormula const& f, boost::any const& data) const {
575 ExportJsonType opDecl;
576 opDecl["op"] = "U";
577 opDecl["left"] = anyToJson(f.getLeftSubformula().accept(*this, data));
578 opDecl["right"] = anyToJson(f.getRightSubformula().accept(*this, data));
579 return opDecl;
580}
581
582boost::any FormulaToJaniJson::visit(storm::logic::HOAPathFormula const&, boost::any const&) const {
583 STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Jani currently does not support HOA path formulae");
584}
585
587 STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "Jani currently does not support discounted cumulative reward formulae");
588}
589
590boost::any FormulaToJaniJson::visit(storm::logic::DiscountedTotalRewardFormula const&, boost::any const&) const {
591 STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "Jani currently does not support discounted total reward formulae");
592}
593
596 switch (optype) {
597 case OpType::And:
598 return "∧";
599 case OpType::Or:
600 return "∨";
601 case OpType::Xor:
602 return "≠";
603 case OpType::Implies:
604 return "⇒";
605 case OpType::Iff:
606 return "=";
607 case OpType::Plus:
608 return "+";
609 case OpType::Minus:
610 return "-";
611 case OpType::Times:
612 return "*";
613 case OpType::Divide:
614 return "/";
615 case OpType::Min:
616 return "min";
617 case OpType::Max:
618 return "max";
619 case OpType::Power:
620 return "pow";
621 case OpType::Modulo:
622 return "%";
623 case OpType::Logarithm:
624 return "log";
625 case OpType::Equal:
626 return "=";
627 case OpType::NotEqual:
628 return "≠";
629 case OpType::Less:
630 return "<";
631 case OpType::LessOrEqual:
632 return "≤";
633 case OpType::Greater:
634 return ">";
635 case OpType::GreaterOrEqual:
636 return "≥";
637 case OpType::Not:
638 return "¬";
639 case OpType::Floor:
640 return "floor";
641 case OpType::Ceil:
642 return "ceil";
643 case OpType::Ite:
644 return "ite";
645 case OpType::Sin:
646 return "sin";
647 case OpType::Cos:
648 return "cos";
649 default:
650 STORM_LOG_THROW(false, storm::exceptions::InvalidJaniException, "Operator not supported by Jani");
651 }
652}
653
654ExportJsonType ExpressionToJson::translate(storm::expressions::Expression const& expr, std::vector<storm::jani::Constant> const& constants,
655 VariableSet const& globalVariables, VariableSet const& localVariables,
656 std::unordered_set<std::string> const& auxiliaryVariables) {
657 // Simplify the expression first and reduce the nesting
658 auto simplifiedExpr = storm::jani::reduceNestingInJaniExpression(expr.simplify());
659
660 ExpressionToJson visitor(constants, globalVariables, localVariables, auxiliaryVariables);
661 return anyToJson(simplifiedExpr.accept(visitor, boost::none));
662}
663
664boost::any ExpressionToJson::visit(storm::expressions::IfThenElseExpression const& expression, boost::any const& data) {
665 ExportJsonType opDecl;
666 opDecl["op"] = "ite";
667 opDecl["if"] = anyToJson(expression.getCondition()->accept(*this, data));
668 opDecl["then"] = anyToJson(expression.getThenExpression()->accept(*this, data));
669 opDecl["else"] = anyToJson(expression.getElseExpression()->accept(*this, data));
670 return opDecl;
671}
672boost::any ExpressionToJson::visit(storm::expressions::BinaryBooleanFunctionExpression const& expression, boost::any const& data) {
673 ExportJsonType opDecl;
674 opDecl["op"] = operatorTypeToJaniString(expression.getOperator());
675 opDecl["left"] = anyToJson(expression.getOperand(0)->accept(*this, data));
676 opDecl["right"] = anyToJson(expression.getOperand(1)->accept(*this, data));
677 return opDecl;
678}
679boost::any ExpressionToJson::visit(storm::expressions::BinaryNumericalFunctionExpression const& expression, boost::any const& data) {
680 ExportJsonType opDecl;
681 opDecl["op"] = operatorTypeToJaniString(expression.getOperator());
682 opDecl["left"] = anyToJson(expression.getOperand(0)->accept(*this, data));
683 opDecl["right"] = anyToJson(expression.getOperand(1)->accept(*this, data));
684 if (expression.getOperator() == storm::expressions::OperatorType::Power && expression.getType().isIntegerType()) {
685 // power expressions that have integer type need to be "type casted"
686 ExportJsonType trc;
687 trc["op"] = "trc";
688 trc["exp"] = std::move(opDecl);
689 return trc;
690 } else {
691 return opDecl;
692 }
693}
694
695boost::any ExpressionToJson::visit(storm::expressions::BinaryRelationExpression const& expression, boost::any const& data) {
696 ExportJsonType opDecl;
697 opDecl["op"] = operatorTypeToJaniString(expression.getOperator());
698 opDecl["left"] = anyToJson(expression.getOperand(0)->accept(*this, data));
699 opDecl["right"] = anyToJson(expression.getOperand(1)->accept(*this, data));
700 return opDecl;
701}
702boost::any ExpressionToJson::visit(storm::expressions::VariableExpression const& expression, boost::any const&) {
703 if (auxiliaryVariables.count(expression.getVariableName())) {
704 return ExportJsonType(expression.getVariableName());
705 } else if (globalVariables.hasVariable(expression.getVariable())) {
706 return ExportJsonType(globalVariables.getVariable(expression.getVariable()).getName());
707 } else if (localVariables.hasVariable(expression.getVariable())) {
708 return ExportJsonType(localVariables.getVariable(expression.getVariable()).getName());
709 } else {
710 for (auto const& constant : constants) {
711 if (constant.getExpressionVariable() == expression.getVariable()) {
712 return ExportJsonType(constant.getName());
713 }
714 }
715 }
716 STORM_LOG_THROW(false, storm::exceptions::InvalidJaniException,
717 "Expression variable '" << expression.getVariableName() << "' not known in Jani data structures.");
718 return ExportJsonType(); // should not reach this point.
719}
720boost::any ExpressionToJson::visit(storm::expressions::UnaryBooleanFunctionExpression const& expression, boost::any const& data) {
721 ExportJsonType opDecl;
722 opDecl["op"] = operatorTypeToJaniString(expression.getOperator());
723 opDecl["exp"] = anyToJson(expression.getOperand()->accept(*this, data));
724 return opDecl;
725}
726boost::any ExpressionToJson::visit(storm::expressions::UnaryNumericalFunctionExpression const& expression, boost::any const& data) {
727 ExportJsonType opDecl;
728 opDecl["op"] = operatorTypeToJaniString(expression.getOperator());
730 opDecl["left"] = 0;
731 opDecl["right"] = anyToJson(expression.getOperand()->accept(*this, data));
732 } else {
733 opDecl["exp"] = anyToJson(expression.getOperand()->accept(*this, data));
734 }
735 return opDecl;
736}
737
738boost::any ExpressionToJson::visit(storm::expressions::BooleanLiteralExpression const& expression, boost::any const&) {
739 return ExportJsonType(expression.getValue());
740}
741boost::any ExpressionToJson::visit(storm::expressions::IntegerLiteralExpression const& expression, boost::any const&) {
742 return ExportJsonType(expression.getValue());
743}
744boost::any ExpressionToJson::visit(storm::expressions::RationalLiteralExpression const& expression, boost::any const&) {
745 ExportJsonType val(expression.getValue());
746
748 // Try if exact export is possible as fraction of two literals
749 auto [num, den] = storm::utility::asFraction(expression.getValue());
750 if (!storm::utility::isOne(den)) {
751 ExportJsonType numJson(num), denJson(den);
753 val = ExportJsonType();
755 val["left"] = std::move(numJson);
756 val["right"] = std::move(denJson);
757 }
758 }
759 }
760 return val;
761}
762
763boost::any ExpressionToJson::visit(storm::expressions::ValueArrayExpression const& expression, boost::any const& data) {
764 ExportJsonType opDecl;
765 opDecl["op"] = "av";
766 std::vector<ExportJsonType> elements;
767 uint64_t size = expression.size()->evaluateAsInt();
768 for (uint64_t i = 0; i < size; ++i) {
769 elements.push_back(anyToJson(expression.at(i)->accept(*this, data)));
770 }
771 opDecl["elements"] = std::move(elements);
772 return opDecl;
773}
774
775boost::any ExpressionToJson::visit(storm::expressions::ConstructorArrayExpression const& expression, boost::any const& data) {
776 ExportJsonType opDecl;
777 opDecl["op"] = "ac";
778 opDecl["var"] = expression.getIndexVar().getName();
779 opDecl["length"] = anyToJson(expression.size()->accept(*this, data));
780 bool inserted = auxiliaryVariables.insert(expression.getIndexVar().getName()).second;
781 opDecl["exp"] = anyToJson(expression.getElementExpression()->accept(*this, data));
782 if (inserted) {
783 auxiliaryVariables.erase(expression.getIndexVar().getName());
784 }
785 return opDecl;
786}
787
788boost::any ExpressionToJson::visit(storm::expressions::ArrayAccessExpression const& expression, boost::any const& data) {
789 ExportJsonType opDecl;
790 opDecl["op"] = "aa";
791 opDecl["exp"] = anyToJson(expression.getOperand(0)->accept(*this, data));
792 opDecl["index"] = anyToJson(expression.getOperand(1)->accept(*this, data));
793 return opDecl;
794}
795
796boost::any ExpressionToJson::visit(storm::expressions::FunctionCallExpression const& expression, boost::any const& data) {
797 ExportJsonType opDecl;
798 opDecl["op"] = "call";
799 opDecl["function"] = expression.getFunctionIdentifier();
800 std::vector<ExportJsonType> arguments;
801 for (uint64_t i = 0; i < expression.getNumberOfArguments(); ++i) {
802 arguments.push_back(anyToJson(expression.getArgument(i)->accept(*this, data)));
803 }
804 opDecl["args"] = std::move(arguments);
805 return opDecl;
806}
807
809 ExportJsonType constantDecl;
810 constantDecl["constant"] = expression.asString();
811 return constantDecl;
812}
813
814void JsonExporter::toFile(storm::jani::Model const& janiModel, std::vector<storm::jani::Property> const& formulas, std::string const& filepath, bool checkValid,
815 bool compact) {
816 std::ofstream stream;
817 storm::io::openFile(filepath, stream, false, true);
818 toStream(janiModel, formulas, stream, checkValid, compact);
819 storm::io::closeFile(stream);
820}
821
822void JsonExporter::toStream(storm::jani::Model const& janiModel, std::vector<storm::jani::Property> const& formulas, std::ostream& os, bool checkValid,
823 bool compact) {
824 if (checkValid) {
825 janiModel.checkValid();
826 }
827 JsonExporter exporter;
828 STORM_LOG_INFO("Started to convert model " << janiModel.getName() << ".");
829 exporter.convertModel(janiModel, !compact);
830 STORM_LOG_INFO("Started to convert properties of model " << janiModel.getName() << ".");
831 exporter.convertProperties(formulas, janiModel);
832 STORM_LOG_INFO("Producing json output... " << janiModel.getName() << ".");
833 os << storm::dumpJson(exporter.finalize(), compact) << '\n';
834 STORM_LOG_INFO("Conversion completed " << janiModel.getName() << ".");
835}
836
837ExportJsonType buildActionArray(std::vector<storm::jani::Action> const& actions) {
838 std::vector<ExportJsonType> actionReprs;
839 uint64_t actIndex = 0;
840 for (auto const& act : actions) {
842 actIndex++;
843 continue;
844 }
845 actIndex++;
846 ExportJsonType actEntry;
847 actEntry["name"] = act.getName();
848 actionReprs.push_back(actEntry);
849 }
850
851 return ExportJsonType(actionReprs);
852}
853
855 ExportJsonType typeDescr;
856 if (type.isIntegerType()) {
857 typeDescr = "int";
858 } else if (type.isRationalType()) {
859 typeDescr = "real";
860 } else if (type.isBooleanType()) {
861 typeDescr = "bool";
862 } else if (type.isArrayType()) {
863 typeDescr["kind"] = "array";
864 typeDescr["base"] = buildTypeDescription(type.getElementType());
865 } else {
866 STORM_LOG_THROW(false, storm::exceptions::IllegalArgumentException, "Unknown expression type.");
867 }
868 return typeDescr;
869}
870
872 std::vector<storm::jani::Constant> const& constants) {
875 getBoundsFromConstraints(typeDesc, var, constraint.getBaseExpression().getOperand(0), constants);
876 getBoundsFromConstraints(typeDesc, var, constraint.getBaseExpression().getOperand(1), constants);
877 } else if (constraint.getBaseExpression().isBinaryRelationExpression()) {
880 std::vector<bool> varOps(2, false);
881 for (int i : {0, 1}) {
882 varOps[i] = constraint.getOperand(i).isVariable() && constraint.getOperand(i).getBaseExpression().asVariableExpression().getVariable() == var;
883 }
884 storm::expressions::Expression boundExpr = varOps[0] ? constraint.getOperand(1) : constraint.getOperand(0);
885 if ((leq && varOps[0]) || (geq && varOps[1])) {
886 typeDesc["upper-bound"] = buildExpression(boundExpr, constants);
887 } else if ((leq && varOps[1]) || (geq && varOps[0])) {
888 typeDesc["lower-bound"] = buildExpression(boundExpr, constants);
889 } else {
890 STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Jani Export for constant constraint " << constraint << " is not supported.");
891 }
892 } else {
893 STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Jani Export for constant constraint " << constraint << " is not supported.");
894 }
895}
896
897ExportJsonType buildConstantsArray(std::vector<storm::jani::Constant> const& constants) {
898 std::vector<ExportJsonType> constantDeclarations;
899 for (auto const& constant : constants) {
900 ExportJsonType constantEntry;
901 constantEntry["name"] = constant.getName();
902 ExportJsonType typeDesc;
903 if (constant.hasConstraint()) {
904 typeDesc["kind"] = "bounded";
905 typeDesc["base"] = buildTypeDescription(constant.getType());
906 getBoundsFromConstraints(typeDesc, constant.getExpressionVariable(), constant.getConstraintExpression(), constants);
907 } else {
908 typeDesc = buildTypeDescription(constant.getType());
909 }
910 constantEntry["type"] = typeDesc;
911 if (constant.isDefined()) {
912 constantEntry["value"] = buildExpression(constant.getExpression(), constants);
913 }
914 constantDeclarations.push_back(constantEntry);
915 }
916 return ExportJsonType(constantDeclarations);
917}
918
919ExportJsonType buildType(storm::jani::JaniType const& type, std::vector<storm::jani::Constant> const& constants, VariableSet const& globalVariables,
920 VariableSet const& localVariables = VariableSet()) {
921 ExportJsonType typeDesc;
922 if (type.isBasicType() || type.isClockType() || type.isContinuousType()) {
923 typeDesc = type.getStringRepresentation();
924 } else if (type.isBoundedType()) {
925 typeDesc["kind"] = "bounded";
926 auto const& bndType = type.asBoundedType();
927 switch (bndType.getBaseType()) {
929 typeDesc["base"] = "int";
930 break;
932 typeDesc["base"] = "real";
933 break;
934 }
935 if (bndType.hasLowerBound()) {
936 typeDesc["lower-bound"] = buildExpression(bndType.getLowerBound(), constants, globalVariables, localVariables);
937 }
938 if (bndType.hasUpperBound()) {
939 typeDesc["upper-bound"] = buildExpression(bndType.getUpperBound(), constants, globalVariables, localVariables);
940 }
941 } else if (type.isArrayType()) {
942 typeDesc["kind"] = "array";
943 typeDesc["base"] = buildType(type.asArrayType().getBaseType(), constants, globalVariables, localVariables);
944 } else {
945 STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "Variable type not recognized in JSONExporter");
946 }
947 return typeDesc;
948}
949
950ExportJsonType buildVariablesArray(storm::jani::VariableSet const& varSet, std::vector<storm::jani::Constant> const& constants,
951 VariableSet const& globalVariables, VariableSet const& localVariables = VariableSet()) {
952 ExportJsonType variableDeclarations = std::vector<ExportJsonType>();
953 for (auto const& variable : varSet) {
954 ExportJsonType varEntry;
955 varEntry["name"] = variable.getName();
956 if (variable.isTransient()) {
957 varEntry["transient"] = variable.isTransient();
958 }
959 varEntry["type"] = buildType(variable.getType(), constants, globalVariables, localVariables);
960 if (variable.hasInitExpression()) {
961 varEntry["initial-value"] = buildExpression(variable.getInitExpression(), constants, globalVariables, localVariables);
962 }
963 variableDeclarations.push_back(std::move(varEntry));
964 }
965 return variableDeclarations;
966}
967
968ExportJsonType buildFunctionsArray(std::unordered_map<std::string, FunctionDefinition> const& functionDefinitions,
969 std::vector<storm::jani::Constant> const& constants, VariableSet const& globalVariables,
970 VariableSet const& localVariables = VariableSet()) {
971 ExportJsonType functionDeclarations = std::vector<ExportJsonType>();
972 for (auto const& nameFunDef : functionDefinitions) {
973 storm::jani::FunctionDefinition const& funDef = nameFunDef.second;
974 ExportJsonType funDefJson;
975 funDefJson["name"] = nameFunDef.first;
976 funDefJson["type"] = buildTypeDescription(funDef.getType());
977 std::vector<ExportJsonType> parameterDeclarations;
978 std::unordered_set<std::string> parameterNames;
979 for (auto const& p : funDef.getParameters()) {
980 ExportJsonType parDefJson;
981 parDefJson["name"] = p.getName();
982 parameterNames.insert(p.getName());
983 parDefJson["type"] = buildTypeDescription(p.getType());
984 parameterDeclarations.push_back(parDefJson);
985 }
986 funDefJson["parameters"] = parameterDeclarations;
987 funDefJson["body"] = buildExpression(funDef.getFunctionBody(), constants, globalVariables, localVariables, parameterNames);
988 functionDeclarations.push_back(std::move(funDefJson));
989 }
990 return functionDeclarations;
991}
992
993ExportJsonType buildLValue(storm::jani::LValue const& lValue, std::vector<storm::jani::Constant> const& constants, VariableSet const& globalVariables,
994 VariableSet const& localVariables) {
995 if (lValue.isVariable()) {
996 return lValue.getVariable().getName();
997 } else {
998 STORM_LOG_ASSERT(lValue.isArrayAccess(), "Unhandled LValue " << lValue << ".");
999 ExportJsonType result = lValue.getVariable().getName();
1000 for (auto const& indexExpr : lValue.getArrayIndexVector()) {
1001 ExportJsonType subLValue = std::move(result);
1002 result.clear();
1003 result["op"] = "aa";
1004 result["exp"] = std::move(subLValue);
1005 result["index"] = buildExpression(indexExpr, constants, globalVariables, localVariables);
1006 }
1007 return result;
1008 }
1009}
1010
1011ExportJsonType buildAssignmentArray(storm::jani::OrderedAssignments const& orderedAssignments, std::vector<storm::jani::Constant> const& constants,
1012 VariableSet const& globalVariables, VariableSet const& localVariables, bool commentExpressions) {
1013 ExportJsonType assignmentDeclarations = std::vector<ExportJsonType>();
1014 bool addIndex = orderedAssignments.hasMultipleLevels();
1015 for (auto const& assignment : orderedAssignments) {
1016 ExportJsonType assignmentEntry;
1017 assignmentEntry["ref"] = buildLValue(assignment.getLValue(), constants, globalVariables, localVariables);
1018 assignmentEntry["value"] = buildExpression(assignment.getAssignedExpression(), constants, globalVariables, localVariables);
1019 if (addIndex) {
1020 assignmentEntry["index"] = assignment.getLevel();
1021 }
1022 if (commentExpressions) {
1023 assignmentEntry["comment"] = assignment.getLValue().getName() + " <- " + assignment.getAssignedExpression().toString();
1024 }
1025 assignmentDeclarations.push_back(std::move(assignmentEntry));
1026 }
1027 return assignmentDeclarations;
1028}
1029
1030ExportJsonType buildLocationsArray(std::vector<storm::jani::Location> const& locations, std::vector<storm::jani::Constant> const& constants,
1031 VariableSet const& globalVariables, VariableSet const& localVariables, bool commentExpressions) {
1032 ExportJsonType locationDeclarations = std::vector<ExportJsonType>();
1033 for (auto const& location : locations) {
1034 ExportJsonType locEntry;
1035 locEntry["name"] = location.getName();
1036 if (location.hasTimeProgressInvariant()) {
1037 ExportJsonType timeProg;
1038 timeProg["exp"] = buildExpression(location.getTimeProgressInvariant(), constants, globalVariables, localVariables);
1039 if (commentExpressions) {
1040 timeProg["comment"] = location.getTimeProgressInvariant().toString();
1041 }
1042 locEntry["time-progress"] = std::move(timeProg);
1043 }
1044 if (!location.getAssignments().empty()) {
1045 locEntry["transient-values"] = buildAssignmentArray(location.getAssignments(), constants, globalVariables, localVariables, commentExpressions);
1046 }
1047 locationDeclarations.push_back(std::move(locEntry));
1048 }
1049 return locationDeclarations;
1050}
1051
1053 std::vector<std::string> names;
1054 for (auto const& initLocIndex : automaton.getInitialLocationIndices()) {
1055 names.push_back(automaton.getLocation(initLocIndex).getName());
1056 }
1057 return ExportJsonType(names);
1058}
1059
1060ExportJsonType buildDestinations(std::vector<EdgeDestination> const& destinations, std::map<uint64_t, std::string> const& locationNames,
1061 std::vector<storm::jani::Constant> const& constants, VariableSet const& globalVariables, VariableSet const& localVariables,
1062 bool commentExpressions) {
1063 assert(destinations.size() > 0);
1064 ExportJsonType destDeclarations = std::vector<ExportJsonType>();
1065 for (auto const& destination : destinations) {
1066 ExportJsonType destEntry;
1067 destEntry["location"] = locationNames.at(destination.getLocationIndex());
1068 bool prob1 = false;
1069 if (destination.getProbability().isLiteral()) {
1070 if (storm::utility::isOne(destination.getProbability().evaluateAsRational())) {
1071 prob1 = true;
1072 }
1073 }
1074 if (!prob1) {
1075 destEntry["probability"]["exp"] = buildExpression(destination.getProbability(), constants, globalVariables, localVariables);
1076 if (commentExpressions) {
1077 destEntry["probability"]["comment"] = destination.getProbability().toString();
1078 }
1079 }
1080 if (!destination.getOrderedAssignments().empty()) {
1081 destEntry["assignments"] =
1082 buildAssignmentArray(destination.getOrderedAssignments(), constants, globalVariables, localVariables, commentExpressions);
1083 }
1084 destDeclarations.push_back(std::move(destEntry));
1085 }
1086 return destDeclarations;
1087}
1088
1089ExportJsonType buildEdge(Edge const& edge, std::map<uint64_t, std::string> const& actionNames, std::map<uint64_t, std::string> const& locationNames,
1090 std::vector<storm::jani::Constant> const& constants, VariableSet const& globalVariables, VariableSet const& localVariables,
1091 bool commentExpressions) {
1092 STORM_LOG_THROW(edge.getDestinations().size() > 0, storm::exceptions::InvalidJaniException, "An edge without destinations is not allowed.");
1093 ExportJsonType edgeEntry;
1094 edgeEntry["location"] = locationNames.at(edge.getSourceLocationIndex());
1095 if (!edge.hasSilentAction()) {
1096 edgeEntry["action"] = actionNames.at(edge.getActionIndex());
1097 }
1098 if (edge.hasRate()) {
1099 edgeEntry["rate"]["exp"] = buildExpression(edge.getRate(), constants, globalVariables, localVariables);
1100 if (commentExpressions) {
1101 edgeEntry["rate"]["comment"] = edge.getRate().toString();
1102 }
1103 }
1104 if (!edge.getGuard().isTrue()) {
1105 edgeEntry["guard"]["exp"] = buildExpression(edge.getGuard(), constants, globalVariables, localVariables);
1106 if (commentExpressions) {
1107 edgeEntry["guard"]["comment"] = edge.getGuard().toString();
1108 }
1109 }
1110 edgeEntry["destinations"] = buildDestinations(edge.getDestinations(), locationNames, constants, globalVariables, localVariables, commentExpressions);
1111 if (!edge.getAssignments().empty()) {
1112 edgeEntry["assignments"] = buildAssignmentArray(edge.getAssignments(), constants, globalVariables, localVariables, commentExpressions);
1113 }
1114 return edgeEntry;
1115}
1116
1117ExportJsonType buildEdges(std::vector<Edge> const& edges, std::map<uint64_t, std::string> const& actionNames,
1118 std::map<uint64_t, std::string> const& locationNames, std::vector<storm::jani::Constant> const& constants,
1119 VariableSet const& globalVariables, VariableSet const& localVariables, bool commentExpressions) {
1120 ExportJsonType edgeDeclarations = std::vector<ExportJsonType>();
1121 for (auto const& edge : edges) {
1122 if (edge.getGuard().isFalse()) {
1123 continue;
1124 }
1125 edgeDeclarations.push_back(buildEdge(edge, actionNames, locationNames, constants, globalVariables, localVariables, commentExpressions));
1126 }
1127 return edgeDeclarations;
1128}
1129
1130ExportJsonType buildAutomataArray(std::vector<storm::jani::Automaton> const& automata, std::map<uint64_t, std::string> const& actionNames,
1131 std::vector<storm::jani::Constant> const& constants, VariableSet const& globalVariables, bool commentExpressions) {
1132 ExportJsonType automataDeclarations = std::vector<ExportJsonType>();
1133 for (auto const& automaton : automata) {
1134 ExportJsonType autoEntry;
1135 autoEntry["name"] = automaton.getName();
1136 autoEntry["variables"] = buildVariablesArray(automaton.getVariables(), constants, globalVariables, automaton.getVariables());
1137 if (!automaton.getFunctionDefinitions().empty()) {
1138 autoEntry["functions"] = buildFunctionsArray(automaton.getFunctionDefinitions(), constants, globalVariables, automaton.getVariables());
1139 }
1140 if (automaton.hasRestrictedInitialStates()) {
1141 autoEntry["restrict-initial"]["exp"] =
1142 buildExpression(automaton.getInitialStatesRestriction(), constants, globalVariables, automaton.getVariables());
1143 }
1144 autoEntry["locations"] = buildLocationsArray(automaton.getLocations(), constants, globalVariables, automaton.getVariables(), commentExpressions);
1145 autoEntry["initial-locations"] = buildInitialLocations(automaton);
1146 autoEntry["edges"] = buildEdges(automaton.getEdges(), actionNames, automaton.buildIdToLocationNameMap(), constants, globalVariables,
1147 automaton.getVariables(), commentExpressions);
1148 automataDeclarations.push_back(std::move(autoEntry));
1149 }
1150 return automataDeclarations;
1151}
1152
1153void JsonExporter::convertModel(storm::jani::Model const& janiModel, bool commentExpressions) {
1154 modelFeatures = janiModel.getModelFeatures();
1155 jsonStruct["jani-version"] = janiModel.getJaniVersion();
1156 jsonStruct["name"] = janiModel.getName();
1157 jsonStruct["type"] = to_string(janiModel.getModelType());
1158 jsonStruct["actions"] = buildActionArray(janiModel.getActions());
1159 jsonStruct["constants"] = buildConstantsArray(janiModel.getConstants());
1160 jsonStruct["variables"] = buildVariablesArray(janiModel.getGlobalVariables(), janiModel.getConstants(), janiModel.getGlobalVariables());
1161 if (!janiModel.getGlobalFunctionDefinitions().empty()) {
1162 jsonStruct["functions"] = buildFunctionsArray(janiModel.getGlobalFunctionDefinitions(), janiModel.getConstants(), janiModel.getGlobalVariables());
1163 }
1164 jsonStruct["restrict-initial"]["exp"] = buildExpression(janiModel.getInitialStatesRestriction(), janiModel.getConstants(), janiModel.getGlobalVariables());
1165 jsonStruct["automata"] = buildAutomataArray(janiModel.getAutomata(), janiModel.getActionIndexToNameMap(), janiModel.getConstants(),
1166 janiModel.getGlobalVariables(), commentExpressions);
1167 jsonStruct["system"] = CompositionJsonExporter::translate(janiModel.getSystemComposition());
1168}
1169
1170ExportJsonType JsonExporter::getEdgeAsJson(storm::jani::Model const& janiModel, uint64_t automatonIndex, uint64_t edgeIndex, bool commentExpressions) {
1171 auto const& automaton = janiModel.getAutomaton(automatonIndex);
1172 return buildEdge(automaton.getEdge(edgeIndex), janiModel.getActionIndexToNameMap(), automaton.buildIdToLocationNameMap(), janiModel.getConstants(),
1173 janiModel.getGlobalVariables(), automaton.getVariables(), commentExpressions);
1174}
1175
1177 switch (ft) {
1179 return "min";
1181 return "max";
1183 return "sum";
1185 return "avg";
1187 return "count";
1189 return "∃";
1191 return "∀";
1193 return "argmin";
1195 return "argmax";
1197 return "values";
1198 }
1199 STORM_LOG_THROW(false, storm::exceptions::IllegalArgumentException, "Unknown FilterType");
1200}
1201
1203 ExportJsonType propDecl;
1204 propDecl["states"]["op"] = "initial";
1205 propDecl["op"] = "filter";
1206 propDecl["fun"] = janiFilterTypeString(fe.getFilterType());
1207 propDecl["values"] = FormulaToJaniJson::translate(*fe.getFormula(), model, modelFeatures);
1208 return propDecl;
1209}
1210
1211void JsonExporter::convertProperties(std::vector<storm::jani::Property> const& formulas, storm::jani::Model const& model) {
1212 ExportJsonType properties;
1213
1214 // Unset model-features that only relate to properties. These are only set if such properties actually exist.
1216 if (formulas.empty()) {
1217 jsonStruct["properties"] = ExportJsonType(ExportJsonType::value_t::array);
1218 return;
1219 }
1220
1221 for (auto const& f : formulas) {
1222 ExportJsonType propDecl;
1223 propDecl["name"] = f.getName();
1224 propDecl["expression"] = convertFilterExpression(f.getFilter(), model, modelFeatures);
1225 properties.push_back(std::move(propDecl));
1226 }
1227 jsonStruct["properties"] = std::move(properties);
1228}
1229
1230ExportJsonType JsonExporter::finalize() {
1231 jsonStruct["features"] = ExportJsonType::parse(modelFeatures.toString());
1232 return jsonStruct;
1233}
1234
1235} // namespace jani
1236} // namespace storm
virtual bool isBinaryRelationExpression() const
virtual bool isBinaryBooleanFunctionExpression() const
virtual std::shared_ptr< BaseExpression const > getOperand(uint_fast64_t operandIndex) const
Retrieves the given operand from the expression.
VariableExpression const & asVariableExpression() const
Type const & getType() const
Retrieves the type of the expression.
virtual OperatorType getOperator() const
Retrieves the operator of a function application.
virtual storm::expressions::OperatorType getOperator() const override
Retrieves the operator of a function application.
virtual std::shared_ptr< BaseExpression const > getOperand(uint_fast64_t operandIndex) const override
Retrieves the given operand from the expression.
virtual storm::expressions::OperatorType getOperator() const override
Retrieves the operator of a function application.
virtual storm::expressions::OperatorType getOperator() const override
Retrieves the operator of a function application.
bool getValue() const
Retrieves the value of the boolean literal.
Represents an array of the given size, where the i'th entry is determined by the elementExpression,...
virtual std::shared_ptr< BaseExpression const > size() const override
std::shared_ptr< BaseExpression const > const & getElementExpression() const
storm::expressions::Variable const & getIndexVar() const
Expression simplify() const
Simplifies the expression according to some basic rules.
bool isVariable() const
Retrieves whether the expression is a variable.
Expression getOperand(uint_fast64_t operandIndex) const
Retrieves the given operand from the expression.
BaseExpression const & getBaseExpression() const
Retrieves the base expression underlying this expression object.
std::string toString() const
Converts the expression into a string.
bool isTrue() const
Checks if the expression is equal to the boolean literal true.
Represents an array with a given list of elements.
std::shared_ptr< BaseExpression const > getArgument(uint64_t i) const
std::shared_ptr< BaseExpression const > getElseExpression() const
Retrieves the else expression of the if-then-else expression.
std::shared_ptr< BaseExpression const > getCondition() const
Retrieves the condition expression of the if-then-else expression.
std::shared_ptr< BaseExpression const > getThenExpression() const
Retrieves the then expression of the if-then-else expression.
int_fast64_t getValue() const
Retrieves the value of the integer literal.
storm::RationalNumber getValue() const
Retrieves the value of the double literal.
std::string asString() const
Get the Transcendental number as string, like in the Jani file (single character)
Type getElementType() const
Retrieves the element type of the type, provided that it is an Array type.
Definition Type.cpp:210
bool isBooleanType() const
Checks whether this type is a boolean type.
Definition Type.cpp:178
bool isIntegerType() const
Checks whether this type is an integral type.
Definition Type.cpp:182
bool isArrayType() const
Checks whether this type is an array type.
Definition Type.cpp:194
bool isRationalType() const
Checks whether this type is a rational type.
Definition Type.cpp:214
virtual storm::expressions::OperatorType getOperator() const override
Retrieves the operator of a function application.
virtual std::shared_ptr< BaseExpression const > getOperand(uint_fast64_t operandIndex) const override
Retrieves the given operand from the expression.
virtual storm::expressions::OperatorType getOperator() const override
Retrieves the operator of a function application.
Represents an array with a given list of elements.
virtual std::shared_ptr< BaseExpression const > size() const override
virtual std::shared_ptr< BaseExpression const > at(uint64_t i) const override
Variable const & getVariable() const
Retrieves the variable associated with this expression.
std::string const & getVariableName() const
Retrieves the name of the variable associated with this expression.
std::string const & getName() const
Retrieves the name of the variable.
Definition Variable.cpp:46
JaniType & getBaseType()
Definition ArrayType.cpp:18
std::string const & getAutomatonName() const
Retrieves the name of the automaton this composition element refers to.
Location const & getLocation(uint64_t index) const
Retrieves the location with the given index.
std::set< uint64_t > const & getInitialLocationIndices() const
Retrieves the indices of the initial locations.
virtual boost::any accept(CompositionVisitor &visitor, boost::any const &data) const =0
virtual boost::any visit(ParallelComposition const &composition, boost::any const &data)
virtual boost::any visit(AutomatonComposition const &composition, boost::any const &)
static ExportJsonType translate(storm::jani::Composition const &comp, bool allowRecursion=true)
CompositionJsonExporter(bool allowRecursion)
bool hasSilentAction() const
Returns whether it contains the silent action.
Definition Edge.cpp:102
uint64_t getActionIndex() const
Retrieves the id of the action with which this edge is labeled.
Definition Edge.cpp:45
std::vector< EdgeDestination > const & getDestinations() const
Retrieves the destinations of this edge.
Definition Edge.cpp:77
bool hasRate() const
Retrieves whether this edge has an associated rate.
Definition Edge.cpp:49
uint64_t getSourceLocationIndex() const
Retrieves the index of the source location.
Definition Edge.cpp:41
OrderedAssignments const & getAssignments() const
Retrieves the assignments of this edge.
Definition Edge.cpp:89
storm::expressions::Expression const & getRate() const
Retrieves the rate of this edge.
Definition Edge.cpp:53
storm::expressions::Expression const & getGuard() const
Retrieves the guard of this edge.
Definition Edge.cpp:65
virtual boost::any visit(storm::expressions::IfThenElseExpression const &expression, boost::any const &data)
static ExportJsonType translate(storm::expressions::Expression const &expr, std::vector< storm::jani::Constant > const &constants, VariableSet const &globalVariables, VariableSet const &localVariables, std::unordered_set< std::string > const &auxiliaryVariables)
std::shared_ptr< storm::logic::Formula const > const & getFormula() const
Definition Property.h:48
storm::modelchecker::FilterType getFilterType() const
Definition Property.h:56
static ExportJsonType translate(storm::logic::Formula const &formula, storm::jani::Model const &model, storm::jani::ModelFeatures &modelFeatures)
virtual boost::any visit(storm::logic::AtomicExpressionFormula const &f, boost::any const &data) const
storm::expressions::Expression const & getFunctionBody() const
Retrieves the expression that defines the function.
std::vector< storm::expressions::Variable > const & getParameters() const
Retrieves the parameters of the function.
storm::expressions::Type const & getType() const
Retrieves the type of the function.
ArrayType const & asArrayType() const
Definition JaniType.cpp:47
virtual bool isContinuousType() const
Definition JaniType.cpp:27
virtual std::string getStringRepresentation() const =0
Retrieves a string representation of the type.
virtual bool isArrayType() const
Definition JaniType.cpp:19
virtual bool isBoundedType() const
Definition JaniType.cpp:15
virtual bool isBasicType() const
Definition JaniType.cpp:11
BoundedType const & asBoundedType() const
Definition JaniType.cpp:39
virtual bool isClockType() const
Definition JaniType.cpp:23
static ExportJsonType getEdgeAsJson(storm::jani::Model const &janiModel, uint64_t automatonIndex, uint64_t edgeIndex, bool commentExpressions=true)
static void toFile(storm::jani::Model const &janiModel, std::vector< storm::jani::Property > const &formulas, std::string const &filepath, bool checkValid=true, bool compact=false)
static void toStream(storm::jani::Model const &janiModel, std::vector< storm::jani::Property > const &formulas, std::ostream &ostream, bool checkValid=false, bool compact=false)
bool isVariable() const
Definition LValue.cpp:20
std::vector< storm::expressions::Expression > & getArrayIndexVector()
Returns the referred variable. In case of an array access, this is the referred array variable.
Definition LValue.cpp:40
bool isArrayAccess() const
Returns true if the lValue refers either to an array variable or to an array access.
Definition LValue.cpp:32
storm::jani::Variable const & getVariable() const
To check if the array is fully accessed, so result will be of the most inner child Type....
Definition LValue.cpp:28
std::string const & getName() const
Retrieves the name of the location.
Definition Location.cpp:19
std::string toString() const
ModelFeatures & add(ModelFeature const &modelFeature)
void remove(ModelFeature const &modelFeature)
VariableSet & getGlobalVariables()
Retrieves the variables of this automaton.
Definition Model.cpp:721
storm::expressions::Expression getRewardModelExpression(std::string const &identifier) const
Retrieves the defining reward expression of the reward model with the given identifier.
Definition Model.cpp:813
Composition const & getSystemComposition() const
Retrieves the system composition expression.
Definition Model.cpp:949
storm::expressions::Expression const & getInitialStatesRestriction() const
Gets the expression restricting the legal initial values of the global variables.
Definition Model.cpp:1288
static const uint64_t SILENT_ACTION_INDEX
The index of the silent action.
Definition Model.h:642
std::vector< Automaton > & getAutomata()
Retrieves the automata of the model.
Definition Model.cpp:872
ModelType const & getModelType() const
Retrieves the type of the model.
Definition Model.cpp:121
std::vector< Constant > const & getConstants() const
Retrieves the constants of the model.
Definition Model.cpp:689
std::vector< Action > const & getActions() const
Retrieves the actions of the model.
Definition Model.cpp:646
uint64_t getJaniVersion() const
Retrieves the JANI-version of the model.
Definition Model.cpp:117
void checkValid() const
Checks if the model is valid JANI, which should be verified before any further operations are applied...
Definition Model.cpp:1405
std::string const & getName() const
Retrieves the name of the model.
Definition Model.cpp:137
bool isDiscreteTimeModel() const
Determines whether this model is a discrete-time model.
Definition Model.cpp:1373
ModelFeatures const & getModelFeatures() const
Retrieves the enabled model features.
Definition Model.cpp:129
Automaton & getAutomaton(std::string const &name)
Retrieves the automaton with the given name.
Definition Model.cpp:888
std::map< uint64_t, std::string > getActionIndexToNameMap() const
Builds a map with action indices mapped to their names.
Definition Model.cpp:1036
std::unordered_map< std::string, FunctionDefinition > const & getGlobalFunctionDefinitions() const
Retrieves all global function definitions.
Definition Model.cpp:781
bool hasMultipleLevels(bool onlyTransient=false) const
Checks whether the assignments have several levels.
bool empty(bool onlyTransient=false) const
Retrieves whether this set of assignments is empty.
std::vector< SynchronizationVector > const & getSynchronizationVectors() const
Retrieves the synchronization vectors of the parallel composition.
std::vector< std::shared_ptr< Composition > > const & getSubcompositions() const
Retrieves the subcompositions of the parallel composition.
static const std::string NO_ACTION_INPUT
std::string const & getName() const
Retrieves the name of the variable.
Definition Variable.cpp:34
bool hasVariable(std::string const &name) const
Retrieves whether this variable set contains a variable with the given name.
detail::Variables< Variable > getRealVariables()
Retrieves the real variables in this set.
Variable const & getVariable(std::string const &name) const
Retrieves the variable with the given name.
uint64_t getNumberOfRealTransientVariables() const
Retrieves the number of real transient variables in this variable set.
storm::expressions::Expression const & getExpression() const
std::string const & getLabel() const
Formula const & getRightSubformula() const
Formula const & getLeftSubformula() const
Formula const & getRightSubformula() const
Formula const & getLeftSubformula() const
virtual bool isTrueFormula() const override
TimeBoundReference const & getTimeBoundReference(unsigned i=0) const
bool isLowerBoundStrict(unsigned i=0) const
storm::expressions::Expression const & getUpperBound(unsigned i=0) const
storm::expressions::Expression const & getLowerBound(unsigned i=0) const
bool isUpperBoundStrict(unsigned i=0) const
TimeBoundReference const & getTimeBoundReference() const
RewardAccumulation const & getRewardAccumulation() const
storm::expressions::Expression const & getBound() const
RewardAccumulation const & getRewardAccumulation() const
virtual bool isInstantaneousRewardFormula() const
Definition Formula.cpp:152
static std::shared_ptr< Formula const > getTrueFormula()
Definition Formula.cpp:213
LongRunAverageRewardFormula & asLongRunAverageRewardFormula()
Definition Formula.cpp:468
virtual bool isCumulativeRewardFormula() const
Definition Formula.cpp:144
virtual bool isLongRunAverageRewardFormula() const
Definition Formula.cpp:160
EventuallyFormula & asEventuallyFormula()
Definition Formula.cpp:341
InstantaneousRewardFormula & asInstantaneousRewardFormula()
Definition Formula.cpp:460
virtual bool isEventuallyFormula() const
Definition Formula.cpp:88
CumulativeRewardFormula & asCumulativeRewardFormula()
Definition Formula.cpp:429
boost::any accept(FormulaVisitor const &visitor) const
Definition Formula.cpp:16
storm::expressions::Expression const & getBound() const
RewardAccumulation const & getRewardAccumulation() const
Bound const & getBound() const
storm::solver::OptimizationDirection const & getOptimalityType() const
std::string const & getRewardModelName() const
Retrieves the name of the reward model this property refers to (if any).
bool hasRewardModelName() const
Retrieves whether the reward model refers to a specific reward model.
Formula const & getSubformula() const
Formula const & getSubformula() const
#define STORM_LOG_INFO(message)
Definition logging.h:24
#define STORM_LOG_WARN(message)
Definition logging.h:25
#define STORM_LOG_TRACE(message)
Definition logging.h:12
#define STORM_LOG_ASSERT(cond, message)
Definition macros.h:11
#define STORM_LOG_WARN_COND(cond, message)
Definition macros.h:38
#define STORM_LOG_THROW(cond, exception, message)
Definition macros.h:30
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
ExportJsonType buildAutomataArray(std::vector< storm::jani::Automaton > const &automata, std::map< uint64_t, std::string > const &actionNames, std::vector< storm::jani::Constant > const &constants, VariableSet const &globalVariables, bool commentExpressions)
ExportJsonType buildEdge(Edge const &edge, std::map< uint64_t, std::string > const &actionNames, std::map< uint64_t, std::string > const &locationNames, std::vector< storm::jani::Constant > const &constants, VariableSet const &globalVariables, VariableSet const &localVariables, bool commentExpressions)
ExportJsonType buildTypeDescription(storm::expressions::Type const &type)
ExportJsonType buildFunctionsArray(std::unordered_map< std::string, FunctionDefinition > const &functionDefinitions, std::vector< storm::jani::Constant > const &constants, VariableSet const &globalVariables, VariableSet const &localVariables=VariableSet())
ExportJsonType convertFilterExpression(storm::jani::FilterExpression const &fe, storm::jani::Model const &model, storm::jani::ModelFeatures &modelFeatures)
storm::json< storm::RationalNumber > ExportJsonType
ExportJsonType buildDestinations(std::vector< EdgeDestination > const &destinations, std::map< uint64_t, std::string > const &locationNames, std::vector< storm::jani::Constant > const &constants, VariableSet const &globalVariables, VariableSet const &localVariables, bool commentExpressions)
std::string comparisonTypeToJani(storm::logic::ComparisonType ct)
ExportJsonType buildLValue(storm::jani::LValue const &lValue, std::vector< storm::jani::Constant > const &constants, VariableSet const &globalVariables, VariableSet const &localVariables)
ExportJsonType buildAssignmentArray(storm::jani::OrderedAssignments const &orderedAssignments, std::vector< storm::jani::Constant > const &constants, VariableSet const &globalVariables, VariableSet const &localVariables, bool commentExpressions)
ExportJsonType buildInitialLocations(storm::jani::Automaton const &automaton)
ExportJsonType buildActionArray(std::vector< storm::jani::Action > const &actions)
ExportJsonType buildExpression(storm::expressions::Expression const &exp, std::vector< storm::jani::Constant > const &constants, VariableSet const &globalVariables=VariableSet(), VariableSet const &localVariables=VariableSet(), std::unordered_set< std::string > const &auxiliaryVariables={})
ExportJsonType buildType(storm::jani::JaniType const &type, std::vector< storm::jani::Constant > const &constants, VariableSet const &globalVariables, VariableSet const &localVariables=VariableSet())
ExportJsonType buildConstantsArray(std::vector< storm::jani::Constant > const &constants)
std::string to_string(ModelType const &type)
Definition ModelType.cpp:10
std::string janiFilterTypeString(storm::modelchecker::FilterType const &ft)
storm::expressions::Expression reduceNestingInJaniExpression(storm::expressions::Expression const &expression)
ExportJsonType anyToJson(boost::any &&input)
ExportJsonType buildEdges(std::vector< Edge > const &edges, std::map< uint64_t, std::string > const &actionNames, std::map< uint64_t, std::string > const &locationNames, std::vector< storm::jani::Constant > const &constants, VariableSet const &globalVariables, VariableSet const &localVariables, bool commentExpressions)
ExportJsonType buildVariablesArray(storm::jani::VariableSet const &varSet, std::vector< storm::jani::Constant > const &constants, VariableSet const &globalVariables, VariableSet const &localVariables=VariableSet())
ExportJsonType buildLocationsArray(std::vector< storm::jani::Location > const &locations, std::vector< storm::jani::Constant > const &constants, VariableSet const &globalVariables, VariableSet const &localVariables, bool commentExpressions)
std::string operatorTypeToJaniString(storm::expressions::OperatorType optype)
void getBoundsFromConstraints(ExportJsonType &typeDesc, storm::expressions::Variable const &var, storm::expressions::Expression const &constraint, std::vector< storm::jani::Constant > const &constants)
bool isLowerBound(ComparisonType t)
bool constexpr minimize(OptimizationDirection d)
bool isOne(ValueType const &a)
Definition constants.cpp:36
std::pair< ValueType, ValueType > asFraction(ValueType const &number)
LabParser.cpp.
bool isJsonNumberExportAccurate(storm::json< ValueType > const &j)
std::string dumpJson(storm::json< ValueType > const &j, bool compact)
Dumps the given json object, producing a String.
ComparisonType comparisonType
Definition Bound.h:18