Browse Source

Merge branch 'future' into jani_support

Former-commit-id: 3ce04a8c05
main
sjunges 10 years ago
parent
commit
621dbbb925
  1. 12
      CMakeLists.txt
  2. 4
      examples/dft/and.dft
  3. 5
      examples/dft/and_param.dft
  4. 4
      examples/dft/be_nonfail.dft
  5. 21
      examples/dft/cardiac.dft
  6. 24
      examples/dft/cas.dft
  7. 22
      examples/dft/cm2.dft
  8. 41
      examples/dft/cm4.dft
  9. 26
      examples/dft/cps.dft
  10. 16
      examples/dft/deathegg.dft
  11. 8
      examples/dft/fdep.dft
  12. 5
      examples/dft/fdep2.dft
  13. 5
      examples/dft/fdep3.dft
  14. 129
      examples/dft/ftpp_complex.dft
  15. 63
      examples/dft/ftpp_large.dft
  16. 53
      examples/dft/ftpp_standard.dft
  17. 22
      examples/dft/mcs.dft
  18. 26
      examples/dft/mdcs.dft
  19. 19
      examples/dft/mdcs2.dft
  20. 7
      examples/dft/mp.dft
  21. 8
      examples/dft/nonmonoton_param.dft
  22. 4
      examples/dft/or.dft
  23. 4
      examples/dft/pand.dft
  24. 6
      examples/dft/pand_param.dft
  25. 12
      examples/dft/pdep.dft
  26. 9
      examples/dft/pdep2.dft
  27. 5
      examples/dft/pdep3.dft
  28. 7
      examples/dft/pdep4.dft
  29. 11
      examples/dft/pdep_symmetry.dft
  30. 5
      examples/dft/por.dft
  31. 5
      examples/dft/seq.dft
  32. 6
      examples/dft/seq2.dft
  33. 6
      examples/dft/seq3.dft
  34. 7
      examples/dft/seq4.dft
  35. 9
      examples/dft/seq5.dft
  36. 5
      examples/dft/spare.dft
  37. 8
      examples/dft/spare2.dft
  38. 10
      examples/dft/spare3.dft
  39. 9
      examples/dft/spare4.dft
  40. 9
      examples/dft/spare5.dft
  41. 7
      examples/dft/spare6.dft
  42. 5
      examples/dft/spare7.dft
  43. 7
      examples/dft/spare8.dft
  44. 5
      examples/dft/spare_cold.dft
  45. 9
      examples/dft/spare_param.dft
  46. 9
      examples/dft/spare_symmetry.dft
  47. 8
      examples/dft/symmetry.dft
  48. 8
      examples/dft/symmetry2.dft
  49. 12
      examples/dft/symmetry3.dft
  50. 12
      examples/dft/symmetry4.dft
  51. 21
      examples/dft/symmetry5.dft
  52. 10
      examples/dft/symmetry_param.dft
  53. 7
      examples/dft/symmetry_shared.dft
  54. 8
      examples/dft/tripple_and1.dft
  55. 8
      examples/dft/tripple_and2.dft
  56. 6
      examples/dft/tripple_and2_c.dft
  57. 7
      examples/dft/tripple_and_c.dft
  58. 9
      examples/dft/tripple_or.dft
  59. 8
      examples/dft/tripple_or2.dft
  60. 6
      examples/dft/tripple_or2_c.dft
  61. 7
      examples/dft/tripple_or_c.dft
  62. 9
      examples/dft/tripple_pand.dft
  63. 8
      examples/dft/tripple_pand2.dft
  64. 6
      examples/dft/tripple_pand2_c.dft
  65. 7
      examples/dft/tripple_pand_c.dft
  66. 5
      examples/dft/voting.dft
  67. 5
      examples/dft/voting2.dft
  68. 14
      src/CMakeLists.txt
  69. 10
      src/adapters/CarlAdapter.h
  70. 4
      src/builder/DdPrismModelBuilder.cpp
  71. 474
      src/builder/ExplicitDFTModelBuilder.cpp
  72. 97
      src/builder/ExplicitDFTModelBuilder.h
  73. 11
      src/builder/ExplicitPrismModelBuilder.cpp
  74. 46
      src/cli/cli.cpp
  75. 27
      src/cli/cli.h
  76. 25
      src/cli/entrypoints.h
  77. 2
      src/counterexamples/MILPMinimalLabelSetGenerator.h
  78. 6
      src/counterexamples/SMTMinimalCommandSetGenerator.h
  79. 2
      src/modelchecker/AbstractModelChecker.cpp
  80. 191
      src/modelchecker/DFTAnalyser.h
  81. 18
      src/modelchecker/csl/SparseCtmcCslModelChecker.cpp
  82. 1
      src/modelchecker/csl/SparseCtmcCslModelChecker.h
  83. 3
      src/modelchecker/csl/SparseMarkovAutomatonCslModelChecker.cpp
  84. 59
      src/modelchecker/csl/helper/SparseCtmcCslHelper.cpp
  85. 6
      src/modelchecker/csl/helper/SparseCtmcCslHelper.h
  86. 54
      src/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp
  87. 4
      src/modelchecker/exploration/ExplorationInformation.cpp
  88. 9
      src/modelchecker/exploration/SparseExplorationModelChecker.cpp
  89. 615
      src/modelchecker/reachability/SparseDtmcEliminationModelChecker.cpp
  90. 106
      src/modelchecker/reachability/SparseDtmcEliminationModelChecker.h
  91. 7
      src/models/sparse/Ctmc.cpp
  92. 14
      src/models/sparse/Ctmc.h
  93. 92
      src/models/sparse/MarkovAutomaton.cpp
  94. 24
      src/models/sparse/MarkovAutomaton.h
  95. 160
      src/parser/DFTGalileoParser.cpp
  96. 44
      src/parser/DFTGalileoParser.h
  97. 4
      src/parser/DeterministicSparseTransitionParser.cpp
  98. 38
      src/parser/ExpressionParser.cpp
  99. 22
      src/parser/ExpressionParser.h
  100. 8
      src/parser/FormulaParser.cpp

12
CMakeLists.txt

