You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

573 lines
26 KiB

  1. /*
  2. * ActionTest.cpp
  3. *
  4. * Created on: Jun 27, 2014
  5. * Author: Manuel Sascha Weiand
  6. */
  7. #include "gtest/gtest.h"
  8. #include "storm-config.h"
  9. #include "src/properties/actions/BoundAction.h"
  10. #include "src/properties/actions/FormulaAction.h"
  11. #include "src/properties/actions/InvertAction.h"
  12. #include "src/properties/actions/RangeAction.h"
  13. #include "src/properties/actions/SortAction.h"
  14. #include "src/parser/MarkovAutomatonParser.h"
  15. #include "src/parser/DeterministicModelParser.h"
  16. #include "src/modelchecker/prctl/SparseDtmcPrctlModelChecker.h"
  17. #include "src/modelchecker/csl/SparseMarkovAutomatonCslModelChecker.h"
  18. #include "src/solver/GmmxxLinearEquationSolver.h"
  19. #include "src/exceptions/InvalidArgumentException.h"
  20. typedef storm::properties::action::AbstractAction<double>::Result Result;
  21. TEST(ActionTest, BoundActionFunctionality) {
  22. // Setup the modelchecker.
  23. storm::models::Dtmc<double> model = storm::parser::DeterministicModelParser::parseDtmc(STORM_CPP_TESTS_BASE_PATH "/functional/parser/tra_files/dtmc_actionTest.tra", STORM_CPP_TESTS_BASE_PATH "/functional/parser/lab_files/dtmc_actionTest.lab");
  24. storm::modelchecker::prctl::SparseDtmcPrctlModelChecker<double> mc(model, std::unique_ptr<storm::solver::LinearEquationSolver<double>>(new storm::solver::GmmxxLinearEquationSolver<double>()));
  25. // Build the filter input.
  26. // Basically the modelchecking result of "F a" on the used DTMC.
  27. std::vector<double> pathResult = mc.checkEventually(storm::properties::prctl::Eventually<double>(std::make_shared<storm::properties::prctl::Ap<double>>("a")), false);
  28. std::vector<uint_fast64_t> stateMap(pathResult.size());
  29. for(uint_fast64_t i = 0; i < pathResult.size(); i++) {
  30. stateMap[i] = i;
  31. }
  32. Result input(storm::storage::BitVector(pathResult.size(), true), stateMap, pathResult, storm::storage::BitVector());
  33. // Test the action.
  34. // First test that the boundAction build by the empty constructor does not change the selection.
  35. storm::properties::action::BoundAction<double> action;
  36. Result result = action.evaluate(input, mc);
  37. for(auto value : result.selection) {
  38. ASSERT_TRUE(input.selection[value]);
  39. }
  40. // Test that using a strict bound can give different results than using a non-strict bound.
  41. action = storm::properties::action::BoundAction<double>(storm::properties::GREATER, 0);
  42. result = action.evaluate(input, mc);
  43. for(uint_fast64_t i = 0; i < result.selection.size()-2; i++) {
  44. ASSERT_TRUE(result.selection[i]);
  45. }
  46. ASSERT_FALSE(result.selection[6]);
  47. ASSERT_FALSE(result.selection[7]);
  48. // Test whether the filter actually uses the selection given by the input.
  49. action = storm::properties::action::BoundAction<double>(storm::properties::LESS, 0.5);
  50. result = action.evaluate(result, mc);
  51. ASSERT_FALSE(result.selection[0]);
  52. ASSERT_TRUE(result.selection[1]);
  53. ASSERT_FALSE(result.selection[6]);
  54. ASSERT_FALSE(result.selection[7]);
  55. // Check whether the state order has any effect on the selected states, which it should not.
  56. for(uint_fast64_t i = 0; i < pathResult.size(); i++) {
  57. stateMap[i] = pathResult.size() - i - 1;
  58. }
  59. action = storm::properties::action::BoundAction<double>(storm::properties::GREATER, 0);
  60. result = action.evaluate(input, mc);
  61. for(uint_fast64_t i = 0; i < result.selection.size()-2; i++) {
  62. ASSERT_TRUE(result.selection[i]);
  63. }
  64. ASSERT_FALSE(result.selection[6]);
  65. ASSERT_FALSE(result.selection[7]);
  66. // Test the functionality for state formulas instead.
  67. input.pathResult = std::vector<double>();
  68. input.stateResult = mc.checkAp(storm::properties::prctl::Ap<double>("a"));
  69. action = storm::properties::action::BoundAction<double>(storm::properties::GREATER, 0.5);
  70. result = action.evaluate(input, mc);
  71. for(uint_fast64_t i = 0; i < result.selection.size(); i++) {
  72. if(i == 5) {
  73. ASSERT_TRUE(result.selection[i]);
  74. } else {
  75. ASSERT_FALSE(result.selection[i]);
  76. }
  77. }
  78. // Make sure that the modelchecker has no influence on the result.
  79. storm::models::MarkovAutomaton<double> ma = storm::parser::MarkovAutomatonParser::parseMarkovAutomaton(STORM_CPP_TESTS_BASE_PATH "/functional/parser/tra_files/ma_general.tra", STORM_CPP_TESTS_BASE_PATH "/functional/parser/lab_files/ma_general.lab");
  80. storm::modelchecker::csl::SparseMarkovAutomatonCslModelChecker<double> cslMc(ma);
  81. result = action.evaluate(input, cslMc);
  82. for(uint_fast64_t i = 0; i < result.selection.size(); i++) {
  83. if(i == 5) {
  84. ASSERT_TRUE(result.selection[i]);
  85. } else {
  86. ASSERT_FALSE(result.selection[i]);
  87. }
  88. }
  89. }
  90. TEST(ActionTest, BoundActionSafety) {
  91. // Setup the modelchecker.
  92. storm::models::Dtmc<double> model = storm::parser::DeterministicModelParser::parseDtmc(STORM_CPP_TESTS_BASE_PATH "/functional/parser/tra_files/dtmc_actionTest.tra", STORM_CPP_TESTS_BASE_PATH "/functional/parser/lab_files/dtmc_actionTest.lab");
  93. storm::modelchecker::prctl::SparseDtmcPrctlModelChecker<double> mc(model, std::unique_ptr<storm::solver::LinearEquationSolver<double>>(new storm::solver::GmmxxLinearEquationSolver<double>()));
  94. // Build the filter input.
  95. // Basically the modelchecking result of "F a" on the used DTMC.
  96. std::vector<double> pathResult = mc.checkEventually(storm::properties::prctl::Eventually<double>(std::make_shared<storm::properties::prctl::Ap<double>>("a")), false);
  97. storm::storage::BitVector stateResult = mc.checkAp(storm::properties::prctl::Ap<double>("a"));
  98. std::vector<uint_fast64_t> stateMap(pathResult.size());
  99. for(uint_fast64_t i = 0; i < pathResult.size(); i++) {
  100. stateMap[i] = i;
  101. }
  102. Result input(storm::storage::BitVector(pathResult.size(), true), stateMap, pathResult, storm::storage::BitVector());
  103. // First, test unusual bounds.
  104. storm::properties::action::BoundAction<double> action(storm::properties::LESS, -2044);
  105. Result result;
  106. ASSERT_NO_THROW(result = action.evaluate(input, mc));
  107. ASSERT_EQ(0, result.selection.getNumberOfSetBits());
  108. action = storm::properties::action::BoundAction<double>(storm::properties::GREATER_EQUAL, 5879);
  109. ASSERT_NO_THROW(result = action.evaluate(input, mc));
  110. ASSERT_EQ(0, result.selection.getNumberOfSetBits());
  111. action = storm::properties::action::BoundAction<double>(storm::properties::LESS_EQUAL, 5879);
  112. ASSERT_NO_THROW(result = action.evaluate(input, mc));
  113. ASSERT_EQ(result.selection.size(), result.selection.getNumberOfSetBits());
  114. // Now, check the behavior under a undefined comparison type.
  115. action = storm::properties::action::BoundAction<double>(static_cast<storm::properties::ComparisonType>(10), 5879);
  116. ASSERT_THROW(action.toString(), storm::exceptions::InvalidArgumentException);
  117. ASSERT_THROW(action.evaluate(input, mc), storm::exceptions::InvalidArgumentException);
  118. // Test for a result input with both results filled.
  119. // It should put out a warning and use the pathResult.
  120. action = storm::properties::action::BoundAction<double>(storm::properties::GREATER_EQUAL, 0.5);
  121. input.stateResult = stateResult;
  122. // To capture the warning, redirect cout and test the written buffer content.
  123. std::stringstream buffer;
  124. std::streambuf *sbuf = std::cout.rdbuf();
  125. std::cout.rdbuf(buffer.rdbuf());
  126. ASSERT_NO_THROW(result = action.evaluate(input, mc));
  127. std::cout.rdbuf(sbuf);
  128. ASSERT_FALSE(buffer.str().empty());
  129. ASSERT_TRUE(result.selection[0]);
  130. ASSERT_FALSE(result.selection[1]);
  131. ASSERT_TRUE(result.selection[2]);
  132. ASSERT_TRUE(result.selection[5]);
  133. // Check for empty input.
  134. ASSERT_NO_THROW(result = action.evaluate(Result(), mc));
  135. }
  136. TEST(ActionTest, FormulaActionFunctionality) {
  137. // Setup the modelchecker.
  138. storm::models::Dtmc<double> model = storm::parser::DeterministicModelParser::parseDtmc(STORM_CPP_TESTS_BASE_PATH "/functional/parser/tra_files/dtmc_actionTest.tra", STORM_CPP_TESTS_BASE_PATH "/functional/parser/lab_files/dtmc_actionTest.lab");
  139. storm::modelchecker::prctl::SparseDtmcPrctlModelChecker<double> mc(model, std::unique_ptr<storm::solver::LinearEquationSolver<double>>(new storm::solver::GmmxxLinearEquationSolver<double>()));
  140. // Build the filter input.
  141. // Basically the modelchecking result of "F a" on the used DTMC.
  142. std::vector<double> pathResult = mc.checkEventually(storm::properties::prctl::Eventually<double>(std::make_shared<storm::properties::prctl::Ap<double>>("a")), false);
  143. storm::storage::BitVector stateResult = mc.checkAp(storm::properties::prctl::Ap<double>("c"));
  144. std::vector<uint_fast64_t> stateMap(pathResult.size());
  145. for(uint_fast64_t i = 0; i < pathResult.size(); i++) {
  146. stateMap[i] = i;
  147. }
  148. Result input(storm::storage::BitVector(pathResult.size(), true), stateMap, pathResult, storm::storage::BitVector());
  149. Result result;
  150. // Test the action.
  151. // First test that the empty action does no change to the input.
  152. storm::properties::action::FormulaAction<double> action;
  153. input.selection.set(0,false);
  154. ASSERT_NO_THROW(result = action.evaluate(input, mc));
  155. for(uint_fast64_t i = 0; i < pathResult.size(); i++) {
  156. if(i != 0) {
  157. ASSERT_TRUE(result.selection[i]);
  158. } else {
  159. ASSERT_FALSE(result.selection[i]);
  160. }
  161. ASSERT_EQ(i, result.stateMap[i]);
  162. ASSERT_EQ(input.pathResult[i], result.pathResult[i]);
  163. }
  164. ASSERT_TRUE(result.stateResult.size() == 0);
  165. input.selection.set(0,true);
  166. // Now test the general functionality.
  167. action = storm::properties::action::FormulaAction<double>(std::make_shared<storm::properties::prctl::ProbabilisticBoundOperator<double>>(storm::properties::LESS, 0.5, std::make_shared<storm::properties::prctl::Eventually<double>>(std::make_shared<storm::properties::prctl::Ap<double>>("b"))));
  168. ASSERT_NO_THROW(result = action.evaluate(input, mc));
  169. ASSERT_TRUE(result.selection[0]);
  170. ASSERT_TRUE(result.selection[1]);
  171. ASSERT_TRUE(result.selection[2]);
  172. ASSERT_FALSE(result.selection[3]);
  173. ASSERT_FALSE(result.selection[4]);
  174. ASSERT_TRUE(result.selection[5]);
  175. ASSERT_FALSE(result.selection[6]);
  176. ASSERT_FALSE(result.selection[7]);
  177. // Check that the actual modelchecking results are not touched.
  178. ASSERT_EQ(input.stateResult.size(), result.stateResult.size());
  179. ASSERT_EQ(input.pathResult.size(), result.pathResult.size());
  180. for(uint_fast64_t i = 0; i < input.pathResult.size(); i++) {
  181. ASSERT_EQ(input.pathResult[i], result.pathResult[i]);
  182. }
  183. // Do the same but this time using a state result instead of a path result.
  184. input.pathResult = std::vector<double>();
  185. input.stateResult = stateResult;
  186. ASSERT_NO_THROW(result = action.evaluate(input, mc));
  187. ASSERT_TRUE(result.selection[0]);
  188. ASSERT_TRUE(result.selection[1]);
  189. ASSERT_TRUE(result.selection[2]);
  190. ASSERT_FALSE(result.selection[3]);
  191. ASSERT_FALSE(result.selection[4]);
  192. ASSERT_TRUE(result.selection[5]);
  193. ASSERT_FALSE(result.selection[6]);
  194. ASSERT_FALSE(result.selection[7]);
  195. ASSERT_EQ(input.stateResult.size(), result.stateResult.size());
  196. ASSERT_EQ(input.pathResult.size(), result.pathResult.size());
  197. for(uint_fast64_t i = 0; i < input.stateResult.size(); i++) {
  198. ASSERT_EQ(input.stateResult[i], result.stateResult[i]);
  199. }
  200. }
  201. TEST(ActionTest, FormulaActionSafety){
  202. // Setup the modelchecker.
  203. storm::models::Dtmc<double> model = storm::parser::DeterministicModelParser::parseDtmc(STORM_CPP_TESTS_BASE_PATH "/functional/parser/tra_files/dtmc_actionTest.tra", STORM_CPP_TESTS_BASE_PATH "/functional/parser/lab_files/dtmc_actionTest.lab");
  204. storm::modelchecker::prctl::SparseDtmcPrctlModelChecker<double> mc(model, std::unique_ptr<storm::solver::LinearEquationSolver<double>>(new storm::solver::GmmxxLinearEquationSolver<double>()));
  205. // Build the filter input.
  206. // Basically the modelchecking result of "F a" on the used DTMC.
  207. std::vector<double> pathResult = mc.checkEventually(storm::properties::prctl::Eventually<double>(std::make_shared<storm::properties::prctl::Ap<double>>("a")), false);
  208. std::vector<uint_fast64_t> stateMap(pathResult.size());
  209. for(uint_fast64_t i = 0; i < pathResult.size(); i++) {
  210. stateMap[i] = i;
  211. }
  212. Result input(storm::storage::BitVector(pathResult.size(), true), stateMap, pathResult, storm::storage::BitVector());
  213. Result result;
  214. // Check that constructing the action using a nullptr and using an empty constructor leads to the same behavior.
  215. storm::properties::action::FormulaAction<double> action(std::shared_ptr<storm::properties::csl::AbstractStateFormula<double>>(nullptr));
  216. input.selection.set(0,false);
  217. ASSERT_NO_THROW(result = action.evaluate(input, mc));
  218. for(uint_fast64_t i = 0; i < pathResult.size(); i++) {
  219. if(i != 0) {
  220. ASSERT_TRUE(result.selection[i]);
  221. } else {
  222. ASSERT_FALSE(result.selection[i]);
  223. }
  224. ASSERT_EQ(i, result.stateMap[i]);
  225. ASSERT_EQ(input.pathResult[i], result.pathResult[i]);
  226. }
  227. ASSERT_TRUE(result.stateResult.size() == 0);
  228. input.selection.set(0,true);
  229. ASSERT_NO_THROW(action.toString());
  230. }
  231. TEST(ActionTest, InvertActionFunctionality){
  232. // Setup the modelchecker.
  233. storm::models::Dtmc<double> model = storm::parser::DeterministicModelParser::parseDtmc(STORM_CPP_TESTS_BASE_PATH "/functional/parser/tra_files/dtmc_actionTest.tra", STORM_CPP_TESTS_BASE_PATH "/functional/parser/lab_files/dtmc_actionTest.lab");
  234. storm::modelchecker::prctl::SparseDtmcPrctlModelChecker<double> mc(model, std::unique_ptr<storm::solver::LinearEquationSolver<double>>(new storm::solver::GmmxxLinearEquationSolver<double>()));
  235. // Build the filter input.
  236. // Basically the modelchecking result of "F a" on the used DTMC.
  237. std::vector<double> pathResult = mc.checkEventually(storm::properties::prctl::Eventually<double>(std::make_shared<storm::properties::prctl::Ap<double>>("a")), false);
  238. storm::storage::BitVector stateResult = mc.checkAp(storm::properties::prctl::Ap<double>("c"));
  239. std::vector<uint_fast64_t> stateMap(pathResult.size());
  240. for(uint_fast64_t i = 0; i < pathResult.size(); i++) {
  241. stateMap[i] = pathResult.size()-i-1;
  242. }
  243. Result input(storm::storage::BitVector(pathResult.size(), true), stateMap, pathResult, storm::storage::BitVector());
  244. Result result;
  245. // Check whether the selection becomes inverted while the rest stays the same.
  246. storm::properties::action::InvertAction<double> action;
  247. input.selection.set(0,false);
  248. ASSERT_NO_THROW(result = action.evaluate(input, mc));
  249. for(uint_fast64_t i = 0; i < pathResult.size(); i++) {
  250. if(i != 0) {
  251. ASSERT_FALSE(result.selection[i]);
  252. } else {
  253. ASSERT_TRUE(result.selection[i]);
  254. }
  255. ASSERT_EQ(pathResult.size()-i-1, result.stateMap[i]);
  256. ASSERT_EQ(input.pathResult[i], result.pathResult[i]);
  257. }
  258. ASSERT_TRUE(result.stateResult.size() == 0);
  259. input.selection.set(0,true);
  260. ASSERT_NO_THROW(action.toString());
  261. }
  262. TEST(ActionTest, RangeActionFunctionality){
  263. // Setup the modelchecker.
  264. storm::models::Dtmc<double> model = storm::parser::DeterministicModelParser::parseDtmc(STORM_CPP_TESTS_BASE_PATH "/functional/parser/tra_files/dtmc_actionTest.tra", STORM_CPP_TESTS_BASE_PATH "/functional/parser/lab_files/dtmc_actionTest.lab");
  265. storm::modelchecker::prctl::SparseDtmcPrctlModelChecker<double> mc(model, std::unique_ptr<storm::solver::LinearEquationSolver<double>>(new storm::solver::GmmxxLinearEquationSolver<double>()));
  266. // Build the filter input.
  267. // Basically the modelchecking result of "F a" on the used DTMC.
  268. std::vector<double> pathResult = mc.checkEventually(storm::properties::prctl::Eventually<double>(std::make_shared<storm::properties::prctl::Ap<double>>("a")), false);
  269. storm::storage::BitVector stateResult = mc.checkAp(storm::properties::prctl::Ap<double>("c"));
  270. std::vector<uint_fast64_t> stateMap(pathResult.size());
  271. for(uint_fast64_t i = 0; i < pathResult.size(); i++) {
  272. stateMap[i] = i;
  273. }
  274. Result input(storm::storage::BitVector(pathResult.size(), true), stateMap, pathResult, storm::storage::BitVector());
  275. Result result;
  276. // Test if the action selects the first 3 states in relation to the order given by the stateMap.
  277. // First in index order.
  278. storm::properties::action::RangeAction<double> action(0,2);
  279. ASSERT_NO_THROW(result = action.evaluate(input, mc));
  280. for(uint_fast64_t i = 0; i < result.selection.size(); i++) {
  281. ASSERT_EQ(input.stateMap[i], result.stateMap[i]);
  282. }
  283. for(uint_fast64_t i = 0; i < 3; i++) {
  284. ASSERT_TRUE(result.selection[i]);
  285. }
  286. for(uint_fast64_t i = 3; i < result.selection.size(); i++) {
  287. ASSERT_FALSE(result.selection[i]);
  288. }
  289. input.selection.clear();
  290. input.selection.complement();
  291. // Now against index order.
  292. for(uint_fast64_t i = 0; i < input.pathResult.size(); i++) {
  293. input.stateMap[i] = input.pathResult.size()-i-1;
  294. }
  295. ASSERT_NO_THROW(result = action.evaluate(input, mc));
  296. for(uint_fast64_t i = 0; i < result.selection.size(); i++) {
  297. ASSERT_EQ(input.stateMap[i], result.stateMap[i]);
  298. }
  299. for(uint_fast64_t i = 0; i < 3; i++) {
  300. ASSERT_TRUE(result.selection[result.selection.size()-i-1]);
  301. }
  302. for(uint_fast64_t i = 3; i < result.selection.size(); i++) {
  303. ASSERT_FALSE(result.selection[result.selection.size()-i-1]);
  304. }
  305. input.selection.clear();
  306. input.selection.complement();
  307. // Finally test a random order.
  308. std::srand(time(nullptr));
  309. uint_fast64_t pos1, pos2, temp;
  310. for(uint_fast64_t i = 0; i < 100; i++) {
  311. // Randomly select two positions.
  312. pos1 = rand() % result.selection.size();
  313. pos2 = rand() % result.selection.size();
  314. // Swap the values there.
  315. temp = input.stateMap[pos1];
  316. input.stateMap[pos1] = input.stateMap[pos2];
  317. input.stateMap[pos2] = temp;
  318. }
  319. ASSERT_NO_THROW(result = action.evaluate(input, mc));
  320. for(uint_fast64_t i = 0; i < 8; i++) {
  321. ASSERT_EQ(input.stateMap[i], result.stateMap[i]);
  322. }
  323. for(uint_fast64_t i = 0; i < 3; i++) {
  324. ASSERT_TRUE(result.selection[result.stateMap[i]]);
  325. }
  326. for(uint_fast64_t i = 3; i < result.selection.size(); i++) {
  327. ASSERT_FALSE(result.selection[result.stateMap[i]]);
  328. }
  329. // Test that specifying and interval of (i,i) selects only state i.
  330. for(uint_fast64_t i = 0; i < input.selection.size(); i++) {
  331. action = storm::properties::action::RangeAction<double>(i,i);
  332. ASSERT_NO_THROW(result = action.evaluate(input, mc));
  333. ASSERT_EQ(1, result.selection.getNumberOfSetBits());
  334. ASSERT_TRUE(result.selection[result.stateMap[i]]);
  335. }
  336. }
  337. TEST(ActionTest, RangeActionSafety){
  338. // Setup the modelchecker.
  339. storm::models::Dtmc<double> model = storm::parser::DeterministicModelParser::parseDtmc(STORM_CPP_TESTS_BASE_PATH "/functional/parser/tra_files/dtmc_actionTest.tra", STORM_CPP_TESTS_BASE_PATH "/functional/parser/lab_files/dtmc_actionTest.lab");
  340. storm::modelchecker::prctl::SparseDtmcPrctlModelChecker<double> mc(model, std::unique_ptr<storm::solver::LinearEquationSolver<double>>(new storm::solver::GmmxxLinearEquationSolver<double>()));
  341. // Build the filter input.
  342. // Basically the modelchecking result of "F a" on the used DTMC.
  343. std::vector<double> pathResult = mc.checkEventually(storm::properties::prctl::Eventually<double>(std::make_shared<storm::properties::prctl::Ap<double>>("a")), false);
  344. storm::storage::BitVector stateResult = mc.checkAp(storm::properties::prctl::Ap<double>("c"));
  345. std::vector<uint_fast64_t> stateMap(pathResult.size());
  346. for(uint_fast64_t i = 0; i < pathResult.size(); i++) {
  347. stateMap[i] = i;
  348. }
  349. Result input(storm::storage::BitVector(pathResult.size(), true), stateMap, pathResult, storm::storage::BitVector());
  350. Result result;
  351. // Test invalid ranges.
  352. // To capture the warning, redirect cout and test the written buffer content.
  353. std::stringstream buffer;
  354. std::streambuf * sbuf = std::cout.rdbuf();
  355. std::cout.rdbuf(buffer.rdbuf());
  356. storm::properties::action::RangeAction<double> action(0,42);
  357. ASSERT_NO_THROW(result = action.evaluate(input, mc));
  358. ASSERT_TRUE(result.selection.full());
  359. ASSERT_FALSE(buffer.str().empty());
  360. buffer.str("");
  361. action = storm::properties::action::RangeAction<double>(42,98);
  362. ASSERT_NO_THROW(result = action.evaluate(input, mc));
  363. ASSERT_TRUE(result.selection.empty());
  364. ASSERT_FALSE(buffer.str().empty());
  365. std::cout.rdbuf(sbuf);
  366. ASSERT_THROW(storm::properties::action::RangeAction<double>(3,1), storm::exceptions::IllegalArgumentValueException);
  367. }
  368. TEST(ActionTest, SortActionFunctionality){
  369. // Setup the modelchecker.
  370. storm::models::Dtmc<double> model = storm::parser::DeterministicModelParser::parseDtmc(STORM_CPP_TESTS_BASE_PATH "/functional/parser/tra_files/dtmc_actionTest.tra", STORM_CPP_TESTS_BASE_PATH "/functional/parser/lab_files/dtmc_actionTest.lab");
  371. storm::modelchecker::prctl::SparseDtmcPrctlModelChecker<double> mc(model, std::unique_ptr<storm::solver::LinearEquationSolver<double>>(new storm::solver::GmmxxLinearEquationSolver<double>()));
  372. // Build the filter input.
  373. // Basically the modelchecking result of "F a" on the used DTMC.
  374. std::vector<double> pathResult = mc.checkEventually(storm::properties::prctl::Eventually<double>(std::make_shared<storm::properties::prctl::Ap<double>>("a")), false);
  375. storm::storage::BitVector stateResult = mc.checkAp(storm::properties::prctl::Ap<double>("c"));
  376. std::vector<uint_fast64_t> stateMap(pathResult.size());
  377. for(uint_fast64_t i = 0; i < pathResult.size(); i++) {
  378. stateMap[i] = pathResult.size()-i-1;
  379. }
  380. Result input(storm::storage::BitVector(pathResult.size(), true), stateMap, pathResult, storm::storage::BitVector());
  381. Result result;
  382. // Test that sorting preserves everything except the state map.
  383. storm::properties::action::SortAction<double> action;
  384. ASSERT_NO_THROW(action.toString());
  385. input.selection.set(0,false);
  386. ASSERT_NO_THROW(result = action.evaluate(input, mc));
  387. for(uint_fast64_t i = 0; i < pathResult.size(); i++) {
  388. if(i != 0) {
  389. ASSERT_TRUE(result.selection[i]);
  390. } else {
  391. ASSERT_FALSE(result.selection[i]);
  392. }
  393. ASSERT_EQ(i, result.stateMap[i]);
  394. ASSERT_EQ(input.pathResult[i], result.pathResult[i]);
  395. }
  396. ASSERT_TRUE(result.stateResult.size() == 0);
  397. input.selection.set(0,true);
  398. // Test sorting cases. Note that the input selection should be irrelevant for the resulting state order.
  399. // 1) index, ascending -> see above
  400. // 2) index descending
  401. input.selection.set(3,false);
  402. action = storm::properties::action::SortAction<double>(storm::properties::action::SortAction<double>::INDEX, false);
  403. ASSERT_NO_THROW(result = action.evaluate(input, mc));
  404. for(uint_fast64_t i = 0; i < pathResult.size(); i++) {
  405. ASSERT_EQ(pathResult.size()-i-1, result.stateMap[i]);
  406. }
  407. // 3) value, ascending
  408. action = storm::properties::action::SortAction<double>(storm::properties::action::SortAction<double>::VALUE);
  409. ASSERT_NO_THROW(result = action.evaluate(input, mc));
  410. ASSERT_EQ(6, result.stateMap[0]);
  411. ASSERT_EQ(7, result.stateMap[1]);
  412. ASSERT_EQ(3, result.stateMap[2]);
  413. ASSERT_EQ(4, result.stateMap[3]);
  414. ASSERT_EQ(1, result.stateMap[4]);
  415. ASSERT_EQ(0, result.stateMap[5]);
  416. ASSERT_EQ(2, result.stateMap[6]);
  417. ASSERT_EQ(5, result.stateMap[7]);
  418. // 3) value, decending
  419. action = storm::properties::action::SortAction<double>(storm::properties::action::SortAction<double>::VALUE, false);
  420. ASSERT_NO_THROW(result = action.evaluate(input, mc));
  421. ASSERT_EQ(5, result.stateMap[0]);
  422. ASSERT_EQ(2, result.stateMap[1]);
  423. ASSERT_EQ(0, result.stateMap[2]);
  424. ASSERT_EQ(1, result.stateMap[3]);
  425. ASSERT_EQ(4, result.stateMap[4]);
  426. ASSERT_EQ(3, result.stateMap[5]);
  427. ASSERT_EQ(6, result.stateMap[6]);
  428. ASSERT_EQ(7, result.stateMap[7]);
  429. // Check that this also works for state results instead.
  430. input.pathResult = std::vector<double>();
  431. input.stateResult = stateResult;
  432. action = storm::properties::action::SortAction<double>(storm::properties::action::SortAction<double>::VALUE);
  433. ASSERT_NO_THROW(result = action.evaluate(input, mc));
  434. ASSERT_EQ(5, result.stateMap[0]);
  435. ASSERT_EQ(6, result.stateMap[1]);
  436. ASSERT_EQ(7, result.stateMap[2]);
  437. ASSERT_EQ(0, result.stateMap[3]);
  438. ASSERT_EQ(1, result.stateMap[4]);
  439. ASSERT_EQ(2, result.stateMap[5]);
  440. ASSERT_EQ(3, result.stateMap[6]);
  441. ASSERT_EQ(4, result.stateMap[7]);
  442. action = storm::properties::action::SortAction<double>(storm::properties::action::SortAction<double>::VALUE, false);
  443. ASSERT_NO_THROW(result = action.evaluate(input, mc));
  444. ASSERT_EQ(0, result.stateMap[0]);
  445. ASSERT_EQ(1, result.stateMap[1]);
  446. ASSERT_EQ(2, result.stateMap[2]);
  447. ASSERT_EQ(3, result.stateMap[3]);
  448. ASSERT_EQ(4, result.stateMap[4]);
  449. ASSERT_EQ(5, result.stateMap[5]);
  450. ASSERT_EQ(6, result.stateMap[6]);
  451. ASSERT_EQ(7, result.stateMap[7]);
  452. // Test if the resulting order does not depend on the input order.
  453. input.stateResult = storm::storage::BitVector();
  454. input.pathResult = pathResult;
  455. action = storm::properties::action::SortAction<double>(storm::properties::action::SortAction<double>::INDEX);
  456. ASSERT_NO_THROW(input = action.evaluate(input, mc));
  457. action = storm::properties::action::SortAction<double>(storm::properties::action::SortAction<double>::VALUE);
  458. ASSERT_NO_THROW(result = action.evaluate(input, mc));
  459. ASSERT_EQ(6, result.stateMap[0]);
  460. ASSERT_EQ(7, result.stateMap[1]);
  461. ASSERT_EQ(3, result.stateMap[2]);
  462. ASSERT_EQ(4, result.stateMap[3]);
  463. ASSERT_EQ(1, result.stateMap[4]);
  464. ASSERT_EQ(0, result.stateMap[5]);
  465. ASSERT_EQ(2, result.stateMap[6]);
  466. ASSERT_EQ(5, result.stateMap[7]);
  467. }
  468. TEST(ActionTest, SortActionSafety){
  469. // Check that the path result has priority over the state result if for some erronous reason both are given.
  470. // Setup the modelchecker.
  471. storm::models::Dtmc<double> model = storm::parser::DeterministicModelParser::parseDtmc(STORM_CPP_TESTS_BASE_PATH "/functional/parser/tra_files/dtmc_actionTest.tra", STORM_CPP_TESTS_BASE_PATH "/functional/parser/lab_files/dtmc_actionTest.lab");
  472. storm::modelchecker::prctl::SparseDtmcPrctlModelChecker<double> mc(model, std::unique_ptr<storm::solver::LinearEquationSolver<double>>(new storm::solver::GmmxxLinearEquationSolver<double>()));
  473. // Build the filter input.
  474. // Basically the modelchecking result of "F a" on the used DTMC.
  475. std::vector<double> pathResult = mc.checkEventually(storm::properties::prctl::Eventually<double>(std::make_shared<storm::properties::prctl::Ap<double>>("a")), false);
  476. storm::storage::BitVector stateResult = mc.checkAp(storm::properties::prctl::Ap<double>("c"));
  477. std::vector<uint_fast64_t> stateMap(pathResult.size());
  478. for(uint_fast64_t i = 0; i < pathResult.size(); i++) {
  479. stateMap[i] = pathResult.size()-i-1;
  480. }
  481. Result input(storm::storage::BitVector(pathResult.size(), true), stateMap, pathResult, stateResult);
  482. Result result;
  483. storm::properties::action::SortAction<double> action(storm::properties::action::SortAction<double>::VALUE);
  484. ASSERT_NO_THROW(result = action.evaluate(input, mc));
  485. ASSERT_EQ(6, result.stateMap[0]);
  486. ASSERT_EQ(7, result.stateMap[1]);
  487. ASSERT_EQ(3, result.stateMap[2]);
  488. ASSERT_EQ(4, result.stateMap[3]);
  489. ASSERT_EQ(1, result.stateMap[4]);
  490. ASSERT_EQ(0, result.stateMap[5]);
  491. ASSERT_EQ(2, result.stateMap[6]);
  492. ASSERT_EQ(5, result.stateMap[7]);
  493. }