Storm
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
588 switch (optype) {
589 case OpType::And:
590 return "∧";
591 case OpType::Or:
592 return "∨";
593 case OpType::Xor:
594 return "≠";
595 case OpType::Implies:
596 return "⇒";
597 case OpType::Iff:
598 return "=";
599 case OpType::Plus:
600 return "+";
601 case OpType::Minus:
602 return "-";
603 case OpType::Times:
604 return "*";
605 case OpType::Divide:
606 return "/";
607 case OpType::Min:
608 return "min";
609 case OpType::Max:
610 return "max";
611 case OpType::Power:
612 return "pow";
613 case OpType::Modulo:
614 return "%";
615 case OpType::Logarithm:
616 return "log";
617 case OpType::Equal:
618 return "=";
619 case OpType::NotEqual:
620 return "≠";
621 case OpType::Less:
622 return "<";
623 case OpType::LessOrEqual:
624 return "≤";
625 case OpType::Greater:
626 return ">";
627 case OpType::GreaterOrEqual:
628 return "≥";
629 case OpType::Not:
630 return "¬";
631 case OpType::Floor:
632 return "floor";
633 case OpType::Ceil:
634 return "ceil";
635 case OpType::Ite:
636 return "ite";
637 case OpType::Sin:
638 return "sin";
639 case OpType::Cos:
640 return "cos";
641 default:
642 STORM_LOG_THROW(false, storm::exceptions::InvalidJaniException, "Operator not supported by Jani");
643 }
644}
645
646ExportJsonType ExpressionToJson::translate(storm::expressions::Expression const& expr, std::vector<storm::jani::Constant> const& constants,
647 VariableSet const& globalVariables, VariableSet const& localVariables,
648 std::unordered_set<std::string> const& auxiliaryVariables) {
649 // Simplify the expression first and reduce the nesting
650 auto simplifiedExpr = storm::jani::reduceNestingInJaniExpression(expr.simplify());
651
652 ExpressionToJson visitor(constants, globalVariables, localVariables, auxiliaryVariables);
653 return anyToJson(simplifiedExpr.accept(visitor, boost::none));
654}
655
656boost::any ExpressionToJson::visit(storm::expressions::IfThenElseExpression const& expression, boost::any const& data) {
657 ExportJsonType opDecl;
658 opDecl["op"] = "ite";
659 opDecl["if"] = anyToJson(expression.getCondition()->accept(*this, data));
660 opDecl["then"] = anyToJson(expression.getThenExpression()->accept(*this, data));
661 opDecl["else"] = anyToJson(expression.getElseExpression()->accept(*this, data));
662 return opDecl;
663}
664boost::any ExpressionToJson::visit(storm::expressions::BinaryBooleanFunctionExpression const& expression, boost::any const& data) {
665 ExportJsonType opDecl;
666 opDecl["op"] = operatorTypeToJaniString(expression.getOperator());
667 opDecl["left"] = anyToJson(expression.getOperand(0)->accept(*this, data));
668 opDecl["right"] = anyToJson(expression.getOperand(1)->accept(*this, data));
669 return opDecl;
670}
671boost::any ExpressionToJson::visit(storm::expressions::BinaryNumericalFunctionExpression const& expression, boost::any const& data) {
672 ExportJsonType opDecl;
673 opDecl["op"] = operatorTypeToJaniString(expression.getOperator());
674 opDecl["left"] = anyToJson(expression.getOperand(0)->accept(*this, data));
675 opDecl["right"] = anyToJson(expression.getOperand(1)->accept(*this, data));
676 if (expression.getOperator() == storm::expressions::OperatorType::Power && expression.getType().isIntegerType()) {
677 // power expressions that have integer type need to be "type casted"
678 ExportJsonType trc;
679 trc["op"] = "trc";
680 trc["exp"] = std::move(opDecl);
681 return trc;
682 } else {
683 return opDecl;
684 }
685}
686
687boost::any ExpressionToJson::visit(storm::expressions::BinaryRelationExpression const& expression, boost::any const& data) {
688 ExportJsonType opDecl;
689 opDecl["op"] = operatorTypeToJaniString(expression.getOperator());
690 opDecl["left"] = anyToJson(expression.getOperand(0)->accept(*this, data));
691 opDecl["right"] = anyToJson(expression.getOperand(1)->accept(*this, data));
692 return opDecl;
693}
694boost::any ExpressionToJson::visit(storm::expressions::VariableExpression const& expression, boost::any const&) {
695 if (auxiliaryVariables.count(expression.getVariableName())) {
696 return ExportJsonType(expression.getVariableName());
697 } else if (globalVariables.hasVariable(expression.getVariable())) {
698 return ExportJsonType(globalVariables.getVariable(expression.getVariable()).getName());
699 } else if (localVariables.hasVariable(expression.getVariable())) {
700 return ExportJsonType(localVariables.getVariable(expression.getVariable()).getName());
701 } else {
702 for (auto const& constant : constants) {
703 if (constant.getExpressionVariable() == expression.getVariable()) {
704 return ExportJsonType(constant.getName());
705 }
706 }
707 }
708 STORM_LOG_THROW(false, storm::exceptions::InvalidJaniException,
709 "Expression variable '" << expression.getVariableName() << "' not known in Jani data structures.");
710 return ExportJsonType(); // should not reach this point.
711}
712boost::any ExpressionToJson::visit(storm::expressions::UnaryBooleanFunctionExpression const& expression, boost::any const& data) {
713 ExportJsonType opDecl;
714 opDecl["op"] = operatorTypeToJaniString(expression.getOperator());
715 opDecl["exp"] = anyToJson(expression.getOperand()->accept(*this, data));
716 return opDecl;
717}
718boost::any ExpressionToJson::visit(storm::expressions::UnaryNumericalFunctionExpression const& expression, boost::any const& data) {
719 ExportJsonType opDecl;
720 opDecl["op"] = operatorTypeToJaniString(expression.getOperator());
722 opDecl["left"] = 0;
723 opDecl["right"] = anyToJson(expression.getOperand()->accept(*this, data));
724 } else {
725 opDecl["exp"] = anyToJson(expression.getOperand()->accept(*this, data));
726 }
727 return opDecl;
728}
729
730boost::any ExpressionToJson::visit(storm::expressions::BooleanLiteralExpression const& expression, boost::any const&) {
731 return ExportJsonType(expression.getValue());
732}
733boost::any ExpressionToJson::visit(storm::expressions::IntegerLiteralExpression const& expression, boost::any const&) {
734 return ExportJsonType(expression.getValue());
735}
736boost::any ExpressionToJson::visit(storm::expressions::RationalLiteralExpression const& expression, boost::any const&) {
737 ExportJsonType val(expression.getValue());
738
740 // Try if exact export is possible as fraction of two literals
741 auto [num, den] = storm::utility::asFraction(expression.getValue());
742 if (!storm::utility::isOne(den)) {
743 ExportJsonType numJson(num), denJson(den);
745 val = ExportJsonType();
747 val["left"] = std::move(numJson);
748 val["right"] = std::move(denJson);
749 }
750 }
751 }
752 return val;
753}
754
755boost::any ExpressionToJson::visit(storm::expressions::ValueArrayExpression const& expression, boost::any const& data) {
756 ExportJsonType opDecl;
757 opDecl["op"] = "av";
758 std::vector<ExportJsonType> elements;
759 uint64_t size = expression.size()->evaluateAsInt();
760 for (uint64_t i = 0; i < size; ++i) {
761 elements.push_back(anyToJson(expression.at(i)->accept(*this, data)));
762 }
763 opDecl["elements"] = std::move(elements);
764 return opDecl;
765}
766
767boost::any ExpressionToJson::visit(storm::expressions::ConstructorArrayExpression const& expression, boost::any const& data) {
768 ExportJsonType opDecl;
769 opDecl["op"] = "ac";
770 opDecl["var"] = expression.getIndexVar().getName();
771 opDecl["length"] = anyToJson(expression.size()->accept(*this, data));
772 bool inserted = auxiliaryVariables.insert(expression.getIndexVar().getName()).second;
773 opDecl["exp"] = anyToJson(expression.getElementExpression()->accept(*this, data));
774 if (inserted) {
775 auxiliaryVariables.erase(expression.getIndexVar().getName());
776 }
777 return opDecl;
778}
779
780boost::any ExpressionToJson::visit(storm::expressions::ArrayAccessExpression const& expression, boost::any const& data) {
781 ExportJsonType opDecl;
782 opDecl["op"] = "aa";
783 opDecl["exp"] = anyToJson(expression.getOperand(0)->accept(*this, data));
784 opDecl["index"] = anyToJson(expression.getOperand(1)->accept(*this, data));
785 return opDecl;
786}
787
788boost::any ExpressionToJson::visit(storm::expressions::FunctionCallExpression const& expression, boost::any const& data) {
789 ExportJsonType opDecl;
790 opDecl["op"] = "call";
791 opDecl["function"] = expression.getFunctionIdentifier();
792 std::vector<ExportJsonType> arguments;
793 for (uint64_t i = 0; i < expression.getNumberOfArguments(); ++i) {
794 arguments.push_back(anyToJson(expression.getArgument(i)->accept(*this, data)));
795 }
796 opDecl["args"] = std::move(arguments);
797 return opDecl;
798}
799
801 ExportJsonType constantDecl;
802 constantDecl["constant"] = expression.asString();
803 return constantDecl;
804}
805
806void JsonExporter::toFile(storm::jani::Model const& janiModel, std::vector<storm::jani::Property> const& formulas, std::string const& filepath, bool checkValid,
807 bool compact) {
808 std::ofstream stream;
809 storm::io::openFile(filepath, stream, false, true);
810 toStream(janiModel, formulas, stream, checkValid, compact);
811 storm::io::closeFile(stream);
812}
813
814void JsonExporter::toStream(storm::jani::Model const& janiModel, std::vector<storm::jani::Property> const& formulas, std::ostream& os, bool checkValid,
815 bool compact) {
816 if (checkValid) {
817 janiModel.checkValid();
818 }
819 JsonExporter exporter;
820 STORM_LOG_INFO("Started to convert model " << janiModel.getName() << ".");
821 exporter.convertModel(janiModel, !compact);
822 STORM_LOG_INFO("Started to convert properties of model " << janiModel.getName() << ".");
823 exporter.convertProperties(formulas, janiModel);
824 STORM_LOG_INFO("Producing json output... " << janiModel.getName() << ".");
825 os << storm::dumpJson(exporter.finalize(), compact) << '\n';
826 STORM_LOG_INFO("Conversion completed " << janiModel.getName() << ".");
827}
828
829ExportJsonType buildActionArray(std::vector<storm::jani::Action> const& actions) {
830 std::vector<ExportJsonType> actionReprs;
831 uint64_t actIndex = 0;
832 for (auto const& act : actions) {
834 actIndex++;
835 continue;
836 }
837 actIndex++;
838 ExportJsonType actEntry;
839 actEntry["name"] = act.getName();
840 actionReprs.push_back(actEntry);
841 }
842
843 return ExportJsonType(actionReprs);
844}
845
847 ExportJsonType typeDescr;
848 if (type.isIntegerType()) {
849 typeDescr = "int";
850 } else if (type.isRationalType()) {
851 typeDescr = "real";
852 } else if (type.isBooleanType()) {
853 typeDescr = "bool";
854 } else if (type.isArrayType()) {
855 typeDescr["kind"] = "array";
856 typeDescr["base"] = buildTypeDescription(type.getElementType());
857 } else {
858 STORM_LOG_THROW(false, storm::exceptions::IllegalArgumentException, "Unknown expression type.");
859 }
860 return typeDescr;
861}
862
864 std::vector<storm::jani::Constant> const& constants) {
867 getBoundsFromConstraints(typeDesc, var, constraint.getBaseExpression().getOperand(0), constants);
868 getBoundsFromConstraints(typeDesc, var, constraint.getBaseExpression().getOperand(1), constants);
869 } else if (constraint.getBaseExpression().isBinaryRelationExpression()) {
872 std::vector<bool> varOps(2, false);
873 for (int i : {0, 1}) {
874 varOps[i] = constraint.getOperand(i).isVariable() && constraint.getOperand(i).getBaseExpression().asVariableExpression().getVariable() == var;
875 }
876 storm::expressions::Expression boundExpr = varOps[0] ? constraint.getOperand(1) : constraint.getOperand(0);
877 if ((leq && varOps[0]) || (geq && varOps[1])) {
878 typeDesc["upper-bound"] = buildExpression(boundExpr, constants);
879 } else if ((leq && varOps[1]) || (geq && varOps[0])) {
880 typeDesc["lower-bound"] = buildExpression(boundExpr, constants);
881 } else {
882 STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Jani Export for constant constraint " << constraint << " is not supported.");
883 }
884 } else {
885 STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Jani Export for constant constraint " << constraint << " is not supported.");
886 }
887}
888
889ExportJsonType buildConstantsArray(std::vector<storm::jani::Constant> const& constants) {
890 std::vector<ExportJsonType> constantDeclarations;
891 for (auto const& constant : constants) {
892 ExportJsonType constantEntry;
893 constantEntry["name"] = constant.getName();
894 ExportJsonType typeDesc;
895 if (constant.hasConstraint()) {
896 typeDesc["kind"] = "bounded";
897 typeDesc["base"] = buildTypeDescription(constant.getType());
898 getBoundsFromConstraints(typeDesc, constant.getExpressionVariable(), constant.getConstraintExpression(), constants);
899 } else {
900 typeDesc = buildTypeDescription(constant.getType());
901 }
902 constantEntry["type"] = typeDesc;
903 if (constant.isDefined()) {
904 constantEntry["value"] = buildExpression(constant.getExpression(), constants);
905 }
906 constantDeclarations.push_back(constantEntry);
907 }
908 return ExportJsonType(constantDeclarations);
909}
910
911ExportJsonType buildType(storm::jani::JaniType const& type, std::vector<storm::jani::Constant> const& constants, VariableSet const& globalVariables,
912 VariableSet const& localVariables = VariableSet()) {
913 ExportJsonType typeDesc;
914 if (type.isBasicType() || type.isClockType() || type.isContinuousType()) {
915 typeDesc = type.getStringRepresentation();
916 } else if (type.isBoundedType()) {
917 typeDesc["kind"] = "bounded";
918 auto const& bndType = type.asBoundedType();
919 switch (bndType.getBaseType()) {
921 typeDesc["base"] = "int";
922 break;
924 typeDesc["base"] = "real";
925 break;
926 }
927 if (bndType.hasLowerBound()) {
928 typeDesc["lower-bound"] = buildExpression(bndType.getLowerBound(), constants, globalVariables, localVariables);
929 }
930 if (bndType.hasUpperBound()) {
931 typeDesc["upper-bound"] = buildExpression(bndType.getUpperBound(), constants, globalVariables, localVariables);
932 }
933 } else if (type.isArrayType()) {
934 typeDesc["kind"] = "array";
935 typeDesc["base"] = buildType(type.asArrayType().getBaseType(), constants, globalVariables, localVariables);
936 } else {
937 STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "Variable type not recognized in JSONExporter");
938 }
939 return typeDesc;
940}
941
942ExportJsonType buildVariablesArray(storm::jani::VariableSet const& varSet, std::vector<storm::jani::Constant> const& constants,
943 VariableSet const& globalVariables, VariableSet const& localVariables = VariableSet()) {
944 ExportJsonType variableDeclarations = std::vector<ExportJsonType>();
945 for (auto const& variable : varSet) {
946 ExportJsonType varEntry;
947 varEntry["name"] = variable.getName();
948 if (variable.isTransient()) {
949 varEntry["transient"] = variable.isTransient();
950 }
951 varEntry["type"] = buildType(variable.getType(), constants, globalVariables, localVariables);
952 if (variable.hasInitExpression()) {
953 varEntry["initial-value"] = buildExpression(variable.getInitExpression(), constants, globalVariables, localVariables);
954 }
955 variableDeclarations.push_back(std::move(varEntry));
956 }
957 return variableDeclarations;
958}
959
960ExportJsonType buildFunctionsArray(std::unordered_map<std::string, FunctionDefinition> const& functionDefinitions,
961 std::vector<storm::jani::Constant> const& constants, VariableSet const& globalVariables,
962 VariableSet const& localVariables = VariableSet()) {
963 ExportJsonType functionDeclarations = std::vector<ExportJsonType>();
964 for (auto const& nameFunDef : functionDefinitions) {
965 storm::jani::FunctionDefinition const& funDef = nameFunDef.second;
966 ExportJsonType funDefJson;
967 funDefJson["name"] = nameFunDef.first;
968 funDefJson["type"] = buildTypeDescription(funDef.getType());
969 std::vector<ExportJsonType> parameterDeclarations;
970 std::unordered_set<std::string> parameterNames;
971 for (auto const& p : funDef.getParameters()) {
972 ExportJsonType parDefJson;
973 parDefJson["name"] = p.getName();
974 parameterNames.insert(p.getName());
975 parDefJson["type"] = buildTypeDescription(p.getType());
976 parameterDeclarations.push_back(parDefJson);
977 }
978 funDefJson["parameters"] = parameterDeclarations;
979 funDefJson["body"] = buildExpression(funDef.getFunctionBody(), constants, globalVariables, localVariables, parameterNames);
980 functionDeclarations.push_back(std::move(funDefJson));
981 }
982 return functionDeclarations;
983}
984
985ExportJsonType buildLValue(storm::jani::LValue const& lValue, std::vector<storm::jani::Constant> const& constants, VariableSet const& globalVariables,
986 VariableSet const& localVariables) {
987 if (lValue.isVariable()) {
988 return lValue.getVariable().getName();
989 } else {
990 STORM_LOG_ASSERT(lValue.isArrayAccess(), "Unhandled LValue " << lValue << ".");
991 ExportJsonType result = lValue.getVariable().getName();
992 for (auto const& indexExpr : lValue.getArrayIndexVector()) {
993 ExportJsonType subLValue = std::move(result);
994 result.clear();
995 result["op"] = "aa";
996 result["exp"] = std::move(subLValue);
997 result["index"] = buildExpression(indexExpr, constants, globalVariables, localVariables);
998 }
999 return result;
1000 }
1001}
1002
1003ExportJsonType buildAssignmentArray(storm::jani::OrderedAssignments const& orderedAssignments, std::vector<storm::jani::Constant> const& constants,
1004 VariableSet const& globalVariables, VariableSet const& localVariables, bool commentExpressions) {
1005 ExportJsonType assignmentDeclarations = std::vector<ExportJsonType>();
1006 bool addIndex = orderedAssignments.hasMultipleLevels();
1007 for (auto const& assignment : orderedAssignments) {
1008 ExportJsonType assignmentEntry;
1009 assignmentEntry["ref"] = buildLValue(assignment.getLValue(), constants, globalVariables, localVariables);
1010 assignmentEntry["value"] = buildExpression(assignment.getAssignedExpression(), constants, globalVariables, localVariables);
1011 if (addIndex) {
1012 assignmentEntry["index"] = assignment.getLevel();
1013 }
1014 if (commentExpressions) {
1015 assignmentEntry["comment"] = assignment.getLValue().getName() + " <- " + assignment.getAssignedExpression().toString();
1016 }
1017 assignmentDeclarations.push_back(std::move(assignmentEntry));
1018 }
1019 return assignmentDeclarations;
1020}
1021
1022ExportJsonType buildLocationsArray(std::vector<storm::jani::Location> const& locations, std::vector<storm::jani::Constant> const& constants,
1023 VariableSet const& globalVariables, VariableSet const& localVariables, bool commentExpressions) {
1024 ExportJsonType locationDeclarations = std::vector<ExportJsonType>();
1025 for (auto const& location : locations) {
1026 ExportJsonType locEntry;
1027 locEntry["name"] = location.getName();
1028 if (location.hasTimeProgressInvariant()) {
1029 ExportJsonType timeProg;
1030 timeProg["exp"] = buildExpression(location.getTimeProgressInvariant(), constants, globalVariables, localVariables);
1031 if (commentExpressions) {
1032 timeProg["comment"] = location.getTimeProgressInvariant().toString();
1033 }
1034 locEntry["time-progress"] = std::move(timeProg);
1035 }
1036 if (!location.getAssignments().empty()) {
1037 locEntry["transient-values"] = buildAssignmentArray(location.getAssignments(), constants, globalVariables, localVariables, commentExpressions);
1038 }
1039 locationDeclarations.push_back(std::move(locEntry));
1040 }
1041 return locationDeclarations;
1042}
1043
1045 std::vector<std::string> names;
1046 for (auto const& initLocIndex : automaton.getInitialLocationIndices()) {
1047 names.push_back(automaton.getLocation(initLocIndex).getName());
1048 }
1049 return ExportJsonType(names);
1050}
1051
1052ExportJsonType buildDestinations(std::vector<EdgeDestination> const& destinations, std::map<uint64_t, std::string> const& locationNames,
1053 std::vector<storm::jani::Constant> const& constants, VariableSet const& globalVariables, VariableSet const& localVariables,
1054 bool commentExpressions) {
1055 assert(destinations.size() > 0);
1056 ExportJsonType destDeclarations = std::vector<ExportJsonType>();
1057 for (auto const& destination : destinations) {
1058 ExportJsonType destEntry;
1059 destEntry["location"] = locationNames.at(destination.getLocationIndex());
1060 bool prob1 = false;
1061 if (destination.getProbability().isLiteral()) {
1062 if (storm::utility::isOne(destination.getProbability().evaluateAsRational())) {
1063 prob1 = true;
1064 }
1065 }
1066 if (!prob1) {
1067 destEntry["probability"]["exp"] = buildExpression(destination.getProbability(), constants, globalVariables, localVariables);
1068 if (commentExpressions) {
1069 destEntry["probability"]["comment"] = destination.getProbability().toString();
1070 }
1071 }
1072 if (!destination.getOrderedAssignments().empty()) {
1073 destEntry["assignments"] =
1074 buildAssignmentArray(destination.getOrderedAssignments(), constants, globalVariables, localVariables, commentExpressions);
1075 }
1076 destDeclarations.push_back(std::move(destEntry));
1077 }
1078 return destDeclarations;
1079}
1080
1081ExportJsonType buildEdge(Edge const& edge, std::map<uint64_t, std::string> const& actionNames, std::map<uint64_t, std::string> const& locationNames,
1082 std::vector<storm::jani::Constant> const& constants, VariableSet const& globalVariables, VariableSet const& localVariables,
1083 bool commentExpressions) {
1084 STORM_LOG_THROW(edge.getDestinations().size() > 0, storm::exceptions::InvalidJaniException, "An edge without destinations is not allowed.");
1085 ExportJsonType edgeEntry;
1086 edgeEntry["location"] = locationNames.at(edge.getSourceLocationIndex());
1087 if (!edge.hasSilentAction()) {
1088 edgeEntry["action"] = actionNames.at(edge.getActionIndex());
1089 }
1090 if (edge.hasRate()) {
1091 edgeEntry["rate"]["exp"] = buildExpression(edge.getRate(), constants, globalVariables, localVariables);
1092 if (commentExpressions) {
1093 edgeEntry["rate"]["comment"] = edge.getRate().toString();
1094 }
1095 }
1096 if (!edge.getGuard().isTrue()) {
1097 edgeEntry["guard"]["exp"] = buildExpression(edge.getGuard(), constants, globalVariables, localVariables);
1098 if (commentExpressions) {
1099 edgeEntry["guard"]["comment"] = edge.getGuard().toString();
1100 }
1101 }
1102 edgeEntry["destinations"] = buildDestinations(edge.getDestinations(), locationNames, constants, globalVariables, localVariables, commentExpressions);
1103 if (!edge.getAssignments().empty()) {
1104 edgeEntry["assignments"] = buildAssignmentArray(edge.getAssignments(), constants, globalVariables, localVariables, commentExpressions);
1105 }
1106 return edgeEntry;
1107}
1108
1109ExportJsonType buildEdges(std::vector<Edge> const& edges, std::map<uint64_t, std::string> const& actionNames,
1110 std::map<uint64_t, std::string> const& locationNames, std::vector<storm::jani::Constant> const& constants,
1111 VariableSet const& globalVariables, VariableSet const& localVariables, bool commentExpressions) {
1112 ExportJsonType edgeDeclarations = std::vector<ExportJsonType>();
1113 for (auto const& edge : edges) {
1114 if (edge.getGuard().isFalse()) {
1115 continue;
1116 }
1117 edgeDeclarations.push_back(buildEdge(edge, actionNames, locationNames, constants, globalVariables, localVariables, commentExpressions));
1118 }
1119 return edgeDeclarations;
1120}
1121
1122ExportJsonType buildAutomataArray(std::vector<storm::jani::Automaton> const& automata, std::map<uint64_t, std::string> const& actionNames,
1123 std::vector<storm::jani::Constant> const& constants, VariableSet const& globalVariables, bool commentExpressions) {
1124 ExportJsonType automataDeclarations = std::vector<ExportJsonType>();
1125 for (auto const& automaton : automata) {
1126 ExportJsonType autoEntry;
1127 autoEntry["name"] = automaton.getName();
1128 autoEntry["variables"] = buildVariablesArray(automaton.getVariables(), constants, globalVariables, automaton.getVariables());
1129 if (!automaton.getFunctionDefinitions().empty()) {
1130 autoEntry["functions"] = buildFunctionsArray(automaton.getFunctionDefinitions(), constants, globalVariables, automaton.getVariables());
1131 }
1132 if (automaton.hasRestrictedInitialStates()) {
1133 autoEntry["restrict-initial"]["exp"] =
1134 buildExpression(automaton.getInitialStatesRestriction(), constants, globalVariables, automaton.getVariables());
1135 }
1136 autoEntry["locations"] = buildLocationsArray(automaton.getLocations(), constants, globalVariables, automaton.getVariables(), commentExpressions);
1137 autoEntry["initial-locations"] = buildInitialLocations(automaton);
1138 autoEntry["edges"] = buildEdges(automaton.getEdges(), actionNames, automaton.buildIdToLocationNameMap(), constants, globalVariables,
1139 automaton.getVariables(), commentExpressions);
1140 automataDeclarations.push_back(std::move(autoEntry));
1141 }
1142 return automataDeclarations;
1143}
1144
1145void JsonExporter::convertModel(storm::jani::Model const& janiModel, bool commentExpressions) {
1146 modelFeatures = janiModel.getModelFeatures();
1147 jsonStruct["jani-version"] = janiModel.getJaniVersion();
1148 jsonStruct["name"] = janiModel.getName();
1149 jsonStruct["type"] = to_string(janiModel.getModelType());
1150 jsonStruct["actions"] = buildActionArray(janiModel.getActions());
1151 jsonStruct["constants"] = buildConstantsArray(janiModel.getConstants());
1152 jsonStruct["variables"] = buildVariablesArray(janiModel.getGlobalVariables(), janiModel.getConstants(), janiModel.getGlobalVariables());
1153 if (!janiModel.getGlobalFunctionDefinitions().empty()) {
1154 jsonStruct["functions"] = buildFunctionsArray(janiModel.getGlobalFunctionDefinitions(), janiModel.getConstants(), janiModel.getGlobalVariables());
1155 }
1156 jsonStruct["restrict-initial"]["exp"] = buildExpression(janiModel.getInitialStatesRestriction(), janiModel.getConstants(), janiModel.getGlobalVariables());
1157 jsonStruct["automata"] = buildAutomataArray(janiModel.getAutomata(), janiModel.getActionIndexToNameMap(), janiModel.getConstants(),
1158 janiModel.getGlobalVariables(), commentExpressions);
1159 jsonStruct["system"] = CompositionJsonExporter::translate(janiModel.getSystemComposition());
1160}
1161
1162ExportJsonType JsonExporter::getEdgeAsJson(storm::jani::Model const& janiModel, uint64_t automatonIndex, uint64_t edgeIndex, bool commentExpressions) {
1163 auto const& automaton = janiModel.getAutomaton(automatonIndex);
1164 return buildEdge(automaton.getEdge(edgeIndex), janiModel.getActionIndexToNameMap(), automaton.buildIdToLocationNameMap(), janiModel.getConstants(),
1165 janiModel.getGlobalVariables(), automaton.getVariables(), commentExpressions);
1166}
1167
1169 switch (ft) {
1171 return "min";
1173 return "max";
1175 return "sum";
1177 return "avg";
1179 return "count";
1181 return "∃";
1183 return "∀";
1185 return "argmin";
1187 return "argmax";
1189 return "values";
1190 }
1191 STORM_LOG_THROW(false, storm::exceptions::IllegalArgumentException, "Unknown FilterType");
1192}
1193
1195 ExportJsonType propDecl;
1196 propDecl["states"]["op"] = "initial";
1197 propDecl["op"] = "filter";
1198 propDecl["fun"] = janiFilterTypeString(fe.getFilterType());
1199 propDecl["values"] = FormulaToJaniJson::translate(*fe.getFormula(), model, modelFeatures);
1200 return propDecl;
1201}
1202
1203void JsonExporter::convertProperties(std::vector<storm::jani::Property> const& formulas, storm::jani::Model const& model) {
1204 ExportJsonType properties;
1205
1206 // Unset model-features that only relate to properties. These are only set if such properties actually exist.
1208 if (formulas.empty()) {
1209 jsonStruct["properties"] = ExportJsonType(ExportJsonType::value_t::array);
1210 return;
1211 }
1212
1213 for (auto const& f : formulas) {
1214 ExportJsonType propDecl;
1215 propDecl["name"] = f.getName();
1216 propDecl["expression"] = convertFilterExpression(f.getFilter(), model, modelFeatures);
1217 properties.push_back(std::move(propDecl));
1218 }
1219 jsonStruct["properties"] = std::move(properties);
1220}
1221
1222ExportJsonType JsonExporter::finalize() {
1223 jsonStruct["features"] = ExportJsonType::parse(modelFeatures.toString());
1224 return jsonStruct;
1225}
1226
1227} // namespace jani
1228} // 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:148
static std::shared_ptr< Formula const > getTrueFormula()
Definition Formula.cpp:205
LongRunAverageRewardFormula & asLongRunAverageRewardFormula()
Definition Formula.cpp:445
virtual bool isCumulativeRewardFormula() const
Definition Formula.cpp:144
virtual bool isLongRunAverageRewardFormula() const
Definition Formula.cpp:156
EventuallyFormula & asEventuallyFormula()
Definition Formula.cpp:333
InstantaneousRewardFormula & asInstantaneousRewardFormula()
Definition Formula.cpp:437
virtual bool isEventuallyFormula() const
Definition Formula.cpp:88
CumulativeRewardFormula & asCumulativeRewardFormula()
Definition Formula.cpp:421
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:29
#define STORM_LOG_WARN(message)
Definition logging.h:30
#define STORM_LOG_TRACE(message)
Definition logging.h:17
#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.
Definition cli.cpp:18
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