@ -18,7 +18,7 @@ include(ExternalProject)
## CMake options of StoRM ## CMake options of StoRM
## ##
############################################################# #############################################################
option(STORM_DEBUG "Sets whether the DEBUG mode is used" ON)
option(STORM_DEVELOPER "Sets whether the development mode is used" OFF)
option(STORM_USE_POPCNT "Sets whether the popcnt instruction is going to be used." ON) option(STORM_USE_POPCNT "Sets whether the popcnt instruction is going to be used." ON)
option(USE_BOOST_STATIC_LIBRARIES "Sets whether the Boost libraries should be linked statically." ON) option(USE_BOOST_STATIC_LIBRARIES "Sets whether the Boost libraries should be linked statically." ON)
option(STORM_USE_INTELTBB "Sets whether the Intel TBB libraries should be used." OFF) option(STORM_USE_INTELTBB "Sets whether the Intel TBB libraries should be used." OFF)
@ -40,11 +40,11 @@ set(MSAT_ROOT "" CACHE STRING "The hint to the root directory of MathSAT (option
set(ADDITIONAL_INCLUDE_DIRS "" CACHE STRING "Additional directories added to the include directories.") set(ADDITIONAL_INCLUDE_DIRS "" CACHE STRING "Additional directories added to the include directories.")
set(ADDITIONAL_LINK_DIRS "" CACHE STRING "Additional directories added to the link directories.") set(ADDITIONAL_LINK_DIRS "" CACHE STRING "Additional directories added to the link directories.")
# If the DEBUG option was turned on, we will target a debug version and a release version otherwise.
if (STORM_DEBUG)
set (CMAKE_BUILD_TYPE "DEBUG")
else()
set (CMAKE_BUILD_TYPE "RELEASE")
# If the STORM_DEVELOPER option was turned on, we will target a debug version.
if (STORM_DEVELOPER)
message(STATUS "StoRM - Using development mode")
set(CMAKE_BUILD_TYPE "DEBUG" CACHE STRING "Set the build type" FORCE)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DSTORM_DEV")
endif() endif()
message(STATUS "StoRM - Building ${CMAKE_BUILD_TYPE} version.") message(STATUS "StoRM - Building ${CMAKE_BUILD_TYPE} version.")

4
examples/dft/and.dft

@ -0,0 +1,4 @@
toplevel "A";
"A" and "B" "C";
"B" lambda=0.5 dorm=0.3;
"C" lambda=0.5 dorm=0.3;

5
examples/dft/and_param.dft

@ -0,0 +1,5 @@
param x;
toplevel "A";
"A" and "B" "C";
"B" lambda=0.5 dorm=0.3;
"C" lambda=x dorm=0.3;

4
examples/dft/be_nonfail.dft

@ -0,0 +1,4 @@
toplevel "A";
"A" and "B" "C";
"B" lambda=0 dorm=0.3;
"C" lambda=0.5 dorm=0.3;

21
examples/dft/cardiac.dft

@ -0,0 +1,21 @@
toplevel "SYSTEM";
"SYSTEM" or "FDEP" "CPU" "MOTOR" "PUMPS";
"FDEP" fdep "TRIGGER" "P" "B";
"TRIGGER" or "CS" "SS";
"CPU" wsp "P" "B";
"MOTOR" or "SWITCH" "MOTORS";
"SWITCH" pand "MS" "MA";
"MOTORS" csp "MA" "MB";
"PUMPS" and "PUMP1" "PUMP2";
"PUMP1" csp "PA" "PS";
"PUMP2" csp "PB" "PS";
"P" lambda=5.0e-5 dorm=0;
"B" lambda=5.0e-5 dorm=0.5;
"CS" lambda=2.0e-5 dorm=0;
"SS" lambda=2.0e-5 dorm=0;
"MS" lambda=1.0e-6 dorm=0;
"MA" lambda=1.0e-4 dorm=0;
"MB" lambda=1.0e-4 dorm=0;
"PA" lambda=1.0e-4 dorm=0;
"PB" lambda=1.0e-4 dorm=0;
"PS" lambda=1.0e-4 dorm=0;

24
examples/dft/cas.dft

@ -0,0 +1,24 @@
toplevel "System";
"System" or "CPUfdep" "CPUunit" "Motorunit" "Pumpunit";
"CPUfdep" fdep "trigger" "P" "B";
"trigger" or "CS" "SS";
"CS" lambda=0.2 dorm=0;
"SS" lambda=0.2 dorm=0;
"CPUunit" wsp "P" "B";
"P" lambda=0.5 dorm=0;
"B" lambda=0.5 dorm=0.5;
"Motorunit" or "MP" "Motors";
"MP" pand "MS" "MA";
"Motors" csp "MA" "MB";
"MS" lambda=0.01 dorm=0;
"MA" lambda=1 dorm=0;
"MB" lambda=1 dorm=0;
"Pumpunit" and "PumpA" "PumpB";
"PumpA" csp "PA" "PS";
"PumpB" csp "PB" "PS";
"PA" lambda=1 dorm=0;
"PB" lambda=1 dorm=0;
"PS" lambda=1 dorm=0;

22
examples/dft/cm2.dft

@ -0,0 +1,22 @@
toplevel "System";
"System" or "BUS" "CM";
"CM" and "CM1" "CM2";
"CM1" or "DISK1" "POWER1" "MEMORY1";
"CM2" or "DISK2" "POWER2" "MEMORY2";
"DISK1" wsp "D11" "D12";
"DISK2" wsp "D21" "D22";
"POWER1" or "P1" "PS";
"POWER2" or "P2" "PS";
"MEMORY1" wsp "M1" "M3";
"MEMORY2" wsp "M2" "M3";
"BUS" lambda=0.0002 dorm=0;
"P1" lambda=0.05 dorm=0;
"P2" lambda=0.05 dorm=0;
"PS" lambda=0.6 dorm=0;
"D11" lambda=8.0 dorm=0;
"D12" lambda=8.0 dorm=0.5;
"D21" lambda=8.0 dorm=0;
"D22" lambda=8.0 dorm=0.5;
"M1" lambda=0.003 dorm=0;
"M2" lambda=0.003 dorm=0;
"M3" lambda=0.003 dorm=0.5;

41
examples/dft/cm4.dft

@ -0,0 +1,41 @@
toplevel "System";
"System" or "BUS" "CM";
"CM" and "CM1" "CM2" "CM3" "CM4";
"CM1" or "DISK1" "POWER1" "MEMORY1";
"CM2" or "DISK2" "POWER2" "MEMORY2";
"CM3" or "DISK3" "POWER3" "MEMORY3";
"CM4" or "DISK4" "POWER4" "MEMORY4";
"DISK1" wsp "D11" "D12";
"DISK2" wsp "D21" "D22";
"DISK3" wsp "D31" "D32";
"DISK4" wsp "D41" "D42";
"POWER1" or "P1" "PS";
"POWER2" or "P2" "PS";
"POWER3" or "P3" "PS2";
"POWER4" or "P4" "PS2";
"MEMORY1" wsp "M1" "M3" "M4";
"MEMORY2" wsp "M2" "M3" "M4";
"MEMORY3" wsp "M31" "M3";
"MEMORY4" wsp "M41" "M4";
"BUS" lambda=0.0002 dorm=0;
"P1" lambda=0.05 dorm=0;
"P2" lambda=0.05 dorm=0;
"P3" lambda=0.05 dorm=0;
"P4" lambda=0.05 dorm=0;
"PS" lambda=0.6 dorm=0;
"PS2" lambda=0.6 dorm=0;
"D11" lambda=8.0 dorm=0;
"D12" lambda=8.0 dorm=0.5;
"D21" lambda=8.0 dorm=0;
"D22" lambda=8.0 dorm=0.5;
"D31" lambda=8.0 dorm=0;
"D32" lambda=8.0 dorm=0.5;
"D41" lambda=8.0 dorm=0;
"D42" lambda=8.0 dorm=0.5;
"M1" lambda=0.003 dorm=0;
"M2" lambda=0.003 dorm=0;
"M31" lambda=0.003 dorm=0;
"M41" lambda=0.003 dorm=0;
"M3" lambda=0.003 dorm=0.5;
"M4" lambda=0.003 dorm=0.5;

26
examples/dft/cps.dft

@ -0,0 +1,26 @@
toplevel "System";
"System" pand "A" "B";
"A" and "AA" "AB" "AC" "AD";
"B" pand "C" "D";
"C" and "CA" "CB" "CC" "CD";
"D" and "DA" "DB" "DC" "DD";
"AA" lambda=1 dorm=0;
"AB" lambda=1 dorm=0;
"AC" lambda=1 dorm=0;
"AD" lambda=1 dorm=0;
"CA" lambda=1 dorm=0;
"CB" lambda=1 dorm=0;
"CC" lambda=1 dorm=0;
"CD" lambda=1 dorm=0;
"DA" lambda=1 dorm=0;
"DB" lambda=1 dorm=0;
"DC" lambda=1 dorm=0;
"DD" lambda=1 dorm=0;

16
examples/dft/deathegg.dft

@ -0,0 +1,16 @@
toplevel "DeathEgg";
"DeathEgg" or "DeathEggProxy" "DeathEggServer" "CampusPowerDependency" "ProxyPowerDependency";
"DeathEggServer" or "CampusNET" "DES_Disks";
"DES_Disks" and "DES_Disks_RAID1" "DES_Disks_RAID2";
"DES_Disks_RAID1" and "DES_Disk_1" "DES_Disk_2";
"DES_Disks_RAID2" and "DES_Disk_3" "DES_Disk_4";
"DeathEggProxy" lambda=0.01 dorm=0;
"DES_Disk_1" lambda=0.01 dorm=0;
"DES_Disk_2" lambda=0.01 dorm=0;
"DES_Disk_3" lambda=0.01 dorm=0;
"DES_Disk_4" lambda=0.01 dorm=0;
"CampusPowerDependency" fdep "CampusPower" "DeathEggServer";
"ProxyPowerDependency" fdep "ProxyPower" "DeathEggProxy";
"CampusPower" lambda=0.01 dorm=0;
"CampusNET" lambda=0.01 dorm=0;
"ProxyPower" lambda=0.01 dorm=0;

8
examples/dft/fdep.dft

@ -0,0 +1,8 @@
toplevel "System";
"System" or "Power" "Machine";
"Power" fdep "B_Power" "P" "B";
"Machine" or "P" "B";
"B_Power" lambda=0.5 dorm=0;
"P" lambda=0.5 dorm=0;
"B" lambda=0.5 dorm=0.5;

5
examples/dft/fdep2.dft

@ -0,0 +1,5 @@
toplevel "A";
"A" and "B" "C";
"F" fdep "B" "C";
"B" lambda=0.5 dorm=0;
"C" lambda=0.5 dorm=0;

5
examples/dft/fdep3.dft

@ -0,0 +1,5 @@
toplevel "A";
"A" and "B" "C" "F";
"F" fdep "B" "C";
"B" lambda=0.4 dorm=0;
"C" lambda=0.8 dorm=0;

129
examples/dft/ftpp_complex.dft

@ -0,0 +1,129 @@
toplevel "System";
"System" or "triadA" "triadB" "triadC" "triadD" "fA" "fB" "fC" "fD";
"triadA" 2of3 "aA" "bA" "cA";
"aA" csp "TAA" "TAS";
"bA" csp "TAB" "TAS";
"cA" csp "TAC" "TAS";
"triadB" 2of3 "aB" "bB" "cB";
"aB" csp "TBA" "TBS";
"bB" csp "TBB" "TBS";
"cB" csp "TBC" "TBS";
"triadC" 2of3 "aC" "bC" "cC";
"aC" csp "TCA" "TCS";
"bC" csp "TCB" "TCS";
"cC" csp "TCC" "TCS";
"triadD" 2of3 "aD" "bD" "cD";
"aD" csp "TDA" "TDS";
"bD" csp "TDB" "TDS";
"cD" csp "TDC" "TDS";
"fA" fdep "NEA" "TAA" "TBA" "TCA" "TDA";
"fB" fdep "NEB" "TAB" "TBB" "TCB" "TDB";
"fC" fdep "NEC" "TAC" "TBC" "TCC" "TDC";
"fD" fdep "NED" "TAS" "TBS" "TCS" "TDS";
"NEA" lambda=0.017 dorm=1;
"NEB" lambda=0.017 dorm=1;
"NEC" lambda=0.017 dorm=1;
"NED" lambda=0.017 dorm=1;
"TAA" or "cpuAA" "memAA";
"memAA" csp "memAA1" "memAA2";
"cpuAA" lambda=0.11 dorm=0;
"memAA1" lambda=0.11 dorm=0;
"memAA2" lambda=0.11 dorm=0;
"TAB" or "cpuAB" "memAB";
"memAB" csp "memAB1" "memAB2";
"cpuAB" lambda=0.11 dorm=0;
"memAB1" lambda=0.11 dorm=0;
"memAB2" lambda=0.11 dorm=0;
"TAC" or "cpuAC" "memAC";
"memAC" csp "memAC1" "memAC2";
"cpuAC" lambda=0.11 dorm=0;
"memAC1" lambda=0.11 dorm=0;
"memAC2" lambda=0.11 dorm=0;
"TAS" or "cpuAS" "memAS";
"memAS" csp "memAS1" "memAS2";
"cpuAS" lambda=0.11 dorm=0;
"memAS1" lambda=0.11 dorm=0;
"memAS2" lambda=0.11 dorm=0;
"TBA" or "cpuBA" "memBA";
"memBA" csp "memBA1" "memBA2";
"cpuBA" lambda=0.11 dorm=0;
"memBA1" lambda=0.11 dorm=0;
"memBA2" lambda=0.11 dorm=0;
"TBB" or "cpuBB" "memBB";
"memBB" csp "memBB1" "memBB2";
"cpuBB" lambda=0.11 dorm=0;
"memBB1" lambda=0.11 dorm=0;
"memBB2" lambda=0.11 dorm=0;
"TBC" or "cpuBC" "memBC";
"memBC" csp "memBC1" "memBC2";
"cpuBC" lambda=0.11 dorm=0;
"memBC1" lambda=0.11 dorm=0;
"memBC2" lambda=0.11 dorm=0;
"TBS" or "cpuBS" "memBS";
"memBS" csp "memBS1" "memBS2";
"cpuBS" lambda=0.11 dorm=0;
"memBS1" lambda=0.11 dorm=0;
"memBS2" lambda=0.11 dorm=0;
"TCA" or "cpuCA" "memCA";
"memCA" csp "memCA1" "memCA2";
"cpuCA" lambda=0.11 dorm=0;
"memCA1" lambda=0.11 dorm=0;
"memCA2" lambda=0.11 dorm=0;
"TCB" or "cpuCB" "memCB";
"memCB" csp "memCB1" "memCB2";
"cpuCB" lambda=0.11 dorm=0;
"memCB1" lambda=0.11 dorm=0;
"memCB2" lambda=0.11 dorm=0;
"TCC" or "cpuCC" "memCC";
"memCC" csp "memCC1" "memCC2";
"cpuCC" lambda=0.11 dorm=0;
"memCC1" lambda=0.11 dorm=0;
"memCC2" lambda=0.11 dorm=0;
"TCS" or "cpuCS" "memCS";
"memCS" csp "memCS1" "memCS2";
"cpuCS" lambda=0.11 dorm=0;
"memCS1" lambda=0.11 dorm=0;
"memCS2" lambda=0.11 dorm=0;
"TDA" or "cpuDA" "memDA";
"memDA" csp "memDA1" "memDA2";
"cpuDA" lambda=0.11 dorm=0;
"memDA1" lambda=0.11 dorm=0;
"memDA2" lambda=0.11 dorm=0;
"TDB" or "cpuDB" "memDB";
"memDB" csp "memDB1" "memDB2";
"cpuDB" lambda=0.11 dorm=0;
"memDB1" lambda=0.11 dorm=0;
"memDB2" lambda=0.11 dorm=0;
"TDC" or "cpuDC" "memDC";
"memDC" csp "memDC1" "memDC2";
"cpuDC" lambda=0.11 dorm=0;
"memDC1" lambda=0.11 dorm=0;
"memDC2" lambda=0.11 dorm=0;
"TDS" or "cpuDS" "memDS";
"memDS" csp "memDS1" "memDS2";
"cpuDS" lambda=0.11 dorm=0;
"memDS1" lambda=0.11 dorm=0;
"memDS2" lambda=0.11 dorm=0;

63
examples/dft/ftpp_large.dft

@ -0,0 +1,63 @@
toplevel "System";
"System" or "triadA" "triadB" "triadC" "triadD" "fA" "fB" "fC" "fD" "fE";
"triadA" 3of4 "aA" "bA" "cA" "dA";
"aA" csp "TAA" "TAS";
"bA" csp "TAB" "TAS";
"cA" csp "TAC" "TAS";
"dA" csp "TAD" "TAS";
"triadB" 3of4 "aB" "bB" "cB" "dB";
"aB" csp "TBA" "TBS";
"bB" csp "TBB" "TBS";
"cB" csp "TBC" "TBS";
"dB" csp "TBD" "TBS";
"triadC" 3of4 "aC" "bC" "cC" "dC";
"aC" csp "TCA" "TCS";
"bC" csp "TCB" "TCS";
"cC" csp "TCC" "TCS";
"dC" csp "TCD" "TCS";
"triadD" 3of4 "aD" "bD" "cD" "dD";
"aD" csp "TDA" "TDS";
"bD" csp "TDB" "TDS";
"cD" csp "TDC" "TDS";
"dD" csp "TDD" "TDS";
"fA" fdep "NEA" "TAA" "TBA" "TCA" "TDA";
"fB" fdep "NEB" "TAB" "TBB" "TCB" "TDB";
"fC" fdep "NEC" "TAC" "TBC" "TCC" "TDC";
"fD" fdep "NED" "TAD" "TBD" "TCD" "TDD";
"fE" fdep "NEE" "TAS" "TBS" "TCS" "TDS";
"NEA" lambda=0.017 dorm=1;
"NEB" lambda=0.017 dorm=1;
"NEC" lambda=0.017 dorm=1;
"NED" lambda=0.017 dorm=1;
"NEE" lambda=0.017 dorm=1;
"TAA" lambda=0.11 dorm=0;
"TAB" lambda=0.11 dorm=0;
"TAC" lambda=0.11 dorm=0;
"TAD" lambda=0.11 dorm=0;
"TAS" lambda=0.11 dorm=0;
"TBA" lambda=0.11 dorm=0;
"TBB" lambda=0.11 dorm=0;
"TBC" lambda=0.11 dorm=0;
"TBD" lambda=0.11 dorm=0;
"TBS" lambda=0.11 dorm=0;
"TCA" lambda=0.11 dorm=0;
"TCB" lambda=0.11 dorm=0;
"TCC" lambda=0.11 dorm=0;
"TCD" lambda=0.11 dorm=0;
"TCS" lambda=0.11 dorm=0;
"TDA" lambda=0.11 dorm=0;
"TDB" lambda=0.11 dorm=0;
"TDC" lambda=0.11 dorm=0;
"TDD" lambda=0.11 dorm=0;
"TDS" lambda=0.11 dorm=0;

53
examples/dft/ftpp_standard.dft

@ -0,0 +1,53 @@
toplevel "System";
"System" or "triadA" "triadB" "triadC" "triadD" "fA" "fB" "fC" "fD";
"triadA" 2of3 "aA" "bA" "cA";
"aA" csp "TAA" "TAS";
"bA" csp "TAB" "TAS";
"cA" csp "TAC" "TAS";
"triadB" 2of3 "aB" "bB" "cB";
"aB" csp "TBA" "TBS";
"bB" csp "TBB" "TBS";
"cB" csp "TBC" "TBS";
"triadC" 2of3 "aC" "bC" "cC";
"aC" csp "TCA" "TCS";
"bC" csp "TCB" "TCS";
"cC" csp "TCC" "TCS";
"triadD" 2of3 "aD" "bD" "cD";
"aD" csp "TDA" "TDS";
"bD" csp "TDB" "TDS";
"cD" csp "TDC" "TDS";
"fA" fdep "NEA" "TAA" "TBA" "TCA" "TDA";
"fB" fdep "NEB" "TAB" "TBB" "TCB" "TDB";
"fC" fdep "NEC" "TAC" "TBC" "TCC" "TDC";
"fD" fdep "NED" "TAS" "TBS" "TCS" "TDS";
"NEA" lambda=0.017 dorm=1;
"NEB" lambda=0.017 dorm=1;
"NEC" lambda=0.017 dorm=1;
"NED" lambda=0.017 dorm=1;
"TAA" lambda=0.11 dorm=0;
"TAB" lambda=0.11 dorm=0;
"TAC" lambda=0.11 dorm=0;
"TAS" lambda=0.11 dorm=0;
"TBA" lambda=0.11 dorm=0;
"TBB" lambda=0.11 dorm=0;
"TBC" lambda=0.11 dorm=0;
"TBS" lambda=0.11 dorm=0;
"TCA" lambda=0.11 dorm=0;
"TCB" lambda=0.11 dorm=0;
"TCC" lambda=0.11 dorm=0;
"TCS" lambda=0.11 dorm=0;
"TDA" lambda=0.11 dorm=0;
"TDB" lambda=0.11 dorm=0;
"TDC" lambda=0.11 dorm=0;
"TDS" lambda=0.11 dorm=0;

22
examples/dft/mcs.dft

@ -0,0 +1,22 @@
toplevel "n12";
"n12" or "n1" "n103" "n7";
"n103" wsp "n106" "n14";
"n7" and "n18" "n26";
"n26" or "n28" "n19" "n23";
"n19" wsp "n16" "n13";
"n23" wsp "n0" "n17";
"n18" or "n15" "n9" "n3";
"n3" wsp "n2" "n17";
"n9" wsp "n8" "n27";
"n16" lambda=8.0 dorm=0.0;
"n0" lambda=0.003 dorm=0.0;
"n13" lambda=8.0 dorm=0.5;
"n2" lambda=0.003 dorm=0.0;
"n17" lambda=0.003 dorm=0.5;
"n15" lambda=0.05 dorm=0.0;
"n106" lambda=1.2 dorm=0.0;
"n14" lambda=0.6 dorm=0.0;
"n1" lambda=2.0E-4 dorm=0.0;
"n27" lambda=8.0 dorm=0.5;
"n8" lambda=8.0 dorm=0.0;
"n28" lambda=0.05 dorm=0.0;

26
examples/dft/mdcs.dft

@ -0,0 +1,26 @@
toplevel "System";
"System" or "S" "N";
"N" lambda=2e-5 dorm=0;
"S" and "CMA" "CMB";
"CMA" or "DiskA" "PA" "MemA";
"DiskA" wsp "DAA" "DAB";
"PA" lambda=500e-5 dorm=0;
"MemA" wsp "MA" "MC";
"DAA" lambda=80000e-5 dorm=0.5;
"DAB" lambda=80000e-5 dorm=0.5;
"MA" lambda=30e-5 dorm=0;
"CMB" or "DiskB" "PB" "MemB";
"DiskB" wsp "DBA" "DBB";
"PB" lambda=500e-5 dorm=0;
"MemB" wsp "MB" "MC";
"DBA" lambda=80000e-5 dorm=0.5;
"DBB" lambda=80000e-5 dorm=0.5;
"MB" lambda=30e-5 dorm=0;
"MC" lambda=30e-5 dorm=0.5;

19
examples/dft/mdcs2.dft

@ -0,0 +1,19 @@
toplevel "System";
"System" or "S" "N";
"N" lambda=0.0000200000 dorm=0.0000000000;
"S" and "CMA" "CMB";
"CMA" or "DiskA" "PA" "MemA";
"DiskA" wsp "DAA" "DAB";
"PA" lambda=0.0049999999 dorm=0.0000000000;
"MemA" wsp "MA" "MC";
"DAA" lambda=0.8000000119 dorm=0.5000000000;
"DAB" lambda=0.8000000119 dorm=0.5000000000;
"MA" lambda=0.0003000000 dorm=0.0000000000;
"CMB" or "DiskB" "PB" "MemB";
"DiskB" wsp "DBA" "DBB";
"PB" lambda=0.0049999999 dorm=0.0000000000;
"MemB" wsp "MB" "MC";
"DBA" lambda=0.8000000119 dorm=0.5000000000;
"DBB" lambda=0.8000000119 dorm=0.5000000000;
"MB" lambda=0.0003000000 dorm=0.0000000000;
"MC" lambda=0.0003000000 dorm=0.5000000000;

7
examples/dft/mp.dft

@ -0,0 +1,7 @@
toplevel "A";
"A" or "B" "C";
"B" or "D" "E";
"C" or "F" "E";
"D" lambda=0.1 dorm=0;
"E" lambda=0.2 dorm=0;
"F" lambda=0.3 dorm=0;

8
examples/dft/nonmonoton_param.dft

@ -0,0 +1,8 @@
param x;
param y;
toplevel "A";
"A" or "B" "Z";
"B" pand "D" "S";
"Z" lambda=y dorm=0;
"D" lambda=100 dorm=0;
"S" lambda=100*x dorm=0;

4
examples/dft/or.dft

@ -0,0 +1,4 @@
toplevel "A";
"A" or "B" "C";
"B" lambda=0.5 dorm=0.3;
"C" lambda=0.5 dorm=0.3;

4
examples/dft/pand.dft

@ -0,0 +1,4 @@
toplevel "A";
"A" pand "B" "C";
"B" lambda=0.4 dorm=0.3;
"C" lambda=0.2 dorm=0.3;

6
examples/dft/pand_param.dft

@ -0,0 +1,6 @@
param x;
param y;
toplevel "A";
"A" pand "B" "C";
"B" lambda=x dorm=0.3;
"C" lambda=y dorm=0.3;

12
examples/dft/pdep.dft

@ -0,0 +1,12 @@
// From Junges2015
// Example 3.19
toplevel "SF";
"SF" or "A" "B" "PDEP";
"A" pand "S" "MA";
"B" and "MA" "MB";
"PDEP" pdep=0.2 "MA" "S";
"S" lambda=0.5 dorm=0;
"MA" lambda=0.5 dorm=0;
"MB" lambda=0.5 dorm=0;

9
examples/dft/pdep2.dft

@ -0,0 +1,9 @@
toplevel "SF";
"SF" or "A" "B" "PDEP";
"A" pand "S" "MA";
"B" and "MA" "MB";
"PDEP" pdep=0.2 "MA" "S" "MB";
"S" lambda=0.5 dorm=0;
"MA" lambda=0.5 dorm=0;
"MB" lambda=0.5 dorm=0;

5
examples/dft/pdep3.dft

@ -0,0 +1,5 @@
toplevel "A";
"A" and "B" "C" "F";
"F" pdep=0.3 "B" "C";
"B" lambda=0.4 dorm=0;
"C" lambda=0.8 dorm=0;

7
examples/dft/pdep4.dft

@ -0,0 +1,7 @@
toplevel "SF";
"SF" pand "S" "A" "B";
"PDEP" pdep=0.2 "S" "A" "B";
"S" lambda=0.5 dorm=0;
"A" lambda=0.5 dorm=0;
"B" lambda=0.5 dorm=0;

11
examples/dft/pdep_symmetry.dft

@ -0,0 +1,11 @@
toplevel "A";
"A" and "B" "B'";
"B" and "C" "D" "PDEP";
"B'" and "C'" "D'" "PDEP'";
"PDEP" pdep=0.6 "C" "D";
"PDEP'" pdep=0.6 "C'" "D'";
"C" lambda=0.5 dorm=0;
"D" lambda=0.5 dorm=0;
"C'" lambda=0.5 dorm=0;
"D'" lambda=0.5 dorm=0;

5
examples/dft/por.dft

@ -0,0 +1,5 @@
toplevel "A";
"A" por "B" "C" "D";
"B" lambda=0.4 dorm=0.0;
"C" lambda=0.2 dorm=0.0;
"D" lambda=0.2 dorm=0.0;

5
examples/dft/seq.dft

@ -0,0 +1,5 @@
toplevel "A";
"A" and "B" "C";
"X" seq "B" "C"
"B" lambda=0.5 dorm=0.3;
"C" lambda=0.5 dorm=0.3;

6
examples/dft/seq2.dft

@ -0,0 +1,6 @@
toplevel "A";
"A" and "B" "C" "D";
"X" seq "B" "C" "D";
"B" lambda=0.5 dorm=0.3;
"C" lambda=0.5 dorm=0.3;
"D" lambda=0.5 dorm=0.3;

6
examples/dft/seq3.dft

@ -0,0 +1,6 @@
toplevel "A";
"A" and "C" "D";
"X" seq "B" "C" "D";
"B" lambda=0.5 dorm=0.3;
"C" lambda=0.5 dorm=0.3;
"D" lambda=0.5 dorm=0.3;

7
examples/dft/seq4.dft

@ -0,0 +1,7 @@
toplevel "A";
"A" and "T1" "B3";
"T1" or "B1" "B2";
"X" seq "B1" "B2" "B3";
"B1" lambda=0.5 dorm=0.3;
"B2" lambda=0.5 dorm=0.3;
"B3" lambda=0.5 dorm=0.3;

9
examples/dft/seq5.dft

@ -0,0 +1,9 @@
toplevel "A";
"A" and "T1" "T2";
"T1" pand "B1" "B2";
"T2" pand "B3" "B4";
"X" seq "B4" "B3";
"B1" lambda=0.7 dorm=0.3;
"B2" lambda=0.5 dorm=0.3;
"B3" lambda=0.5 dorm=0.3;
"B4" lambda=0.7 dorm=0.3;

5
examples/dft/spare.dft

@ -0,0 +1,5 @@
toplevel "A";
"A" wsp "I" "M";
"I" lambda=0.5 dorm=0.3;
"M" lambda=0.5 dorm=0.3;

8
examples/dft/spare2.dft

@ -0,0 +1,8 @@
toplevel "A";
"A" or "B" "C";
"B" wsp "I" "J";
"C" wsp "M" "J";
"I" lambda=0.5 dorm=0.3;
"J" lambda=0.5 dorm=0.3;
"M" lambda=0.5 dorm=0.3;

10
examples/dft/spare3.dft

@ -0,0 +1,10 @@
toplevel "A";
"A" or "B" "C" "D";
"B" wsp "I" "M";
"C" wsp "J" "M";
"D" wsp "K" "M";
"I" lambda=0.5 dorm=0.3;
"J" lambda=0.5 dorm=0.3;
"K" lambda=0.5 dorm=0.3;
"M" lambda=0.5 dorm=0.3;

9
examples/dft/spare4.dft

@ -0,0 +1,9 @@
toplevel "A";
"A" and "B" "C";
"B" wsp "I" "J" "K";
"C" wsp "M" "J";
"I" lambda=0.5 dorm=0.3;
"J" lambda=0.5 dorm=0.3;
"K" lambda=0.5 dorm=0.3;
"M" lambda=0.5 dorm=0.3;

9
examples/dft/spare5.dft

@ -0,0 +1,9 @@
toplevel "A";
"A" wsp "I" "B";
"B" or "C" "J";
"C" or "K" "L";
"I" lambda=0.5 dorm=0;
"J" lambda=0.5 dorm=0;
"K" lambda=0.5 dorm=0;
"L" lambda=0.5 dorm=0;

7
examples/dft/spare6.dft

@ -0,0 +1,7 @@
toplevel "A";
"A" or "I" "B";
"B" wsp "J" "M";
"I" lambda=0.5 dorm=0.5;
"J" lambda=0.5 dorm=0.5;
"M" lambda=0.5 dorm=0.5;

5
examples/dft/spare7.dft

@ -0,0 +1,5 @@
toplevel "A";
"A" wsp "K" "J" "I";
"I" lambda=0.5 dorm=0.5;
"J" lambda=1 dorm=0.5;
"K" lambda=0.5 dorm=0.5;

7
examples/dft/spare8.dft

@ -0,0 +1,7 @@
toplevel "A";
"A" wsp "I" "B";
"B" wsp "J" "K";
"I" lambda=0.5 dorm=0.3;
"J" lambda=0.5 dorm=0.3;
"K" lambda=0.5 dorm=0.3;

5
examples/dft/spare_cold.dft

@ -0,0 +1,5 @@
toplevel "A";
"A" wsp "I" "M";
"I" lambda=0.5 dorm=0.0;
"M" lambda=0.5 dorm=0.0;

9
examples/dft/spare_param.dft

@ -0,0 +1,9 @@
param x;
param y;
toplevel "SF";
"SF" or "FW" "BW";
"FW" wsp "W1" "WS";
"BW" wsp "W2" "WS";
"W1" lambda=x dorm=0;
"W2" lambda=1 dorm=0;
"WS" lambda=y dorm=0;

9
examples/dft/spare_symmetry.dft

@ -0,0 +1,9 @@
toplevel "A";
"A" and "B" "C";
"B" wsp "I" "J";
"C" wsp "K" "L";
"I" lambda=0.5 dorm=0.3;
"J" lambda=0.5 dorm=0.3;
"K" lambda=0.5 dorm=0.3;
"L" lambda=0.5 dorm=0.3;

8
examples/dft/symmetry.dft

@ -0,0 +1,8 @@
toplevel "A";
"A" and "B" "B'";
"B" and "C" "D";
"B'" and "C'" "D'";
"C" lambda=0.5 dorm=0;
"D" lambda=0.5 dorm=0;
"C'" lambda=0.5 dorm=0;
"D'" lambda=0.5 dorm=0;

8
examples/dft/symmetry2.dft

@ -0,0 +1,8 @@
toplevel "A";
"A" and "B" "B'";
"B" and "C" "D";
"B'" and "C'" "D'";
"C" lambda=0.5 dorm=0;
"D" lambda=2 dorm=0;
"C'" lambda=0.5 dorm=0;
"D'" lambda=2 dorm=0;

12
examples/dft/symmetry3.dft

@ -0,0 +1,12 @@
toplevel "A";
"A" and "B" "B'" "B''";
"B" and "C" "D";
"B'" and "C'" "D'";
"B''" and "C''" "D''";
"C" lambda=0.5 dorm=0;
"D" lambda=0.5 dorm=0;
"C'" lambda=0.5 dorm=0;
"D'" lambda=0.5 dorm=0;
"C''" lambda=0.5 dorm=0;
"D''" lambda=0.5 dorm=0;

12
examples/dft/symmetry4.dft

@ -0,0 +1,12 @@
toplevel "A";
"A" and "B" "B'" "C" "C'";
"B" and "D" "E";
"B'" and "D'" "E'";
"C" or "F";
"C'" or "F'";
"D" lambda=0.5 dorm=0;
"E" lambda=0.5 dorm=0;
"D'" lambda=0.5 dorm=0;
"E'" lambda=0.5 dorm=0;
"F" lambda=0.5 dorm=0;
"F'" lambda=0.5 dorm=0;

21
examples/dft/symmetry5.dft

@ -0,0 +1,21 @@
toplevel "A";
"A" and "BA" "BB" "BC" "BD" "BE" "BF";
"BA" and "CA" "DA";
"BB" and "CB" "DB";
"BC" and "CC" "DC";
"BD" and "CD" "DD";
"BE" and "CE" "DE";
"BF" and "CF" "DF";
"CA" lambda=0.5 dorm=0;
"DA" lambda=0.5 dorm=0;
"CB" lambda=0.5 dorm=0;
"DB" lambda=0.5 dorm=0;
"CC" lambda=0.5 dorm=0;
"DC" lambda=0.5 dorm=0;
"CD" lambda=0.5 dorm=0;
"DD" lambda=0.5 dorm=0;
"CE" lambda=0.5 dorm=0;
"DE" lambda=0.5 dorm=0;
"CF" lambda=0.5 dorm=0;
"DF" lambda=0.5 dorm=0;

10
examples/dft/symmetry_param.dft

@ -0,0 +1,10 @@
param x;
param y;
toplevel "A";
"A" and "B" "B'";
"B" and "C" "D";
"B'" and "C'" "D'";
"C" lambda=x dorm=0;
"D" lambda=y dorm=0;
"C'" lambda=x dorm=0;
"D'" lambda=y dorm=0;

7
examples/dft/symmetry_shared.dft

@ -0,0 +1,7 @@
toplevel "A";
"A" and "B" "B'";
"B" wsp "C" "D";
"B'" wsp "C'" "D";
"C" lambda=0.5 dorm=0;
"D" lambda=0.5 dorm=0;
"C'" lambda=0.5 dorm=0;

8
examples/dft/tripple_and1.dft

@ -0,0 +1,8 @@
toplevel "A";
"A" and "B" "C";
"B" and "BE1" "BE2";
"C" and "BE3" "BE4";
"BE1" lambda=0.5 dorm=0.3;
"BE2" lambda=0.5 dorm=0.3;
"BE3" lambda=0.5 dorm=0.3;
"BE4" lambda=0.5 dorm=0.3;

8
examples/dft/tripple_and2.dft

@ -0,0 +1,8 @@
toplevel "A";
"A" and "B" "C";
"B" and "BE1" "BE2";
"C" and "BE2" "BE3";
"BE1" lambda=0.5 dorm=0.3;
"BE2" lambda=0.5 dorm=0.3;
"BE3" lambda=0.5 dorm=0.3;

6
examples/dft/tripple_and2_c.dft

@ -0,0 +1,6 @@
toplevel "A";
"A" and "BE1" "BE2" "BE3";
"BE1" lambda=0.5 dorm=3;
"BE2" lambda=0.5 dorm=3;
"BE3" lambda=0.5 dorm=3;

7
examples/dft/tripple_and_c.dft

@ -0,0 +1,7 @@
toplevel "A";
"A" and "BE1" "BE2" "BE3" "BE4";
"BE1" lambda=0.5 dorm=3;
"BE2" lambda=0.5 dorm=3;
"BE3" lambda=0.5 dorm=3;
"BE4" lambda=0.5 dorm=3;

9
examples/dft/tripple_or.dft

@ -0,0 +1,9 @@
toplevel "A";
"A" or "B" "C";
"B" or "BE1" "BE2";
"C" or "BE3" "BE4";
"BE1" lambda=0.5 dorm=3;
"BE2" lambda=0.5 dorm=3;
"BE3" lambda=0.5 dorm=3;
"BE4" lambda=0.5 dorm=3;

8
examples/dft/tripple_or2.dft

@ -0,0 +1,8 @@
toplevel "A";
"A" or "B" "C";
"B" or "BE1" "BE2";
"C" or "BE2" "BE3";
"BE1" lambda=0.5 dorm=3;
"BE2" lambda=0.5 dorm=3;
"BE3" lambda=0.5 dorm=3;

6
examples/dft/tripple_or2_c.dft

@ -0,0 +1,6 @@
toplevel "A";
"A" or "BE1" "BE2" "BE3";
"BE1" lambda=0.5 dorm=3;
"BE2" lambda=0.5 dorm=3;
"BE3" lambda=0.5 dorm=3;

7
examples/dft/tripple_or_c.dft

@ -0,0 +1,7 @@
toplevel "A";
"A" or "BE1" "BE2" "BE3" "BE4";
"BE1" lambda=0.5 dorm=3;
"BE2" lambda=0.5 dorm=3;
"BE3" lambda=0.5 dorm=3;
"BE4" lambda=0.5 dorm=3;

9
examples/dft/tripple_pand.dft

@ -0,0 +1,9 @@
toplevel "A";
"A" pand "B" "BE4";
"B" pand "C" "BE3";
"C" pand "BE1" "BE2";
"BE1" lambda=0.5 dorm=3;
"BE2" lambda=0.5 dorm=3;
"BE3" lambda=0.5 dorm=3;
"BE4" lambda=0.5 dorm=3;

8
examples/dft/tripple_pand2.dft

@ -0,0 +1,8 @@
toplevel "A";
"A" pand "B" "C";
"B" pand "BE1" "BE2";
"C" pand "BE2" "BE3";
"BE1" lambda=0.5 dorm=3;
"BE2" lambda=0.5 dorm=3;
"BE3" lambda=0.5 dorm=3;

6
examples/dft/tripple_pand2_c.dft

@ -0,0 +1,6 @@
toplevel "A";
"A" pand "BE1" "BE2" "BE3";
"BE1" lambda=0.5 dorm=3;
"BE2" lambda=0.5 dorm=3;
"BE3" lambda=0.5 dorm=3;

7
examples/dft/tripple_pand_c.dft

@ -0,0 +1,7 @@
toplevel "A";
"A" pand "BE1" "BE2" "BE3" "BE4";
"BE1" lambda=0.5 dorm=3;
"BE2" lambda=0.5 dorm=3;
"BE3" lambda=0.5 dorm=3;
"BE4" lambda=0.5 dorm=3;

5
examples/dft/voting.dft

@ -0,0 +1,5 @@
toplevel "A";
"A" 1of3 "B" "C" "D";
"B" lambda=0.1 dorm=0;
"C" lambda=0.2 dorm=0;
"D" lambda=0.3 dorm=0;

5
examples/dft/voting2.dft

@ -0,0 +1,5 @@
toplevel "A";
"A" 1of3 "B" "C" "D";
"B" lambda=0.3 dorm=0;
"C" lambda=0.4 dorm=0;
"D" lambda=1 dorm=0;

14
src/CMakeLists.txt

@ -9,6 +9,7 @@ file(GLOB_RECURSE STORM_HEADERS_CLI ${PROJECT_SOURCE_DIR}/src/cli/*.h)
file(GLOB_RECURSE STORM_SOURCES_WITHOUT_MAIN ${PROJECT_SOURCE_DIR}/src/*/*.cpp) file(GLOB_RECURSE STORM_SOURCES_WITHOUT_MAIN ${PROJECT_SOURCE_DIR}/src/*/*.cpp)
file(GLOB_RECURSE STORM_SOURCES_CLI ${PROJECT_SOURCE_DIR}/src/cli/*.cpp) file(GLOB_RECURSE STORM_SOURCES_CLI ${PROJECT_SOURCE_DIR}/src/cli/*.cpp)
file(GLOB_RECURSE STORM_MAIN_FILE ${PROJECT_SOURCE_DIR}/src/storm.cpp) file(GLOB_RECURSE STORM_MAIN_FILE ${PROJECT_SOURCE_DIR}/src/storm.cpp)
file(GLOB_RECURSE STORM_DFT_MAIN_FILE ${PROJECT_SOURCE_DIR}/src/storm-dyftee.cpp)
file(GLOB_RECURSE STORM_ADAPTERS_FILES ${PROJECT_SOURCE_DIR}/src/adapters/*.h ${PROJECT_SOURCE_DIR}/src/adapters/*.cpp) file(GLOB_RECURSE STORM_ADAPTERS_FILES ${PROJECT_SOURCE_DIR}/src/adapters/*.h ${PROJECT_SOURCE_DIR}/src/adapters/*.cpp)
file(GLOB_RECURSE STORM_BUILDER_FILES ${PROJECT_SOURCE_DIR}/src/builder/*.h ${PROJECT_SOURCE_DIR}/src/builder/*.cpp) file(GLOB_RECURSE STORM_BUILDER_FILES ${PROJECT_SOURCE_DIR}/src/builder/*.h ${PROJECT_SOURCE_DIR}/src/builder/*.cpp)
file(GLOB_RECURSE STORM_GENERATOR_FILES ${PROJECT_SOURCE_DIR}/src/generator/*.h ${PROJECT_SOURCE_DIR}/src/generator/*.cpp) file(GLOB_RECURSE STORM_GENERATOR_FILES ${PROJECT_SOURCE_DIR}/src/generator/*.h ${PROJECT_SOURCE_DIR}/src/generator/*.cpp)
@ -33,10 +34,13 @@ file(GLOB STORM_PARSER_FILES ${PROJECT_SOURCE_DIR}/src/parser/*.h ${PROJECT_SOUR
file(GLOB_RECURSE STORM_PARSER_PRISMPARSER_FILES ${PROJECT_SOURCE_DIR}/src/parser/prismparser/*.h ${PROJECT_SOURCE_DIR}/src/parser/prismparser/*.cpp) file(GLOB_RECURSE STORM_PARSER_PRISMPARSER_FILES ${PROJECT_SOURCE_DIR}/src/parser/prismparser/*.h ${PROJECT_SOURCE_DIR}/src/parser/prismparser/*.cpp)
file(GLOB STORM_SETTINGS_FILES ${PROJECT_SOURCE_DIR}/src/settings/*.h ${PROJECT_SOURCE_DIR}/src/settings/*.cpp) file(GLOB STORM_SETTINGS_FILES ${PROJECT_SOURCE_DIR}/src/settings/*.h ${PROJECT_SOURCE_DIR}/src/settings/*.cpp)
file(GLOB STORM_SETTINGS_MODULES_FILES ${PROJECT_SOURCE_DIR}/src/settings/modules/*.h ${PROJECT_SOURCE_DIR}/src/settings/modules/*.cpp) file(GLOB STORM_SETTINGS_MODULES_FILES ${PROJECT_SOURCE_DIR}/src/settings/modules/*.h ${PROJECT_SOURCE_DIR}/src/settings/modules/*.cpp)
file(GLOB_RECURSE STORM_SOLVER_FILES ${PROJECT_SOURCE_DIR}/src/solver/*.h ${PROJECT_SOURCE_DIR}/src/solver/*.cpp)
file(GLOB STORM_SOLVER_FILES ${PROJECT_SOURCE_DIR}/src/solver/*.h ${PROJECT_SOURCE_DIR}/src/solver/*.cpp)
file(GLOB STORM_SOLVER_STATEELIMINATION_FILES ${PROJECT_SOURCE_DIR}/src/solver/stateelimination/*.h ${PROJECT_SOURCE_DIR}/src/solver/stateelimination/*.cpp)
file(GLOB STORM_STORAGE_FILES ${PROJECT_SOURCE_DIR}/src/storage/*.h ${PROJECT_SOURCE_DIR}/src/storage/*.cpp) file(GLOB STORM_STORAGE_FILES ${PROJECT_SOURCE_DIR}/src/storage/*.h ${PROJECT_SOURCE_DIR}/src/storage/*.cpp)
file(GLOB STORM_STORAGE_BISIMULATION_FILES ${PROJECT_SOURCE_DIR}/src/storage/bisimulation/*.h ${PROJECT_SOURCE_DIR}/src/storage/bisimulation/*.cpp) file(GLOB STORM_STORAGE_BISIMULATION_FILES ${PROJECT_SOURCE_DIR}/src/storage/bisimulation/*.h ${PROJECT_SOURCE_DIR}/src/storage/bisimulation/*.cpp)
file(GLOB STORM_STORAGE_DD_FILES ${PROJECT_SOURCE_DIR}/src/storage/dd/*.h ${PROJECT_SOURCE_DIR}/src/storage/dd/*.cpp) file(GLOB STORM_STORAGE_DD_FILES ${PROJECT_SOURCE_DIR}/src/storage/dd/*.h ${PROJECT_SOURCE_DIR}/src/storage/dd/*.cpp)
file(GLOB STORM_STORAGE_DFT_FILES ${PROJECT_SOURCE_DIR}/src/storage/dft/*.h ${PROJECT_SOURCE_DIR}/src/storage/dft/*.cpp)
file(GLOB STORM_STORAGE_DFT_ELEMENTS_FILES ${PROJECT_SOURCE_DIR}/src/storage/dft/elements/*.h ${PROJECT_SOURCE_DIR}/src/storage/dft/elements/*.cpp)
file(GLOB_RECURSE STORM_STORAGE_DD_CUDD_FILES ${PROJECT_SOURCE_DIR}/src/storage/dd/cudd/*.h ${PROJECT_SOURCE_DIR}/src/storage/dd/cudd/*.cpp) file(GLOB_RECURSE STORM_STORAGE_DD_CUDD_FILES ${PROJECT_SOURCE_DIR}/src/storage/dd/cudd/*.h ${PROJECT_SOURCE_DIR}/src/storage/dd/cudd/*.cpp)
file(GLOB_RECURSE STORM_STORAGE_DD_SYLVAN_FILES ${PROJECT_SOURCE_DIR}/src/storage/dd/sylvan/*.h ${PROJECT_SOURCE_DIR}/src/storage/dd/sylvan/*.cpp) file(GLOB_RECURSE STORM_STORAGE_DD_SYLVAN_FILES ${PROJECT_SOURCE_DIR}/src/storage/dd/sylvan/*.h ${PROJECT_SOURCE_DIR}/src/storage/dd/sylvan/*.cpp)
file(GLOB_RECURSE STORM_STORAGE_EXPRESSIONS_FILES ${PROJECT_SOURCE_DIR}/src/storage/expressions/*.h ${PROJECT_SOURCE_DIR}/src/storage/expressions/*.cpp) file(GLOB_RECURSE STORM_STORAGE_EXPRESSIONS_FILES ${PROJECT_SOURCE_DIR}/src/storage/expressions/*.h ${PROJECT_SOURCE_DIR}/src/storage/expressions/*.cpp)
@ -53,10 +57,12 @@ list(REMOVE_ITEM STORM_LIB_SOURCES ${STORM_SOURCES_CLI})
set(STORM_LIB_HEADERS ${STORM_HEADERS}) set(STORM_LIB_HEADERS ${STORM_HEADERS})
list(REMOVE_ITEM STORM_LIB_HEADERS ${STORM_HEADERS_CLI}) list(REMOVE_ITEM STORM_LIB_HEADERS ${STORM_HEADERS_CLI})
set(STORM_MAIN_SOURCES ${STORM_SOURCES_CLI} ${STORM_MAIN_FILE}) set(STORM_MAIN_SOURCES ${STORM_SOURCES_CLI} ${STORM_MAIN_FILE})
set(STORM_DFT_MAIN_SOURCES ${STORM_SOURCES_CLI} ${STORM_DFT_MAIN_FILE})
set(STORM_MAIN_HEADERS ${STORM_HEADERS_CLI}) set(STORM_MAIN_HEADERS ${STORM_HEADERS_CLI})
# Group the headers and sources # Group the headers and sources
source_group(main FILES ${STORM_MAIN_FILE}) source_group(main FILES ${STORM_MAIN_FILE})
source_group(dft FILES ${STORM_DYFTTEE_FILE})
source_group(adapters FILES ${STORM_ADAPTERS_FILES}) source_group(adapters FILES ${STORM_ADAPTERS_FILES})
source_group(builder FILES ${STORM_BUILDER_FILES}) source_group(builder FILES ${STORM_BUILDER_FILES})
source_group(generator FILES ${STORM_GENERATOR_FILES}) source_group(generator FILES ${STORM_GENERATOR_FILES})
@ -83,6 +89,7 @@ source_group(parser\\prismparser FILES ${STORM_PARSER_PRISMPARSER_FILES})
source_group(settings FILES ${STORM_SETTINGS_FILES}) source_group(settings FILES ${STORM_SETTINGS_FILES})
source_group(settings\\modules FILES ${STORM_SETTINGS_MODULES_FILES}) source_group(settings\\modules FILES ${STORM_SETTINGS_MODULES_FILES})
source_group(solver FILES ${STORM_SOLVER_FILES}) source_group(solver FILES ${STORM_SOLVER_FILES})
source_group(solver\\stateelimination FILES ${STORM_SOLVER_STATEELIMINATION_FILES})
source_group(storage FILES ${STORM_STORAGE_FILES}) source_group(storage FILES ${STORM_STORAGE_FILES})
source_group(storage\\bisimulation FILES ${STORM_STORAGE_BISIMULATION_FILES}) source_group(storage\\bisimulation FILES ${STORM_STORAGE_BISIMULATION_FILES})
source_group(storage\\dd FILES ${STORM_STORAGE_DD_FILES}) source_group(storage\\dd FILES ${STORM_STORAGE_DD_FILES})
@ -91,6 +98,8 @@ source_group(storage\\dd\\sylvan FILES ${STORM_STORAGE_DD_SYLVAN_FILES})
source_group(storage\\expressions FILES ${STORM_STORAGE_EXPRESSIONS_FILES}) source_group(storage\\expressions FILES ${STORM_STORAGE_EXPRESSIONS_FILES})
source_group(storage\\prism FILES ${STORM_STORAGE_PRISM_FILES}) source_group(storage\\prism FILES ${STORM_STORAGE_PRISM_FILES})
source_group(storage\\sparse FILES ${STORM_STORAGE_SPARSE_FILES}) source_group(storage\\sparse FILES ${STORM_STORAGE_SPARSE_FILES})
source_group(storage\\dft FILES ${STORM_STORAGE_DFT_FILES})
source_group(storage\\dft\\elements FILES ${STORM_STORAGE_DFT_ELEMENTS_FILES})
source_group(utility FILES ${STORM_UTILITY_FILES}) source_group(utility FILES ${STORM_UTILITY_FILES})
# Add custom additional include or link directories # Add custom additional include or link directories
@ -117,6 +126,9 @@ add_executable(storm-main ${STORM_MAIN_SOURCES} ${STORM_MAIN_HEADERS})
target_link_libraries(storm-main storm) # Adding headers for xcode target_link_libraries(storm-main storm) # Adding headers for xcode
set_target_properties(storm-main PROPERTIES OUTPUT_NAME "storm") set_target_properties(storm-main PROPERTIES OUTPUT_NAME "storm")
add_executable(storm-dft-main ${STORM_DFT_MAIN_SOURCES} ${STORM_MAIN_HEADERS})
target_link_libraries(storm-dft-main storm) # Adding headers for xcode
set_target_properties(storm-dft-main PROPERTIES OUTPUT_NAME "storm-dft")
target_link_libraries(storm ${STORM_LINK_LIBRARIES}) target_link_libraries(storm ${STORM_LINK_LIBRARIES})

10
src/adapters/CarlAdapter.h

@ -4,6 +4,8 @@
// Include config to know whether CARL is available or not. // Include config to know whether CARL is available or not.
#include "storm-config.h" #include "storm-config.h"
#include <boost/multiprecision/gmp.hpp>
#ifdef STORM_HAVE_CARL #ifdef STORM_HAVE_CARL
#include <carl/numbers/numbers.h> #include <carl/numbers/numbers.h>
@ -39,6 +41,14 @@ namespace carl {
std::hash<Interval<Number>> h; std::hash<Interval<Number>> h;
return h(i); return h(i);
} }
}
namespace cln {
inline size_t hash_value(cl_RA const& n) {
std::hash<cln::cl_RA> h;
return h(n);
}
} }
namespace storm { namespace storm {

4
src/builder/DdPrismModelBuilder.cpp

@ -20,7 +20,7 @@
#include "src/storage/dd/cudd/CuddAddIterator.h" #include "src/storage/dd/cudd/CuddAddIterator.h"
#include "src/storage/dd/Bdd.h" #include "src/storage/dd/Bdd.h"
#include "src/settings/modules/GeneralSettings.h"
#include "src/settings/modules/MarkovChainSettings.h"
namespace storm { namespace storm {
namespace builder { namespace builder {
@ -1081,7 +1081,7 @@ namespace storm {
if (!deadlockStates.isZero()) { if (!deadlockStates.isZero()) {
// If we need to fix deadlocks, we do so now. // If we need to fix deadlocks, we do so now.
if (!storm::settings::generalSettings().isDontFixDeadlocksSet()) {
if (!storm::settings::getModule<storm::settings::modules::MarkovChainSettings>().isDontFixDeadlocksSet()) {
STORM_LOG_INFO("Fixing deadlocks in " << deadlockStates.getNonZeroCount() << " states. The first three of these states are: "); STORM_LOG_INFO("Fixing deadlocks in " << deadlockStates.getNonZeroCount() << " states. The first three of these states are: ");
uint_fast64_t count = 0; uint_fast64_t count = 0;

474
src/builder/ExplicitDFTModelBuilder.cpp

@ -0,0 +1,474 @@
#include "src/builder/ExplicitDFTModelBuilder.h"
#include <src/models/sparse/MarkovAutomaton.h>
#include <src/models/sparse/Ctmc.h>
#include <src/utility/constants.h>
#include <src/utility/vector.h>
#include <src/exceptions/UnexpectedException.h>
#include <map>
namespace storm {
namespace builder {
template <typename ValueType>
ExplicitDFTModelBuilder<ValueType>::ModelComponents::ModelComponents() : transitionMatrix(), stateLabeling(), markovianStates(), exitRates(), choiceLabeling() {
// Intentionally left empty.
}
template <typename ValueType>
ExplicitDFTModelBuilder<ValueType>::ExplicitDFTModelBuilder(storm::storage::DFT<ValueType> const& dft, storm::storage::DFTIndependentSymmetries const& symmetries, bool enableDC) : mDft(dft), mStates(((mDft.stateVectorSize() / 64) + 1) * 64, INITIAL_BUCKETSIZE), enableDC(enableDC) {
// stateVectorSize is bound for size of bitvector
mStateGenerationInfo = std::make_shared<storm::storage::DFTStateGenerationInfo>(mDft.buildStateGenerationInfo(symmetries));
}
template <typename ValueType>
std::shared_ptr<storm::models::sparse::Model<ValueType>> ExplicitDFTModelBuilder<ValueType>::buildModel(LabelOptions const& labelOpts) {
// Initialize
bool deterministicModel = false;
size_t rowOffset = 0;
ModelComponents modelComponents;
std::vector<uint_fast64_t> tmpMarkovianStates;
storm::storage::SparseMatrixBuilder<ValueType> transitionMatrixBuilder(0, 0, 0, false, !deterministicModel, 0);
if(mergeFailedStates) {
// Introduce explicit fail state
failedIndex = newIndex;
newIndex++;
transitionMatrixBuilder.newRowGroup(failedIndex);
transitionMatrixBuilder.addNextValue(failedIndex, failedIndex, storm::utility::one<ValueType>());
STORM_LOG_TRACE("Introduce fail state with id: " << failedIndex);
modelComponents.exitRates.push_back(storm::utility::one<ValueType>());
tmpMarkovianStates.push_back(failedIndex);
}
// Explore state space
DFTStatePointer state = std::make_shared<storm::storage::DFTState<ValueType>>(mDft, *mStateGenerationInfo, newIndex);
auto exploreResult = exploreStates(state, rowOffset, transitionMatrixBuilder, tmpMarkovianStates, modelComponents.exitRates);
initialStateIndex = exploreResult.first;
bool deterministic = exploreResult.second;
// Before ending the exploration check for pseudo states which are not initialized yet
for (auto & pseudoStatePair : mPseudoStatesMapping) {
if (pseudoStatePair.first == 0) {
// Create state from pseudo state and explore
STORM_LOG_ASSERT(mStates.contains(pseudoStatePair.second), "Pseudo state not contained.");
STORM_LOG_ASSERT(mStates.getValue(pseudoStatePair.second) >= OFFSET_PSEUDO_STATE, "State is no pseudo state.");
STORM_LOG_TRACE("Create pseudo state from bit vector " << pseudoStatePair.second);
DFTStatePointer pseudoState = std::make_shared<storm::storage::DFTState<ValueType>>(pseudoStatePair.second, mDft, *mStateGenerationInfo, newIndex);
STORM_LOG_ASSERT(pseudoStatePair.second == pseudoState->status(), "Pseudo states do not coincide.");
STORM_LOG_TRACE("Explore pseudo state " << mDft.getStateString(pseudoState) << " with id " << pseudoState->getId());
auto exploreResult = exploreStates(pseudoState, rowOffset, transitionMatrixBuilder, tmpMarkovianStates, modelComponents.exitRates);
deterministic &= exploreResult.second;
STORM_LOG_ASSERT(pseudoStatePair.first == pseudoState->getId(), "Pseudo state ids do not coincide");
STORM_LOG_ASSERT(pseudoState->getId() == exploreResult.first, "Pseudo state ids do not coincide.");
}
}
// Replace pseudo states in matrix
std::vector<uint_fast64_t> pseudoStatesVector;
for (auto const& pseudoStatePair : mPseudoStatesMapping) {
pseudoStatesVector.push_back(pseudoStatePair.first);
}
STORM_LOG_ASSERT(std::find(pseudoStatesVector.begin(), pseudoStatesVector.end(), 0) == pseudoStatesVector.end(), "Unexplored pseudo state still contained.");
transitionMatrixBuilder.replaceColumns(pseudoStatesVector, OFFSET_PSEUDO_STATE);
STORM_LOG_DEBUG("Generated " << mStates.size() + (mergeFailedStates ? 1 : 0) << " states");
STORM_LOG_DEBUG("Model is " << (deterministic ? "deterministic" : "non-deterministic"));
size_t stateSize = mStates.size() + (mergeFailedStates ? 1 : 0);
// Build Markov Automaton
modelComponents.markovianStates = storm::storage::BitVector(stateSize, tmpMarkovianStates);
// Build transition matrix
modelComponents.transitionMatrix = transitionMatrixBuilder.build(stateSize, stateSize);
if (stateSize <= 15) {
STORM_LOG_TRACE("Transition matrix: " << std::endl << modelComponents.transitionMatrix);
} else {
STORM_LOG_TRACE("Transition matrix: too big to print");
}
STORM_LOG_TRACE("Exit rates: " << modelComponents.exitRates);
STORM_LOG_TRACE("Markovian states: " << modelComponents.markovianStates);
// Build state labeling
modelComponents.stateLabeling = storm::models::sparse::StateLabeling(mStates.size() + (mergeFailedStates ? 1 : 0));
// Initial state is always first state without any failure
modelComponents.stateLabeling.addLabel("init");
modelComponents.stateLabeling.addLabelToState("init", initialStateIndex);
// Label all states corresponding to their status (failed, failsafe, failed BE)
if(labelOpts.buildFailLabel) {
modelComponents.stateLabeling.addLabel("failed");
}
if(labelOpts.buildFailSafeLabel) {
modelComponents.stateLabeling.addLabel("failsafe");
}
// Collect labels for all BE
std::vector<std::shared_ptr<storage::DFTBE<ValueType>>> basicElements = mDft.getBasicElements();
for (std::shared_ptr<storage::DFTBE<ValueType>> elem : basicElements) {
if(labelOpts.beLabels.count(elem->name()) > 0) {
modelComponents.stateLabeling.addLabel(elem->name() + "_fail");
}
}
if(mergeFailedStates) {
modelComponents.stateLabeling.addLabelToState("failed", failedIndex);
}
for (auto const& stateIdPair : mStates) {
storm::storage::BitVector state = stateIdPair.first;
size_t stateId = stateIdPair.second;
if (!mergeFailedStates && labelOpts.buildFailLabel && mDft.hasFailed(state, *mStateGenerationInfo)) {
modelComponents.stateLabeling.addLabelToState("failed", stateId);
}
if (labelOpts.buildFailSafeLabel && mDft.isFailsafe(state, *mStateGenerationInfo)) {
modelComponents.stateLabeling.addLabelToState("failsafe", stateId);
};
// Set fail status for each BE
for (std::shared_ptr<storage::DFTBE<ValueType>> elem : basicElements) {
if (labelOpts.beLabels.count(elem->name()) > 0 && storm::storage::DFTState<ValueType>::hasFailed(state, mStateGenerationInfo->getStateIndex(elem->id())) ) {
modelComponents.stateLabeling.addLabelToState(elem->name() + "_fail", stateId);
}
}
}
std::shared_ptr<storm::models::sparse::Model<ValueType>> model;
if (deterministic) {
// Turn the probabilities into rates by multiplying each row with the exit rate of the state.
// TODO Matthias: avoid transforming back and forth
storm::storage::SparseMatrix<ValueType> rateMatrix(modelComponents.transitionMatrix);
for (uint_fast64_t row = 0; row < rateMatrix.getRowCount(); ++row) {
STORM_LOG_ASSERT(row < modelComponents.markovianStates.size(), "Row exceeds no. of markovian states.");
if (modelComponents.markovianStates.get(row)) {
for (auto& entry : rateMatrix.getRow(row)) {
entry.setValue(entry.getValue() * modelComponents.exitRates[row]);
}
}
}
model = std::make_shared<storm::models::sparse::Ctmc<ValueType>>(std::move(rateMatrix), std::move(modelComponents.exitRates), std::move(modelComponents.stateLabeling));
} else {
std::shared_ptr<storm::models::sparse::MarkovAutomaton<ValueType>> ma = std::make_shared<storm::models::sparse::MarkovAutomaton<ValueType>>(std::move(modelComponents.transitionMatrix), std::move(modelComponents.stateLabeling), std::move(modelComponents.markovianStates), std::move(modelComponents.exitRates), true);
if (ma->hasOnlyTrivialNondeterminism()) {
// Markov automaton can be converted into CTMC
model = ma->convertToCTMC();
} else {
model = ma;
}
}
return model;
}
template <typename ValueType>
std::pair<uint_fast64_t, bool> ExplicitDFTModelBuilder<ValueType>::exploreStates(DFTStatePointer const& state, size_t& rowOffset, storm::storage::SparseMatrixBuilder<ValueType>& transitionMatrixBuilder, std::vector<uint_fast64_t>& markovianStates, std::vector<ValueType>& exitRates) {
STORM_LOG_TRACE("Explore state: " << mDft.getStateString(state));
auto explorePair = checkForExploration(state);
if (!explorePair.first) {
// State does not need any exploration
return std::make_pair(explorePair.second, true);
}
// Initialization
// TODO Matthias: set Markovian states directly as bitvector?
std::map<uint_fast64_t, ValueType> outgoingRates;
std::vector<std::map<uint_fast64_t, ValueType>> outgoingProbabilities;
bool hasDependencies = state->nrFailableDependencies() > 0;
size_t failableCount = hasDependencies ? state->nrFailableDependencies() : state->nrFailableBEs();
size_t smallest = 0;
ValueType exitRate = storm::utility::zero<ValueType>();
bool deterministic = !hasDependencies;
// Absorbing state
if (mDft.hasFailed(state) || mDft.isFailsafe(state) || state->nrFailableBEs() == 0) {
uint_fast64_t stateId = addState(state);
STORM_LOG_ASSERT(stateId == state->getId(), "Ids do not coincide.");
// Add self loop
transitionMatrixBuilder.newRowGroup(stateId + rowOffset);
transitionMatrixBuilder.addNextValue(stateId + rowOffset, stateId, storm::utility::one<ValueType>());
STORM_LOG_TRACE("Added self loop for " << stateId);
exitRates.push_back(storm::utility::one<ValueType>());
STORM_LOG_ASSERT(exitRates.size()-1 == stateId, "No. of considered states does not match state id.");
markovianStates.push_back(stateId);
// No further exploration required
return std::make_pair(stateId, true);
}
// Let BE fail
while (smallest < failableCount) {
STORM_LOG_ASSERT(!mDft.hasFailed(state), "Dft has failed.");
// Construct new state as copy from original one
DFTStatePointer newState = std::make_shared<storm::storage::DFTState<ValueType>>(*state);
std::pair<std::shared_ptr<storm::storage::DFTBE<ValueType> const>, bool> nextBEPair = newState->letNextBEFail(smallest++);
std::shared_ptr<storm::storage::DFTBE<ValueType> const>& nextBE = nextBEPair.first;
STORM_LOG_ASSERT(nextBE, "NextBE is null.");
STORM_LOG_ASSERT(nextBEPair.second == hasDependencies, "Failure due to dependencies does not match.");
STORM_LOG_TRACE("With the failure of: " << nextBE->name() << " [" << nextBE->id() << "] in " << mDft.getStateString(state));
// Propagate failures
storm::storage::DFTStateSpaceGenerationQueues<ValueType> queues;
for (DFTGatePointer parent : nextBE->parents()) {
if (newState->isOperational(parent->id())) {
queues.propagateFailure(parent);
}
}
for (DFTRestrictionPointer restr : nextBE->restrictions()) {
queues.checkRestrictionLater(restr);
}
while (!queues.failurePropagationDone()) {
DFTGatePointer next = queues.nextFailurePropagation();
next->checkFails(*newState, queues);
newState->updateFailableDependencies(next->id());
}
while(!queues.restrictionChecksDone()) {
DFTRestrictionPointer next = queues.nextRestrictionCheck();
next->checkFails(*newState, queues);
newState->updateFailableDependencies(next->id());
}
if(newState->isInvalid()) {
continue;
}
bool dftFailed = newState->hasFailed(mDft.getTopLevelIndex());
while (!dftFailed && !queues.failsafePropagationDone()) {
DFTGatePointer next = queues.nextFailsafePropagation();
next->checkFailsafe(*newState, queues);
}
while (!dftFailed && enableDC && !queues.dontCarePropagationDone()) {
DFTElementPointer next = queues.nextDontCarePropagation();
next->checkDontCareAnymore(*newState, queues);
}
// Update failable dependencies
if (!dftFailed) {
newState->updateFailableDependencies(nextBE->id());
newState->updateDontCareDependencies(nextBE->id());
}
uint_fast64_t newStateId;
if(dftFailed && mergeFailedStates) {
newStateId = failedIndex;
} else {
// Explore new state recursively
auto explorePair = exploreStates(newState, rowOffset, transitionMatrixBuilder, markovianStates, exitRates);
newStateId = explorePair.first;
deterministic &= explorePair.second;
}
// Set transitions
if (hasDependencies) {
// Failure is due to dependency -> add non-deterministic choice
std::map<uint_fast64_t, ValueType> choiceProbabilities;
std::shared_ptr<storm::storage::DFTDependency<ValueType> const> dependency = mDft.getDependency(state->getDependencyId(smallest-1));
choiceProbabilities.insert(std::make_pair(newStateId, dependency->probability()));
STORM_LOG_TRACE("Added transition to " << newStateId << " with probability " << dependency->probability());
if (!storm::utility::isOne(dependency->probability())) {
// Add transition to state where dependency was unsuccessful
DFTStatePointer unsuccessfulState = std::make_shared<storm::storage::DFTState<ValueType>>(*state);
unsuccessfulState->letDependencyBeUnsuccessful(smallest-1);
auto explorePair = exploreStates(unsuccessfulState, rowOffset, transitionMatrixBuilder, markovianStates, exitRates);
uint_fast64_t unsuccessfulStateId = explorePair.first;
deterministic &= explorePair.second;
ValueType remainingProbability = storm::utility::one<ValueType>() - dependency->probability();
choiceProbabilities.insert(std::make_pair(unsuccessfulStateId, remainingProbability));
STORM_LOG_TRACE("Added transition to " << unsuccessfulStateId << " with remaining probability " << remainingProbability);
}
outgoingProbabilities.push_back(choiceProbabilities);
} else {
// Set failure rate according to activation
bool isActive = true;
if (mDft.hasRepresentant(nextBE->id())) {
// Active must be checked for the state we are coming from as this state is responsible for the
// rate and not the new state we are going to
isActive = state->isActive(mDft.getRepresentant(nextBE->id())->id());
}
ValueType rate = isActive ? nextBE->activeFailureRate() : nextBE->passiveFailureRate();
STORM_LOG_ASSERT(!storm::utility::isZero(rate), "Rate is 0.");
auto resultFind = outgoingRates.find(newStateId);
if (resultFind != outgoingRates.end()) {
// Add to existing transition
resultFind->second += rate;
STORM_LOG_TRACE("Updated transition to " << resultFind->first << " with " << (isActive ? "active" : "passive") << " rate " << rate << " to new rate " << resultFind->second);
} else {
// Insert new transition
outgoingRates.insert(std::make_pair(newStateId, rate));
STORM_LOG_TRACE("Added transition to " << newStateId << " with " << (isActive ? "active" : "passive") << " rate " << rate);
}
exitRate += rate;
}
} // end while failing BE
// Add state
uint_fast64_t stateId = addState(state);
STORM_LOG_ASSERT(stateId == state->getId(), "Ids do not match.");
STORM_LOG_ASSERT(stateId == newIndex-1, "Id does not match no. of states.");
if (hasDependencies) {
// Add all probability transitions
STORM_LOG_ASSERT(outgoingRates.empty(), "Outgoing transitions not empty.");
transitionMatrixBuilder.newRowGroup(stateId + rowOffset);
for (size_t i = 0; i < outgoingProbabilities.size(); ++i, ++rowOffset) {
STORM_LOG_ASSERT(outgoingProbabilities[i].size() == 1 || outgoingProbabilities[i].size() == 2, "No. of outgoing transitions is not valid.");
for (auto it = outgoingProbabilities[i].begin(); it != outgoingProbabilities[i].end(); ++it)
{
STORM_LOG_TRACE("Set transition from " << stateId << " to " << it->first << " with probability " << it->second);
transitionMatrixBuilder.addNextValue(stateId + rowOffset, it->first, it->second);
}
}
rowOffset--; // One increment too many
} else {
// Try to merge pseudo states with their instantiation
// TODO Matthias: improve?
for (auto it = outgoingRates.begin(); it != outgoingRates.end(); ) {
if (it->first >= OFFSET_PSEUDO_STATE) {
uint_fast64_t newId = it->first - OFFSET_PSEUDO_STATE;
STORM_LOG_ASSERT(newId < mPseudoStatesMapping.size(), "Id is not valid.");
if (mPseudoStatesMapping[newId].first > 0) {
// State exists already
newId = mPseudoStatesMapping[newId].first;
auto itFind = outgoingRates.find(newId);
if (itFind != outgoingRates.end()) {
// Add probability from pseudo state to instantiation
itFind->second += it->second;
STORM_LOG_TRACE("Merged pseudo state " << newId << " adding rate " << it->second << " to total rate of " << itFind->second);
} else {
// Only change id
outgoingRates.emplace(newId, it->second);
STORM_LOG_TRACE("Instantiated pseudo state " << newId << " with rate " << it->second);
}
// Remove pseudo state
it = outgoingRates.erase(it);
} else {
++it;
}
} else {
++it;
}
}
// Add all rate transitions
STORM_LOG_ASSERT(outgoingProbabilities.empty(), "Outgoing probabilities not empty.");
transitionMatrixBuilder.newRowGroup(state->getId() + rowOffset);
STORM_LOG_TRACE("Exit rate for " << state->getId() << ": " << exitRate);
for (auto it = outgoingRates.begin(); it != outgoingRates.end(); ++it)
{
ValueType probability = it->second / exitRate; // Transform rate to probability
STORM_LOG_TRACE("Set transition from " << state->getId() << " to " << it->first << " with rate " << it->second);
transitionMatrixBuilder.addNextValue(state->getId() + rowOffset, it->first, probability);
}
markovianStates.push_back(state->getId());
}
STORM_LOG_TRACE("Finished exploring state: " << mDft.getStateString(state));
exitRates.push_back(exitRate);
STORM_LOG_ASSERT(exitRates.size()-1 == state->getId(), "Id does not match no. of states.");
return std::make_pair(state->getId(), deterministic);
}
template <typename ValueType>
std::pair<bool, uint_fast64_t> ExplicitDFTModelBuilder<ValueType>::checkForExploration(DFTStatePointer const& state) {
bool changed = false;
if (mStateGenerationInfo->hasSymmetries()) {
// Order state by symmetry
STORM_LOG_TRACE("Check for symmetry: " << mDft.getStateString(state));
changed = state->orderBySymmetry();
STORM_LOG_TRACE("State " << (changed ? "changed to " : "did not change") << (changed ? mDft.getStateString(state) : ""));
}
if (mStates.contains(state->status())) {
// State already exists
uint_fast64_t stateId = mStates.getValue(state->status());
STORM_LOG_TRACE("State " << mDft.getStateString(state) << " with id " << stateId << " already exists");
if (changed || stateId < OFFSET_PSEUDO_STATE) {
// State is changed or an explored "normal" state
return std::make_pair(false, stateId);
}
stateId -= OFFSET_PSEUDO_STATE;
STORM_LOG_ASSERT(stateId < mPseudoStatesMapping.size(), "Id not valid.");
if (mPseudoStatesMapping[stateId].first > 0) {
// Pseudo state already explored
return std::make_pair(false, mPseudoStatesMapping[stateId].first);
}
STORM_LOG_ASSERT(mPseudoStatesMapping[stateId].second == state->status(), "States do not coincide.");
STORM_LOG_TRACE("Pseudo state " << mDft.getStateString(state) << " can be explored now");
return std::make_pair(true, stateId);
} else {
// State does not exists
if (changed) {
// Remember state for later creation
state->setId(mPseudoStatesMapping.size() + OFFSET_PSEUDO_STATE);
mPseudoStatesMapping.push_back(std::make_pair(0, state->status()));
mStates.findOrAdd(state->status(), state->getId());
STORM_LOG_TRACE("Remember state for later creation: " << mDft.getStateString(state));
return std::make_pair(false, state->getId());
} else {
// State needs exploration
return std::make_pair(true, 0);
}
}
}
template <typename ValueType>
uint_fast64_t ExplicitDFTModelBuilder<ValueType>::addState(DFTStatePointer const& state) {
uint_fast64_t stateId;
// TODO remove
bool changed = state->orderBySymmetry();
STORM_LOG_ASSERT(!changed, "State to add has changed by applying symmetry.");
// Check if state already exists
if (mStates.contains(state->status())) {
// State already exists
stateId = mStates.getValue(state->status());
STORM_LOG_TRACE("State " << mDft.getStateString(state) << " with id " << stateId << " already exists");
// Check if possible pseudo state can be created now
STORM_LOG_ASSERT(stateId >= OFFSET_PSEUDO_STATE, "State is no pseudo state.");
stateId -= OFFSET_PSEUDO_STATE;
STORM_LOG_ASSERT(stateId < mPseudoStatesMapping.size(), "Pseudo state not known.");
if (mPseudoStatesMapping[stateId].first == 0) {
// Create pseudo state now
STORM_LOG_ASSERT(mPseudoStatesMapping[stateId].second == state->status(), "Pseudo states do not coincide.");
state->setId(newIndex++);
mPseudoStatesMapping[stateId].first = state->getId();
stateId = state->getId();
mStates.setOrAdd(state->status(), stateId);
STORM_LOG_TRACE("Now create state " << mDft.getStateString(state) << " with id " << stateId);
return stateId;
} else {
STORM_LOG_ASSERT(false, "Pseudo state already created.");
return 0;
}
} else {
// Create new state
state->setId(newIndex++);
stateId = mStates.findOrAdd(state->status(), state->getId());
STORM_LOG_TRACE("New state: " << mDft.getStateString(state));
return stateId;
}
}
// Explicitly instantiate the class.
template class ExplicitDFTModelBuilder<double>;
#ifdef STORM_HAVE_CARL
template class ExplicitDFTModelBuilder<storm::RationalFunction>;
#endif
} // namespace builder
} // namespace storm

97
src/builder/ExplicitDFTModelBuilder.h

@ -0,0 +1,97 @@
#ifndef EXPLICITDFTMODELBUILDER_H
#define EXPLICITDFTMODELBUILDER_H
#include <src/models/sparse/StateLabeling.h>
#include <src/models/sparse/StandardRewardModel.h>
#include <src/models/sparse/Model.h>
#include <src/storage/SparseMatrix.h>
#include <src/storage/BitVectorHashMap.h>
#include <src/storage/dft/DFT.h>
#include <src/storage/dft/SymmetricUnits.h>
#include <boost/container/flat_set.hpp>
#include <boost/optional/optional.hpp>
#include <stack>
#include <unordered_set>
namespace storm {
namespace builder {
template<typename ValueType>
class ExplicitDFTModelBuilder {
using DFTElementPointer = std::shared_ptr<storm::storage::DFTElement<ValueType>>;
using DFTElementCPointer = std::shared_ptr<storm::storage::DFTElement<ValueType> const>;
using DFTGatePointer = std::shared_ptr<storm::storage::DFTGate<ValueType>>;
using DFTStatePointer = std::shared_ptr<storm::storage::DFTState<ValueType>>;
using DFTRestrictionPointer = std::shared_ptr<storm::storage::DFTRestriction<ValueType>>;
// A structure holding the individual components of a model.
struct ModelComponents {
ModelComponents();
// The transition matrix.
storm::storage::SparseMatrix<ValueType> transitionMatrix;
// The state labeling.
storm::models::sparse::StateLabeling stateLabeling;
// The Markovian states.
storm::storage::BitVector markovianStates;
// The exit rates.
std::vector<ValueType> exitRates;
// A vector that stores a labeling for each choice.
boost::optional<std::vector<boost::container::flat_set<uint_fast64_t>>> choiceLabeling;
};
const size_t INITIAL_BUCKETSIZE = 20000;
const uint_fast64_t OFFSET_PSEUDO_STATE = UINT_FAST64_MAX / 2;
storm::storage::DFT<ValueType> const& mDft;
std::shared_ptr<storm::storage::DFTStateGenerationInfo> mStateGenerationInfo;
storm::storage::BitVectorHashMap<uint_fast64_t> mStates;
std::vector<std::pair<uint_fast64_t, storm::storage::BitVector>> mPseudoStatesMapping; // vector of (id to concrete state, bitvector)
size_t newIndex = 0;
bool mergeFailedStates = true;
bool enableDC = true;
size_t failedIndex = 0;
size_t initialStateIndex = 0;
public:
struct LabelOptions {
bool buildFailLabel = true;
bool buildFailSafeLabel = false;
std::set<std::string> beLabels = {};
};
ExplicitDFTModelBuilder(storm::storage::DFT<ValueType> const& dft, storm::storage::DFTIndependentSymmetries const& symmetries, bool enableDC);
std::shared_ptr<storm::models::sparse::Model<ValueType>> buildModel(LabelOptions const& labelOpts);
private:
std::pair<uint_fast64_t, bool> exploreStates(DFTStatePointer const& state, size_t& rowOffset, storm::storage::SparseMatrixBuilder<ValueType>& transitionMatrixBuilder, std::vector<uint_fast64_t>& markovianStates, std::vector<ValueType>& exitRates);
/*!
* Adds a state to the explored states and handles pseudo states.
*
* @param state The state to add.
* @return Id of added state.
*/
uint_fast64_t addState(DFTStatePointer const& state);
/*!
* Check if state needs an exploration and remember pseudo states for later creation.
*
* @param state State which might need exploration.
* @return Pair of flag indicating whether the state needs exploration now and the state id if the state already
* exists.
*/
std::pair<bool, uint_fast64_t> checkForExploration(DFTStatePointer const& state);
};
}
}
#endif /* EXPLICITDFTMODELBUILDER_H */

11
src/builder/ExplicitPrismModelBuilder.cpp

@ -9,7 +9,8 @@
#include "src/storage/expressions/ExpressionManager.h" #include "src/storage/expressions/ExpressionManager.h"
#include "src/settings/modules/GeneralSettings.h"
#include "src/settings/modules/MarkovChainSettings.h"
#include "src/settings/modules/IOSettings.h"
#include "src/generator/PrismNextStateGenerator.h" #include "src/generator/PrismNextStateGenerator.h"
#include "src/generator/PrismStateLabelingGenerator.h" #include "src/generator/PrismStateLabelingGenerator.h"
@ -69,17 +70,17 @@ namespace storm {
} }
template <typename ValueType, typename RewardModelType, typename StateType> template <typename ValueType, typename RewardModelType, typename StateType>
ExplicitPrismModelBuilder<ValueType, RewardModelType, StateType>::Options::Options() : explorationOrder(storm::settings::generalSettings().getExplorationOrder()), buildCommandLabels(false), buildAllRewardModels(true), buildStateValuations(false), rewardModelsToBuild(), constantDefinitions(), buildAllLabels(true), labelsToBuild(), expressionLabels(), terminalStates(), negatedTerminalStates() {
ExplicitPrismModelBuilder<ValueType, RewardModelType, StateType>::Options::Options() : explorationOrder(storm::settings::getModule<storm::settings::modules::IOSettings>().getExplorationOrder()), buildCommandLabels(false), buildAllRewardModels(true), buildStateValuations(false), rewardModelsToBuild(), constantDefinitions(), buildAllLabels(true), labelsToBuild(), expressionLabels(), terminalStates(), negatedTerminalStates() {
// Intentionally left empty. // Intentionally left empty.
} }
template <typename ValueType, typename RewardModelType, typename StateType> template <typename ValueType, typename RewardModelType, typename StateType>
ExplicitPrismModelBuilder<ValueType, RewardModelType, StateType>::Options::Options(storm::logic::Formula const& formula) : explorationOrder(storm::settings::generalSettings().getExplorationOrder()), buildCommandLabels(false), buildAllRewardModels(false), buildStateValuations(false), rewardModelsToBuild(), constantDefinitions(), buildAllLabels(false), labelsToBuild(std::set<std::string>()), expressionLabels(std::vector<storm::expressions::Expression>()), terminalStates(), negatedTerminalStates() {
ExplicitPrismModelBuilder<ValueType, RewardModelType, StateType>::Options::Options(storm::logic::Formula const& formula) : explorationOrder(storm::settings::getModule<storm::settings::modules::IOSettings>().getExplorationOrder()), buildCommandLabels(false), buildAllRewardModels(false), buildStateValuations(false), rewardModelsToBuild(), constantDefinitions(), buildAllLabels(false), labelsToBuild(std::set<std::string>()), expressionLabels(std::vector<storm::expressions::Expression>()), terminalStates(), negatedTerminalStates() {
this->preserveFormula(formula); this->preserveFormula(formula);
} }
template <typename ValueType, typename RewardModelType, typename StateType> template <typename ValueType, typename RewardModelType, typename StateType>
ExplicitPrismModelBuilder<ValueType, RewardModelType, StateType>::Options::Options(std::vector<std::shared_ptr<storm::logic::Formula const>> const& formulas) : explorationOrder(storm::settings::generalSettings().getExplorationOrder()), buildCommandLabels(false), buildAllRewardModels(false), buildStateValuations(false), rewardModelsToBuild(), constantDefinitions(), buildAllLabels(false), labelsToBuild(), expressionLabels(), terminalStates(), negatedTerminalStates() {
ExplicitPrismModelBuilder<ValueType, RewardModelType, StateType>::Options::Options(std::vector<std::shared_ptr<storm::logic::Formula const>> const& formulas) : explorationOrder(storm::settings::getModule<storm::settings::modules::IOSettings>().getExplorationOrder()), buildCommandLabels(false), buildAllRewardModels(false), buildStateValuations(false), rewardModelsToBuild(), constantDefinitions(), buildAllLabels(false), labelsToBuild(), expressionLabels(), terminalStates(), negatedTerminalStates() {
if (formulas.empty()) { if (formulas.empty()) {
this->buildAllRewardModels = true; this->buildAllRewardModels = true;
this->buildAllLabels = true; this->buildAllLabels = true;
@ -304,7 +305,7 @@ namespace storm {
// If there is no behavior, we might have to introduce a self-loop. // If there is no behavior, we might have to introduce a self-loop.
if (behavior.empty()) { if (behavior.empty()) {
if (!storm::settings::generalSettings().isDontFixDeadlocksSet() || !behavior.wasExpanded()) {
if (!storm::settings::getModule<storm::settings::modules::MarkovChainSettings>().isDontFixDeadlocksSet() || !behavior.wasExpanded()) {
if (options.buildCommandLabels) { if (options.buildCommandLabels) {
// Insert empty choice labeling for added self-loop transitions. // Insert empty choice labeling for added self-loop transitions.
choiceLabels.get().push_back(boost::container::flat_set<uint_fast64_t>()); choiceLabels.get().push_back(boost::container::flat_set<uint_fast64_t>());

46
src/cli/cli.cpp

@ -4,6 +4,8 @@
#include "../utility/storm.h" #include "../utility/storm.h"
#include "src/settings/modules/DebugSettings.h" #include "src/settings/modules/DebugSettings.h"
#include "src/settings/modules/IOSettings.h"
#include "src/settings/modules/MarkovChainSettings.h"
#include "src/exceptions/OptionParserException.h" #include "src/exceptions/OptionParserException.h"
#include "src/utility/storm-version.h" #include "src/utility/storm-version.h"
@ -41,9 +43,9 @@ namespace storm {
return (GetCurrentDir(temp, 512 - 1) ? std::string(temp) : std::string("")); return (GetCurrentDir(temp, 512 - 1) ? std::string(temp) : std::string(""));
} }
void printHeader(const int argc, const char* argv[]) {
std::cout << "StoRM" << std::endl;
std::cout << "--------" << std::endl << std::endl;
void printHeader(const std::string name, const int argc, const char* argv[]) {
std::cout << name << std::endl;
std::cout << "---------------" << std::endl << std::endl;
std::cout << storm::utility::StormVersion::longVersionString() << std::endl; std::cout << storm::utility::StormVersion::longVersionString() << std::endl;
@ -166,59 +168,56 @@ namespace storm {
} }
bool parseOptions(const int argc, const char* argv[]) { bool parseOptions(const int argc, const char* argv[]) {
storm::settings::SettingsManager& manager = storm::settings::mutableManager();
try { try {
manager.setFromCommandLine(argc, argv);
storm::settings::mutableManager().setFromCommandLine(argc, argv);
} catch (storm::exceptions::OptionParserException& e) { } catch (storm::exceptions::OptionParserException& e) {
manager.printHelp();
storm::settings::manager().printHelp();
throw e; throw e;
return false; return false;
} }
if (storm::settings::generalSettings().isHelpSet()) {
storm::settings::manager().printHelp(storm::settings::generalSettings().getHelpModuleName());
if (storm::settings::getModule<storm::settings::modules::GeneralSettings>().isHelpSet()) {
storm::settings::manager().printHelp(storm::settings::getModule<storm::settings::modules::GeneralSettings>().getHelpModuleName());
return false; return false;
} }
if (storm::settings::generalSettings().isVersionSet()) {
if (storm::settings::getModule<storm::settings::modules::GeneralSettings>().isVersionSet()) {
storm::settings::manager().printVersion(); storm::settings::manager().printVersion();
return false; return false;
} }
if (storm::settings::generalSettings().isVerboseSet()) {
if (storm::settings::getModule<storm::settings::modules::GeneralSettings>().isVerboseSet()) {
STORM_GLOBAL_LOGLEVEL_INFO(); STORM_GLOBAL_LOGLEVEL_INFO();
} }
if (storm::settings::debugSettings().isDebugSet()) {
if (storm::settings::getModule<storm::settings::modules::DebugSettings>().isDebugSet()) {
STORM_GLOBAL_LOGLEVEL_DEBUG(); STORM_GLOBAL_LOGLEVEL_DEBUG();
} }
if (storm::settings::debugSettings().isTraceSet()) {
if (storm::settings::getModule<storm::settings::modules::DebugSettings>().isTraceSet()) {
STORM_GLOBAL_LOGLEVEL_TRACE(); STORM_GLOBAL_LOGLEVEL_TRACE();
} }
if (storm::settings::debugSettings().isLogfileSet()) {
if (storm::settings::getModule<storm::settings::modules::DebugSettings>().isLogfileSet()) {
storm::utility::initializeFileLogging(); storm::utility::initializeFileLogging();
} }
return true; return true;
} }
void processOptions() { void processOptions() {
if (storm::settings::debugSettings().isLogfileSet()) {
if (storm::settings::getModule<storm::settings::modules::DebugSettings>().isLogfileSet()) {
storm::utility::initializeFileLogging(); storm::utility::initializeFileLogging();
} }
storm::settings::modules::GeneralSettings const& settings = storm::settings::generalSettings();
// If we have to build the model from a symbolic representation, we need to parse the representation first. // If we have to build the model from a symbolic representation, we need to parse the representation first.
boost::optional<storm::prism::Program> program; boost::optional<storm::prism::Program> program;
if (settings.isSymbolicSet()) {
std::string const& programFile = settings.getSymbolicModelFilename();
if (storm::settings::getModule<storm::settings::modules::IOSettings>().isSymbolicSet()) {
std::string const& programFile = storm::settings::getModule<storm::settings::modules::IOSettings>().getSymbolicModelFilename();
program = storm::parseProgram(programFile); program = storm::parseProgram(programFile);
} }
// Then proceed to parsing the property (if given), since the model we are building may depend on the property. // Then proceed to parsing the property (if given), since the model we are building may depend on the property.
std::vector<std::shared_ptr<storm::logic::Formula const>> parsedFormulas; std::vector<std::shared_ptr<storm::logic::Formula const>> parsedFormulas;
if (settings.isPropertySet()) {
std::string properties = settings.getProperty();
if (storm::settings::getModule<storm::settings::modules::GeneralSettings>().isPropertySet()) {
std::string properties = storm::settings::getModule<storm::settings::modules::GeneralSettings>().getProperty();
if(program) { if(program) {
parsedFormulas = storm::parseFormulasForProgram(properties, program.get()); parsedFormulas = storm::parseFormulasForProgram(properties, program.get());
@ -229,9 +228,9 @@ namespace storm {
} }
std::vector<std::shared_ptr<storm::logic::Formula const>> formulas(parsedFormulas.begin(), parsedFormulas.end()); std::vector<std::shared_ptr<storm::logic::Formula const>> formulas(parsedFormulas.begin(), parsedFormulas.end());
if (settings.isSymbolicSet()) {
if (storm::settings::getModule<storm::settings::modules::IOSettings>().isSymbolicSet()) {
#ifdef STORM_HAVE_CARL #ifdef STORM_HAVE_CARL
if (settings.isParametricSet()) {
if (storm::settings::getModule<storm::settings::modules::GeneralSettings>().isParametricSet()) {
buildAndCheckSymbolicModel<storm::RationalFunction>(program.get(), formulas, true); buildAndCheckSymbolicModel<storm::RationalFunction>(program.get(), formulas, true);
} else { } else {
#endif #endif
@ -239,7 +238,8 @@ namespace storm {
#ifdef STORM_HAVE_CARL #ifdef STORM_HAVE_CARL
} }
#endif #endif
} else if (settings.isExplicitSet()) {
} else if (storm::settings::getModule<storm::settings::modules::IOSettings>().isExplicitSet()) {
STORM_LOG_THROW(storm::settings::getModule<storm::settings::modules::MarkovChainSettings>().getEngine() == storm::settings::modules::MarkovChainSettings::Engine::Sparse, storm::exceptions::InvalidSettingsException, "Cannot use explicit input models with this engine.");
buildAndCheckExplicitModel<double>(formulas, true); buildAndCheckExplicitModel<double>(formulas, true);
} else { } else {
STORM_LOG_THROW(false, storm::exceptions::InvalidSettingsException, "No input model."); STORM_LOG_THROW(false, storm::exceptions::InvalidSettingsException, "No input model.");

27
src/cli/cli.h

@ -6,23 +6,22 @@
namespace storm { namespace storm {
namespace cli { namespace cli {
std::string getCurrentWorkingDirectory();
std::string getCurrentWorkingDirectory();
void printHeader(const int argc, const char* argv[]);
void printHeader(std::string name, const int argc, const char* argv[]);
void printUsage();
void printUsage();
/*!
* Parses the given command line arguments.
*
* @param argc The argc argument of main().
* @param argv The argv argument of main().
* @return True iff the program should continue to run after parsing the options.
*/
bool parseOptions(const int argc, const char* argv[]);
/*!
* Parses the given command line arguments.
*
* @param argc The argc argument of main().
* @param argv The argv argument of main().
* @return True iff the program should continue to run after parsing the options.
*/
bool parseOptions(const int argc, const char* argv[]);
void processOptions();
void processOptions();
} }
} }

25
src/cli/entrypoints.h

@ -29,7 +29,7 @@ namespace storm {
inline void verifySparseModel(std::shared_ptr<storm::models::sparse::Model<storm::RationalFunction>> model, std::vector<std::shared_ptr<storm::logic::Formula const>> const& formulas, bool onlyInitialStatesRelevant) { inline void verifySparseModel(std::shared_ptr<storm::models::sparse::Model<storm::RationalFunction>> model, std::vector<std::shared_ptr<storm::logic::Formula const>> const& formulas, bool onlyInitialStatesRelevant) {
for (auto const& formula : formulas) { for (auto const& formula : formulas) {
STORM_LOG_THROW(model->getType() == storm::models::ModelType::Dtmc, storm::exceptions::InvalidSettingsException, "Currently parametric verification is only available for DTMCs.");
STORM_LOG_THROW(model->getType() == storm::models::ModelType::Dtmc || model->getType() == storm::models::ModelType::Ctmc, storm::exceptions::InvalidSettingsException, "Currently parametric verification is only available for DTMCs and CTMCs.");
std::cout << std::endl << "Model checking property: " << *formula << " ..."; std::cout << std::endl << "Model checking property: " << *formula << " ...";
std::unique_ptr<storm::modelchecker::CheckResult> result(storm::verifySparseModel(model, formula, onlyInitialStatesRelevant)); std::unique_ptr<storm::modelchecker::CheckResult> result(storm::verifySparseModel(model, formula, onlyInitialStatesRelevant));
if (result) { if (result) {
@ -41,9 +41,8 @@ namespace storm {
std::cout << " skipped, because the modelling formalism is currently unsupported." << std::endl; std::cout << " skipped, because the modelling formalism is currently unsupported." << std::endl;
} }
storm::settings::modules::ParametricSettings const& parametricSettings = storm::settings::parametricSettings();
if (parametricSettings.exportResultToFile()) {
exportParametricResultToFile(result->asExplicitQuantitativeCheckResult<storm::RationalFunction>()[*model->getInitialStates().begin()], storm::models::sparse::Dtmc<storm::RationalFunction>::ConstraintCollector(*(model->template as<storm::models::sparse::Dtmc<storm::RationalFunction>>())), parametricSettings.exportResultPath());
if (storm::settings::getModule<storm::settings::modules::ParametricSettings>().exportResultToFile()) {
exportParametricResultToFile(result->asExplicitQuantitativeCheckResult<storm::RationalFunction>()[*model->getInitialStates().begin()], storm::models::sparse::Dtmc<storm::RationalFunction>::ConstraintCollector(*(model->template as<storm::models::sparse::Dtmc<storm::RationalFunction>>())), storm::settings::getModule<storm::settings::modules::ParametricSettings>().exportResultPath());
} }
} }
} }
@ -61,7 +60,7 @@ namespace storm {
STORM_LOG_THROW(program.getModelType() == storm::prism::Program::ModelType::DTMC || program.getModelType() == storm::prism::Program::ModelType::MDP, storm::exceptions::InvalidSettingsException, "Currently exploration-based verification is only available for DTMCs and MDPs."); STORM_LOG_THROW(program.getModelType() == storm::prism::Program::ModelType::DTMC || program.getModelType() == storm::prism::Program::ModelType::MDP, storm::exceptions::InvalidSettingsException, "Currently exploration-based verification is only available for DTMCs and MDPs.");
std::cout << std::endl << "Model checking property: " << *formula << " ..."; std::cout << std::endl << "Model checking property: " << *formula << " ...";
storm::modelchecker::CheckTask<storm::logic::Formula> task(*formula, onlyInitialStatesRelevant); storm::modelchecker::CheckTask<storm::logic::Formula> task(*formula, onlyInitialStatesRelevant);
storm::modelchecker::SparseExplorationModelChecker<ValueType> checker(program, storm::utility::prism::parseConstantDefinitionString(program, storm::settings::generalSettings().getConstantDefinitionString()));
storm::modelchecker::SparseExplorationModelChecker<ValueType> checker(program, storm::utility::prism::parseConstantDefinitionString(program, storm::settings::getModule<storm::settings::modules::IOSettings>().getConstantDefinitionString()));
std::unique_ptr<storm::modelchecker::CheckResult> result; std::unique_ptr<storm::modelchecker::CheckResult> result;
if (checker.canHandle(task)) { if (checker.canHandle(task)) {
result = checker.check(task); result = checker.check(task);
@ -147,11 +146,9 @@ namespace storm {
template<typename ValueType, storm::dd::DdType LibraryType> template<typename ValueType, storm::dd::DdType LibraryType>
void buildAndCheckSymbolicModel(storm::prism::Program const& program, std::vector<std::shared_ptr<storm::logic::Formula const>> const& formulas, bool onlyInitialStatesRelevant = false) { void buildAndCheckSymbolicModel(storm::prism::Program const& program, std::vector<std::shared_ptr<storm::logic::Formula const>> const& formulas, bool onlyInitialStatesRelevant = false) {
storm::settings::modules::GeneralSettings const& settings = storm::settings::generalSettings();
if (settings.getEngine() == storm::settings::modules::GeneralSettings::Engine::AbstractionRefinement) {
if (storm::settings::getModule<storm::settings::modules::MarkovChainSettings>().getEngine() == storm::settings::modules::MarkovChainSettings::Engine::AbstractionRefinement) {
verifySymbolicModelWithAbstractionRefinementEngine<LibraryType>(program, formulas, onlyInitialStatesRelevant); verifySymbolicModelWithAbstractionRefinementEngine<LibraryType>(program, formulas, onlyInitialStatesRelevant);
} else if (settings.getEngine() == storm::settings::modules::GeneralSettings::Engine::Exploration) {
} else if (storm::settings::getModule<storm::settings::modules::MarkovChainSettings>().getEngine() == storm::settings::modules::MarkovChainSettings::Engine::Exploration) {
verifySymbolicModelWithExplorationEngine<ValueType>(program, formulas, onlyInitialStatesRelevant); verifySymbolicModelWithExplorationEngine<ValueType>(program, formulas, onlyInitialStatesRelevant);
} else { } else {
storm::storage::ModelFormulasPair modelFormulasPair = buildSymbolicModel<ValueType, LibraryType>(program, formulas); storm::storage::ModelFormulasPair modelFormulasPair = buildSymbolicModel<ValueType, LibraryType>(program, formulas);
@ -167,7 +164,7 @@ namespace storm {
// Verify the model, if a formula was given. // Verify the model, if a formula was given.
if (!formulas.empty()) { if (!formulas.empty()) {
if (modelFormulasPair.model->isSparseModel()) { if (modelFormulasPair.model->isSparseModel()) {
if (storm::settings::generalSettings().isCounterexampleSet()) {
if (storm::settings::getModule<storm::settings::modules::MarkovChainSettings>().isCounterexampleSet()) {
// If we were requested to generate a counterexample, we now do so for each formula. // If we were requested to generate a counterexample, we now do so for each formula.
for (auto const& formula : modelFormulasPair.formulas) { for (auto const& formula : modelFormulasPair.formulas) {
generateCounterexample<ValueType>(program, modelFormulasPair.model->as<storm::models::sparse::Model<ValueType>>(), formula); generateCounterexample<ValueType>(program, modelFormulasPair.model->as<storm::models::sparse::Model<ValueType>>(), formula);
@ -176,7 +173,7 @@ namespace storm {
verifySparseModel<ValueType>(modelFormulasPair.model->as<storm::models::sparse::Model<ValueType>>(), modelFormulasPair.formulas, onlyInitialStatesRelevant); verifySparseModel<ValueType>(modelFormulasPair.model->as<storm::models::sparse::Model<ValueType>>(), modelFormulasPair.formulas, onlyInitialStatesRelevant);
} }
} else if (modelFormulasPair.model->isSymbolicModel()) { } else if (modelFormulasPair.model->isSymbolicModel()) {
if (storm::settings::generalSettings().getEngine() == storm::settings::modules::GeneralSettings::Engine::Hybrid) {
if (storm::settings::getModule<storm::settings::modules::MarkovChainSettings>().getEngine() == storm::settings::modules::MarkovChainSettings::Engine::Hybrid) {
verifySymbolicModelWithHybridEngine(modelFormulasPair.model->as<storm::models::symbolic::Model<LibraryType>>(), verifySymbolicModelWithHybridEngine(modelFormulasPair.model->as<storm::models::symbolic::Model<LibraryType>>(),
modelFormulasPair.formulas, onlyInitialStatesRelevant); modelFormulasPair.formulas, onlyInitialStatesRelevant);
} else { } else {
@ -192,16 +189,16 @@ namespace storm {
template<typename ValueType> template<typename ValueType>
void buildAndCheckSymbolicModel(storm::prism::Program const& program, std::vector<std::shared_ptr<storm::logic::Formula const>> const& formulas, bool onlyInitialStatesRelevant = false) { void buildAndCheckSymbolicModel(storm::prism::Program const& program, std::vector<std::shared_ptr<storm::logic::Formula const>> const& formulas, bool onlyInitialStatesRelevant = false) {
if (storm::settings::generalSettings().getDdLibraryType() == storm::dd::DdType::CUDD) {
if (storm::settings::getModule<storm::settings::modules::MarkovChainSettings>().getDdLibraryType() == storm::dd::DdType::CUDD) {
buildAndCheckSymbolicModel<ValueType, storm::dd::DdType::CUDD>(program, formulas, onlyInitialStatesRelevant); buildAndCheckSymbolicModel<ValueType, storm::dd::DdType::CUDD>(program, formulas, onlyInitialStatesRelevant);
} else if (storm::settings::generalSettings().getDdLibraryType() == storm::dd::DdType::Sylvan) {
} else if (storm::settings::getModule<storm::settings::modules::MarkovChainSettings>().getDdLibraryType() == storm::dd::DdType::Sylvan) {
buildAndCheckSymbolicModel<ValueType, storm::dd::DdType::Sylvan>(program, formulas, onlyInitialStatesRelevant); buildAndCheckSymbolicModel<ValueType, storm::dd::DdType::Sylvan>(program, formulas, onlyInitialStatesRelevant);
} }
} }
template<typename ValueType> template<typename ValueType>
void buildAndCheckExplicitModel(std::vector<std::shared_ptr<storm::logic::Formula const>> const& formulas, bool onlyInitialStatesRelevant = false) { void buildAndCheckExplicitModel(std::vector<std::shared_ptr<storm::logic::Formula const>> const& formulas, bool onlyInitialStatesRelevant = false) {
storm::settings::modules::GeneralSettings const& settings = storm::settings::generalSettings();
storm::settings::modules::IOSettings const& settings = storm::settings::getModule<storm::settings::modules::IOSettings>();
STORM_LOG_THROW(settings.isExplicitSet(), storm::exceptions::InvalidStateException, "Unable to build explicit model without model files."); STORM_LOG_THROW(settings.isExplicitSet(), storm::exceptions::InvalidStateException, "Unable to build explicit model without model files.");
std::shared_ptr<storm::models::ModelBase> model = buildExplicitModel<ValueType>(settings.getTransitionFilename(), settings.getLabelingFilename(), settings.isStateRewardsSet() ? boost::optional<std::string>(settings.getStateRewardsFilename()) : boost::none, settings.isTransitionRewardsSet() ? boost::optional<std::string>(settings.getTransitionRewardsFilename()) : boost::none, settings.isChoiceLabelingSet() ? boost::optional<std::string>(settings.getChoiceLabelingFilename()) : boost::none); std::shared_ptr<storm::models::ModelBase> model = buildExplicitModel<ValueType>(settings.getTransitionFilename(), settings.getLabelingFilename(), settings.isStateRewardsSet() ? boost::optional<std::string>(settings.getStateRewardsFilename()) : boost::none, settings.isTransitionRewardsSet() ? boost::optional<std::string>(settings.getTransitionRewardsFilename()) : boost::none, settings.isChoiceLabelingSet() ? boost::optional<std::string>(settings.getChoiceLabelingFilename()) : boost::none);

2
src/counterexamples/MILPMinimalLabelSetGenerator.h

@ -1015,7 +1015,7 @@ namespace storm {
// Delegate the actual computation work to the function of equal name. // Delegate the actual computation work to the function of equal name.
auto startTime = std::chrono::high_resolution_clock::now(); auto startTime = std::chrono::high_resolution_clock::now();
boost::container::flat_set<uint_fast64_t> usedLabelSet = getMinimalLabelSet(probabilityOperator.getSubformula(), labeledMdp, phiStates, psiStates, threshold, strictBound, true, storm::settings::counterexampleGeneratorSettings().isUseSchedulerCutsSet());
boost::container::flat_set<uint_fast64_t> usedLabelSet = getMinimalLabelSet(probabilityOperator.getSubformula(), labeledMdp, phiStates, psiStates, threshold, strictBound, true, storm::settings::getModule<storm::settings::modules::CounterexampleGeneratorSettings>().isUseSchedulerCutsSet());
auto endTime = std::chrono::high_resolution_clock::now(); auto endTime = std::chrono::high_resolution_clock::now();
std::cout << std::endl << "Computed minimal label set of size " << usedLabelSet.size() << " in " << std::chrono::duration_cast<std::chrono::milliseconds>(endTime - startTime).count() << "ms." << std::endl; std::cout << std::endl << "Computed minimal label set of size " << usedLabelSet.size() << " in " << std::chrono::duration_cast<std::chrono::milliseconds>(endTime - startTime).count() << "ms." << std::endl;

6
src/counterexamples/SMTMinimalCommandSetGenerator.h

@ -12,7 +12,7 @@
#include "src/modelchecker/results/ExplicitQuantitativeCheckResult.h" #include "src/modelchecker/results/ExplicitQuantitativeCheckResult.h"
#include "src/solver/GmmxxMinMaxLinearEquationSolver.h" #include "src/solver/GmmxxMinMaxLinearEquationSolver.h"
#include "src/settings/SettingsManager.h" #include "src/settings/SettingsManager.h"
#include "src/settings/modules/GeneralSettings.h"
#include "src/settings/modules/MarkovChainSettings.h"
#include "src/utility/counterexamples.h" #include "src/utility/counterexamples.h"
#include "src/utility/prism.h" #include "src/utility/prism.h"
@ -1729,7 +1729,7 @@ namespace storm {
// Compute and emit the time measurements if the corresponding flag was set. // Compute and emit the time measurements if the corresponding flag was set.
totalTime = std::chrono::high_resolution_clock::now() - totalClock; totalTime = std::chrono::high_resolution_clock::now() - totalClock;
if (storm::settings::generalSettings().isShowStatisticsSet()) {
if (storm::settings::getModule<storm::settings::modules::MarkovChainSettings>().isShowStatisticsSet()) {
std::cout << std::endl; std::cout << std::endl;
std::cout << "Time breakdown:" << std::endl; std::cout << "Time breakdown:" << std::endl;
std::cout << " * time for setup: " << std::chrono::duration_cast<std::chrono::milliseconds>(totalSetupTime).count() << "ms" << std::endl; std::cout << " * time for setup: " << std::chrono::duration_cast<std::chrono::milliseconds>(totalSetupTime).count() << "ms" << std::endl;
@ -1793,7 +1793,7 @@ namespace storm {
// Delegate the actual computation work to the function of equal name. // Delegate the actual computation work to the function of equal name.
auto startTime = std::chrono::high_resolution_clock::now(); auto startTime = std::chrono::high_resolution_clock::now();
auto labelSet = getMinimalCommandSet(probabilityOperator.getSubformula(), program, constantDefinitionString, labeledMdp, phiStates, psiStates, threshold, strictBound, true, storm::settings::counterexampleGeneratorSettings().isEncodeReachabilitySet());
auto labelSet = getMinimalCommandSet(probabilityOperator.getSubformula(), program, constantDefinitionString, labeledMdp, phiStates, psiStates, threshold, strictBound, true, storm::settings::getModule<storm::settings::modules::CounterexampleGeneratorSettings>().isEncodeReachabilitySet());
auto endTime = std::chrono::high_resolution_clock::now(); auto endTime = std::chrono::high_resolution_clock::now();
std::cout << std::endl << "Computed minimal label set of size " << labelSet.size() << " in " << std::chrono::duration_cast<std::chrono::milliseconds>(endTime - startTime).count() << "ms." << std::endl; std::cout << std::endl << "Computed minimal label set of size " << labelSet.size() << " in " << std::chrono::duration_cast<std::chrono::milliseconds>(endTime - startTime).count() << "ms." << std::endl;

2
src/modelchecker/AbstractModelChecker.cpp

@ -241,4 +241,4 @@ namespace storm {
return subResult; return subResult;
} }
} }
}
}

191
src/modelchecker/DFTAnalyser.h

@ -0,0 +1,191 @@
#pragma once
#include "logic/Formula.h"
#include "parser/DFTGalileoParser.h"
#include "builder/ExplicitDFTModelBuilder.h"
#include "modelchecker/results/CheckResult.h"
#include "utility/storm.h"
#include "storage/dft/DFTIsomorphism.h"
#include "utility/bitoperations.h"
#include <chrono>
template<typename ValueType>
class DFTAnalyser {
std::chrono::duration<double> buildingTime = std::chrono::duration<double>::zero();
std::chrono::duration<double> explorationTime = std::chrono::duration<double>::zero();
std::chrono::duration<double> bisimulationTime = std::chrono::duration<double>::zero();
std::chrono::duration<double> modelCheckingTime = std::chrono::duration<double>::zero();
std::chrono::duration<double> totalTime = std::chrono::duration<double>::zero();
ValueType checkResult = storm::utility::zero<ValueType>();
public:
void check(storm::storage::DFT<ValueType> const& origDft , std::shared_ptr<const storm::logic::Formula> const& formula, bool symred = true, bool allowModularisation = true, bool enableDC = true) {
// Building DFT
std::chrono::high_resolution_clock::time_point totalStart = std::chrono::high_resolution_clock::now();
// Optimizing DFT
storm::storage::DFT<ValueType> dft = origDft.optimize();
checkResult = checkHelper(dft, formula, symred, allowModularisation, enableDC);
totalTime = std::chrono::high_resolution_clock::now() - totalStart;
}
private:
ValueType checkHelper(storm::storage::DFT<ValueType> const& dft , std::shared_ptr<const storm::logic::Formula> const& formula, bool symred = true, bool allowModularisation = true, bool enableDC = true) {
STORM_LOG_TRACE("Check helper called");
bool invResults = false;
std::vector<storm::storage::DFT<ValueType>> dfts = {dft};
std::vector<ValueType> res;
size_t nrK = 0; // K out of M
size_t nrM = 0; // K out of M
if(allowModularisation) {
if(dft.topLevelType() == storm::storage::DFTElementType::AND) {
STORM_LOG_TRACE("top modularisation called AND");
dfts = dft.topModularisation();
STORM_LOG_TRACE("Modularsation into " << dfts.size() << " submodules.");
nrK = dfts.size();
nrM = dfts.size();
}
if(dft.topLevelType() == storm::storage::DFTElementType::OR) {
STORM_LOG_TRACE("top modularisation called OR");
dfts = dft.topModularisation();
STORM_LOG_TRACE("Modularsation into " << dfts.size() << " submodules.");
nrK = 0;
nrM = dfts.size();
invResults = true;
}
if(dft.topLevelType() == storm::storage::DFTElementType::VOT) {
STORM_LOG_TRACE("top modularisation called VOT");
dfts = dft.topModularisation();
STORM_LOG_TRACE("Modularsation into " << dfts.size() << " submodules.");
nrK = std::static_pointer_cast<storm::storage::DFTVot<ValueType> const>(dft.getTopLevelGate())->threshold();
nrM = dfts.size();
if(nrK <= nrM/2) {
nrK -= 1;
invResults = true;
}
}
if(dfts.size() > 1) {
STORM_LOG_TRACE("Recursive CHECK Call");
for(auto const ft : dfts) {
res.push_back(checkHelper(ft, formula, symred, allowModularisation));
}
}
}
if(res.empty()) {
// Model based modularisation.
auto const& models = buildMarkovModels(dfts, formula, symred, enableDC);
for (auto const& model : models) {
// Model checking
STORM_LOG_INFO("Model checking...");
std::chrono::high_resolution_clock::time_point modelCheckingStart = std::chrono::high_resolution_clock::now();
std::unique_ptr<storm::modelchecker::CheckResult> result(storm::verifySparseModel(model, formula));
STORM_LOG_INFO("Model checking done.");
STORM_LOG_ASSERT(result, "Result does not exist.");
result->filter(storm::modelchecker::ExplicitQualitativeCheckResult(model->getInitialStates()));
modelCheckingTime += std::chrono::high_resolution_clock::now() - modelCheckingStart;
res.push_back(result->asExplicitQuantitativeCheckResult<ValueType>().getValueMap().begin()->second);
}
}
if(nrM <= 1) {
// No modularisation done.
STORM_LOG_ASSERT(res.size()==1, "Result size not 1.");
return res[0];
}
STORM_LOG_TRACE("Combining all results... K=" << nrK << "; M=" << nrM << "; invResults=" << (invResults?"On":"Off"));
ValueType result = storm::utility::zero<ValueType>();
int limK = invResults ? -1 : nrM+1;
int chK = invResults ? -1 : 1;
for(int cK = nrK; cK != limK; cK += chK ) {
STORM_LOG_ASSERT(cK >= 0, "ck negative.");
size_t permutation = smallestIntWithNBitsSet(static_cast<size_t>(cK));
do {
STORM_LOG_TRACE("Permutation="<<permutation);
ValueType permResult = storm::utility::one<ValueType>();
for(size_t i = 0; i < res.size(); ++i) {
if(permutation & (1 << i)) {
permResult *= res[i];
} else {
permResult *= storm::utility::one<ValueType>() - res[i];
}
}
STORM_LOG_TRACE("Result for permutation:"<<permResult);
permutation = nextBitPermutation(permutation);
result += permResult;
} while(permutation < (1 << nrM) && permutation != 0);
}
if(invResults) {
return storm::utility::one<ValueType>() - result;
}
return result;
}
std::vector<std::shared_ptr<storm::models::sparse::Model<ValueType>>> buildMarkovModels(std::vector<storm::storage::DFT<ValueType>> const& dfts, std::shared_ptr<const storm::logic::Formula> const& formula, bool symred, bool enableDC) {
std::vector<std::shared_ptr<storm::models::sparse::Model<ValueType>>> models;
for(auto& dft : dfts) {
std::chrono::high_resolution_clock::time_point buildingStart = std::chrono::high_resolution_clock::now();
std::map<size_t, std::vector<std::vector<size_t>>> emptySymmetry;
storm::storage::DFTIndependentSymmetries symmetries(emptySymmetry);
if(symred) {
auto colouring = dft.colourDFT();
symmetries = dft.findSymmetries(colouring);
STORM_LOG_INFO("Found " << symmetries.groups.size() << " symmetries.");
STORM_LOG_TRACE("Symmetries: " << std::endl << symmetries);
}
std::chrono::high_resolution_clock::time_point buildingEnd = std::chrono::high_resolution_clock::now();
buildingTime += buildingEnd - buildingStart;
// Building Markov Automaton
STORM_LOG_INFO("Building Model...");
storm::builder::ExplicitDFTModelBuilder<ValueType> builder(dft, symmetries, enableDC);
typename storm::builder::ExplicitDFTModelBuilder<ValueType>::LabelOptions labeloptions; // TODO initialize this with the formula
std::shared_ptr<storm::models::sparse::Model<ValueType>> model = builder.buildModel(labeloptions);
//model->printModelInformationToStream(std::cout);
STORM_LOG_INFO("No. states (Explored): " << model->getNumberOfStates());
STORM_LOG_INFO("No. transitions (Explored): " << model->getNumberOfTransitions());
std::chrono::high_resolution_clock::time_point explorationEnd = std::chrono::high_resolution_clock::now();
explorationTime += explorationEnd -buildingEnd;
// Bisimulation
if (model->isOfType(storm::models::ModelType::Ctmc) && storm::settings::getModule<storm::settings::modules::GeneralSettings>().isBisimulationSet()) {
STORM_LOG_INFO("Bisimulation...");
model = storm::performDeterministicSparseBisimulationMinimization<storm::models::sparse::Ctmc<ValueType>>(model->template as<storm::models::sparse::Ctmc<ValueType>>(), {formula}, storm::storage::BisimulationType::Weak)->template as<storm::models::sparse::Ctmc<ValueType>>();
//model->printModelInformationToStream(std::cout);
}
STORM_LOG_INFO("No. states (Bisimulation): " << model->getNumberOfStates());
STORM_LOG_INFO("No. transitions (Bisimulation): " << model->getNumberOfTransitions());
bisimulationTime += std::chrono::high_resolution_clock::now() - explorationEnd;
models.push_back(model);
}
return models;
}
public:
void printTimings(std::ostream& os = std::cout) {
os << "Times:" << std::endl;
os << "Building:\t" << buildingTime.count() << std::endl;
os << "Exploration:\t" << explorationTime.count() << std::endl;
os << "Bisimulation:\t" << bisimulationTime.count() << std::endl;
os << "Modelchecking:\t" << modelCheckingTime.count() << std::endl;
os << "Total:\t\t" << totalTime.count() << std::endl;
}
void printResult(std::ostream& os = std::cout) {
os << "Result: [";
os << checkResult << "]" << std::endl;
}
};

18
src/modelchecker/csl/SparseCtmcCslModelChecker.cpp

@ -34,7 +34,7 @@ namespace storm {
template <typename SparseCtmcModelType> template <typename SparseCtmcModelType>
bool SparseCtmcCslModelChecker<SparseCtmcModelType>::canHandle(CheckTask<storm::logic::Formula> const& checkTask) const { bool SparseCtmcCslModelChecker<SparseCtmcModelType>::canHandle(CheckTask<storm::logic::Formula> const& checkTask) const {
storm::logic::Formula const& formula = checkTask.getFormula(); storm::logic::Formula const& formula = checkTask.getFormula();
return formula.isInFragment(storm::logic::csrl().setGloballyFormulasAllowed(false).setLongRunAverageRewardFormulasAllowed(false).setLongRunAverageProbabilitiesAllowed(true));
return formula.isInFragment(storm::logic::csrl().setGloballyFormulasAllowed(false).setLongRunAverageRewardFormulasAllowed(false).setLongRunAverageProbabilitiesAllowed(true).setTimeAllowed(true));
} }
template <typename SparseCtmcModelType> template <typename SparseCtmcModelType>
@ -111,10 +111,20 @@ namespace storm {
storm::storage::SparseMatrix<ValueType> probabilityMatrix = storm::modelchecker::helper::SparseCtmcCslHelper<ValueType>::computeProbabilityMatrix(this->getModel().getTransitionMatrix(), this->getModel().getExitRateVector()); storm::storage::SparseMatrix<ValueType> probabilityMatrix = storm::modelchecker::helper::SparseCtmcCslHelper<ValueType>::computeProbabilityMatrix(this->getModel().getTransitionMatrix(), this->getModel().getExitRateVector());
std::vector<ValueType> numericResult = storm::modelchecker::helper::SparseCtmcCslHelper<ValueType>::computeLongRunAverageProbabilities(probabilityMatrix, subResult.getTruthValuesVector(), &this->getModel().getExitRateVector(), checkTask.isQualitativeSet(), *linearEquationSolverFactory); std::vector<ValueType> numericResult = storm::modelchecker::helper::SparseCtmcCslHelper<ValueType>::computeLongRunAverageProbabilities(probabilityMatrix, subResult.getTruthValuesVector(), &this->getModel().getExitRateVector(), checkTask.isQualitativeSet(), *linearEquationSolverFactory);
return std::unique_ptr<CheckResult>(new ExplicitQuantitativeCheckResult<ValueType>(std::move(numericResult))); return std::unique_ptr<CheckResult>(new ExplicitQuantitativeCheckResult<ValueType>(std::move(numericResult)));
}
}
template <typename SparseCtmcModelType>
std::unique_ptr<CheckResult> SparseCtmcCslModelChecker<SparseCtmcModelType>::computeReachabilityTimes(storm::logic::RewardMeasureType rewardMeasureType, CheckTask<storm::logic::EventuallyFormula> const& checkTask) {
storm::logic::EventuallyFormula const& eventuallyFormula = checkTask.getFormula();
std::unique_ptr<CheckResult> subResultPointer = this->check(eventuallyFormula.getSubformula());
ExplicitQualitativeCheckResult& subResult = subResultPointer->asExplicitQualitativeCheckResult();
std::vector<ValueType> numericResult = storm::modelchecker::helper::SparseCtmcCslHelper<ValueType>::computeReachabilityTimes(this->getModel().getTransitionMatrix(), this->getModel().getBackwardTransitions(), this->getModel().getExitRateVector(), this->getModel().getInitialStates(), subResult.getTruthValuesVector(), checkTask.isQualitativeSet(), *linearEquationSolverFactory);
return std::unique_ptr<CheckResult>(new ExplicitQuantitativeCheckResult<ValueType>(std::move(numericResult)));
}
// Explicitly instantiate the model checker. // Explicitly instantiate the model checker.
template class SparseCtmcCslModelChecker<storm::models::sparse::Ctmc<double>>; template class SparseCtmcCslModelChecker<storm::models::sparse::Ctmc<double>>;
} // namespace modelchecker } // namespace modelchecker
} // namespace storm
} // namespace storm

1
src/modelchecker/csl/SparseCtmcCslModelChecker.h

@ -28,6 +28,7 @@ namespace storm {
virtual std::unique_ptr<CheckResult> computeInstantaneousRewards(storm::logic::RewardMeasureType rewardMeasureType, CheckTask<storm::logic::InstantaneousRewardFormula> const& checkTask) override; virtual std::unique_ptr<CheckResult> computeInstantaneousRewards(storm::logic::RewardMeasureType rewardMeasureType, CheckTask<storm::logic::InstantaneousRewardFormula> const& checkTask) override;
virtual std::unique_ptr<CheckResult> computeReachabilityRewards(storm::logic::RewardMeasureType rewardMeasureType, CheckTask<storm::logic::EventuallyFormula> const& checkTask) override; virtual std::unique_ptr<CheckResult> computeReachabilityRewards(storm::logic::RewardMeasureType rewardMeasureType, CheckTask<storm::logic::EventuallyFormula> const& checkTask) override;
virtual std::unique_ptr<CheckResult> computeLongRunAverageProbabilities(CheckTask<storm::logic::StateFormula> const& checkTask) override; virtual std::unique_ptr<CheckResult> computeLongRunAverageProbabilities(CheckTask<storm::logic::StateFormula> const& checkTask) override;
virtual std::unique_ptr<CheckResult> computeReachabilityTimes(storm::logic::RewardMeasureType rewardMeasureType, CheckTask<storm::logic::EventuallyFormula> const& checkTask) override;
private: private:
// An object that is used for solving linear equations and performing matrix-vector multiplication. // An object that is used for solving linear equations and performing matrix-vector multiplication.

3
src/modelchecker/csl/SparseMarkovAutomatonCslModelChecker.cpp

@ -45,7 +45,6 @@ namespace storm {
STORM_LOG_THROW(this->getModel().isClosed(), storm::exceptions::InvalidPropertyException, "Unable to compute time-bounded reachability probabilities in non-closed Markov automaton."); STORM_LOG_THROW(this->getModel().isClosed(), storm::exceptions::InvalidPropertyException, "Unable to compute time-bounded reachability probabilities in non-closed Markov automaton.");
std::unique_ptr<CheckResult> rightResultPointer = this->check(pathFormula.getRightSubformula()); std::unique_ptr<CheckResult> rightResultPointer = this->check(pathFormula.getRightSubformula());
ExplicitQualitativeCheckResult const& rightResult = rightResultPointer->asExplicitQualitativeCheckResult(); ExplicitQualitativeCheckResult const& rightResult = rightResultPointer->asExplicitQualitativeCheckResult();
double lowerBound = 0; double lowerBound = 0;
double upperBound = 0; double upperBound = 0;
if (!pathFormula.hasDiscreteTimeBound()) { if (!pathFormula.hasDiscreteTimeBound()) {
@ -111,4 +110,4 @@ namespace storm {
template class SparseMarkovAutomatonCslModelChecker<storm::models::sparse::MarkovAutomaton<double>>; template class SparseMarkovAutomatonCslModelChecker<storm::models::sparse::MarkovAutomaton<double>>;
} }
}
}

59
src/modelchecker/csl/helper/SparseCtmcCslHelper.cpp

@ -1,6 +1,7 @@
#include "src/modelchecker/csl/helper/SparseCtmcCslHelper.h" #include "src/modelchecker/csl/helper/SparseCtmcCslHelper.h"
#include "src/modelchecker/prctl/helper/SparseDtmcPrctlHelper.h" #include "src/modelchecker/prctl/helper/SparseDtmcPrctlHelper.h"
#include "src/modelchecker/reachability/SparseDtmcEliminationModelChecker.h"
#include "src/models/sparse/StandardRewardModel.h" #include "src/models/sparse/StandardRewardModel.h"
@ -11,6 +12,8 @@
#include "src/storage/StronglyConnectedComponentDecomposition.h" #include "src/storage/StronglyConnectedComponentDecomposition.h"
#include "src/adapters/CarlAdapter.h"
#include "src/utility/macros.h" #include "src/utility/macros.h"
#include "src/utility/vector.h" #include "src/utility/vector.h"
#include "src/utility/graph.h" #include "src/utility/graph.h"
@ -192,6 +195,12 @@ namespace storm {
return SparseDtmcPrctlHelper<ValueType>::computeUntilProbabilities(computeProbabilityMatrix(rateMatrix, exitRateVector), backwardTransitions, phiStates, psiStates, qualitative, linearEquationSolverFactory); return SparseDtmcPrctlHelper<ValueType>::computeUntilProbabilities(computeProbabilityMatrix(rateMatrix, exitRateVector), backwardTransitions, phiStates, psiStates, qualitative, linearEquationSolverFactory);
} }
template <typename ValueType>
std::vector<ValueType> SparseCtmcCslHelper<ValueType>::computeUntilProbabilitiesElimination(storm::storage::SparseMatrix<ValueType> const& rateMatrix, storm::storage::SparseMatrix<ValueType> const& backwardTransitions, std::vector<ValueType> const& exitRateVector, storm::storage::BitVector const& initialStates, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, bool qualitative) {
// Use "normal" function again, if RationalFunction finally is supported.
return storm::modelchecker::SparseDtmcEliminationModelChecker<storm::models::sparse::Dtmc<ValueType>>::computeUntilProbabilities(computeProbabilityMatrix(rateMatrix, exitRateVector), backwardTransitions, initialStates, phiStates, psiStates, false);
}
template <typename ValueType> template <typename ValueType>
std::vector<ValueType> SparseCtmcCslHelper<ValueType>::computeNextProbabilities(storm::storage::SparseMatrix<ValueType> const& rateMatrix, std::vector<ValueType> const& exitRateVector, storm::storage::BitVector const& nextStates, storm::utility::solver::LinearEquationSolverFactory<ValueType> const& linearEquationSolverFactory) { std::vector<ValueType> SparseCtmcCslHelper<ValueType>::computeNextProbabilities(storm::storage::SparseMatrix<ValueType> const& rateMatrix, std::vector<ValueType> const& exitRateVector, storm::storage::BitVector const& nextStates, storm::utility::solver::LinearEquationSolverFactory<ValueType> const& linearEquationSolverFactory) {
return SparseDtmcPrctlHelper<ValueType>::computeNextProbabilities(computeProbabilityMatrix(rateMatrix, exitRateVector), nextStates, linearEquationSolverFactory); return SparseDtmcPrctlHelper<ValueType>::computeNextProbabilities(computeProbabilityMatrix(rateMatrix, exitRateVector), nextStates, linearEquationSolverFactory);
@ -236,7 +245,7 @@ namespace storm {
} }
// Use Fox-Glynn to get the truncation points and the weights. // Use Fox-Glynn to get the truncation points and the weights.
std::tuple<uint_fast64_t, uint_fast64_t, ValueType, std::vector<ValueType>> foxGlynnResult = storm::utility::numerical::getFoxGlynnCutoff(lambda, 1e-300, 1e+300, storm::settings::generalSettings().getPrecision() / 8.0);
std::tuple<uint_fast64_t, uint_fast64_t, ValueType, std::vector<ValueType>> foxGlynnResult = storm::utility::numerical::getFoxGlynnCutoff(lambda, 1e-300, 1e+300, storm::settings::getModule<storm::settings::modules::GeneralSettings>().getPrecision() / 8.0);
STORM_LOG_DEBUG("Fox-Glynn cutoff points: left=" << std::get<0>(foxGlynnResult) << ", right=" << std::get<1>(foxGlynnResult)); STORM_LOG_DEBUG("Fox-Glynn cutoff points: left=" << std::get<0>(foxGlynnResult) << ", right=" << std::get<1>(foxGlynnResult));
// Scale the weights so they add up to one. // Scale the weights so they add up to one.
@ -645,12 +654,58 @@ namespace storm {
return result; return result;
} }
template <typename ValueType>
std::vector<ValueType> SparseCtmcCslHelper<ValueType>::computeReachabilityTimes(storm::storage::SparseMatrix<ValueType> const& rateMatrix, storm::storage::SparseMatrix<ValueType> const& backwardTransitions, std::vector<ValueType> const& exitRateVector, storm::storage::BitVector const& initialStates, storm::storage::BitVector const& targetStates, bool qualitative, storm::utility::solver::LinearEquationSolverFactory<ValueType> const& linearEquationSolverFactory) {
// Compute expected time on CTMC by reduction to DTMC with rewards.
storm::storage::SparseMatrix<ValueType> probabilityMatrix = computeProbabilityMatrix(rateMatrix, exitRateVector);
// Initialize rewards.
std::vector<ValueType> totalRewardVector;
for (size_t i = 0; i < exitRateVector.size(); ++i) {
if (targetStates[i] || storm::utility::isZero(exitRateVector[i])) {
// Set reward for target states or states without outgoing transitions to 0.
totalRewardVector.push_back(storm::utility::zero<ValueType>());
} else {
// Reward is (1 / exitRate).
totalRewardVector.push_back(storm::utility::one<ValueType>() / exitRateVector[i]);
}
}
return storm::modelchecker::helper::SparseDtmcPrctlHelper<ValueType>::computeReachabilityRewards(probabilityMatrix, backwardTransitions, totalRewardVector, targetStates, qualitative, linearEquationSolverFactory);
}
template <typename ValueType>
std::vector<ValueType> SparseCtmcCslHelper<ValueType>::computeReachabilityTimesElimination(storm::storage::SparseMatrix<ValueType> const& rateMatrix, storm::storage::SparseMatrix<ValueType> const& backwardTransitions, std::vector<ValueType> const& exitRateVector, storm::storage::BitVector const& initialStates, storm::storage::BitVector const& targetStates, bool qualitative) {
// Use "normal" function again, if RationalFunction finally is supported.
// Compute expected time on CTMC by reduction to DTMC with rewards.
storm::storage::SparseMatrix<ValueType> probabilityMatrix = computeProbabilityMatrix(rateMatrix, exitRateVector);
// Initialize rewards.
std::vector<ValueType> totalRewardVector;
for (size_t i = 0; i < exitRateVector.size(); ++i) {
if (targetStates[i] || storm::utility::isZero(exitRateVector[i])) {
// Set reward for target states or states without outgoing transitions to 0.
totalRewardVector.push_back(storm::utility::zero<ValueType>());
} else {
// Reward is (1 / exitRate).
totalRewardVector.push_back(storm::utility::one<ValueType>() / exitRateVector[i]);
}
}
return storm::modelchecker::SparseDtmcEliminationModelChecker<storm::models::sparse::Dtmc<ValueType>>::computeReachabilityRewards(probabilityMatrix, backwardTransitions, initialStates, targetStates, totalRewardVector, false);
}
template class SparseCtmcCslHelper<double>; template class SparseCtmcCslHelper<double>;
template std::vector<double> SparseCtmcCslHelper<double>::computeInstantaneousRewards(storm::storage::SparseMatrix<double> const& rateMatrix, std::vector<double> const& exitRateVector, storm::models::sparse::StandardRewardModel<double> const& rewardModel, double timeBound, storm::utility::solver::LinearEquationSolverFactory<double> const& linearEquationSolverFactory); template std::vector<double> SparseCtmcCslHelper<double>::computeInstantaneousRewards(storm::storage::SparseMatrix<double> const& rateMatrix, std::vector<double> const& exitRateVector, storm::models::sparse::StandardRewardModel<double> const& rewardModel, double timeBound, storm::utility::solver::LinearEquationSolverFactory<double> const& linearEquationSolverFactory);
template std::vector<double> SparseCtmcCslHelper<double>::computeCumulativeRewards(storm::storage::SparseMatrix<double> const& rateMatrix, std::vector<double> const& exitRateVector, storm::models::sparse::StandardRewardModel<double> const& rewardModel, double timeBound, storm::utility::solver::LinearEquationSolverFactory<double> const& linearEquationSolverFactory); template std::vector<double> SparseCtmcCslHelper<double>::computeCumulativeRewards(storm::storage::SparseMatrix<double> const& rateMatrix, std::vector<double> const& exitRateVector, storm::models::sparse::StandardRewardModel<double> const& rewardModel, double timeBound, storm::utility::solver::LinearEquationSolverFactory<double> const& linearEquationSolverFactory);
template std::vector<double> SparseCtmcCslHelper<double>::computeReachabilityRewards(storm::storage::SparseMatrix<double> const& rateMatrix, storm::storage::SparseMatrix<double> const& backwardTransitions, std::vector<double> const& exitRateVector, storm::models::sparse::StandardRewardModel<double> const& rewardModel, storm::storage::BitVector const& targetStates, bool qualitative, storm::utility::solver::LinearEquationSolverFactory<double> const& linearEquationSolverFactory); template std::vector<double> SparseCtmcCslHelper<double>::computeReachabilityRewards(storm::storage::SparseMatrix<double> const& rateMatrix, storm::storage::SparseMatrix<double> const& backwardTransitions, std::vector<double> const& exitRateVector, storm::models::sparse::StandardRewardModel<double> const& rewardModel, storm::storage::BitVector const& targetStates, bool qualitative, storm::utility::solver::LinearEquationSolverFactory<double> const& linearEquationSolverFactory);
#ifdef STORM_HAVE_CARL
template std::vector<storm::RationalFunction> SparseCtmcCslHelper<storm::RationalFunction>::computeUntilProbabilitiesElimination(storm::storage::SparseMatrix<storm::RationalFunction> const& rateMatrix, storm::storage::SparseMatrix<storm::RationalFunction> const& backwardTransitions, std::vector<storm::RationalFunction> const& exitRateVector, storm::storage::BitVector const& initialStates, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, bool qualitative);
template std::vector<storm::RationalFunction> SparseCtmcCslHelper<storm::RationalFunction>::computeReachabilityTimesElimination(storm::storage::SparseMatrix<storm::RationalFunction> const& rateMatrix, storm::storage::SparseMatrix<storm::RationalFunction> const& backwardTransitions, std::vector<storm::RationalFunction> const& exitRateVector, storm::storage::BitVector const& initialStates, storm::storage::BitVector const& targetStates, bool qualitative);
#endif
} }
} }
}
}

6
src/modelchecker/csl/helper/SparseCtmcCslHelper.h

@ -16,6 +16,7 @@ namespace storm {
static std::vector<ValueType> computeNextProbabilities(storm::storage::SparseMatrix<ValueType> const& rateMatrix, std::vector<ValueType> const& exitRateVector, storm::storage::BitVector const& nextStates, storm::utility::solver::LinearEquationSolverFactory<ValueType> const& linearEquationSolverFactory); static std::vector<ValueType> computeNextProbabilities(storm::storage::SparseMatrix<ValueType> const& rateMatrix, std::vector<ValueType> const& exitRateVector, storm::storage::BitVector const& nextStates, storm::utility::solver::LinearEquationSolverFactory<ValueType> const& linearEquationSolverFactory);
static std::vector<ValueType> computeUntilProbabilities(storm::storage::SparseMatrix<ValueType> const& rateMatrix, storm::storage::SparseMatrix<ValueType> const& backwardTransitions, std::vector<ValueType> const& exitRateVector, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, bool qualitative, storm::utility::solver::LinearEquationSolverFactory<ValueType> const& linearEquationSolverFactory); static std::vector<ValueType> computeUntilProbabilities(storm::storage::SparseMatrix<ValueType> const& rateMatrix, storm::storage::SparseMatrix<ValueType> const& backwardTransitions, std::vector<ValueType> const& exitRateVector, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, bool qualitative, storm::utility::solver::LinearEquationSolverFactory<ValueType> const& linearEquationSolverFactory);
static std::vector<ValueType> computeUntilProbabilitiesElimination(storm::storage::SparseMatrix<ValueType> const& rateMatrix, storm::storage::SparseMatrix<ValueType> const& backwardTransitions, std::vector<ValueType> const& exitRateVector, storm::storage::BitVector const& initialStates, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, bool qualitative);
template <typename RewardModelType> template <typename RewardModelType>
static std::vector<ValueType> computeInstantaneousRewards(storm::storage::SparseMatrix<ValueType> const& rateMatrix, std::vector<ValueType> const& exitRateVector, RewardModelType const& rewardModel, double timeBound, storm::utility::solver::LinearEquationSolverFactory<ValueType> const& linearEquationSolverFactory); static std::vector<ValueType> computeInstantaneousRewards(storm::storage::SparseMatrix<ValueType> const& rateMatrix, std::vector<ValueType> const& exitRateVector, RewardModelType const& rewardModel, double timeBound, storm::utility::solver::LinearEquationSolverFactory<ValueType> const& linearEquationSolverFactory);
@ -28,6 +29,9 @@ namespace storm {
static std::vector<ValueType> computeLongRunAverageProbabilities(storm::storage::SparseMatrix<ValueType> const& probabilityMatrix, storm::storage::BitVector const& psiStates, std::vector<ValueType> const* exitRateVector, bool qualitative, storm::utility::solver::LinearEquationSolverFactory<ValueType> const& linearEquationSolverFactory); static std::vector<ValueType> computeLongRunAverageProbabilities(storm::storage::SparseMatrix<ValueType> const& probabilityMatrix, storm::storage::BitVector const& psiStates, std::vector<ValueType> const* exitRateVector, bool qualitative, storm::utility::solver::LinearEquationSolverFactory<ValueType> const& linearEquationSolverFactory);
static std::vector<ValueType> computeReachabilityTimes(storm::storage::SparseMatrix<ValueType> const& rateMatrix, storm::storage::SparseMatrix<ValueType> const& backwardTransitions, std::vector<ValueType> const& exitRateVector, storm::storage::BitVector const& initialStates, storm::storage::BitVector const& targetStates, bool qualitative, storm::utility::solver::LinearEquationSolverFactory<ValueType> const& minMaxLinearEquationSolverFactory);
static std::vector<ValueType> computeReachabilityTimesElimination(storm::storage::SparseMatrix<ValueType> const& rateMatrix, storm::storage::SparseMatrix<ValueType> const& backwardTransitions, std::vector<ValueType> const& exitRateVector, storm::storage::BitVector const& initialStates, storm::storage::BitVector const& targetStates, bool qualitative);
/*! /*!
* Computes the matrix representing the transitions of the uniformized CTMC. * Computes the matrix representing the transitions of the uniformized CTMC.
* *
@ -78,4 +82,4 @@ namespace storm {
} }
} }
#endif /* STORM_MODELCHECKER_SPARSE_CTMC_CSL_MODELCHECKER_HELPER_H_ */
#endif /* STORM_MODELCHECKER_SPARSE_CTMC_CSL_MODELCHECKER_HELPER_H_ */

54
src/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp

@ -122,17 +122,17 @@ namespace storm {
std::vector<ValueType> SparseMarkovAutomatonCslHelper<ValueType>::computeBoundedUntilProbabilities(OptimizationDirection dir, storm::storage::SparseMatrix<ValueType> const& transitionMatrix, std::vector<ValueType> const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, std::pair<double, double> const& boundsPair, storm::utility::solver::MinMaxLinearEquationSolverFactory<ValueType> const& minMaxLinearEquationSolverFactory) { std::vector<ValueType> SparseMarkovAutomatonCslHelper<ValueType>::computeBoundedUntilProbabilities(OptimizationDirection dir, storm::storage::SparseMatrix<ValueType> const& transitionMatrix, std::vector<ValueType> const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, std::pair<double, double> const& boundsPair, storm::utility::solver::MinMaxLinearEquationSolverFactory<ValueType> const& minMaxLinearEquationSolverFactory) {
uint_fast64_t numberOfStates = transitionMatrix.getRowGroupCount(); uint_fast64_t numberOfStates = transitionMatrix.getRowGroupCount();
// 'Unpack' the bounds to make them more easily accessible. // 'Unpack' the bounds to make them more easily accessible.
double lowerBound = boundsPair.first; double lowerBound = boundsPair.first;
double upperBound = boundsPair.second; double upperBound = boundsPair.second;
// (1) Compute the accuracy we need to achieve the required error bound. // (1) Compute the accuracy we need to achieve the required error bound.
ValueType maxExitRate = 0; ValueType maxExitRate = 0;
for (auto value : exitRateVector) { for (auto value : exitRateVector) {
maxExitRate = std::max(maxExitRate, value); maxExitRate = std::max(maxExitRate, value);
} }
ValueType delta = (2 * storm::settings::generalSettings().getPrecision()) / (upperBound * maxExitRate * maxExitRate);
ValueType delta = (2 * storm::settings::getModule<storm::settings::modules::GeneralSettings>().getPrecision()) / (upperBound * maxExitRate * maxExitRate);
// (2) Compute the number of steps we need to make for the interval. // (2) Compute the number of steps we need to make for the interval.
uint_fast64_t numberOfSteps = static_cast<uint_fast64_t>(std::ceil((upperBound - lowerBound) / delta)); uint_fast64_t numberOfSteps = static_cast<uint_fast64_t>(std::ceil((upperBound - lowerBound) / delta));
@ -408,33 +408,35 @@ namespace storm {
infinityStates = storm::storage::BitVector(numberOfStates); infinityStates = storm::storage::BitVector(numberOfStates);
} }
} }
// Now we identify the states for which values need to be computed. // Now we identify the states for which values need to be computed.
storm::storage::BitVector maybeStates = ~(goalStates | infinityStates); storm::storage::BitVector maybeStates = ~(goalStates | infinityStates);
// Then, we can eliminate the rows and columns for all states whose values are already known to be 0.
std::vector<ValueType> x(maybeStates.getNumberOfSetBits());
storm::storage::SparseMatrix<ValueType> submatrix = transitionMatrix.getSubmatrix(true, maybeStates, maybeStates);
// Now prepare the expected reward values for all states so they can be used as the right-hand side of the equation system.
std::vector<ValueType> rewardValues(stateRewards);
for (auto state : markovianStates) {
rewardValues[state] = rewardValues[state] / exitRateVector[state];
}
// Finally, prepare the actual right-hand side.
std::vector<ValueType> b(submatrix.getRowCount());
storm::utility::vector::selectVectorValuesRepeatedly(b, maybeStates, transitionMatrix.getRowGroupIndices(), rewardValues);
// Solve the corresponding system of equations.
std::unique_ptr<storm::solver::MinMaxLinearEquationSolver<ValueType>> solver = minMaxLinearEquationSolverFactory.create(submatrix);
solver->solveEquationSystem(dir, x, b);
// Create resulting vector. // Create resulting vector.
std::vector<ValueType> result(numberOfStates); std::vector<ValueType> result(numberOfStates);
// Set values of resulting vector according to previous result and return the result.
storm::utility::vector::setVectorValues<ValueType>(result, maybeStates, x);
if (!maybeStates.empty()) {
// Then, we can eliminate the rows and columns for all states whose values are already known.
std::vector<ValueType> x(maybeStates.getNumberOfSetBits());
storm::storage::SparseMatrix<ValueType> submatrix = transitionMatrix.getSubmatrix(true, maybeStates, maybeStates);
// Now prepare the expected reward values for all states so they can be used as the right-hand side of the equation system.
std::vector<ValueType> rewardValues(stateRewards);
for (auto state : markovianStates) {
rewardValues[state] = rewardValues[state] / exitRateVector[state];
}
// Finally, prepare the actual right-hand side.
std::vector<ValueType> b(submatrix.getRowCount());
storm::utility::vector::selectVectorValuesRepeatedly(b, maybeStates, transitionMatrix.getRowGroupIndices(), rewardValues);
// Solve the corresponding system of equations.
std::unique_ptr<storm::solver::MinMaxLinearEquationSolver<ValueType>> solver = minMaxLinearEquationSolverFactory.create(submatrix);
solver->solveEquationSystem(dir, x, b);
// Set values of resulting vector according to previous result and return the result.
storm::utility::vector::setVectorValues<ValueType>(result, maybeStates, x);
}
storm::utility::vector::setVectorValues(result, goalStates, storm::utility::zero<ValueType>()); storm::utility::vector::setVectorValues(result, goalStates, storm::utility::zero<ValueType>());
storm::utility::vector::setVectorValues(result, infinityStates, storm::utility::infinity<ValueType>()); storm::utility::vector::setVectorValues(result, infinityStates, storm::utility::infinity<ValueType>());
@ -508,4 +510,4 @@ namespace storm {
} }
} }
}
}

4
src/modelchecker/exploration/ExplorationInformation.cpp

@ -12,7 +12,7 @@ namespace storm {
template<typename StateType, typename ValueType> template<typename StateType, typename ValueType>
ExplorationInformation<StateType, ValueType>::ExplorationInformation(storm::OptimizationDirection const& direction, ActionType const& unexploredMarker) : unexploredMarker(unexploredMarker), optimizationDirection(direction), localPrecomputation(false), numberOfExplorationStepsUntilPrecomputation(100000), numberOfSampledPathsUntilPrecomputation(), nextStateHeuristic(storm::settings::modules::ExplorationSettings::NextStateHeuristic::DifferenceProbabilitySum) { ExplorationInformation<StateType, ValueType>::ExplorationInformation(storm::OptimizationDirection const& direction, ActionType const& unexploredMarker) : unexploredMarker(unexploredMarker), optimizationDirection(direction), localPrecomputation(false), numberOfExplorationStepsUntilPrecomputation(100000), numberOfSampledPathsUntilPrecomputation(), nextStateHeuristic(storm::settings::modules::ExplorationSettings::NextStateHeuristic::DifferenceProbabilitySum) {
storm::settings::modules::ExplorationSettings const& settings = storm::settings::explorationSettings();
storm::settings::modules::ExplorationSettings const& settings = storm::settings::getModule<storm::settings::modules::ExplorationSettings>();
localPrecomputation = settings.isLocalPrecomputationSet(); localPrecomputation = settings.isLocalPrecomputationSet();
numberOfExplorationStepsUntilPrecomputation = settings.getNumberOfExplorationStepsUntilPrecomputation(); numberOfExplorationStepsUntilPrecomputation = settings.getNumberOfExplorationStepsUntilPrecomputation();
if (settings.isNumberOfSampledPathsUntilPrecomputationSet()) { if (settings.isNumberOfSampledPathsUntilPrecomputationSet()) {
@ -224,4 +224,4 @@ namespace storm {
template class ExplorationInformation<uint32_t, double>; template class ExplorationInformation<uint32_t, double>;
} }
} }
}
}

9
src/modelchecker/exploration/SparseExplorationModelChecker.cpp

@ -19,7 +19,8 @@
#include "src/models/sparse/StandardRewardModel.h" #include "src/models/sparse/StandardRewardModel.h"
#include "src/settings/SettingsManager.h" #include "src/settings/SettingsManager.h"
#include "src/settings/modules/GeneralSettings.h"
#include "src/settings/modules/MarkovChainSettings.h"
#include "src/settings/modules/ExplorationSettings.h"
#include "src/utility/macros.h" #include "src/utility/macros.h"
#include "src/utility/constants.h" #include "src/utility/constants.h"
@ -34,7 +35,7 @@ namespace storm {
namespace modelchecker { namespace modelchecker {
template<typename ValueType, typename StateType> template<typename ValueType, typename StateType>
SparseExplorationModelChecker<ValueType, StateType>::SparseExplorationModelChecker(storm::prism::Program const& program, boost::optional<std::map<storm::expressions::Variable, storm::expressions::Expression>> const& constantDefinitions) : program(storm::utility::prism::preprocessProgram<ValueType>(program, constantDefinitions)), variableInformation(this->program), randomGenerator(std::chrono::system_clock::now().time_since_epoch().count()), comparator(storm::settings::explorationSettings().getPrecision()) {
SparseExplorationModelChecker<ValueType, StateType>::SparseExplorationModelChecker(storm::prism::Program const& program, boost::optional<std::map<storm::expressions::Variable, storm::expressions::Expression>> const& constantDefinitions) : program(storm::utility::prism::preprocessProgram<ValueType>(program, constantDefinitions)), variableInformation(this->program), randomGenerator(std::chrono::system_clock::now().time_since_epoch().count()), comparator(storm::settings::getModule<storm::settings::modules::ExplorationSettings>().getPrecision()) {
// Intentionally left empty. // Intentionally left empty.
} }
@ -112,7 +113,7 @@ namespace storm {
} }
// Show statistics if required. // Show statistics if required.
if (storm::settings::generalSettings().isShowStatisticsSet()) {
if (storm::settings::getModule<storm::settings::modules::MarkovChainSettings>().isShowStatisticsSet()) {
stats.printToStream(std::cout, explorationInformation); stats.printToStream(std::cout, explorationInformation);
} }
@ -684,4 +685,4 @@ namespace storm {
template class SparseExplorationModelChecker<double, uint32_t>; template class SparseExplorationModelChecker<double, uint32_t>;
} }
}
}

615
src/modelchecker/reachability/SparseDtmcEliminationModelChecker.cpp

@ -7,7 +7,7 @@
#include "src/adapters/CarlAdapter.h" #include "src/adapters/CarlAdapter.h"
#include "src/settings/modules/SparseDtmcEliminationModelCheckerSettings.h" #include "src/settings/modules/SparseDtmcEliminationModelCheckerSettings.h"
#include "src/settings/modules/GeneralSettings.h"
#include "src/settings/modules/MarkovChainSettings.h"
#include "src/settings/SettingsManager.h" #include "src/settings/SettingsManager.h"
#include "src/storage/StronglyConnectedComponentDecomposition.h" #include "src/storage/StronglyConnectedComponentDecomposition.h"
@ -27,6 +27,10 @@
#include "src/exceptions/InvalidSettingsException.h" #include "src/exceptions/InvalidSettingsException.h"
#include "src/exceptions/IllegalArgumentException.h" #include "src/exceptions/IllegalArgumentException.h"
#include "src/solver/stateelimination/LongRunAverageEliminator.h"
#include "src/solver/stateelimination/ConditionalEliminator.h"
#include "src/solver/stateelimination/PrioritizedEliminator.h"
namespace storm { namespace storm {
namespace modelchecker { namespace modelchecker {
@ -221,15 +225,15 @@ namespace storm {
std::chrono::high_resolution_clock::time_point conversionStart = std::chrono::high_resolution_clock::now(); std::chrono::high_resolution_clock::time_point conversionStart = std::chrono::high_resolution_clock::now();
// Then, we convert the reduced matrix to a more flexible format to be able to perform state elimination more easily. // Then, we convert the reduced matrix to a more flexible format to be able to perform state elimination more easily.
FlexibleSparseMatrix flexibleMatrix = getFlexibleSparseMatrix(transitionMatrix);
flexibleMatrix.filter(maybeStates, maybeStates);
FlexibleSparseMatrix flexibleBackwardTransitions = getFlexibleSparseMatrix(backwardTransitions);
flexibleBackwardTransitions.filter(maybeStates, maybeStates);
storm::storage::FlexibleSparseMatrix<ValueType> flexibleMatrix(transitionMatrix);
flexibleMatrix.createSubmatrix(maybeStates, maybeStates);
storm::storage::FlexibleSparseMatrix<ValueType> flexibleBackwardTransitions(backwardTransitions);
flexibleBackwardTransitions.createSubmatrix(maybeStates, maybeStates);
auto conversionEnd = std::chrono::high_resolution_clock::now(); auto conversionEnd = std::chrono::high_resolution_clock::now();
std::chrono::high_resolution_clock::time_point modelCheckingStart = std::chrono::high_resolution_clock::now(); std::chrono::high_resolution_clock::time_point modelCheckingStart = std::chrono::high_resolution_clock::now();
storm::settings::modules::SparseDtmcEliminationModelCheckerSettings::EliminationOrder order = storm::settings::sparseDtmcEliminationModelCheckerSettings().getEliminationOrder();
storm::settings::modules::SparseDtmcEliminationModelCheckerSettings::EliminationOrder order = storm::settings::getModule<storm::settings::modules::SparseDtmcEliminationModelCheckerSettings>().getEliminationOrder();
boost::optional<std::vector<uint_fast64_t>> distanceBasedPriorities; boost::optional<std::vector<uint_fast64_t>> distanceBasedPriorities;
if (eliminationOrderNeedsDistances(order)) { if (eliminationOrderNeedsDistances(order)) {
distanceBasedPriorities = getDistanceBasedPriorities(transitionMatrix, backwardTransitions, initialStates, stateValues, distanceBasedPriorities = getDistanceBasedPriorities(transitionMatrix, backwardTransitions, initialStates, stateValues,
@ -261,30 +265,15 @@ namespace storm {
std::vector<ValueType> averageTimeInStates(stateValues.size(), storm::utility::one<ValueType>()); std::vector<ValueType> averageTimeInStates(stateValues.size(), storm::utility::one<ValueType>());
// First, we eliminate all states in BSCCs (except for the representative states). // First, we eliminate all states in BSCCs (except for the representative states).
{
std::unique_ptr<StatePriorityQueue> priorityQueue = createStatePriorityQueue(distanceBasedPriorities, flexibleMatrix, flexibleBackwardTransitions, stateValues, regularStatesInBsccs);
ValueUpdateCallback valueUpdateCallback = [&stateValues,&averageTimeInStates] (storm::storage::sparse::state_type const& state, ValueType const& loopProbability) {
stateValues[state] = storm::utility::simplify(loopProbability * stateValues[state]);
averageTimeInStates[state] = storm::utility::simplify(loopProbability * averageTimeInStates[state]);
};
PredecessorUpdateCallback predecessorCallback = [&stateValues,&averageTimeInStates] (storm::storage::sparse::state_type const& predecessor, ValueType const& probability, storm::storage::sparse::state_type const& state) {
stateValues[predecessor] = storm::utility::simplify(stateValues[predecessor] + storm::utility::simplify(probability * stateValues[state]));
averageTimeInStates[predecessor] = storm::utility::simplify(averageTimeInStates[predecessor] + storm::utility::simplify(probability * averageTimeInStates[state]));
};
boost::optional<PriorityUpdateCallback> priorityUpdateCallback = PriorityUpdateCallback([&flexibleMatrix,&flexibleBackwardTransitions,&stateValues,&priorityQueue] (storm::storage::sparse::state_type const& state) {
priorityQueue->update(state, flexibleMatrix, flexibleBackwardTransitions, stateValues);
});
boost::optional<PredecessorFilterCallback> predecessorFilterCallback = boost::none;
while (priorityQueue->hasNextState()) {
storm::storage::sparse::state_type state = priorityQueue->popNextState();
eliminateState(state, flexibleMatrix, flexibleBackwardTransitions, valueUpdateCallback, predecessorCallback, priorityUpdateCallback, predecessorFilterCallback, true);
STORM_LOG_ASSERT(checkConsistent(flexibleMatrix, flexibleBackwardTransitions), "The forward and backward transition matrices became inconsistent.");
}
std::shared_ptr<StatePriorityQueue<ValueType>> priorityQueue = createStatePriorityQueue(distanceBasedPriorities, flexibleMatrix, flexibleBackwardTransitions, stateValues, regularStatesInBsccs);
storm::solver::stateelimination::LongRunAverageEliminator<SparseDtmcModelType> stateEliminator(flexibleMatrix, flexibleBackwardTransitions, priorityQueue, stateValues, averageTimeInStates);
while (priorityQueue->hasNextState()) {
storm::storage::sparse::state_type state = priorityQueue->popNextState();
stateEliminator.eliminateState(state, true);
#ifdef STORM_DEV
STORM_LOG_ASSERT(checkConsistent(flexibleMatrix, flexibleBackwardTransitions), "The forward and backward transition matrices became inconsistent.");
#endif
} }
// Now, we set the values of all states in BSCCs to that of the representative value (and clear the // Now, we set the values of all states in BSCCs to that of the representative value (and clear the
@ -306,11 +295,11 @@ namespace storm {
stateValues[*representativeIt] = bsccValue; stateValues[*representativeIt] = bsccValue;
} }
typename SparseDtmcEliminationModelChecker<SparseDtmcModelType>::FlexibleSparseMatrix::row_type& representativeForwardRow = flexibleMatrix.getRow(*representativeIt);
FlexibleRowType& representativeForwardRow = flexibleMatrix.getRow(*representativeIt);
representativeForwardRow.clear(); representativeForwardRow.clear();
representativeForwardRow.shrink_to_fit(); representativeForwardRow.shrink_to_fit();
typename SparseDtmcEliminationModelChecker<SparseDtmcModelType>::FlexibleSparseMatrix::row_type& representativeBackwardRow = flexibleBackwardTransitions.getRow(*representativeIt);
FlexibleRowType& representativeBackwardRow = flexibleBackwardTransitions.getRow(*representativeIt);
auto it = representativeBackwardRow.begin(), ite = representativeBackwardRow.end(); auto it = representativeBackwardRow.begin(), ite = representativeBackwardRow.end();
for (; it != ite; ++it) { for (; it != ite; ++it) {
if (it->getColumn() == *representativeIt) { if (it->getColumn() == *representativeIt) {
@ -343,7 +332,7 @@ namespace storm {
std::chrono::high_resolution_clock::time_point modelCheckingEnd = std::chrono::high_resolution_clock::now(); std::chrono::high_resolution_clock::time_point modelCheckingEnd = std::chrono::high_resolution_clock::now();
std::chrono::high_resolution_clock::time_point totalTimeEnd = std::chrono::high_resolution_clock::now(); std::chrono::high_resolution_clock::time_point totalTimeEnd = std::chrono::high_resolution_clock::now();
if (storm::settings::generalSettings().isShowStatisticsSet()) {
if (storm::settings::getModule<storm::settings::modules::MarkovChainSettings>().isShowStatisticsSet()) {
std::chrono::high_resolution_clock::duration sccDecompositionTime = sccDecompositionEnd - sccDecompositionStart; std::chrono::high_resolution_clock::duration sccDecompositionTime = sccDecompositionEnd - sccDecompositionStart;
std::chrono::milliseconds sccDecompositionTimeInMilliseconds = std::chrono::duration_cast<std::chrono::milliseconds>(sccDecompositionTime); std::chrono::milliseconds sccDecompositionTimeInMilliseconds = std::chrono::duration_cast<std::chrono::milliseconds>(sccDecompositionTime);
std::chrono::high_resolution_clock::duration conversionTime = conversionEnd - conversionStart; std::chrono::high_resolution_clock::duration conversionTime = conversionEnd - conversionStart;
@ -482,46 +471,56 @@ namespace storm {
std::unique_ptr<CheckResult> rightResultPointer = this->check(pathFormula.getRightSubformula()); std::unique_ptr<CheckResult> rightResultPointer = this->check(pathFormula.getRightSubformula());
storm::storage::BitVector const& phiStates = leftResultPointer->asExplicitQualitativeCheckResult().getTruthValuesVector(); storm::storage::BitVector const& phiStates = leftResultPointer->asExplicitQualitativeCheckResult().getTruthValuesVector();
storm::storage::BitVector const& psiStates = rightResultPointer->asExplicitQualitativeCheckResult().getTruthValuesVector(); storm::storage::BitVector const& psiStates = rightResultPointer->asExplicitQualitativeCheckResult().getTruthValuesVector();
std::vector<ValueType> result = computeUntilProbabilities(this->getModel().getTransitionMatrix(), this->getModel().getBackwardTransitions(), this->getModel().getInitialStates(), phiStates, psiStates, checkTask.isOnlyInitialStatesRelevantSet());
// Construct check result.
std::unique_ptr<CheckResult> checkResult(new ExplicitQuantitativeCheckResult<ValueType>(result));
return checkResult;
}
template<typename SparseDtmcModelType>
std::vector<typename SparseDtmcModelType::ValueType> SparseDtmcEliminationModelChecker<SparseDtmcModelType>::computeUntilProbabilities(storm::storage::SparseMatrix<ValueType> const& probabilityMatrix, storm::storage::SparseMatrix<ValueType> const& backwardTransitions, storm::storage::BitVector const& initialStates, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, bool computeForInitialStatesOnly) {
// Then, compute the subset of states that has a probability of 0 or 1, respectively. // Then, compute the subset of states that has a probability of 0 or 1, respectively.
std::pair<storm::storage::BitVector, storm::storage::BitVector> statesWithProbability01 = storm::utility::graph::performProb01(this->getModel(), phiStates, psiStates);
std::pair<storm::storage::BitVector, storm::storage::BitVector> statesWithProbability01 = storm::utility::graph::performProb01(backwardTransitions, phiStates, psiStates);
storm::storage::BitVector statesWithProbability0 = statesWithProbability01.first; storm::storage::BitVector statesWithProbability0 = statesWithProbability01.first;
storm::storage::BitVector statesWithProbability1 = statesWithProbability01.second; storm::storage::BitVector statesWithProbability1 = statesWithProbability01.second;
storm::storage::BitVector maybeStates = ~(statesWithProbability0 | statesWithProbability1); storm::storage::BitVector maybeStates = ~(statesWithProbability0 | statesWithProbability1);
// Determine whether we need to perform some further computation. // Determine whether we need to perform some further computation.
bool furtherComputationNeeded = true; bool furtherComputationNeeded = true;
if (checkTask.isOnlyInitialStatesRelevantSet() && this->getModel().getInitialStates().isDisjointFrom(maybeStates)) {
if (computeForInitialStatesOnly && initialStates.isDisjointFrom(maybeStates)) {
STORM_LOG_DEBUG("The probability for all initial states was found in a preprocessing step."); STORM_LOG_DEBUG("The probability for all initial states was found in a preprocessing step.");
furtherComputationNeeded = false; furtherComputationNeeded = false;
} else if (maybeStates.empty()) { } else if (maybeStates.empty()) {
STORM_LOG_DEBUG("The probability for all states was found in a preprocessing step."); STORM_LOG_DEBUG("The probability for all states was found in a preprocessing step.");
furtherComputationNeeded = false; furtherComputationNeeded = false;
} }
std::vector<ValueType> result(maybeStates.size()); std::vector<ValueType> result(maybeStates.size());
if (furtherComputationNeeded) { if (furtherComputationNeeded) {
// If we compute the results for the initial states only, we can cut off all maybe state that are not // If we compute the results for the initial states only, we can cut off all maybe state that are not
// reachable from them. // reachable from them.
if (checkTask.isOnlyInitialStatesRelevantSet()) {
if (computeForInitialStatesOnly) {
// Determine the set of states that is reachable from the initial state without jumping over a target state. // Determine the set of states that is reachable from the initial state without jumping over a target state.
storm::storage::BitVector reachableStates = storm::utility::graph::getReachableStates(this->getModel().getTransitionMatrix(), this->getModel().getInitialStates(), maybeStates, statesWithProbability1);
storm::storage::BitVector reachableStates = storm::utility::graph::getReachableStates(probabilityMatrix, initialStates, maybeStates, statesWithProbability1);
// Subtract from the maybe states the set of states that is not reachable (on a path from the initial to a target state). // Subtract from the maybe states the set of states that is not reachable (on a path from the initial to a target state).
maybeStates &= reachableStates; maybeStates &= reachableStates;
} }
// Create a vector for the probabilities to go to a state with probability 1 in one step. // Create a vector for the probabilities to go to a state with probability 1 in one step.
std::vector<ValueType> oneStepProbabilities = this->getModel().getTransitionMatrix().getConstrainedRowSumVector(maybeStates, statesWithProbability1);
std::vector<ValueType> oneStepProbabilities = probabilityMatrix.getConstrainedRowSumVector(maybeStates, statesWithProbability1);
// Determine the set of initial states of the sub-model. // Determine the set of initial states of the sub-model.
storm::storage::BitVector newInitialStates = this->getModel().getInitialStates() % maybeStates;
storm::storage::BitVector newInitialStates = initialStates % maybeStates;
// We then build the submatrix that only has the transitions of the maybe states. // We then build the submatrix that only has the transitions of the maybe states.
storm::storage::SparseMatrix<ValueType> submatrix = this->getModel().getTransitionMatrix().getSubmatrix(false, maybeStates, maybeStates);
storm::storage::SparseMatrix<ValueType> submatrix = probabilityMatrix.getSubmatrix(false, maybeStates, maybeStates);
storm::storage::SparseMatrix<ValueType> submatrixTransposed = submatrix.transpose(); storm::storage::SparseMatrix<ValueType> submatrixTransposed = submatrix.transpose();
std::vector<ValueType> subresult = computeReachabilityValues(submatrix, oneStepProbabilities, submatrixTransposed, newInitialStates, checkTask.isOnlyInitialStatesRelevantSet(), phiStates, psiStates, oneStepProbabilities);
std::vector<ValueType> subresult = computeReachabilityValues(submatrix, oneStepProbabilities, submatrixTransposed, newInitialStates, computeForInitialStatesOnly, phiStates, psiStates, oneStepProbabilities);
storm::utility::vector::setVectorValues<ValueType>(result, maybeStates, subresult); storm::utility::vector::setVectorValues<ValueType>(result, maybeStates, subresult);
} }
@ -529,14 +528,12 @@ namespace storm {
storm::utility::vector::setVectorValues<ValueType>(result, statesWithProbability0, storm::utility::zero<ValueType>()); storm::utility::vector::setVectorValues<ValueType>(result, statesWithProbability0, storm::utility::zero<ValueType>());
storm::utility::vector::setVectorValues<ValueType>(result, statesWithProbability1, storm::utility::one<ValueType>()); storm::utility::vector::setVectorValues<ValueType>(result, statesWithProbability1, storm::utility::one<ValueType>());
// Construct check result based on whether we have computed values for all states or just the initial states.
std::unique_ptr<CheckResult> checkResult(new ExplicitQuantitativeCheckResult<ValueType>(result));
if (checkTask.isOnlyInitialStatesRelevantSet()) {
if (computeForInitialStatesOnly) {
// If we computed the results for the initial (and prob 0 and prob1) states only, we need to filter the // If we computed the results for the initial (and prob 0 and prob1) states only, we need to filter the
// result to only communicate these results. // result to only communicate these results.
checkResult->filter(ExplicitQualitativeCheckResult(~maybeStates | this->getModel().getInitialStates()));
result = storm::utility::vector::filterVector(result, ~maybeStates | initialStates);
} }
return checkResult;
return result;
} }
template<typename SparseDtmcModelType> template<typename SparseDtmcModelType>
@ -545,27 +542,54 @@ namespace storm {
// Retrieve the appropriate bitvectors by model checking the subformulas. // Retrieve the appropriate bitvectors by model checking the subformulas.
std::unique_ptr<CheckResult> subResultPointer = this->check(eventuallyFormula.getSubformula()); std::unique_ptr<CheckResult> subResultPointer = this->check(eventuallyFormula.getSubformula());
storm::storage::BitVector phiStates(this->getModel().getNumberOfStates(), true);
storm::storage::BitVector const& psiStates = subResultPointer->asExplicitQualitativeCheckResult().getTruthValuesVector();
storm::storage::BitVector trueStates(this->getModel().getNumberOfStates(), true);
storm::storage::BitVector const& targetStates = subResultPointer->asExplicitQualitativeCheckResult().getTruthValuesVector();
// Do some sanity checks to establish some required properties. // Do some sanity checks to establish some required properties.
RewardModelType const& rewardModel = this->getModel().getRewardModel(checkTask.isRewardModelSet() ? checkTask.getRewardModel() : ""); RewardModelType const& rewardModel = this->getModel().getRewardModel(checkTask.isRewardModelSet() ? checkTask.getRewardModel() : "");
STORM_LOG_THROW(!rewardModel.empty(), storm::exceptions::IllegalArgumentException, "Input model does not have a reward model."); STORM_LOG_THROW(!rewardModel.empty(), storm::exceptions::IllegalArgumentException, "Input model does not have a reward model.");
std::vector<ValueType> result = computeReachabilityRewards(this->getModel().getTransitionMatrix(), this->getModel().getBackwardTransitions(), this->getModel().getInitialStates(), targetStates,
[&] (uint_fast64_t numberOfRows, storm::storage::SparseMatrix<ValueType> const& transitionMatrix, storm::storage::BitVector const& maybeStates) {
return rewardModel.getTotalRewardVector(numberOfRows, transitionMatrix, maybeStates);
},
checkTask.isOnlyInitialStatesRelevantSet());
// Construct check result.
std::unique_ptr<CheckResult> checkResult(new ExplicitQuantitativeCheckResult<ValueType>(result));
return checkResult;
}
template<typename SparseDtmcModelType>
std::vector<typename SparseDtmcModelType::ValueType> SparseDtmcEliminationModelChecker<SparseDtmcModelType>::computeReachabilityRewards(storm::storage::SparseMatrix<ValueType> const& probabilityMatrix, storm::storage::SparseMatrix<ValueType> const& backwardTransitions, storm::storage::BitVector const& initialStates, storm::storage::BitVector const& targetStates, std::vector<ValueType>& stateRewardValues, bool computeForInitialStatesOnly) {
return computeReachabilityRewards(probabilityMatrix, backwardTransitions, initialStates, targetStates,
[&] (uint_fast64_t numberOfRows, storm::storage::SparseMatrix<ValueType> const& transitionMatrix, storm::storage::BitVector const& maybeStates) {
std::vector<ValueType> result(numberOfRows);
storm::utility::vector::selectVectorValues(result, maybeStates, stateRewardValues);
return result;
},
computeForInitialStatesOnly);
}
template<typename SparseDtmcModelType>
std::vector<typename SparseDtmcModelType::ValueType> SparseDtmcEliminationModelChecker<SparseDtmcModelType>::computeReachabilityRewards(storm::storage::SparseMatrix<ValueType> const& probabilityMatrix, storm::storage::SparseMatrix<ValueType> const& backwardTransitions, storm::storage::BitVector const& initialStates, storm::storage::BitVector const& targetStates, std::function<std::vector<ValueType>(uint_fast64_t, storm::storage::SparseMatrix<ValueType> const&, storm::storage::BitVector const&)> const& totalStateRewardVectorGetter, bool computeForInitialStatesOnly) {
uint_fast64_t numberOfStates = probabilityMatrix.getRowCount();
// Then, compute the subset of states that has a reachability reward less than infinity.
storm::storage::BitVector trueStates(this->getModel().getNumberOfStates(), true);
storm::storage::BitVector infinityStates = storm::utility::graph::performProb1(this->getModel().getBackwardTransitions(), trueStates, psiStates);
// Compute the subset of states that has a reachability reward less than infinity.
storm::storage::BitVector trueStates(numberOfStates, true);
storm::storage::BitVector infinityStates = storm::utility::graph::performProb1(backwardTransitions, trueStates, targetStates);
infinityStates.complement(); infinityStates.complement();
storm::storage::BitVector maybeStates = ~psiStates & ~infinityStates;
storm::storage::BitVector maybeStates = ~targetStates & ~infinityStates;
// Determine whether we need to perform some further computation. // Determine whether we need to perform some further computation.
bool furtherComputationNeeded = true; bool furtherComputationNeeded = true;
if (checkTask.isOnlyInitialStatesRelevantSet()) {
if (this->getModel().getInitialStates().isSubsetOf(infinityStates)) {
if (computeForInitialStatesOnly) {
if (initialStates.isSubsetOf(infinityStates)) {
STORM_LOG_DEBUG("The reward of all initial states was found in a preprocessing step."); STORM_LOG_DEBUG("The reward of all initial states was found in a preprocessing step.");
furtherComputationNeeded = false; furtherComputationNeeded = false;
} }
if (this->getModel().getInitialStates().isSubsetOf(psiStates)) {
if (initialStates.isSubsetOf(targetStates)) {
STORM_LOG_DEBUG("The reward of all initial states was found in a preprocessing step."); STORM_LOG_DEBUG("The reward of all initial states was found in a preprocessing step.");
furtherComputationNeeded = false; furtherComputationNeeded = false;
} }
@ -575,40 +599,37 @@ namespace storm {
if (furtherComputationNeeded) { if (furtherComputationNeeded) {
// If we compute the results for the initial states only, we can cut off all maybe state that are not // If we compute the results for the initial states only, we can cut off all maybe state that are not
// reachable from them. // reachable from them.
if (checkTask.isOnlyInitialStatesRelevantSet()) {
if (computeForInitialStatesOnly) {
// Determine the set of states that is reachable from the initial state without jumping over a target state. // Determine the set of states that is reachable from the initial state without jumping over a target state.
storm::storage::BitVector reachableStates = storm::utility::graph::getReachableStates(this->getModel().getTransitionMatrix(), this->getModel().getInitialStates(), maybeStates, psiStates);
storm::storage::BitVector reachableStates = storm::utility::graph::getReachableStates(probabilityMatrix, initialStates, maybeStates, targetStates);
// Subtract from the maybe states the set of states that is not reachable (on a path from the initial to a target state). // Subtract from the maybe states the set of states that is not reachable (on a path from the initial to a target state).
maybeStates &= reachableStates; maybeStates &= reachableStates;
} }
// Determine the set of initial states of the sub-model. // Determine the set of initial states of the sub-model.
storm::storage::BitVector newInitialStates = this->getModel().getInitialStates() % maybeStates;
storm::storage::BitVector newInitialStates = initialStates % maybeStates;
// We then build the submatrix that only has the transitions of the maybe states. // We then build the submatrix that only has the transitions of the maybe states.
storm::storage::SparseMatrix<ValueType> submatrix = this->getModel().getTransitionMatrix().getSubmatrix(false, maybeStates, maybeStates);
storm::storage::SparseMatrix<ValueType> submatrix = probabilityMatrix.getSubmatrix(false, maybeStates, maybeStates);
storm::storage::SparseMatrix<ValueType> submatrixTransposed = submatrix.transpose(); storm::storage::SparseMatrix<ValueType> submatrixTransposed = submatrix.transpose();
// Project the state reward vector to all maybe-states. // Project the state reward vector to all maybe-states.
std::vector<ValueType> stateRewardValues = rewardModel.getTotalRewardVector(maybeStates.getNumberOfSetBits(), this->getModel().getTransitionMatrix(), maybeStates);
std::vector<ValueType> stateRewardValues = totalStateRewardVectorGetter(submatrix.getRowCount(), probabilityMatrix, maybeStates);
std::vector<ValueType> subresult = computeReachabilityValues(submatrix, stateRewardValues, submatrixTransposed, newInitialStates, checkTask.isOnlyInitialStatesRelevantSet(), phiStates, psiStates, this->getModel().getTransitionMatrix().getConstrainedRowSumVector(maybeStates, psiStates));
std::vector<ValueType> subresult = computeReachabilityValues(submatrix, stateRewardValues, submatrixTransposed, newInitialStates, computeForInitialStatesOnly, trueStates, targetStates, probabilityMatrix.getConstrainedRowSumVector(maybeStates, targetStates));
storm::utility::vector::setVectorValues<ValueType>(result, maybeStates, subresult); storm::utility::vector::setVectorValues<ValueType>(result, maybeStates, subresult);
} }
// Construct full result. // Construct full result.
storm::utility::vector::setVectorValues<ValueType>(result, infinityStates, storm::utility::infinity<ValueType>()); storm::utility::vector::setVectorValues<ValueType>(result, infinityStates, storm::utility::infinity<ValueType>());
storm::utility::vector::setVectorValues<ValueType>(result, psiStates, storm::utility::zero<ValueType>());
// Construct check result based on whether we have computed values for all states or just the initial states.
std::unique_ptr<CheckResult> checkResult(new ExplicitQuantitativeCheckResult<ValueType>(result));
if (checkTask.isOnlyInitialStatesRelevantSet()) {
storm::utility::vector::setVectorValues<ValueType>(result, targetStates, storm::utility::zero<ValueType>());
if (computeForInitialStatesOnly) {
// If we computed the results for the initial (and inf) states only, we need to filter the result to // If we computed the results for the initial (and inf) states only, we need to filter the result to
// only communicate these results. // only communicate these results.
checkResult->filter(ExplicitQualitativeCheckResult(~maybeStates | this->getModel().getInitialStates()));
result = storm::utility::vector::filterVector(result, ~maybeStates | initialStates);
} }
return checkResult;
return result;
} }
template<typename SparseDtmcModelType> template<typename SparseDtmcModelType>
@ -626,7 +647,7 @@ namespace storm {
storm::storage::BitVector trueStates(this->getModel().getNumberOfStates(), true); storm::storage::BitVector trueStates(this->getModel().getNumberOfStates(), true);
// Do some sanity checks to establish some required properties. // Do some sanity checks to establish some required properties.
// STORM_LOG_WARN_COND(storm::settings::sparseDtmcEliminationModelCheckerSettings().getEliminationMethod() == storm::settings::modules::SparseDtmcEliminationModelCheckerSettings::EliminationMethod::State, "The chosen elimination method is not available for computing conditional probabilities. Falling back to regular state elimination.");
// STORM_LOG_WARN_COND(storm::settings::getModule<storm::settings::modules::SparseDtmcEliminationModelCheckerSettings>().getEliminationMethod() == storm::settings::modules::SparseDtmcEliminationModelCheckerSettings::EliminationMethod::State, "The chosen elimination method is not available for computing conditional probabilities. Falling back to regular state elimination.");
STORM_LOG_THROW(this->getModel().getInitialStates().getNumberOfSetBits() == 1, storm::exceptions::IllegalArgumentException, "Input model is required to have exactly one initial state."); STORM_LOG_THROW(this->getModel().getInitialStates().getNumberOfSetBits() == 1, storm::exceptions::IllegalArgumentException, "Input model is required to have exactly one initial state.");
STORM_LOG_THROW(checkTask.isOnlyInitialStatesRelevantSet(), storm::exceptions::IllegalArgumentException, "Cannot compute conditional probabilities for all states."); STORM_LOG_THROW(checkTask.isOnlyInitialStatesRelevantSet(), storm::exceptions::IllegalArgumentException, "Cannot compute conditional probabilities for all states.");
storm::storage::sparse::state_type initialState = *this->getModel().getInitialStates().begin(); storm::storage::sparse::state_type initialState = *this->getModel().getInitialStates().begin();
@ -687,28 +708,28 @@ namespace storm {
// Before starting the model checking process, we assign priorities to states so we can use them to // Before starting the model checking process, we assign priorities to states so we can use them to
// impose ordering constraints later. // impose ordering constraints later.
boost::optional<std::vector<uint_fast64_t>> distanceBasedPriorities; boost::optional<std::vector<uint_fast64_t>> distanceBasedPriorities;
storm::settings::modules::SparseDtmcEliminationModelCheckerSettings::EliminationOrder order = storm::settings::sparseDtmcEliminationModelCheckerSettings().getEliminationOrder();
storm::settings::modules::SparseDtmcEliminationModelCheckerSettings::EliminationOrder order = storm::settings::getModule<storm::settings::modules::SparseDtmcEliminationModelCheckerSettings>().getEliminationOrder();
if (eliminationOrderNeedsDistances(order)) { if (eliminationOrderNeedsDistances(order)) {
distanceBasedPriorities = getDistanceBasedPriorities(submatrix, submatrixTransposed, newInitialStates, oneStepProbabilities, distanceBasedPriorities = getDistanceBasedPriorities(submatrix, submatrixTransposed, newInitialStates, oneStepProbabilities,
eliminationOrderNeedsForwardDistances(order), eliminationOrderNeedsForwardDistances(order),
eliminationOrderNeedsReversedDistances(order)); eliminationOrderNeedsReversedDistances(order));
} }
FlexibleSparseMatrix flexibleMatrix = getFlexibleSparseMatrix(submatrix);
FlexibleSparseMatrix flexibleBackwardTransitions = getFlexibleSparseMatrix(submatrixTransposed, true);
storm::storage::FlexibleSparseMatrix<ValueType> flexibleMatrix(submatrix);
storm::storage::FlexibleSparseMatrix<ValueType> flexibleBackwardTransitions(submatrixTransposed, true);
std::unique_ptr<StatePriorityQueue> statePriorities = createStatePriorityQueue(distanceBasedPriorities, flexibleMatrix, flexibleBackwardTransitions, oneStepProbabilities, statesToEliminate);
std::shared_ptr<StatePriorityQueue<ValueType>> statePriorities = createStatePriorityQueue(distanceBasedPriorities, flexibleMatrix, flexibleBackwardTransitions, oneStepProbabilities, statesToEliminate);
STORM_LOG_INFO("Computing conditional probilities." << std::endl);
uint_fast64_t numberOfStatesToEliminate = statePriorities->size();
STORM_LOG_INFO("Eliminating " << numberOfStatesToEliminate << " states using the state elimination technique." << std::endl);
performPrioritizedStateElimination(statePriorities, flexibleMatrix, flexibleBackwardTransitions, oneStepProbabilities, this->getModel().getInitialStates(), true); performPrioritizedStateElimination(statePriorities, flexibleMatrix, flexibleBackwardTransitions, oneStepProbabilities, this->getModel().getInitialStates(), true);
// Prepare some callbacks for the elimination procedure.
ValueUpdateCallback valueUpdateCallback = [&oneStepProbabilities] (storm::storage::sparse::state_type const& state, ValueType const& loopProbability) { oneStepProbabilities[state] = storm::utility::simplify(loopProbability * oneStepProbabilities[state]); };
PredecessorUpdateCallback predecessorUpdateCallback = [&oneStepProbabilities] (storm::storage::sparse::state_type const& predecessor, ValueType const& probability, storm::storage::sparse::state_type const& state) { oneStepProbabilities[predecessor] = storm::utility::simplify(oneStepProbabilities[predecessor] * storm::utility::simplify(probability * oneStepProbabilities[state])); };
boost::optional<PredecessorFilterCallback> phiFilterCallback = PredecessorFilterCallback([&phiStates] (storm::storage::sparse::state_type const& state) { return phiStates.get(state); });
boost::optional<PredecessorFilterCallback> psiFilterCallback = PredecessorFilterCallback([&psiStates] (storm::storage::sparse::state_type const& state) { return psiStates.get(state); });
storm::solver::stateelimination::ConditionalEliminator<SparseDtmcModelType> stateEliminator = storm::solver::stateelimination::ConditionalEliminator<SparseDtmcModelType>(flexibleMatrix, flexibleBackwardTransitions, oneStepProbabilities, phiStates, psiStates);
// Eliminate the transitions going into the initial state (if there are any). // Eliminate the transitions going into the initial state (if there are any).
if (!flexibleBackwardTransitions.getRow(*newInitialStates.begin()).empty()) { if (!flexibleBackwardTransitions.getRow(*newInitialStates.begin()).empty()) {
eliminateState(*newInitialStates.begin(), flexibleMatrix, flexibleBackwardTransitions, valueUpdateCallback, predecessorUpdateCallback, boost::none, boost::none, false);
stateEliminator.eliminateState(*newInitialStates.begin(), false);
} }
// Now we need to basically eliminate all chains of not-psi states after phi states and chains of not-phi // Now we need to basically eliminate all chains of not-psi states after phi states and chains of not-phi
@ -739,11 +760,13 @@ namespace storm {
for (auto const& element : currentRow) { for (auto const& element : currentRow) {
// If any of the successors is a phi state, we eliminate it (wrt. all its phi predecessors). // If any of the successors is a phi state, we eliminate it (wrt. all its phi predecessors).
if (!psiStates.get(element.getColumn())) { if (!psiStates.get(element.getColumn())) {
typename FlexibleSparseMatrix::row_type const& successorRow = flexibleMatrix.getRow(element.getColumn());
FlexibleRowType const& successorRow = flexibleMatrix.getRow(element.getColumn());
// Eliminate the successor only if there possibly is a psi state reachable through it. // Eliminate the successor only if there possibly is a psi state reachable through it.
if (successorRow.size() > 1 || (!successorRow.empty() && successorRow.front().getColumn() != element.getColumn())) { if (successorRow.size() > 1 || (!successorRow.empty() && successorRow.front().getColumn() != element.getColumn())) {
STORM_LOG_TRACE("Found non-psi successor " << element.getColumn() << " that needs to be eliminated."); STORM_LOG_TRACE("Found non-psi successor " << element.getColumn() << " that needs to be eliminated.");
eliminateState(element.getColumn(), flexibleMatrix, flexibleBackwardTransitions, valueUpdateCallback, predecessorUpdateCallback, boost::none, phiFilterCallback, false);
stateEliminator.setStatePhi();
stateEliminator.eliminateState(element.getColumn(), false);
stateEliminator.clearState();
hasNonPsiSuccessor = true; hasNonPsiSuccessor = true;
} }
} }
@ -769,10 +792,12 @@ namespace storm {
for (auto const& element : currentRow) { for (auto const& element : currentRow) {
// If any of the successors is a psi state, we eliminate it (wrt. all its psi predecessors). // If any of the successors is a psi state, we eliminate it (wrt. all its psi predecessors).
if (!phiStates.get(element.getColumn())) { if (!phiStates.get(element.getColumn())) {
typename FlexibleSparseMatrix::row_type const& successorRow = flexibleMatrix.getRow(element.getColumn());
FlexibleRowType const& successorRow = flexibleMatrix.getRow(element.getColumn());
if (successorRow.size() > 1 || (!successorRow.empty() && successorRow.front().getColumn() != element.getColumn())) { if (successorRow.size() > 1 || (!successorRow.empty() && successorRow.front().getColumn() != element.getColumn())) {
STORM_LOG_TRACE("Found non-phi successor " << element.getColumn() << " that needs to be eliminated."); STORM_LOG_TRACE("Found non-phi successor " << element.getColumn() << " that needs to be eliminated.");
eliminateState(element.getColumn(), flexibleMatrix, flexibleBackwardTransitions, valueUpdateCallback, predecessorUpdateCallback, boost::none, psiFilterCallback, false);
stateEliminator.setStatePsi();
stateEliminator.eliminateState(element.getColumn(), false);
stateEliminator.clearState();
hasNonPhiSuccessor = true; hasNonPhiSuccessor = true;
} }
} }
@ -819,12 +844,12 @@ namespace storm {
} }
template<typename SparseDtmcModelType> template<typename SparseDtmcModelType>
std::unique_ptr<typename SparseDtmcEliminationModelChecker<SparseDtmcModelType>::StatePriorityQueue> SparseDtmcEliminationModelChecker<SparseDtmcModelType>::createStatePriorityQueue(boost::optional<std::vector<uint_fast64_t>> const& distanceBasedStatePriorities, FlexibleSparseMatrix const& transitionMatrix, FlexibleSparseMatrix const& backwardTransitions, std::vector<typename SparseDtmcModelType::ValueType>& oneStepProbabilities, storm::storage::BitVector const& states) {
std::shared_ptr<StatePriorityQueue<typename SparseDtmcModelType::ValueType>> SparseDtmcEliminationModelChecker<SparseDtmcModelType>::createStatePriorityQueue(boost::optional<std::vector<uint_fast64_t>> const& distanceBasedStatePriorities, storm::storage::FlexibleSparseMatrix<ValueType> const& transitionMatrix, storm::storage::FlexibleSparseMatrix<ValueType> const& backwardTransitions, std::vector<ValueType>& oneStepProbabilities, storm::storage::BitVector const& states) {
STORM_LOG_TRACE("Creating state priority queue for states " << states); STORM_LOG_TRACE("Creating state priority queue for states " << states);
// Get the settings to customize the priority queue. // Get the settings to customize the priority queue.
storm::settings::modules::SparseDtmcEliminationModelCheckerSettings::EliminationOrder order = storm::settings::sparseDtmcEliminationModelCheckerSettings().getEliminationOrder();
storm::settings::modules::SparseDtmcEliminationModelCheckerSettings::EliminationOrder order = storm::settings::getModule<storm::settings::modules::SparseDtmcEliminationModelCheckerSettings>().getEliminationOrder();
std::vector<storm::storage::sparse::state_type> sortedStates(states.begin(), states.end()); std::vector<storm::storage::sparse::state_type> sortedStates(states.begin(), states.end());
@ -859,37 +884,36 @@ namespace storm {
} }
} }
} }
STORM_LOG_THROW(false, storm::exceptions::InvalidSettingsException, "Illlegal elimination order selected.");
STORM_LOG_THROW(false, storm::exceptions::InvalidSettingsException, "Illegal elimination order selected.");
} }
template<typename SparseDtmcModelType> template<typename SparseDtmcModelType>
std::unique_ptr<typename SparseDtmcEliminationModelChecker<SparseDtmcModelType>::StatePriorityQueue> SparseDtmcEliminationModelChecker<SparseDtmcModelType>::createNaivePriorityQueue(storm::storage::BitVector const& states) {
std::shared_ptr<StatePriorityQueue<typename SparseDtmcModelType::ValueType>> SparseDtmcEliminationModelChecker<SparseDtmcModelType>::createNaivePriorityQueue(storm::storage::BitVector const& states) {
std::vector<storm::storage::sparse::state_type> sortedStates(states.begin(), states.end()); std::vector<storm::storage::sparse::state_type> sortedStates(states.begin(), states.end());
return std::unique_ptr<StatePriorityQueue>(new StaticStatePriorityQueue(sortedStates));
return std::shared_ptr<StatePriorityQueue<ValueType>>(new StaticStatePriorityQueue(sortedStates));
} }
template<typename SparseDtmcModelType> template<typename SparseDtmcModelType>
void SparseDtmcEliminationModelChecker<SparseDtmcModelType>::performPrioritizedStateElimination(std::unique_ptr<StatePriorityQueue>& priorityQueue, FlexibleSparseMatrix& transitionMatrix, FlexibleSparseMatrix& backwardTransitions, std::vector<ValueType>& values, storm::storage::BitVector const& initialStates, bool computeResultsForInitialStatesOnly) {
void SparseDtmcEliminationModelChecker<SparseDtmcModelType>::performPrioritizedStateElimination(std::shared_ptr<StatePriorityQueue<ValueType>>& priorityQueue, storm::storage::FlexibleSparseMatrix<ValueType>& transitionMatrix, storm::storage::FlexibleSparseMatrix<ValueType>& backwardTransitions, std::vector<ValueType>& values, storm::storage::BitVector const& initialStates, bool computeResultsForInitialStatesOnly) {
ValueUpdateCallback valueUpdateCallback = [&values] (storm::storage::sparse::state_type const& state, ValueType const& loopProbability) { values[state] = storm::utility::simplify(loopProbability * values[state]); };
PredecessorUpdateCallback predecessorCallback = [&values] (storm::storage::sparse::state_type const& predecessor, ValueType const& probability, storm::storage::sparse::state_type const& state) { values[predecessor] = storm::utility::simplify(values[predecessor] + storm::utility::simplify(probability * values[state])); };
boost::optional<PriorityUpdateCallback> priorityUpdateCallback = PriorityUpdateCallback([&transitionMatrix,&backwardTransitions,&values,&priorityQueue] (storm::storage::sparse::state_type const& state) { priorityQueue->update(state, transitionMatrix, backwardTransitions, values); });
boost::optional<PredecessorFilterCallback> predecessorFilterCallback = boost::none;
storm::solver::stateelimination::PrioritizedEliminator<SparseDtmcModelType> stateEliminator(transitionMatrix, backwardTransitions, priorityQueue, values);
while (priorityQueue->hasNextState()) { while (priorityQueue->hasNextState()) {
storm::storage::sparse::state_type state = priorityQueue->popNextState(); storm::storage::sparse::state_type state = priorityQueue->popNextState();
bool removeForwardTransitions = computeResultsForInitialStatesOnly && !initialStates.get(state); bool removeForwardTransitions = computeResultsForInitialStatesOnly && !initialStates.get(state);
eliminateState(state, transitionMatrix, backwardTransitions, valueUpdateCallback, predecessorCallback, priorityUpdateCallback, predecessorFilterCallback, removeForwardTransitions);
stateEliminator.eliminateState(state, removeForwardTransitions);
if (removeForwardTransitions) { if (removeForwardTransitions) {
values[state] = storm::utility::zero<ValueType>(); values[state] = storm::utility::zero<ValueType>();
} }
#ifdef STORM_DEV
STORM_LOG_ASSERT(checkConsistent(transitionMatrix, backwardTransitions), "The forward and backward transition matrices became inconsistent."); STORM_LOG_ASSERT(checkConsistent(transitionMatrix, backwardTransitions), "The forward and backward transition matrices became inconsistent.");
#endif
} }
} }
template<typename SparseDtmcModelType> template<typename SparseDtmcModelType>
void SparseDtmcEliminationModelChecker<SparseDtmcModelType>::performOrdinaryStateElimination(FlexibleSparseMatrix& transitionMatrix, FlexibleSparseMatrix& backwardTransitions, storm::storage::BitVector const& subsystem, storm::storage::BitVector const& initialStates, bool computeResultsForInitialStatesOnly, std::vector<ValueType>& values, boost::optional<std::vector<uint_fast64_t>> const& distanceBasedPriorities) {
std::unique_ptr<StatePriorityQueue> statePriorities = createStatePriorityQueue(distanceBasedPriorities, transitionMatrix, backwardTransitions, values, subsystem);
void SparseDtmcEliminationModelChecker<SparseDtmcModelType>::performOrdinaryStateElimination(storm::storage::FlexibleSparseMatrix<ValueType>& transitionMatrix, storm::storage::FlexibleSparseMatrix<ValueType>& backwardTransitions, storm::storage::BitVector const& subsystem, storm::storage::BitVector const& initialStates, bool computeResultsForInitialStatesOnly, std::vector<ValueType>& values, boost::optional<std::vector<uint_fast64_t>> const& distanceBasedPriorities) {
std::shared_ptr<StatePriorityQueue<ValueType>> statePriorities = createStatePriorityQueue(distanceBasedPriorities, transitionMatrix, backwardTransitions, values, subsystem);
std::size_t numberOfStatesToEliminate = statePriorities->size(); std::size_t numberOfStatesToEliminate = statePriorities->size();
STORM_LOG_DEBUG("Eliminating " << numberOfStatesToEliminate << " states using the state elimination technique." << std::endl); STORM_LOG_DEBUG("Eliminating " << numberOfStatesToEliminate << " states using the state elimination technique." << std::endl);
@ -898,17 +922,17 @@ namespace storm {
} }
template<typename SparseDtmcModelType> template<typename SparseDtmcModelType>
uint_fast64_t SparseDtmcEliminationModelChecker<SparseDtmcModelType>::performHybridStateElimination(storm::storage::SparseMatrix<ValueType> const& forwardTransitions, FlexibleSparseMatrix& transitionMatrix, FlexibleSparseMatrix& backwardTransitions, storm::storage::BitVector const& subsystem, storm::storage::BitVector const& initialStates, bool computeResultsForInitialStatesOnly, std::vector<ValueType>& values, boost::optional<std::vector<uint_fast64_t>> const& distanceBasedPriorities) {
uint_fast64_t SparseDtmcEliminationModelChecker<SparseDtmcModelType>::performHybridStateElimination(storm::storage::SparseMatrix<ValueType> const& forwardTransitions, storm::storage::FlexibleSparseMatrix<ValueType>& transitionMatrix, storm::storage::FlexibleSparseMatrix<ValueType>& backwardTransitions, storm::storage::BitVector const& subsystem, storm::storage::BitVector const& initialStates, bool computeResultsForInitialStatesOnly, std::vector<ValueType>& values, boost::optional<std::vector<uint_fast64_t>> const& distanceBasedPriorities) {
// When using the hybrid technique, we recursively treat the SCCs up to some size. // When using the hybrid technique, we recursively treat the SCCs up to some size.
std::vector<storm::storage::sparse::state_type> entryStateQueue; std::vector<storm::storage::sparse::state_type> entryStateQueue;
STORM_LOG_DEBUG("Eliminating " << subsystem.size() << " states using the hybrid elimination technique." << std::endl); STORM_LOG_DEBUG("Eliminating " << subsystem.size() << " states using the hybrid elimination technique." << std::endl);
uint_fast64_t maximalDepth = treatScc(transitionMatrix, values, initialStates, subsystem, initialStates, forwardTransitions, backwardTransitions, false, 0, storm::settings::sparseDtmcEliminationModelCheckerSettings().getMaximalSccSize(), entryStateQueue, computeResultsForInitialStatesOnly, distanceBasedPriorities);
uint_fast64_t maximalDepth = treatScc(transitionMatrix, values, initialStates, subsystem, initialStates, forwardTransitions, backwardTransitions, false, 0, storm::settings::getModule<storm::settings::modules::SparseDtmcEliminationModelCheckerSettings>().getMaximalSccSize(), entryStateQueue, computeResultsForInitialStatesOnly, distanceBasedPriorities);
// If the entry states were to be eliminated last, we need to do so now. // If the entry states were to be eliminated last, we need to do so now.
if (storm::settings::sparseDtmcEliminationModelCheckerSettings().isEliminateEntryStatesLastSet()) {
if (storm::settings::getModule<storm::settings::modules::SparseDtmcEliminationModelCheckerSettings>().isEliminateEntryStatesLastSet()) {
STORM_LOG_DEBUG("Eliminating " << entryStateQueue.size() << " entry states as a last step."); STORM_LOG_DEBUG("Eliminating " << entryStateQueue.size() << " entry states as a last step.");
std::vector<storm::storage::sparse::state_type> sortedStates(entryStateQueue.begin(), entryStateQueue.end()); std::vector<storm::storage::sparse::state_type> sortedStates(entryStateQueue.begin(), entryStateQueue.end());
std::unique_ptr<StatePriorityQueue> queuePriorities = std::unique_ptr<StatePriorityQueue>(new StaticStatePriorityQueue(sortedStates));
std::shared_ptr<StatePriorityQueue<ValueType>> queuePriorities = std::shared_ptr<StatePriorityQueue<ValueType>>(new StaticStatePriorityQueue(sortedStates));
performPrioritizedStateElimination(queuePriorities, transitionMatrix, backwardTransitions, values, initialStates, computeResultsForInitialStatesOnly); performPrioritizedStateElimination(queuePriorities, transitionMatrix, backwardTransitions, values, initialStates, computeResultsForInitialStatesOnly);
} }
STORM_LOG_DEBUG("Eliminated " << subsystem.size() << " states." << std::endl); STORM_LOG_DEBUG("Eliminated " << subsystem.size() << " states." << std::endl);
@ -918,10 +942,10 @@ namespace storm {
template<typename SparseDtmcModelType> template<typename SparseDtmcModelType>
std::vector<typename SparseDtmcEliminationModelChecker<SparseDtmcModelType>::ValueType> SparseDtmcEliminationModelChecker<SparseDtmcModelType>::computeReachabilityValues(storm::storage::SparseMatrix<ValueType> const& transitionMatrix, std::vector<ValueType>& values, storm::storage::SparseMatrix<ValueType> const& backwardTransitions, storm::storage::BitVector const& initialStates, bool computeResultsForInitialStatesOnly, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, std::vector<ValueType> const& oneStepProbabilitiesToTarget) { std::vector<typename SparseDtmcEliminationModelChecker<SparseDtmcModelType>::ValueType> SparseDtmcEliminationModelChecker<SparseDtmcModelType>::computeReachabilityValues(storm::storage::SparseMatrix<ValueType> const& transitionMatrix, std::vector<ValueType>& values, storm::storage::SparseMatrix<ValueType> const& backwardTransitions, storm::storage::BitVector const& initialStates, bool computeResultsForInitialStatesOnly, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, std::vector<ValueType> const& oneStepProbabilitiesToTarget) {
// Then, we convert the reduced matrix to a more flexible format to be able to perform state elimination more easily. // Then, we convert the reduced matrix to a more flexible format to be able to perform state elimination more easily.
FlexibleSparseMatrix flexibleMatrix = getFlexibleSparseMatrix(transitionMatrix);
FlexibleSparseMatrix flexibleBackwardTransitions = getFlexibleSparseMatrix(backwardTransitions);
storm::settings::modules::SparseDtmcEliminationModelCheckerSettings::EliminationOrder order = storm::settings::sparseDtmcEliminationModelCheckerSettings().getEliminationOrder();
storm::storage::FlexibleSparseMatrix<ValueType> flexibleMatrix(transitionMatrix);
storm::storage::FlexibleSparseMatrix<ValueType> flexibleBackwardTransitions(backwardTransitions);
storm::settings::modules::SparseDtmcEliminationModelCheckerSettings::EliminationOrder order = storm::settings::getModule<storm::settings::modules::SparseDtmcEliminationModelCheckerSettings>().getEliminationOrder();
boost::optional<std::vector<uint_fast64_t>> distanceBasedPriorities; boost::optional<std::vector<uint_fast64_t>> distanceBasedPriorities;
if (eliminationOrderNeedsDistances(order)) { if (eliminationOrderNeedsDistances(order)) {
distanceBasedPriorities = getDistanceBasedPriorities(transitionMatrix, backwardTransitions, initialStates, oneStepProbabilitiesToTarget, distanceBasedPriorities = getDistanceBasedPriorities(transitionMatrix, backwardTransitions, initialStates, oneStepProbabilitiesToTarget,
@ -932,9 +956,9 @@ namespace storm {
storm::storage::BitVector subsystem = storm::storage::BitVector(transitionMatrix.getRowCount(), true); storm::storage::BitVector subsystem = storm::storage::BitVector(transitionMatrix.getRowCount(), true);
uint_fast64_t maximalDepth = 0; uint_fast64_t maximalDepth = 0;
if (storm::settings::sparseDtmcEliminationModelCheckerSettings().getEliminationMethod() == storm::settings::modules::SparseDtmcEliminationModelCheckerSettings::EliminationMethod::State) {
if (storm::settings::getModule<storm::settings::modules::SparseDtmcEliminationModelCheckerSettings>().getEliminationMethod() == storm::settings::modules::SparseDtmcEliminationModelCheckerSettings::EliminationMethod::State) {
performOrdinaryStateElimination(flexibleMatrix, flexibleBackwardTransitions, subsystem, initialStates, computeResultsForInitialStatesOnly, values, distanceBasedPriorities); performOrdinaryStateElimination(flexibleMatrix, flexibleBackwardTransitions, subsystem, initialStates, computeResultsForInitialStatesOnly, values, distanceBasedPriorities);
} else if (storm::settings::sparseDtmcEliminationModelCheckerSettings().getEliminationMethod() == storm::settings::modules::SparseDtmcEliminationModelCheckerSettings::EliminationMethod::Hybrid) {
} else if (storm::settings::getModule<storm::settings::modules::SparseDtmcEliminationModelCheckerSettings>().getEliminationMethod() == storm::settings::modules::SparseDtmcEliminationModelCheckerSettings::EliminationMethod::Hybrid) {
maximalDepth = performHybridStateElimination(transitionMatrix, flexibleMatrix, flexibleBackwardTransitions, subsystem, initialStates, computeResultsForInitialStatesOnly, values, distanceBasedPriorities); maximalDepth = performHybridStateElimination(transitionMatrix, flexibleMatrix, flexibleBackwardTransitions, subsystem, initialStates, computeResultsForInitialStatesOnly, values, distanceBasedPriorities);
} }
@ -950,7 +974,7 @@ namespace storm {
} }
template<typename SparseDtmcModelType> template<typename SparseDtmcModelType>
uint_fast64_t SparseDtmcEliminationModelChecker<SparseDtmcModelType>::treatScc(FlexibleSparseMatrix& matrix, std::vector<ValueType>& values, storm::storage::BitVector const& entryStates, storm::storage::BitVector const& scc, storm::storage::BitVector const& initialStates, storm::storage::SparseMatrix<ValueType> const& forwardTransitions, FlexibleSparseMatrix& backwardTransitions, bool eliminateEntryStates, uint_fast64_t level, uint_fast64_t maximalSccSize, std::vector<storm::storage::sparse::state_type>& entryStateQueue, bool computeResultsForInitialStatesOnly, boost::optional<std::vector<uint_fast64_t>> const& distanceBasedPriorities) {
uint_fast64_t SparseDtmcEliminationModelChecker<SparseDtmcModelType>::treatScc(storm::storage::FlexibleSparseMatrix<ValueType>& matrix, std::vector<ValueType>& values, storm::storage::BitVector const& entryStates, storm::storage::BitVector const& scc, storm::storage::BitVector const& initialStates, storm::storage::SparseMatrix<ValueType> const& forwardTransitions, storm::storage::FlexibleSparseMatrix<ValueType>& backwardTransitions, bool eliminateEntryStates, uint_fast64_t level, uint_fast64_t maximalSccSize, std::vector<storm::storage::sparse::state_type>& entryStateQueue, bool computeResultsForInitialStatesOnly, boost::optional<std::vector<uint_fast64_t>> const& distanceBasedPriorities) {
uint_fast64_t maximalDepth = level; uint_fast64_t maximalDepth = level;
// If the SCCs are large enough, we try to split them further. // If the SCCs are large enough, we try to split them further.
@ -966,7 +990,7 @@ namespace storm {
storm::storage::BitVector remainingSccs(decomposition.size(), true); storm::storage::BitVector remainingSccs(decomposition.size(), true);
// First, get rid of the trivial SCCs. // First, get rid of the trivial SCCs.
storm::storage::BitVector statesInTrivialSccs(matrix.getNumberOfRows());
storm::storage::BitVector statesInTrivialSccs(matrix.getRowCount());
for (uint_fast64_t sccIndex = 0; sccIndex < decomposition.size(); ++sccIndex) { for (uint_fast64_t sccIndex = 0; sccIndex < decomposition.size(); ++sccIndex) {
storm::storage::StronglyConnectedComponent const& scc = decomposition.getBlock(sccIndex); storm::storage::StronglyConnectedComponent const& scc = decomposition.getBlock(sccIndex);
if (scc.isTrivial()) { if (scc.isTrivial()) {
@ -976,7 +1000,7 @@ namespace storm {
} }
} }
std::unique_ptr<StatePriorityQueue> statePriorities = createStatePriorityQueue(distanceBasedPriorities, matrix, backwardTransitions, values, statesInTrivialSccs);
std::shared_ptr<StatePriorityQueue<ValueType>> statePriorities = createStatePriorityQueue(distanceBasedPriorities, matrix, backwardTransitions, values, statesInTrivialSccs);
STORM_LOG_TRACE("Eliminating " << statePriorities->size() << " trivial SCCs."); STORM_LOG_TRACE("Eliminating " << statePriorities->size() << " trivial SCCs.");
performPrioritizedStateElimination(statePriorities, matrix, backwardTransitions, values, initialStates, computeResultsForInitialStatesOnly); performPrioritizedStateElimination(statePriorities, matrix, backwardTransitions, values, initialStates, computeResultsForInitialStatesOnly);
STORM_LOG_TRACE("Eliminated all trivial SCCs."); STORM_LOG_TRACE("Eliminated all trivial SCCs.");
@ -1000,13 +1024,13 @@ namespace storm {
} }
// Recursively descend in SCC-hierarchy. // Recursively descend in SCC-hierarchy.
uint_fast64_t depth = treatScc(matrix, values, entryStates, newSccAsBitVector, initialStates, forwardTransitions, backwardTransitions, eliminateEntryStates || !storm::settings::sparseDtmcEliminationModelCheckerSettings().isEliminateEntryStatesLastSet(), level + 1, maximalSccSize, entryStateQueue, computeResultsForInitialStatesOnly, distanceBasedPriorities);
uint_fast64_t depth = treatScc(matrix, values, entryStates, newSccAsBitVector, initialStates, forwardTransitions, backwardTransitions, eliminateEntryStates || !storm::settings::getModule<storm::settings::modules::SparseDtmcEliminationModelCheckerSettings>().isEliminateEntryStatesLastSet(), level + 1, maximalSccSize, entryStateQueue, computeResultsForInitialStatesOnly, distanceBasedPriorities);
maximalDepth = std::max(maximalDepth, depth); maximalDepth = std::max(maximalDepth, depth);
} }
} else { } else {
// In this case, we perform simple state elimination in the current SCC. // In this case, we perform simple state elimination in the current SCC.
STORM_LOG_TRACE("SCC of size " << scc.getNumberOfSetBits() << " is small enough to be eliminated directly."); STORM_LOG_TRACE("SCC of size " << scc.getNumberOfSetBits() << " is small enough to be eliminated directly.");
std::unique_ptr<StatePriorityQueue> statePriorities = createStatePriorityQueue(distanceBasedPriorities, matrix, backwardTransitions, values, scc & ~entryStates);
std::shared_ptr<StatePriorityQueue<ValueType>> statePriorities = createStatePriorityQueue(distanceBasedPriorities, matrix, backwardTransitions, values, scc & ~entryStates);
performPrioritizedStateElimination(statePriorities, matrix, backwardTransitions, values, initialStates, computeResultsForInitialStatesOnly); performPrioritizedStateElimination(statePriorities, matrix, backwardTransitions, values, initialStates, computeResultsForInitialStatesOnly);
STORM_LOG_TRACE("Eliminated all states of SCC."); STORM_LOG_TRACE("Eliminated all states of SCC.");
} }
@ -1014,7 +1038,7 @@ namespace storm {
// Finally, eliminate the entry states (if we are required to do so). // Finally, eliminate the entry states (if we are required to do so).
if (eliminateEntryStates) { if (eliminateEntryStates) {
STORM_LOG_TRACE("Finally, eliminating entry states."); STORM_LOG_TRACE("Finally, eliminating entry states.");
std::unique_ptr<StatePriorityQueue> naivePriorities = createNaivePriorityQueue(entryStates);
std::shared_ptr<StatePriorityQueue<ValueType>> naivePriorities = createNaivePriorityQueue(entryStates);
performPrioritizedStateElimination(naivePriorities, matrix, backwardTransitions, values, initialStates, computeResultsForInitialStatesOnly); performPrioritizedStateElimination(naivePriorities, matrix, backwardTransitions, values, initialStates, computeResultsForInitialStatesOnly);
STORM_LOG_TRACE("Eliminated/added entry states."); STORM_LOG_TRACE("Eliminated/added entry states.");
} else { } else {
@ -1027,229 +1051,6 @@ namespace storm {
return maximalDepth; return maximalDepth;
} }
template<typename SparseDtmcModelType>
void SparseDtmcEliminationModelChecker<SparseDtmcModelType>::eliminateState(storm::storage::sparse::state_type state, FlexibleSparseMatrix& matrix, FlexibleSparseMatrix& backwardTransitions,
ValueUpdateCallback const& callback, PredecessorUpdateCallback const& predecessorCallback,
boost::optional<PriorityUpdateCallback> const& priorityUpdateCallback,
boost::optional<PredecessorFilterCallback> const& predecessorFilterCallback, bool removeForwardTransitions) {
STORM_LOG_TRACE("Eliminating state " << state << ".");
// Start by finding loop probability.
bool hasSelfLoop = false;
ValueType loopProbability = storm::utility::zero<ValueType>();
typename FlexibleSparseMatrix::row_type& currentStateSuccessors = matrix.getRow(state);
for (auto entryIt = currentStateSuccessors.begin(), entryIte = currentStateSuccessors.end(); entryIt != entryIte; ++entryIt) {
if (entryIt->getColumn() >= state) {
if (entryIt->getColumn() == state) {
loopProbability = entryIt->getValue();
hasSelfLoop = true;
// If we do not clear the forward transitions completely, we need to remove the self-loop,
// because we scale all the other outgoing transitions with it anyway.
if (!removeForwardTransitions) {
currentStateSuccessors.erase(entryIt);
}
}
break;
}
}
// Scale all entries in this row with (1 / (1 - loopProbability)) only in case there was a self-loop.
STORM_LOG_TRACE((hasSelfLoop ? "State has self-loop." : "State does not have a self-loop."));
if (hasSelfLoop) {
STORM_LOG_ASSERT(loopProbability != storm::utility::one<ValueType>(), "Must not eliminate state with probability 1 self-loop.");
loopProbability = storm::utility::simplify(storm::utility::one<ValueType>() / (storm::utility::one<ValueType>() - loopProbability));
for (auto& entry : matrix.getRow(state)) {
// Only scale the non-diagonal entries.
if (entry.getColumn() != state) {
entry.setValue(storm::utility::simplify(entry.getValue() * loopProbability));
}
}
callback(state, loopProbability);
}
// Now connect the predecessors of the state being eliminated with its successors.
typename FlexibleSparseMatrix::row_type& currentStatePredecessors = backwardTransitions.getRow(state);
// In case we have a constrained elimination, we need to keep track of the new predecessors.
typename FlexibleSparseMatrix::row_type newCurrentStatePredecessors;
std::vector<typename FlexibleSparseMatrix::row_type> newBackwardProbabilities(currentStateSuccessors.size());
for (auto& backwardProbabilities : newBackwardProbabilities) {
backwardProbabilities.reserve(currentStatePredecessors.size());
}
// Now go through the predecessors and eliminate the ones (satisfying the constraint if given).
for (auto const& predecessorEntry : currentStatePredecessors) {
uint_fast64_t predecessor = predecessorEntry.getColumn();
STORM_LOG_TRACE("Found predecessor " << predecessor << ".");
// Skip the state itself as one of its predecessors.
if (predecessor == state) {
assert(hasSelfLoop);
continue;
}
// Skip the state if the elimination is constrained, but the predecessor is not in the constraint.
if (predecessorFilterCallback && !predecessorFilterCallback.get()(predecessor)) {
newCurrentStatePredecessors.emplace_back(predecessorEntry);
STORM_LOG_TRACE("Not eliminating predecessor " << predecessor << ", because it does not fit the filter.");
continue;
}
STORM_LOG_TRACE("Eliminating predecessor " << predecessor << ".");
// First, find the probability with which the predecessor can move to the current state, because
// the forward probabilities of the state to be eliminated need to be scaled with this factor.
typename FlexibleSparseMatrix::row_type& predecessorForwardTransitions = matrix.getRow(predecessor);
typename FlexibleSparseMatrix::row_type::iterator multiplyElement = std::find_if(predecessorForwardTransitions.begin(), predecessorForwardTransitions.end(), [&](storm::storage::MatrixEntry<typename FlexibleSparseMatrix::index_type, typename FlexibleSparseMatrix::value_type> const& a) { return a.getColumn() == state; });
// Make sure we have found the probability and set it to zero.
STORM_LOG_THROW(multiplyElement != predecessorForwardTransitions.end(), storm::exceptions::InvalidStateException, "No probability for successor found.");
ValueType multiplyFactor = multiplyElement->getValue();
multiplyElement->setValue(storm::utility::zero<ValueType>());
// At this point, we need to update the (forward) transitions of the predecessor.
typename FlexibleSparseMatrix::row_type::iterator first1 = predecessorForwardTransitions.begin();
typename FlexibleSparseMatrix::row_type::iterator last1 = predecessorForwardTransitions.end();
typename FlexibleSparseMatrix::row_type::iterator first2 = currentStateSuccessors.begin();
typename FlexibleSparseMatrix::row_type::iterator last2 = currentStateSuccessors.end();
typename FlexibleSparseMatrix::row_type newSuccessors;
newSuccessors.reserve((last1 - first1) + (last2 - first2));
std::insert_iterator<typename FlexibleSparseMatrix::row_type> result(newSuccessors, newSuccessors.end());
uint_fast64_t successorOffsetInNewBackwardTransitions = 0;
// Now we merge the two successor lists. (Code taken from std::set_union and modified to suit our needs).
for (; first1 != last1; ++result) {
// Skip the transitions to the state that is currently being eliminated.
if (first1->getColumn() == state || (first2 != last2 && first2->getColumn() == state)) {
if (first1->getColumn() == state) {
++first1;
}
if (first2 != last2 && first2->getColumn() == state) {
++first2;
}
continue;
}
if (first2 == last2) {
std::copy_if(first1, last1, result, [&] (storm::storage::MatrixEntry<typename FlexibleSparseMatrix::index_type, typename FlexibleSparseMatrix::value_type> const& a) { return a.getColumn() != state; } );
break;
}
if (first2->getColumn() < first1->getColumn()) {
auto successorEntry = storm::utility::simplify(std::move(*first2 * multiplyFactor));
*result = successorEntry;
newBackwardProbabilities[successorOffsetInNewBackwardTransitions].emplace_back(predecessor, successorEntry.getValue());
++first2;
++successorOffsetInNewBackwardTransitions;
} else if (first1->getColumn() < first2->getColumn()) {
*result = *first1;
++first1;
} else {
auto probability = storm::utility::simplify(first1->getValue() + storm::utility::simplify(multiplyFactor * first2->getValue()));
*result = storm::storage::MatrixEntry<typename FlexibleSparseMatrix::index_type, typename FlexibleSparseMatrix::value_type>(first1->getColumn(), probability);
newBackwardProbabilities[successorOffsetInNewBackwardTransitions].emplace_back(predecessor, probability);
++first1;
++first2;
++successorOffsetInNewBackwardTransitions;
}
}
for (; first2 != last2; ++first2) {
if (first2->getColumn() != state) {
auto stateProbability = storm::utility::simplify(std::move(*first2 * multiplyFactor));
*result = stateProbability;
newBackwardProbabilities[successorOffsetInNewBackwardTransitions].emplace_back(predecessor, stateProbability.getValue());
++successorOffsetInNewBackwardTransitions;
}
}
// Now move the new transitions in place.
predecessorForwardTransitions = std::move(newSuccessors);
STORM_LOG_TRACE("Fixed new next-state probabilities of predecessor state " << predecessor << ".");
predecessorCallback(predecessor, multiplyFactor, state);
if (priorityUpdateCallback) {
STORM_LOG_TRACE("Updating priority of predecessor.");
priorityUpdateCallback.get()(predecessor);
}
}
// Finally, we need to add the predecessor to the set of predecessors of every successor.
uint_fast64_t successorOffsetInNewBackwardTransitions = 0;
for (auto const& successorEntry : currentStateSuccessors) {
if (successorEntry.getColumn() == state) {
continue;
}
typename FlexibleSparseMatrix::row_type& successorBackwardTransitions = backwardTransitions.getRow(successorEntry.getColumn());
// Delete the current state as a predecessor of the successor state only if we are going to remove the
// current state's forward transitions.
if (removeForwardTransitions) {
typename FlexibleSparseMatrix::row_type::iterator elimIt = std::find_if(successorBackwardTransitions.begin(), successorBackwardTransitions.end(), [&](storm::storage::MatrixEntry<typename FlexibleSparseMatrix::index_type, typename FlexibleSparseMatrix::value_type> const& a) { return a.getColumn() == state; });
STORM_LOG_ASSERT(elimIt != successorBackwardTransitions.end(), "Expected a proper backward transition from " << successorEntry.getColumn() << " to " << state << ", but found none.");
successorBackwardTransitions.erase(elimIt);
}
typename FlexibleSparseMatrix::row_type::iterator first1 = successorBackwardTransitions.begin();
typename FlexibleSparseMatrix::row_type::iterator last1 = successorBackwardTransitions.end();
typename FlexibleSparseMatrix::row_type::iterator first2 = newBackwardProbabilities[successorOffsetInNewBackwardTransitions].begin();
typename FlexibleSparseMatrix::row_type::iterator last2 = newBackwardProbabilities[successorOffsetInNewBackwardTransitions].end();
typename FlexibleSparseMatrix::row_type newPredecessors;
newPredecessors.reserve((last1 - first1) + (last2 - first2));
std::insert_iterator<typename FlexibleSparseMatrix::row_type> result(newPredecessors, newPredecessors.end());
for (; first1 != last1; ++result) {
if (first2 == last2) {
std::copy(first1, last1, result);
break;
}
if (first2->getColumn() < first1->getColumn()) {
if (first2->getColumn() != state) {
*result = *first2;
}
++first2;
} else if (first1->getColumn() == first2->getColumn()) {
if (estimateComplexity(first1->getValue()) > estimateComplexity(first2->getValue())) {
*result = *first1;
} else {
*result = *first2;
}
++first1;
++first2;
} else {
*result = *first1;
++first1;
}
}
if (predecessorFilterCallback) {
std::copy_if(first2, last2, result, [&] (storm::storage::MatrixEntry<typename FlexibleSparseMatrix::index_type, typename FlexibleSparseMatrix::value_type> const& a) { return a.getColumn() != state && predecessorFilterCallback.get()(a.getColumn()); });
} else {
std::copy_if(first2, last2, result, [&] (storm::storage::MatrixEntry<typename FlexibleSparseMatrix::index_type, typename FlexibleSparseMatrix::value_type> const& a) { return a.getColumn() != state; });
}
// Now move the new predecessors in place.
successorBackwardTransitions = std::move(newPredecessors);
++successorOffsetInNewBackwardTransitions;
}
STORM_LOG_TRACE("Fixed predecessor lists of successor states.");
if (removeForwardTransitions) {
// Clear the eliminated row to reduce memory consumption.
currentStateSuccessors.clear();
currentStateSuccessors.shrink_to_fit();
}
if (predecessorFilterCallback) {
currentStatePredecessors = std::move(newCurrentStatePredecessors);
} else {
currentStatePredecessors.clear();
currentStatePredecessors.shrink_to_fit();
}
}
template<typename SparseDtmcModelType> template<typename SparseDtmcModelType>
std::vector<uint_fast64_t> SparseDtmcEliminationModelChecker<SparseDtmcModelType>::getDistanceBasedPriorities(storm::storage::SparseMatrix<ValueType> const& transitionMatrix, storm::storage::SparseMatrix<ValueType> const& transitionMatrixTransposed, storm::storage::BitVector const& initialStates, std::vector<ValueType> const& oneStepProbabilities, bool forward, bool reverse) { std::vector<uint_fast64_t> SparseDtmcEliminationModelChecker<SparseDtmcModelType>::getDistanceBasedPriorities(storm::storage::SparseMatrix<ValueType> const& transitionMatrix, storm::storage::SparseMatrix<ValueType> const& transitionMatrixTransposed, storm::storage::BitVector const& initialStates, std::vector<ValueType> const& oneStepProbabilities, bool forward, bool reverse) {
std::vector<uint_fast64_t> statePriorities(transitionMatrix.getRowCount()); std::vector<uint_fast64_t> statePriorities(transitionMatrix.getRowCount());
@ -1259,8 +1060,8 @@ namespace storm {
} }
std::vector<std::size_t> distances = getStateDistances(transitionMatrix, transitionMatrixTransposed, initialStates, oneStepProbabilities, std::vector<std::size_t> distances = getStateDistances(transitionMatrix, transitionMatrixTransposed, initialStates, oneStepProbabilities,
storm::settings::sparseDtmcEliminationModelCheckerSettings().getEliminationOrder() == storm::settings::modules::SparseDtmcEliminationModelCheckerSettings::EliminationOrder::Forward ||
storm::settings::sparseDtmcEliminationModelCheckerSettings().getEliminationOrder() == storm::settings::modules::SparseDtmcEliminationModelCheckerSettings::EliminationOrder::ForwardReversed);
storm::settings::getModule<storm::settings::modules::SparseDtmcEliminationModelCheckerSettings>().getEliminationOrder() == storm::settings::modules::SparseDtmcEliminationModelCheckerSettings::EliminationOrder::Forward ||
storm::settings::getModule<storm::settings::modules::SparseDtmcEliminationModelCheckerSettings>().getEliminationOrder() == storm::settings::modules::SparseDtmcEliminationModelCheckerSettings::EliminationOrder::ForwardReversed);
// In case of the forward or backward ordering, we can sort the states according to the distances. // In case of the forward or backward ordering, we can sort the states according to the distances.
if (forward ^ reverse) { if (forward ^ reverse) {
@ -1298,111 +1099,7 @@ namespace storm {
} }
template<typename SparseDtmcModelType> template<typename SparseDtmcModelType>
SparseDtmcEliminationModelChecker<SparseDtmcModelType>::FlexibleSparseMatrix::FlexibleSparseMatrix(index_type rows) : data(rows) {
// Intentionally left empty.
}
template<typename SparseDtmcModelType>
void SparseDtmcEliminationModelChecker<SparseDtmcModelType>::FlexibleSparseMatrix::reserveInRow(index_type row, index_type numberOfElements) {
this->data[row].reserve(numberOfElements);
}
template<typename SparseDtmcModelType>
typename SparseDtmcEliminationModelChecker<SparseDtmcModelType>::FlexibleSparseMatrix::row_type& SparseDtmcEliminationModelChecker<SparseDtmcModelType>::FlexibleSparseMatrix::getRow(index_type index) {
return this->data[index];
}
template<typename SparseDtmcModelType>
typename SparseDtmcEliminationModelChecker<SparseDtmcModelType>::FlexibleSparseMatrix::row_type const& SparseDtmcEliminationModelChecker<SparseDtmcModelType>::FlexibleSparseMatrix::getRow(index_type index) const {
return this->data[index];
}
template<typename SparseDtmcModelType>
typename SparseDtmcEliminationModelChecker<SparseDtmcModelType>::FlexibleSparseMatrix::index_type SparseDtmcEliminationModelChecker<SparseDtmcModelType>::FlexibleSparseMatrix::getNumberOfRows() const {
return this->data.size();
}
template<typename SparseDtmcModelType>
bool SparseDtmcEliminationModelChecker<SparseDtmcModelType>::FlexibleSparseMatrix::hasSelfLoop(storm::storage::sparse::state_type state) {
for (auto const& entry : this->getRow(state)) {
if (entry.getColumn() < state) {
continue;
} else if (entry.getColumn() > state) {
return false;
} else if (entry.getColumn() == state) {
return true;
}
}
return false;
}
template<typename SparseDtmcModelType>
void SparseDtmcEliminationModelChecker<SparseDtmcModelType>::FlexibleSparseMatrix::print() const {
for (uint_fast64_t index = 0; index < this->data.size(); ++index) {
std::cout << index << " - ";
for (auto const& element : this->getRow(index)) {
std::cout << "(" << element.getColumn() << ", " << element.getValue() << ") ";
}
std::cout << std::endl;
}
}
template<typename SparseDtmcModelType>
bool SparseDtmcEliminationModelChecker<SparseDtmcModelType>::FlexibleSparseMatrix::empty() const {
for (auto const& row : this->data) {
if (!row.empty()) {
return false;
}
}
return true;
}
template<typename SparseDtmcModelType>
void SparseDtmcEliminationModelChecker<SparseDtmcModelType>::FlexibleSparseMatrix::filter(storm::storage::BitVector const& rowFilter, storm::storage::BitVector const& columnFilter) {
for (uint_fast64_t rowIndex = 0; rowIndex < this->data.size(); ++rowIndex) {
auto& row = this->data[rowIndex];
if (!rowFilter.get(rowIndex)) {
row.clear();
row.shrink_to_fit();
continue;
}
row_type newRow;
for (auto const& element : row) {
if (columnFilter.get(element.getColumn())) {
newRow.push_back(element);
}
}
row = std::move(newRow);
}
}
template<typename SparseDtmcModelType>
typename SparseDtmcEliminationModelChecker<SparseDtmcModelType>::FlexibleSparseMatrix SparseDtmcEliminationModelChecker<SparseDtmcModelType>::getFlexibleSparseMatrix(storm::storage::SparseMatrix<ValueType> const& matrix, bool setAllValuesToOne) {
FlexibleSparseMatrix flexibleMatrix(matrix.getRowCount());
for (typename FlexibleSparseMatrix::index_type rowIndex = 0; rowIndex < matrix.getRowCount(); ++rowIndex) {
typename storm::storage::SparseMatrix<ValueType>::const_rows row = matrix.getRow(rowIndex);
flexibleMatrix.reserveInRow(rowIndex, row.getNumberOfEntries());
for (auto const& element : row) {
// If the probability is zero, we skip this entry.
if (storm::utility::isZero(element.getValue())) {
continue;
}
if (setAllValuesToOne) {
flexibleMatrix.getRow(rowIndex).emplace_back(element.getColumn(), storm::utility::one<ValueType>());
} else {
flexibleMatrix.getRow(rowIndex).emplace_back(element);
}
}
}
return flexibleMatrix;
}
template<typename SparseDtmcModelType>
uint_fast64_t SparseDtmcEliminationModelChecker<SparseDtmcModelType>::computeStatePenalty(storm::storage::sparse::state_type const& state, FlexibleSparseMatrix const& transitionMatrix, FlexibleSparseMatrix const& backwardTransitions, std::vector<ValueType> const& oneStepProbabilities) {
uint_fast64_t SparseDtmcEliminationModelChecker<SparseDtmcModelType>::computeStatePenalty(storm::storage::sparse::state_type const& state, storm::storage::FlexibleSparseMatrix<ValueType> const& transitionMatrix, storm::storage::FlexibleSparseMatrix<ValueType> const& backwardTransitions, std::vector<ValueType> const& oneStepProbabilities) {
uint_fast64_t penalty = 0; uint_fast64_t penalty = 0;
bool hasParametricSelfLoop = false; bool hasParametricSelfLoop = false;
@ -1429,17 +1126,17 @@ namespace storm {
} }
template<typename SparseDtmcModelType> template<typename SparseDtmcModelType>
uint_fast64_t SparseDtmcEliminationModelChecker<SparseDtmcModelType>::computeStatePenaltyRegularExpression(storm::storage::sparse::state_type const& state, FlexibleSparseMatrix const& transitionMatrix, FlexibleSparseMatrix const& backwardTransitions, std::vector<ValueType> const& oneStepProbabilities) {
uint_fast64_t SparseDtmcEliminationModelChecker<SparseDtmcModelType>::computeStatePenaltyRegularExpression(storm::storage::sparse::state_type const& state, storm::storage::FlexibleSparseMatrix<ValueType> const& transitionMatrix, storm::storage::FlexibleSparseMatrix<ValueType> const& backwardTransitions, std::vector<ValueType> const& oneStepProbabilities) {
return backwardTransitions.getRow(state).size() * transitionMatrix.getRow(state).size(); return backwardTransitions.getRow(state).size() * transitionMatrix.getRow(state).size();
} }
template<typename SparseDtmcModelType>
void SparseDtmcEliminationModelChecker<SparseDtmcModelType>::StatePriorityQueue::update(storm::storage::sparse::state_type, FlexibleSparseMatrix const& transitionMatrix, FlexibleSparseMatrix const& backwardTransitions, std::vector<ValueType> const& oneStepProbabilities) {
template<typename ValueType>
void StatePriorityQueue<ValueType>::update(storm::storage::sparse::state_type, storm::storage::FlexibleSparseMatrix<ValueType> const& transitionMatrix, storm::storage::FlexibleSparseMatrix<ValueType> const& backwardTransitions, std::vector<ValueType> const& oneStepProbabilities) {
// Intentionally left empty. // Intentionally left empty.
} }
template<typename SparseDtmcModelType> template<typename SparseDtmcModelType>
SparseDtmcEliminationModelChecker<SparseDtmcModelType>::StaticStatePriorityQueue::StaticStatePriorityQueue(std::vector<storm::storage::sparse::state_type> const& sortedStates) : StatePriorityQueue(), sortedStates(sortedStates), currentPosition(0) {
SparseDtmcEliminationModelChecker<SparseDtmcModelType>::StaticStatePriorityQueue::StaticStatePriorityQueue(std::vector<storm::storage::sparse::state_type> const& sortedStates) : StatePriorityQueue<ValueType>(), sortedStates(sortedStates), currentPosition(0) {
// Intentionally left empty. // Intentionally left empty.
} }
@ -1460,7 +1157,7 @@ namespace storm {
} }
template<typename SparseDtmcModelType> template<typename SparseDtmcModelType>
SparseDtmcEliminationModelChecker<SparseDtmcModelType>::DynamicPenaltyStatePriorityQueue::DynamicPenaltyStatePriorityQueue(std::vector<std::pair<storm::storage::sparse::state_type, uint_fast64_t>> const& sortedStatePenaltyPairs, PenaltyFunctionType const& penaltyFunction) : StatePriorityQueue(), priorityQueue(), stateToPriorityMapping(), penaltyFunction(penaltyFunction) {
SparseDtmcEliminationModelChecker<SparseDtmcModelType>::DynamicPenaltyStatePriorityQueue::DynamicPenaltyStatePriorityQueue(std::vector<std::pair<storm::storage::sparse::state_type, uint_fast64_t>> const& sortedStatePenaltyPairs, PenaltyFunctionType const& penaltyFunction) : StatePriorityQueue<ValueType>(), priorityQueue(), stateToPriorityMapping(), penaltyFunction(penaltyFunction) {
// Insert all state-penalty pairs into our priority queue. // Insert all state-penalty pairs into our priority queue.
for (auto const& statePenalty : sortedStatePenaltyPairs) { for (auto const& statePenalty : sortedStatePenaltyPairs) {
priorityQueue.insert(priorityQueue.end(), statePenalty); priorityQueue.insert(priorityQueue.end(), statePenalty);
@ -1487,7 +1184,7 @@ namespace storm {
} }
template<typename SparseDtmcModelType> template<typename SparseDtmcModelType>
void SparseDtmcEliminationModelChecker<SparseDtmcModelType>::DynamicPenaltyStatePriorityQueue::update(storm::storage::sparse::state_type state, FlexibleSparseMatrix const& transitionMatrix, FlexibleSparseMatrix const& backwardTransitions, std::vector<ValueType> const& oneStepProbabilities) {
void SparseDtmcEliminationModelChecker<SparseDtmcModelType>::DynamicPenaltyStatePriorityQueue::update(storm::storage::sparse::state_type state, storm::storage::FlexibleSparseMatrix<ValueType> const& transitionMatrix, storm::storage::FlexibleSparseMatrix<ValueType> const& backwardTransitions, std::vector<ValueType> const& oneStepProbabilities) {
// First, we need to find the priority until now. // First, we need to find the priority until now.
auto priorityIt = stateToPriorityMapping.find(state); auto priorityIt = stateToPriorityMapping.find(state);
@ -1516,8 +1213,8 @@ namespace storm {
} }
template<typename SparseDtmcModelType> template<typename SparseDtmcModelType>
bool SparseDtmcEliminationModelChecker<SparseDtmcModelType>::checkConsistent(FlexibleSparseMatrix& transitionMatrix, FlexibleSparseMatrix& backwardTransitions) {
for (uint_fast64_t forwardIndex = 0; forwardIndex < transitionMatrix.getNumberOfRows(); ++forwardIndex) {
bool SparseDtmcEliminationModelChecker<SparseDtmcModelType>::checkConsistent(storm::storage::FlexibleSparseMatrix<ValueType>& transitionMatrix, storm::storage::FlexibleSparseMatrix<ValueType>& backwardTransitions) {
for (uint_fast64_t forwardIndex = 0; forwardIndex < transitionMatrix.getRowCount(); ++forwardIndex) {
for (auto const& forwardEntry : transitionMatrix.getRow(forwardIndex)) { for (auto const& forwardEntry : transitionMatrix.getRow(forwardIndex)) {
if (forwardEntry.getColumn() == forwardIndex) { if (forwardEntry.getColumn() == forwardIndex) {
continue; continue;
@ -1538,9 +1235,13 @@ namespace storm {
return true; return true;
} }
template class StatePriorityQueue<double>;
template class SparseDtmcEliminationModelChecker<storm::models::sparse::Dtmc<double>>; template class SparseDtmcEliminationModelChecker<storm::models::sparse::Dtmc<double>>;
template uint_fast64_t estimateComplexity(double const& value);
#ifdef STORM_HAVE_CARL #ifdef STORM_HAVE_CARL
template class StatePriorityQueue<storm::RationalFunction>;
template class SparseDtmcEliminationModelChecker<storm::models::sparse::Dtmc<storm::RationalFunction>>; template class SparseDtmcEliminationModelChecker<storm::models::sparse::Dtmc<storm::RationalFunction>>;
#endif #endif
} // namespace modelchecker } // namespace modelchecker

106
src/modelchecker/reachability/SparseDtmcEliminationModelChecker.h

@ -2,6 +2,7 @@
#define STORM_MODELCHECKER_REACHABILITY_SPARSEDTMCELIMINATIONMODELCHECKER_H_ #define STORM_MODELCHECKER_REACHABILITY_SPARSEDTMCELIMINATIONMODELCHECKER_H_
#include "src/storage/sparse/StateType.h" #include "src/storage/sparse/StateType.h"
#include "src/storage/FlexibleSparseMatrix.h"
#include "src/models/sparse/Dtmc.h" #include "src/models/sparse/Dtmc.h"
#include "src/modelchecker/propositional/SparsePropositionalModelChecker.h" #include "src/modelchecker/propositional/SparsePropositionalModelChecker.h"
#include "src/utility/constants.h" #include "src/utility/constants.h"
@ -9,12 +10,26 @@
namespace storm { namespace storm {
namespace modelchecker { namespace modelchecker {
template<typename ValueType>
uint_fast64_t estimateComplexity(ValueType const& value);
template<typename ValueType>
class StatePriorityQueue {
public:
virtual bool hasNextState() const = 0;
virtual storm::storage::sparse::state_type popNextState() = 0;
virtual void update(storm::storage::sparse::state_type state, storm::storage::FlexibleSparseMatrix<ValueType> const& transitionMatrix, storm::storage::FlexibleSparseMatrix<ValueType> const& backwardTransitions, std::vector<ValueType> const& oneStepProbabilities);
virtual std::size_t size() const = 0;
};
template<typename SparseDtmcModelType> template<typename SparseDtmcModelType>
class SparseDtmcEliminationModelChecker : public SparsePropositionalModelChecker<SparseDtmcModelType> { class SparseDtmcEliminationModelChecker : public SparsePropositionalModelChecker<SparseDtmcModelType> {
public: public:
typedef typename SparseDtmcModelType::ValueType ValueType; typedef typename SparseDtmcModelType::ValueType ValueType;
typedef typename SparseDtmcModelType::RewardModelType RewardModelType; typedef typename SparseDtmcModelType::RewardModelType RewardModelType;
typedef typename storm::storage::FlexibleSparseMatrix<ValueType>::row_type FlexibleRowType;
typedef typename FlexibleRowType::iterator FlexibleRowIterator;
/*! /*!
* Creates an elimination-based model checker for the given model. * Creates an elimination-based model checker for the given model.
* *
@ -30,53 +45,15 @@ namespace storm {
virtual std::unique_ptr<CheckResult> computeLongRunAverageRewards(storm::logic::RewardMeasureType rewardMeasureType, CheckTask<storm::logic::LongRunAverageRewardFormula> const& checkTask) override; virtual std::unique_ptr<CheckResult> computeLongRunAverageRewards(storm::logic::RewardMeasureType rewardMeasureType, CheckTask<storm::logic::LongRunAverageRewardFormula> const& checkTask) override;
virtual std::unique_ptr<CheckResult> computeConditionalProbabilities(CheckTask<storm::logic::ConditionalFormula> const& checkTask) override; virtual std::unique_ptr<CheckResult> computeConditionalProbabilities(CheckTask<storm::logic::ConditionalFormula> const& checkTask) override;
virtual std::unique_ptr<CheckResult> computeLongRunAverageProbabilities(CheckTask<storm::logic::StateFormula> const& checkTask) override; virtual std::unique_ptr<CheckResult> computeLongRunAverageProbabilities(CheckTask<storm::logic::StateFormula> const& checkTask) override;
// Static helper methods
static std::vector<ValueType> computeUntilProbabilities(storm::storage::SparseMatrix<ValueType> const& probabilityMatrix, storm::storage::SparseMatrix<ValueType> const& backwardTransitions, storm::storage::BitVector const& initialStates, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, bool computeForInitialStatesOnly);
static std::vector<ValueType> computeReachabilityRewards(storm::storage::SparseMatrix<ValueType> const& probabilityMatrix, storm::storage::SparseMatrix<ValueType> const& backwardTransitions, storm::storage::BitVector const& initialStates, storm::storage::BitVector const& targetStates, std::vector<ValueType>& stateRewardValues, bool computeForInitialStatesOnly);
private: private:
class FlexibleSparseMatrix {
public:
typedef uint_fast64_t index_type;
typedef ValueType value_type;
typedef std::vector<storm::storage::MatrixEntry<index_type, value_type>> row_type;
typedef typename row_type::iterator iterator;
typedef typename row_type::const_iterator const_iterator;
FlexibleSparseMatrix() = default;
FlexibleSparseMatrix(index_type rows);
void reserveInRow(index_type row, index_type numberOfElements);
row_type& getRow(index_type);
row_type const& getRow(index_type) const;
index_type getNumberOfRows() const;
void print() const;
bool empty() const;
void filter(storm::storage::BitVector const& rowFilter, storm::storage::BitVector const& columnFilter);
/*!
* Checks whether the given state has a self-loop with an arbitrary probability in the probability matrix.
*
* @param state The state for which to check whether it possesses a self-loop.
* @return True iff the given state has a self-loop with an arbitrary probability in the probability matrix.
*/
bool hasSelfLoop(storm::storage::sparse::state_type state);
private:
std::vector<row_type> data;
};
class StatePriorityQueue {
public:
virtual bool hasNextState() const = 0;
virtual storm::storage::sparse::state_type popNextState() = 0;
virtual void update(storm::storage::sparse::state_type state, FlexibleSparseMatrix const& transitionMatrix, FlexibleSparseMatrix const& backwardTransitions, std::vector<ValueType> const& oneStepProbabilities);
virtual std::size_t size() const = 0;
};
class StaticStatePriorityQueue : public StatePriorityQueue {
class StaticStatePriorityQueue : public StatePriorityQueue<ValueType> {
public: public:
StaticStatePriorityQueue(std::vector<storm::storage::sparse::state_type> const& sortedStates); StaticStatePriorityQueue(std::vector<storm::storage::sparse::state_type> const& sortedStates);
@ -95,15 +72,15 @@ namespace storm {
} }
}; };
typedef std::function<uint_fast64_t (storm::storage::sparse::state_type const& state, FlexibleSparseMatrix const& transitionMatrix, FlexibleSparseMatrix const& backwardTransitions, std::vector<ValueType> const& oneStepProbabilities)> PenaltyFunctionType;
typedef std::function<uint_fast64_t (storm::storage::sparse::state_type const& state, storm::storage::FlexibleSparseMatrix<ValueType> const& transitionMatrix, storm::storage::FlexibleSparseMatrix<ValueType> const& backwardTransitions, std::vector<ValueType> const& oneStepProbabilities)> PenaltyFunctionType;
class DynamicPenaltyStatePriorityQueue : public StatePriorityQueue {
class DynamicPenaltyStatePriorityQueue : public StatePriorityQueue<ValueType> {
public: public:
DynamicPenaltyStatePriorityQueue(std::vector<std::pair<storm::storage::sparse::state_type, uint_fast64_t>> const& sortedStatePenaltyPairs, PenaltyFunctionType const& penaltyFunction); DynamicPenaltyStatePriorityQueue(std::vector<std::pair<storm::storage::sparse::state_type, uint_fast64_t>> const& sortedStatePenaltyPairs, PenaltyFunctionType const& penaltyFunction);
virtual bool hasNextState() const override; virtual bool hasNextState() const override;
virtual storm::storage::sparse::state_type popNextState() override; virtual storm::storage::sparse::state_type popNextState() override;
virtual void update(storm::storage::sparse::state_type state, FlexibleSparseMatrix const& transitionMatrix, FlexibleSparseMatrix const& backwardTransitions, std::vector<ValueType> const& oneStepProbabilities) override;
virtual void update(storm::storage::sparse::state_type state, storm::storage::FlexibleSparseMatrix<ValueType> const& transitionMatrix, storm::storage::FlexibleSparseMatrix<ValueType> const& backwardTransitions, std::vector<ValueType> const& oneStepProbabilities) override;
virtual std::size_t size() const override; virtual std::size_t size() const override;
private: private:
@ -114,40 +91,33 @@ namespace storm {
static std::vector<ValueType> computeLongRunValues(storm::storage::SparseMatrix<ValueType> const& transitionMatrix, storm::storage::SparseMatrix<ValueType> const& backwardTransitions, storm::storage::BitVector const& initialStates, storm::storage::BitVector const& maybeStates, bool computeResultsForInitialStatesOnly, std::vector<ValueType>& stateValues); static std::vector<ValueType> computeLongRunValues(storm::storage::SparseMatrix<ValueType> const& transitionMatrix, storm::storage::SparseMatrix<ValueType> const& backwardTransitions, storm::storage::BitVector const& initialStates, storm::storage::BitVector const& maybeStates, bool computeResultsForInitialStatesOnly, std::vector<ValueType>& stateValues);
static std::vector<ValueType> computeReachabilityRewards(storm::storage::SparseMatrix<ValueType> const& probabilityMatrix, storm::storage::SparseMatrix<ValueType> const& backwardTransitions, storm::storage::BitVector const& initialStates, storm::storage::BitVector const& targetStates, std::function<std::vector<ValueType>(uint_fast64_t, storm::storage::SparseMatrix<ValueType> const&, storm::storage::BitVector const&)> const& totalStateRewardVectorGetter, bool computeForInitialStatesOnly);
static std::vector<ValueType> computeReachabilityValues(storm::storage::SparseMatrix<ValueType> const& transitionMatrix, std::vector<ValueType>& values, storm::storage::SparseMatrix<ValueType> const& backwardTransitions, storm::storage::BitVector const& initialStates, bool computeResultsForInitialStatesOnly, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, std::vector<ValueType> const& oneStepProbabilitiesToTarget); static std::vector<ValueType> computeReachabilityValues(storm::storage::SparseMatrix<ValueType> const& transitionMatrix, std::vector<ValueType>& values, storm::storage::SparseMatrix<ValueType> const& backwardTransitions, storm::storage::BitVector const& initialStates, bool computeResultsForInitialStatesOnly, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, std::vector<ValueType> const& oneStepProbabilitiesToTarget);
static std::unique_ptr<StatePriorityQueue> createStatePriorityQueue(boost::optional<std::vector<uint_fast64_t>> const& stateDistances, FlexibleSparseMatrix const& transitionMatrix, FlexibleSparseMatrix const& backwardTransitions, std::vector<ValueType>& oneStepProbabilities, storm::storage::BitVector const& states);
static std::shared_ptr<StatePriorityQueue<ValueType>> createStatePriorityQueue(boost::optional<std::vector<uint_fast64_t>> const& stateDistances, storm::storage::FlexibleSparseMatrix<ValueType> const& transitionMatrix, storm::storage::FlexibleSparseMatrix<ValueType> const& backwardTransitions, std::vector<ValueType>& oneStepProbabilities, storm::storage::BitVector const& states);
static std::unique_ptr<StatePriorityQueue> createNaivePriorityQueue(storm::storage::BitVector const& states);
static std::shared_ptr<StatePriorityQueue<ValueType>> createNaivePriorityQueue(storm::storage::BitVector const& states);
static void performPrioritizedStateElimination(std::unique_ptr<StatePriorityQueue>& priorityQueue, FlexibleSparseMatrix& transitionMatrix, FlexibleSparseMatrix& backwardTransitions, std::vector<ValueType>& values, storm::storage::BitVector const& initialStates, bool computeResultsForInitialStatesOnly);
static void performPrioritizedStateElimination(std::shared_ptr<StatePriorityQueue<ValueType>>& priorityQueue, storm::storage::FlexibleSparseMatrix<ValueType>& transitionMatrix, storm::storage::FlexibleSparseMatrix<ValueType>& backwardTransitions, std::vector<ValueType>& values, storm::storage::BitVector const& initialStates, bool computeResultsForInitialStatesOnly);
static void performOrdinaryStateElimination(FlexibleSparseMatrix& transitionMatrix, FlexibleSparseMatrix& backwardTransitions, storm::storage::BitVector const& subsystem, storm::storage::BitVector const& initialStates, bool computeResultsForInitialStatesOnly, std::vector<ValueType>& values, boost::optional<std::vector<ValueType>>& additionalStateValues, boost::optional<std::vector<uint_fast64_t>> const& distanceBasedPriorities);
static void performOrdinaryStateElimination(storm::storage::FlexibleSparseMatrix<ValueType>& transitionMatrix, storm::storage::FlexibleSparseMatrix<ValueType>& backwardTransitions, storm::storage::BitVector const& subsystem, storm::storage::BitVector const& initialStates, bool computeResultsForInitialStatesOnly, std::vector<ValueType>& values, boost::optional<std::vector<ValueType>>& additionalStateValues, boost::optional<std::vector<uint_fast64_t>> const& distanceBasedPriorities);
static void performOrdinaryStateElimination(FlexibleSparseMatrix& transitionMatrix, FlexibleSparseMatrix& backwardTransitions, storm::storage::BitVector const& subsystem, storm::storage::BitVector const& initialStates, bool computeResultsForInitialStatesOnly, std::vector<ValueType>& values, boost::optional<std::vector<uint_fast64_t>> const& distanceBasedPriorities);
static uint_fast64_t performHybridStateElimination(storm::storage::SparseMatrix<ValueType> const& forwardTransitions, FlexibleSparseMatrix& transitionMatrix, FlexibleSparseMatrix& backwardTransitions, storm::storage::BitVector const& subsystem, storm::storage::BitVector const& initialStates, bool computeResultsForInitialStatesOnly, std::vector<ValueType>& values, boost::optional<std::vector<uint_fast64_t>> const& distanceBasedPriorities);
static void performOrdinaryStateElimination(storm::storage::FlexibleSparseMatrix<ValueType>& transitionMatrix, storm::storage::FlexibleSparseMatrix<ValueType>& backwardTransitions, storm::storage::BitVector const& subsystem, storm::storage::BitVector const& initialStates, bool computeResultsForInitialStatesOnly, std::vector<ValueType>& values, boost::optional<std::vector<uint_fast64_t>> const& distanceBasedPriorities);
static uint_fast64_t treatScc(FlexibleSparseMatrix& matrix, std::vector<ValueType>& values, storm::storage::BitVector const& entryStates, storm::storage::BitVector const& scc, storm::storage::BitVector const& initialStates, storm::storage::SparseMatrix<ValueType> const& forwardTransitions, FlexibleSparseMatrix& backwardTransitions, bool eliminateEntryStates, uint_fast64_t level, uint_fast64_t maximalSccSize, std::vector<storm::storage::sparse::state_type>& entryStateQueue, bool computeResultsForInitialStatesOnly, boost::optional<std::vector<uint_fast64_t>> const& distanceBasedPriorities = boost::none);
static FlexibleSparseMatrix getFlexibleSparseMatrix(storm::storage::SparseMatrix<ValueType> const& matrix, bool setAllValuesToOne = false);
typedef std::function<void (storm::storage::sparse::state_type const& state, ValueType const& loopProbability)> ValueUpdateCallback;
typedef std::function<void (storm::storage::sparse::state_type const& predecessor, ValueType const& probability, storm::storage::sparse::state_type const& state)> PredecessorUpdateCallback;
typedef std::function<void (storm::storage::sparse::state_type const& state)> PriorityUpdateCallback;
typedef std::function<bool (storm::storage::sparse::state_type const& state)> PredecessorFilterCallback;
static void eliminateState(storm::storage::sparse::state_type state, FlexibleSparseMatrix& matrix, FlexibleSparseMatrix& backwardTransitions, ValueUpdateCallback const& valueUpdateCallback, PredecessorUpdateCallback const& predecessorCallback, boost::optional<PriorityUpdateCallback> const& priorityUpdateCallback = boost::none, boost::optional<PredecessorFilterCallback> const& predecessorFilterCallback = boost::none, bool removeForwardTransitions = true);
static uint_fast64_t performHybridStateElimination(storm::storage::SparseMatrix<ValueType> const& forwardTransitions, storm::storage::FlexibleSparseMatrix<ValueType>& transitionMatrix, storm::storage::FlexibleSparseMatrix<ValueType>& backwardTransitions, storm::storage::BitVector const& subsystem, storm::storage::BitVector const& initialStates, bool computeResultsForInitialStatesOnly, std::vector<ValueType>& values, boost::optional<std::vector<uint_fast64_t>> const& distanceBasedPriorities);
static uint_fast64_t treatScc(storm::storage::FlexibleSparseMatrix<ValueType>& matrix, std::vector<ValueType>& values, storm::storage::BitVector const& entryStates, storm::storage::BitVector const& scc, storm::storage::BitVector const& initialStates, storm::storage::SparseMatrix<ValueType> const& forwardTransitions, storm::storage::FlexibleSparseMatrix<ValueType>& backwardTransitions, bool eliminateEntryStates, uint_fast64_t level, uint_fast64_t maximalSccSize, std::vector<storm::storage::sparse::state_type>& entryStateQueue, bool computeResultsForInitialStatesOnly, boost::optional<std::vector<uint_fast64_t>> const& distanceBasedPriorities = boost::none);
static std::vector<uint_fast64_t> getDistanceBasedPriorities(storm::storage::SparseMatrix<ValueType> const& transitionMatrix, storm::storage::SparseMatrix<ValueType> const& transitionMatrixTransposed, storm::storage::BitVector const& initialStates, std::vector<ValueType> const& oneStepProbabilities, bool forward, bool reverse); static std::vector<uint_fast64_t> getDistanceBasedPriorities(storm::storage::SparseMatrix<ValueType> const& transitionMatrix, storm::storage::SparseMatrix<ValueType> const& transitionMatrixTransposed, storm::storage::BitVector const& initialStates, std::vector<ValueType> const& oneStepProbabilities, bool forward, bool reverse);
static std::vector<std::size_t> getStateDistances(storm::storage::SparseMatrix<ValueType> const& transitionMatrix, storm::storage::SparseMatrix<ValueType> const& transitionMatrixTransposed, storm::storage::BitVector const& initialStates, std::vector<ValueType> const& oneStepProbabilities, bool forward); static std::vector<std::size_t> getStateDistances(storm::storage::SparseMatrix<ValueType> const& transitionMatrix, storm::storage::SparseMatrix<ValueType> const& transitionMatrixTransposed, storm::storage::BitVector const& initialStates, std::vector<ValueType> const& oneStepProbabilities, bool forward);
static uint_fast64_t computeStatePenalty(storm::storage::sparse::state_type const& state, FlexibleSparseMatrix const& transitionMatrix, FlexibleSparseMatrix const& backwardTransitions, std::vector<ValueType> const& oneStepProbabilities);
static uint_fast64_t computeStatePenalty(storm::storage::sparse::state_type const& state, storm::storage::FlexibleSparseMatrix<ValueType> const& transitionMatrix, storm::storage::FlexibleSparseMatrix<ValueType> const& backwardTransitions, std::vector<ValueType> const& oneStepProbabilities);
static uint_fast64_t computeStatePenaltyRegularExpression(storm::storage::sparse::state_type const& state, FlexibleSparseMatrix const& transitionMatrix, FlexibleSparseMatrix const& backwardTransitions, std::vector<ValueType> const& oneStepProbabilities);
static uint_fast64_t computeStatePenaltyRegularExpression(storm::storage::sparse::state_type const& state, storm::storage::FlexibleSparseMatrix<ValueType> const& transitionMatrix, storm::storage::FlexibleSparseMatrix<ValueType> const& backwardTransitions, std::vector<ValueType> const& oneStepProbabilities);
static bool checkConsistent(FlexibleSparseMatrix& transitionMatrix, FlexibleSparseMatrix& backwardTransitions);
static bool checkConsistent(storm::storage::FlexibleSparseMatrix<ValueType>& transitionMatrix, storm::storage::FlexibleSparseMatrix<ValueType>& backwardTransitions);
}; };

7
src/models/sparse/Ctmc.cpp

@ -24,6 +24,13 @@ namespace storm {
exitRates = createExitRateVector(this->getTransitionMatrix()); exitRates = createExitRateVector(this->getTransitionMatrix());
} }
template <typename ValueType, typename RewardModelType>
Ctmc<ValueType, RewardModelType>::Ctmc(storm::storage::SparseMatrix<ValueType> const& rateMatrix, std::vector<ValueType> const& exitRates, storm::models::sparse::StateLabeling const& stateLabeling,
std::unordered_map<std::string, RewardModelType> const& rewardModels,
boost::optional<std::vector<LabelSet>> const& optionalChoiceLabeling)
: DeterministicModel<ValueType, RewardModelType>(storm::models::ModelType::Ctmc, std::move(rateMatrix), std::move(stateLabeling), std::move(rewardModels), std::move(optionalChoiceLabeling)), exitRates(exitRates) {
}
template <typename ValueType, typename RewardModelType> template <typename ValueType, typename RewardModelType>
std::vector<ValueType> const& Ctmc<ValueType, RewardModelType>::getExitRateVector() const { std::vector<ValueType> const& Ctmc<ValueType, RewardModelType>::getExitRateVector() const {
return exitRates; return exitRates;

14
src/models/sparse/Ctmc.h

@ -38,6 +38,20 @@ namespace storm {
std::unordered_map<std::string, RewardModelType>&& rewardModels = std::unordered_map<std::string, RewardModelType>(), std::unordered_map<std::string, RewardModelType>&& rewardModels = std::unordered_map<std::string, RewardModelType>(),
boost::optional<std::vector<LabelSet>>&& optionalChoiceLabeling = boost::optional<std::vector<LabelSet>>()); boost::optional<std::vector<LabelSet>>&& optionalChoiceLabeling = boost::optional<std::vector<LabelSet>>());
/*!
* Constructs a model from the given data.
*
* @param rateMatrix The matrix representing the transitions in the model.
* @param exitRates The exit rates of all states.
* @param stateLabeling The labeling of the states.
* @param rewardModels A mapping of reward model names to reward models.
* @param optionalChoiceLabeling A vector that represents the labels associated with the choices of each state.
*/
Ctmc(storm::storage::SparseMatrix<ValueType> const& rateMatrix, std::vector<ValueType> const& exitRates, storm::models::sparse::StateLabeling const& stateLabeling,
std::unordered_map<std::string, RewardModelType> const& rewardModels = std::unordered_map<std::string, RewardModelType>(),
boost::optional<std::vector<LabelSet>> const& optionalChoiceLabeling = boost::optional<std::vector<LabelSet>>());
Ctmc(Ctmc<ValueType, RewardModelType> const& ctmc) = default; Ctmc(Ctmc<ValueType, RewardModelType> const& ctmc) = default;
Ctmc& operator=(Ctmc<ValueType, RewardModelType> const& ctmc) = default; Ctmc& operator=(Ctmc<ValueType, RewardModelType> const& ctmc) = default;

92
src/models/sparse/MarkovAutomaton.cpp

@ -3,6 +3,10 @@
#include "src/exceptions/InvalidArgumentException.h" #include "src/exceptions/InvalidArgumentException.h"
#include "src/utility/constants.h" #include "src/utility/constants.h"
#include "src/adapters/CarlAdapter.h" #include "src/adapters/CarlAdapter.h"
#include "src/storage/FlexibleSparseMatrix.h"
#include "src/models/sparse/Dtmc.h"
#include "src/solver/stateelimination/MAEliminator.h"
#include "src/utility/vector.h"
namespace storm { namespace storm {
namespace models { namespace models {
@ -30,6 +34,19 @@ namespace storm {
this->turnRatesToProbabilities(); this->turnRatesToProbabilities();
} }
template <typename ValueType, typename RewardModelType>
MarkovAutomaton<ValueType, RewardModelType>::MarkovAutomaton(storm::storage::SparseMatrix<ValueType>&& transitionMatrix,
storm::models::sparse::StateLabeling&& stateLabeling,
storm::storage::BitVector const& markovianStates,
std::vector<ValueType> const& exitRates,
bool probabilities,
std::unordered_map<std::string, RewardModelType>&& rewardModels,
boost::optional<std::vector<LabelSet>>&& optionalChoiceLabeling)
: NondeterministicModel<ValueType, RewardModelType>(storm::models::ModelType::MarkovAutomaton, std::move(transitionMatrix), std::move(stateLabeling), std::move(rewardModels), std::move(optionalChoiceLabeling)), markovianStates(markovianStates), exitRates(std::move(exitRates)), closed(this->checkIsClosed()) {
assert(probabilities);
assert(this->getTransitionMatrix().isProbabilistic());
}
template <typename ValueType, typename RewardModelType> template <typename ValueType, typename RewardModelType>
bool MarkovAutomaton<ValueType, RewardModelType>::isClosed() const { bool MarkovAutomaton<ValueType, RewardModelType>::isClosed() const {
return closed; return closed;
@ -220,6 +237,23 @@ namespace storm {
} }
} }
template <typename ValueType, typename RewardModelType>
bool MarkovAutomaton<ValueType, RewardModelType>::hasOnlyTrivialNondeterminism() const {
// Check every state
for (uint_fast64_t state = 0; state < this->getNumberOfStates(); ++state) {
// Get number of choices in current state
uint_fast64_t numberChoices = this->getTransitionMatrix().getRowGroupIndices()[state + 1] - this->getTransitionMatrix().getRowGroupIndices()[state];
if (isMarkovianState(state)) {
assert(numberChoices == 1);
}
if (numberChoices > 1) {
assert(isProbabilisticState(state));
return false;
}
}
return true;
}
template <typename ValueType, typename RewardModelType> template <typename ValueType, typename RewardModelType>
bool MarkovAutomaton<ValueType, RewardModelType>::checkIsClosed() const { bool MarkovAutomaton<ValueType, RewardModelType>::checkIsClosed() const {
for (auto state : markovianStates) { for (auto state : markovianStates) {
@ -230,6 +264,62 @@ namespace storm {
return true; return true;
} }
template <typename ValueType, typename RewardModelType>
std::shared_ptr<storm::models::sparse::Ctmc<ValueType, RewardModelType>> MarkovAutomaton<ValueType, RewardModelType>::convertToCTMC() {
STORM_LOG_TRACE("MA matrix:" << std::endl << this->getTransitionMatrix());
STORM_LOG_TRACE("Markovian states: " << getMarkovianStates());
// Eliminate all probabilistic states by state elimination
// Initialize
storm::storage::FlexibleSparseMatrix<ValueType> flexibleMatrix(this->getTransitionMatrix());
storm::storage::FlexibleSparseMatrix<ValueType> flexibleBackwardTransitions(this->getTransitionMatrix().transpose());
storm::solver::stateelimination::MAEliminator<storm::models::sparse::Dtmc<ValueType>> stateEliminator(flexibleMatrix, flexibleBackwardTransitions);
for (uint_fast64_t state = 0; state < this->getNumberOfStates(); ++state) {
assert(!this->isHybridState(state));
if (this->isProbabilisticState(state)) {
// Eliminate this probabilistic state
stateEliminator.eliminateState(state, true);
STORM_LOG_TRACE("Flexible matrix after eliminating state " << state << ":" << std::endl << flexibleMatrix);
}
}
// Create the rate matrix for the CTMC
storm::storage::SparseMatrixBuilder<ValueType> transitionMatrixBuilder(0, 0, 0, false, false);
// Remember state to keep
storm::storage::BitVector keepStates(this->getNumberOfStates(), true);
for (uint_fast64_t state = 0; state < this->getNumberOfStates(); ++state) {
if (storm::utility::isZero(flexibleMatrix.getRowSum(state))) {
// State is eliminated and can be discarded
keepStates.set(state, false);
} else {
assert(this->isMarkovianState(state));
// Copy transitions
for (uint_fast64_t row = flexibleMatrix.getRowGroupIndices()[state]; row < flexibleMatrix.getRowGroupIndices()[state + 1]; ++row) {
for (auto const& entry : flexibleMatrix.getRow(row)) {
// Convert probabilities into rates
transitionMatrixBuilder.addNextValue(state, entry.getColumn(), entry.getValue() * exitRates[state]);
}
}
}
}
storm::storage::SparseMatrix<ValueType> rateMatrix = transitionMatrixBuilder.build();
rateMatrix = rateMatrix.getSubmatrix(false, keepStates, keepStates, false);
STORM_LOG_TRACE("New CTMC matrix:" << std::endl << rateMatrix);
// Construct CTMC
storm::models::sparse::StateLabeling stateLabeling = this->getStateLabeling().getSubLabeling(keepStates);
boost::optional<std::vector<LabelSet>> optionalChoiceLabeling = this->getOptionalChoiceLabeling();
if (optionalChoiceLabeling) {
optionalChoiceLabeling = storm::utility::vector::filterVector(optionalChoiceLabeling.get(), keepStates);
}
//TODO update reward models according to kept states
std::unordered_map<std::string, RewardModelType> rewardModels = this->getRewardModels();
return std::make_shared<storm::models::sparse::Ctmc<ValueType, RewardModelType>>(std::move(rateMatrix), std::move(stateLabeling), std::move(rewardModels), std::move(optionalChoiceLabeling));
}
template class MarkovAutomaton<double>; template class MarkovAutomaton<double>;
// template class MarkovAutomaton<float>; // template class MarkovAutomaton<float>;
@ -241,4 +331,4 @@ namespace storm {
} // namespace sparse } // namespace sparse
} // namespace models } // namespace models
} // namespace storm
} // namespace storm

24
src/models/sparse/MarkovAutomaton.h

@ -2,6 +2,7 @@
#define STORM_MODELS_SPARSE_MARKOVAUTOMATON_H_ #define STORM_MODELS_SPARSE_MARKOVAUTOMATON_H_
#include "src/models/sparse/NondeterministicModel.h" #include "src/models/sparse/NondeterministicModel.h"
#include "src/models/sparse/Ctmc.h"
#include "src/utility/OsDetection.h" #include "src/utility/OsDetection.h"
namespace storm { namespace storm {
@ -48,6 +49,25 @@ namespace storm {
std::unordered_map<std::string, RewardModelType>&& rewardModels = std::unordered_map<std::string, RewardModelType>(), std::unordered_map<std::string, RewardModelType>&& rewardModels = std::unordered_map<std::string, RewardModelType>(),
boost::optional<std::vector<LabelSet>>&& optionalChoiceLabeling = boost::optional<std::vector<LabelSet>>()); boost::optional<std::vector<LabelSet>>&& optionalChoiceLabeling = boost::optional<std::vector<LabelSet>>());
/*!
* Constructs a model by moving the given data.
*
* @param transitionMatrix The matrix representing the transitions in the model in terms of rates.
* @param stateLabeling The labeling of the states.
* @param markovianStates A bit vector indicating the Markovian states of the automaton.
* @param exitRates A vector storing the exit rates of the states.
* @param probabilities Flag if transitions matrix contains probabilities or rates
* @param rewardModels A mapping of reward model names to reward models.
* @param optionalChoiceLabeling A vector that represents the labels associated with the choices of each state.
*/
MarkovAutomaton(storm::storage::SparseMatrix<ValueType>&& transitionMatrix,
storm::models::sparse::StateLabeling&& stateLabeling,
storm::storage::BitVector const& markovianStates,
std::vector<ValueType> const& exitRates,
bool probabilities,
std::unordered_map<std::string, RewardModelType>&& rewardModels = std::unordered_map<std::string, RewardModelType>(),
boost::optional<std::vector<LabelSet>>&& optionalChoiceLabeling = boost::optional<std::vector<LabelSet>>());
MarkovAutomaton(MarkovAutomaton<ValueType, RewardModelType> const& other) = default; MarkovAutomaton(MarkovAutomaton<ValueType, RewardModelType> const& other) = default;
MarkovAutomaton& operator=(MarkovAutomaton<ValueType, RewardModelType> const& other) = default; MarkovAutomaton& operator=(MarkovAutomaton<ValueType, RewardModelType> const& other) = default;
@ -128,6 +148,10 @@ namespace storm {
*/ */
void close(); void close();
bool hasOnlyTrivialNondeterminism() const;
std::shared_ptr<storm::models::sparse::Ctmc<ValueType, RewardModelType>> convertToCTMC();
virtual void writeDotToStream(std::ostream& outStream, bool includeLabeling = true, storm::storage::BitVector const* subsystem = nullptr, std::vector<ValueType> const* firstValue = nullptr, std::vector<ValueType> const* secondValue = nullptr, std::vector<uint_fast64_t> const* stateColoring = nullptr, std::vector<std::string> const* colors = nullptr, std::vector<uint_fast64_t>* scheduler = nullptr, bool finalizeOutput = true) const; virtual void writeDotToStream(std::ostream& outStream, bool includeLabeling = true, storm::storage::BitVector const* subsystem = nullptr, std::vector<ValueType> const* firstValue = nullptr, std::vector<ValueType> const* secondValue = nullptr, std::vector<uint_fast64_t> const* stateColoring = nullptr, std::vector<std::string> const* colors = nullptr, std::vector<uint_fast64_t>* scheduler = nullptr, bool finalizeOutput = true) const;
std::size_t getSizeInBytes() const; std::size_t getSizeInBytes() const;

160
src/parser/DFTGalileoParser.cpp

@ -0,0 +1,160 @@
#include "DFTGalileoParser.h"
#include <iostream>
#include <fstream>
#include <boost/algorithm/string.hpp>
#include <boost/lexical_cast.hpp>
#include "src/storage/expressions/ExpressionManager.h"
#include "src/exceptions/NotImplementedException.h"
#include "src/exceptions/FileIoException.h"
#include "src/exceptions/NotSupportedException.h"
#include "src/utility/macros.h"
namespace storm {
namespace parser {
template<typename ValueType>
storm::storage::DFT<ValueType> DFTGalileoParser<ValueType>::parseDFT(const std::string& filename) {
readFile(filename);
storm::storage::DFT<ValueType> dft = builder.build();
STORM_LOG_DEBUG("Elements:" << std::endl << dft.getElementsString());
STORM_LOG_DEBUG("Spare Modules:" << std::endl << dft.getSpareModulesString());
return dft;
}
template<typename ValueType>
std::string DFTGalileoParser<ValueType>::stripQuotsFromName(std::string const& name) {
size_t firstQuots = name.find("\"");
size_t secondQuots = name.find("\"", firstQuots+1);
if(firstQuots == std::string::npos) {
return name;
} else {
STORM_LOG_THROW(secondQuots != std::string::npos, storm::exceptions::FileIoException, "No ending quotation mark found in " << name);
return name.substr(firstQuots+1,secondQuots-1);
}
}
template<typename ValueType>
void DFTGalileoParser<ValueType>::readFile(const std::string& filename) {
// constants
std::string toplevelToken = "toplevel";
std::string toplevelId;
std::string parametricToken = "param";
std::ifstream file;
file.exceptions ( std::ifstream::failbit );
try {
file.open(filename);
}
catch (std::ifstream::failure e) {
STORM_LOG_THROW(false, storm::exceptions::FileIoException, "Exception during file opening on " << filename << ".");
return;
}
file.exceptions( std::ifstream::goodbit );
std::string line;
while(std::getline(file, line)) {
bool success = true;
STORM_LOG_TRACE("Parsing: " << line);
size_t commentstarts = line.find("//");
line = line.substr(0, commentstarts);
size_t firstsemicolon = line.find(";");
line = line.substr(0, firstsemicolon);
if (line.find_first_not_of(' ') == std::string::npos) {
// Only whitespace
continue;
}
// Top level indicator.
if(boost::starts_with(line, toplevelToken)) {
toplevelId = stripQuotsFromName(line.substr(toplevelToken.size() + 1));
}
else if (boost::starts_with(line, parametricToken)) {
STORM_LOG_THROW((std::is_same<ValueType, storm::RationalFunction>::value), storm::exceptions::NotSupportedException, "Parameters only allowed when using rational functions.");
std::string parameter = stripQuotsFromName(line.substr(parametricToken.size() + 1));
storm::expressions::Variable var = manager->declareRationalVariable(parameter);
identifierMapping.emplace(var.getName(), var);
parser.setIdentifierMapping(identifierMapping);
STORM_LOG_TRACE("Added parameter: " << var.getName());
} else {
std::vector<std::string> tokens;
boost::split(tokens, line, boost::is_any_of(" "));
std::string name(stripQuotsFromName(tokens[0]));
std::vector<std::string> childNames;
for(unsigned i = 2; i < tokens.size(); ++i) {
childNames.push_back(stripQuotsFromName(tokens[i]));
}
if(tokens[1] == "and") {
success = builder.addAndElement(name, childNames);
} else if (tokens[1] == "or") {
success = builder.addOrElement(name, childNames);
} else if (boost::starts_with(tokens[1], "vot")) {
success = builder.addVotElement(name, boost::lexical_cast<unsigned>(tokens[1].substr(3)), childNames);
} else if (tokens[1].find("of") != std::string::npos) {
size_t pos = tokens[1].find("of");
unsigned threshold = boost::lexical_cast<unsigned>(tokens[1].substr(0, pos));
unsigned count = boost::lexical_cast<unsigned>(tokens[1].substr(pos + 2));
STORM_LOG_THROW(count == childNames.size(), storm::exceptions::FileIoException, "Voting gate does not correspond to number of children.");
success = builder.addVotElement(name, threshold, childNames);
} else if (tokens[1] == "pand") {
success = builder.addPandElement(name, childNames);
} else if (tokens[1] == "por") {
success = builder.addPorElement(name, childNames);
} else if (tokens[1] == "wsp" || tokens[1] == "csp") {
success = builder.addSpareElement(name, childNames);
} else if (tokens[1] == "seq") {
success = builder.addSequenceEnforcer(name, childNames);
} else if (tokens[1] == "fdep") {
success = builder.addDepElement(name, childNames, storm::utility::one<ValueType>());
} else if (boost::starts_with(tokens[1], "pdep=")) {
ValueType probability = parseRationalExpression(tokens[1].substr(5));
success = builder.addDepElement(name, childNames, probability);
} else if (boost::starts_with(tokens[1], "lambda=")) {
ValueType failureRate = parseRationalExpression(tokens[1].substr(7));
ValueType dormancyFactor = parseRationalExpression(tokens[2].substr(5));
success = builder.addBasicElement(name, failureRate, dormancyFactor);
} else {
STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Type name: " << tokens[1] << " not recognized.");
success = false;
}
STORM_LOG_THROW(success, storm::exceptions::FileIoException, "Error while adding element '" << name << "' of line '" << line << "'.");
}
}
if(!builder.setTopLevel(toplevelId)) {
STORM_LOG_THROW(false, storm::exceptions::FileIoException, "Top level id unknown.");
}
file.close();
}
template<typename ValueType>
ValueType DFTGalileoParser<ValueType>::parseRationalExpression(std::string const& expr) {
STORM_LOG_ASSERT(false, "Specialized method should be called.");
return 0;
}
template<>
double DFTGalileoParser<double>::parseRationalExpression(std::string const& expr) {
return boost::lexical_cast<double>(expr);
}
// Explicitly instantiate the class.
template class DFTGalileoParser<double>;
#ifdef STORM_HAVE_CARL
template<>
storm::RationalFunction DFTGalileoParser<storm::RationalFunction>::parseRationalExpression(std::string const& expr) {
STORM_LOG_TRACE("Translating expression: " << expr);
storm::expressions::Expression expression = parser.parseFromString(expr);
STORM_LOG_TRACE("Expression: " << expression);
storm::RationalFunction rationalFunction = evaluator.asRational(expression);
STORM_LOG_TRACE("Parsed expression: " << rationalFunction);
return rationalFunction;
}
template class DFTGalileoParser<RationalFunction>;
#endif
}
}

44
src/parser/DFTGalileoParser.h

@ -0,0 +1,44 @@
#ifndef DFTGALILEOPARSER_H
#define DFTGALILEOPARSER_H
#include "src/storage/dft/DFT.h"
#include "src/storage/dft/DFTBuilder.h"
#include "src/storage/expressions/ExpressionManager.h"
#include "src/parser/ExpressionParser.h"
#include "src/storage/expressions/ExpressionEvaluator.h"
#include <map>
namespace storm {
namespace parser {
template<typename ValueType>
class DFTGalileoParser {
storm::storage::DFTBuilder<ValueType> builder;
std::shared_ptr<storm::expressions::ExpressionManager> manager;
storm::parser::ExpressionParser parser;
storm::expressions::ExpressionEvaluator<ValueType> evaluator;
std::unordered_map<std::string, storm::expressions::Expression> identifierMapping;
public:
DFTGalileoParser() : manager(new storm::expressions::ExpressionManager()), parser(*manager), evaluator(*manager) {
}
storm::storage::DFT<ValueType> parseDFT(std::string const& filename);
private:
void readFile(std::string const& filename);
std::string stripQuotsFromName(std::string const& name);
ValueType parseRationalExpression(std::string const& expr);
};
}
}
#endif /* DFTGALILEOPARSER_H */

4
src/parser/DeterministicSparseTransitionParser.cpp

@ -14,7 +14,7 @@
#include "src/exceptions/WrongFormatException.h" #include "src/exceptions/WrongFormatException.h"
#include "src/exceptions/InvalidArgumentException.h" #include "src/exceptions/InvalidArgumentException.h"
#include "src/settings/SettingsManager.h" #include "src/settings/SettingsManager.h"
#include "src/settings/modules/GeneralSettings.h"
#include "src/settings/modules/MarkovChainSettings.h"
#include "src/adapters/CarlAdapter.h" #include "src/adapters/CarlAdapter.h"
#include "src/utility/macros.h" #include "src/utility/macros.h"
@ -88,7 +88,7 @@ namespace storm {
uint_fast64_t row, col, lastRow = 0; uint_fast64_t row, col, lastRow = 0;
double val; double val;
bool dontFixDeadlocks = storm::settings::generalSettings().isDontFixDeadlocksSet();
bool dontFixDeadlocks = storm::settings::getModule<storm::settings::modules::MarkovChainSettings>().isDontFixDeadlocksSet();
bool hadDeadlocks = false; bool hadDeadlocks = false;
bool rowHadDiagonalEntry = false; bool rowHadDiagonalEntry = false;

38
src/parser/ExpressionParser.cpp

@ -134,9 +134,23 @@ namespace storm {
this->identifiers_ = nullptr; this->identifiers_ = nullptr;
} }
} }
void ExpressionParser::setIdentifierMapping(std::unordered_map<std::string, storm::expressions::Expression> const& identifierMapping) {
unsetIdentifierMapping();
this->createExpressions = true;
this->identifiers_ = new qi::symbols<char, storm::expressions::Expression>();
for (auto const& identifierExpressionPair : identifierMapping) {
this->identifiers_->add(identifierExpressionPair.first, identifierExpressionPair.second);
}
deleteIdentifierMapping = true;
}
void ExpressionParser::unsetIdentifierMapping() { void ExpressionParser::unsetIdentifierMapping() {
this->createExpressions = false; this->createExpressions = false;
if (deleteIdentifierMapping) {
delete this->identifiers_;
deleteIdentifierMapping = false;
}
this->identifiers_ = nullptr; this->identifiers_ = nullptr;
} }
@ -352,5 +366,25 @@ namespace storm {
} }
return true; return true;
} }
storm::expressions::Expression ExpressionParser::parseFromString(std::string const& expressionString) const {
PositionIteratorType first(expressionString.begin());
PositionIteratorType iter = first;
PositionIteratorType last(expressionString.end());
// Create empty result;
storm::expressions::Expression result;
try {
// Start parsing.
bool succeeded = qi::phrase_parse(iter, last, *this, boost::spirit::ascii::space | qi::lit("//") >> *(qi::char_ - (qi::eol | qi::eoi)) >> (qi::eol | qi::eoi), result);
STORM_LOG_THROW(succeeded, storm::exceptions::WrongFormatException, "Could not parse expression.");
STORM_LOG_DEBUG("Parsed expression successfully.");
} catch (qi::expectation_failure<PositionIteratorType> const& e) {
STORM_LOG_THROW(false, storm::exceptions::WrongFormatException, e.what_);
}
return result;
}
} }
}
}

22
src/parser/ExpressionParser.h

@ -26,7 +26,7 @@ namespace storm {
* points it would typically allow. This can, for example, be used to prevent errors if the outer grammar * points it would typically allow. This can, for example, be used to prevent errors if the outer grammar
* also parses boolean conjuncts that are erroneously consumed by the expression parser. * also parses boolean conjuncts that are erroneously consumed by the expression parser.
*/ */
ExpressionParser(storm::expressions::ExpressionManager const& manager, qi::symbols<char, uint_fast64_t> const& invalidIdentifiers_, bool enableErrorHandling = true, bool allowBacktracking = false);
ExpressionParser(storm::expressions::ExpressionManager const& manager, qi::symbols<char, uint_fast64_t> const& invalidIdentifiers_ = qi::symbols<char, uint_fast64_t>(), bool enableErrorHandling = true, bool allowBacktracking = false);
ExpressionParser(ExpressionParser const& other) = default; ExpressionParser(ExpressionParser const& other) = default;
ExpressionParser& operator=(ExpressionParser const& other) = default; ExpressionParser& operator=(ExpressionParser const& other) = default;
@ -39,6 +39,15 @@ namespace storm {
* @param identifiers_ A pointer to a mapping from identifiers to expressions. * @param identifiers_ A pointer to a mapping from identifiers to expressions.
*/ */
void setIdentifierMapping(qi::symbols<char, storm::expressions::Expression> const* identifiers_); void setIdentifierMapping(qi::symbols<char, storm::expressions::Expression> const* identifiers_);
/*!
* Sets an identifier mapping that is used to determine valid variables in the expression. The mapped-to
* expressions will be substituted wherever the key value appears in the parsed expression. After setting
* this, the parser will generate expressions.
*
* @param identifierMapping A mapping from identifiers to expressions.
*/
void setIdentifierMapping(std::unordered_map<std::string, storm::expressions::Expression> const& identifierMapping);
/*! /*!
* Unsets a previously set identifier mapping. This will make the parser not generate expressions any more * Unsets a previously set identifier mapping. This will make the parser not generate expressions any more
@ -52,7 +61,9 @@ namespace storm {
* @param flag If set to true, double literals are accepted. * @param flag If set to true, double literals are accepted.
*/ */
void setAcceptDoubleLiterals(bool flag); void setAcceptDoubleLiterals(bool flag);
storm::expressions::Expression parseFromString(std::string const& expressionString) const;
private: private:
struct orOperatorStruct : qi::symbols<char, storm::expressions::OperatorType> { struct orOperatorStruct : qi::symbols<char, storm::expressions::OperatorType> {
orOperatorStruct() { orOperatorStruct() {
@ -195,12 +206,15 @@ namespace storm {
// A flag that indicates whether double literals are accepted. // A flag that indicates whether double literals are accepted.
bool acceptDoubleLiterals; bool acceptDoubleLiterals;
// A flag that indicates whether the mapping must be deleted on unsetting.
bool deleteIdentifierMapping;
// The currently used mapping of identifiers to expressions. This is used if the parser is set to create // The currently used mapping of identifiers to expressions. This is used if the parser is set to create
// expressions. // expressions.
qi::symbols<char, storm::expressions::Expression> const* identifiers_; qi::symbols<char, storm::expressions::Expression> const* identifiers_;
// The symbol table of invalid identifiers. // The symbol table of invalid identifiers.
qi::symbols<char, uint_fast64_t> const& invalidIdentifiers_;
qi::symbols<char, uint_fast64_t> invalidIdentifiers_;
// Rules for parsing a composed expression. // Rules for parsing a composed expression.
qi::rule<Iterator, storm::expressions::Expression(), Skipper> expression; qi::rule<Iterator, storm::expressions::Expression(), Skipper> expression;
@ -248,4 +262,4 @@ namespace storm {
} // namespace parser } // namespace parser
} // namespace storm } // namespace storm
#endif /* STORM_PARSER_EXPRESSIONPARSER_H_ */
#endif /* STORM_PARSER_EXPRESSIONPARSER_H_ */

8
src/parser/FormulaParser.cpp

@ -280,7 +280,7 @@ namespace storm {
booleanLiteralFormula = (qi::lit("true")[qi::_a = true] | qi::lit("false")[qi::_a = false])[qi::_val = phoenix::bind(&FormulaParserGrammar::createBooleanLiteralFormula, phoenix::ref(*this), qi::_a)]; booleanLiteralFormula = (qi::lit("true")[qi::_a = true] | qi::lit("false")[qi::_a = false])[qi::_val = phoenix::bind(&FormulaParserGrammar::createBooleanLiteralFormula, phoenix::ref(*this), qi::_a)];
booleanLiteralFormula.name("boolean literal formula"); booleanLiteralFormula.name("boolean literal formula");
operatorFormula = probabilityOperator | rewardOperator | longRunAverageOperator;
operatorFormula = probabilityOperator | rewardOperator | longRunAverageOperator | timeOperator;
operatorFormula.name("operator formulas"); operatorFormula.name("operator formulas");
atomicStateFormula = booleanLiteralFormula | labelFormula | expressionFormula | (qi::lit("(") > stateFormula > qi::lit(")")) | operatorFormula; atomicStateFormula = booleanLiteralFormula | labelFormula | expressionFormula | (qi::lit("(") > stateFormula > qi::lit(")")) | operatorFormula;
@ -346,8 +346,8 @@ namespace storm {
start = qi::eps > (stateFormula % +(qi::char_("\n;"))) >> qi::skip(boost::spirit::ascii::space | qi::lit("//") >> *(qi::char_ - (qi::eol | qi::eoi)))[qi::eps] >> qi::eoi; start = qi::eps > (stateFormula % +(qi::char_("\n;"))) >> qi::skip(boost::spirit::ascii::space | qi::lit("//") >> *(qi::char_ - (qi::eol | qi::eoi)))[qi::eps] >> qi::eoi;
start.name("start"); start.name("start");
/*!
* Enable the following lines to print debug output for most the rules.
//Enable the following lines to print debug output for most the rules.
/*
debug(start); debug(start);
debug(stateFormula); debug(stateFormula);
debug(orStateFormula); debug(orStateFormula);
@ -355,6 +355,7 @@ namespace storm {
debug(probabilityOperator); debug(probabilityOperator);
debug(rewardOperator); debug(rewardOperator);
debug(longRunAverageOperator); debug(longRunAverageOperator);
debug(timeOperator);
debug(pathFormulaWithoutUntil); debug(pathFormulaWithoutUntil);
debug(pathFormula); debug(pathFormula);
// debug(conditionalFormula); // debug(conditionalFormula);
@ -378,6 +379,7 @@ namespace storm {
qi::on_error<qi::fail>(probabilityOperator, handler(qi::_1, qi::_2, qi::_3, qi::_4)); qi::on_error<qi::fail>(probabilityOperator, handler(qi::_1, qi::_2, qi::_3, qi::_4));
qi::on_error<qi::fail>(rewardOperator, handler(qi::_1, qi::_2, qi::_3, qi::_4)); qi::on_error<qi::fail>(rewardOperator, handler(qi::_1, qi::_2, qi::_3, qi::_4));
qi::on_error<qi::fail>(longRunAverageOperator, handler(qi::_1, qi::_2, qi::_3, qi::_4)); qi::on_error<qi::fail>(longRunAverageOperator, handler(qi::_1, qi::_2, qi::_3, qi::_4));
qi::on_error<qi::fail>(timeOperator, handler(qi::_1, qi::_2, qi::_3, qi::_4));
qi::on_error<qi::fail>(operatorInformation, handler(qi::_1, qi::_2, qi::_3, qi::_4)); qi::on_error<qi::fail>(operatorInformation, handler(qi::_1, qi::_2, qi::_3, qi::_4));
qi::on_error<qi::fail>(pathFormulaWithoutUntil, handler(qi::_1, qi::_2, qi::_3, qi::_4)); qi::on_error<qi::fail>(pathFormulaWithoutUntil, handler(qi::_1, qi::_2, qi::_3, qi::_4));
qi::on_error<qi::fail>(pathFormula, handler(qi::_1, qi::_2, qi::_3, qi::_4)); qi::on_error<qi::fail>(pathFormula, handler(qi::_1, qi::_2, qi::_3, qi::_4));

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save