Browse Source

Merge branch 'deterministicScheds' of https://srv-i2.informatik.rwth-aachen.de/scm/git/storm into deterministicScheds

main
radioGiorgio 6 years ago
parent
commit
9e6e78c69e
  1. 261
      .travis.yml
  2. 18
      CMakeLists.txt
  3. 36
      resources/doxygen/CMakeLists.txt
  4. 2891
      resources/doxygen/Doxyfile.in
  5. 5
      resources/examples/testfiles/dft/cyclic.dft
  6. 15
      resources/examples/testfiles/dft/fdep_bound.dft
  7. 40
      resources/examples/testfiles/dft/hecs_2_2.dft
  8. 5
      resources/examples/testfiles/dft/seqChild.dft
  9. 8
      resources/examples/testfiles/dft/spare_two_modules.dft
  10. 24
      resources/examples/testfiles/dft/symmetry6.dft
  11. 13
      src/storm-dft-cli/storm-dft.cpp
  12. 33
      src/storm-dft/api/storm-dft.cpp
  13. 11
      src/storm-dft/api/storm-dft.h
  14. 8
      src/storm-dft/builder/DFTBuilder.cpp
  15. 2
      src/storm-dft/builder/DftExplorationHeuristic.h
  16. 25
      src/storm-dft/builder/ExplicitDFTModelBuilder.cpp
  17. 1
      src/storm-dft/generator/DftNextStateGenerator.cpp
  18. 1098
      src/storm-dft/modelchecker/dft/DFTASFChecker.cpp
  19. 210
      src/storm-dft/modelchecker/dft/DFTASFChecker.h
  20. 701
      src/storm-dft/modelchecker/dft/SmtConstraint.cpp
  21. 39
      src/storm-dft/modelchecker/dft/SmtConstraint.h
  22. 14
      src/storm-dft/settings/modules/DftIOSettings.cpp
  23. 15
      src/storm-dft/settings/modules/DftIOSettings.h
  24. 40
      src/storm-dft/settings/modules/FaultTreeSettings.cpp
  25. 15
      src/storm-dft/settings/modules/FaultTreeSettings.h
  26. 13
      src/storm-dft/storage/dft/DFT.cpp
  27. 1
      src/storm-dft/storage/dft/DFT.h
  28. 2
      src/storm-dft/storage/dft/DFTState.cpp
  29. 70
      src/storm-dft/storage/dft/DFTStateGenerationInfo.h
  30. 9
      src/storm-pars/modelchecker/region/SparseDtmcParameterLiftingModelChecker.cpp
  31. 5
      src/storm/builder/DdJaniModelBuilder.cpp
  32. 62
      src/storm/generator/JaniNextStateGenerator.cpp
  33. 6
      src/storm/generator/JaniNextStateGenerator.h
  34. 2
      src/storm/logic/EventuallyFormula.cpp
  35. 14
      src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp
  36. 313
      src/storm/modelchecker/multiobjective/deterministicScheds/DeterministicSchedsLpChecker.cpp
  37. 10
      src/storm/modelchecker/multiobjective/deterministicScheds/DeterministicSchedsLpChecker.h
  38. 4
      src/storm/modelchecker/multiobjective/deterministicScheds/DeterministicSchedsObjectiveHelper.cpp
  39. 2
      src/storm/modelchecker/multiobjective/deterministicScheds/DeterministicSchedsObjectiveHelper.h
  40. 2
      src/storm/modelchecker/multiobjective/deterministicScheds/DeterministicSchedsParetoExplorer.cpp
  41. 1
      src/storm/modelchecker/multiobjective/pcaa/RewardBoundedMdpPcaaWeightVectorChecker.cpp
  42. 1
      src/storm/modelchecker/multiobjective/pcaa/StandardMaPcaaWeightVectorChecker.cpp
  43. 48
      src/storm/modelchecker/multiobjective/pcaa/StandardPcaaWeightVectorChecker.cpp
  44. 52
      src/storm/modelchecker/prctl/helper/HybridMdpPrctlHelper.cpp
  45. 36
      src/storm/modelchecker/prctl/helper/SparseMdpPrctlHelper.cpp
  46. 8
      src/storm/modelchecker/prctl/helper/SymbolicMdpPrctlHelper.cpp
  47. 1
      src/storm/modelchecker/prctl/helper/rewardbounded/EpochModel.cpp
  48. 20
      src/storm/modelchecker/results/ParetoCurveCheckResult.cpp
  49. 27
      src/storm/solver/GurobiLpSolver.cpp
  50. 16
      src/storm/solver/IterativeMinMaxLinearEquationSolver.cpp
  51. 2
      src/storm/solver/LpMinMaxLinearEquationSolver.cpp
  52. 17
      src/storm/solver/MinMaxLinearEquationSolver.cpp
  53. 21
      src/storm/solver/MinMaxLinearEquationSolver.h
  54. 25
      src/storm/solver/MinMaxLinearEquationSolverRequirements.cpp
  55. 10
      src/storm/solver/MinMaxLinearEquationSolverRequirements.h
  56. 2
      src/storm/solver/SmtSolver.h
  57. 2
      src/storm/solver/SymbolicMinMaxLinearEquationSolver.cpp
  58. 17
      src/storm/solver/TopologicalMinMaxLinearEquationSolver.cpp
  59. 3
      src/storm/storage/Qvbs.cpp
  60. 9
      src/storm/storage/expressions/UnaryNumericalFunctionExpression.cpp
  61. 11
      src/storm/storage/jani/Model.cpp
  62. 16
      src/storm/storage/jani/Model.h
  63. 9
      src/storm/storm.cpp
  64. 41
      src/test/storm-dft/api/DftModelCheckerTest.cpp
  65. 10
      src/test/storm-dft/api/DftParserTest.cpp
  66. 59
      src/test/storm-dft/api/DftSmtTest.cpp
  67. 1
      src/test/storm/solver/MinMaxLinearEquationSolverTest.cpp
  68. 33
      src/test/storm/transformer/EndComponentEliminatorTest.cpp
  69. 9
      travis/build.sh
  70. 59
      travis/build_helper.sh
  71. 13
      travis/deploy_docker.sh
  72. 47
      travis/deploy_storm.sh
  73. 151
      travis/generate_travis.py
  74. 3
      travis/mtime_cache/globs.txt
  75. 5
      travis/skip_test.sh

261
.travis.yml

@ -6,7 +6,6 @@ branches:
- master
- stable
sudo: required
dist: trusty
language: cpp
git:
@ -39,46 +38,48 @@ jobs:
###
# Stage: Build Carl
###
# ubuntu-19.04 - DefaultDebugTravis
- stage: Build Carl
os: linux
compiler: gcc
env: CONFIG=DefaultDebugTravis LINUX=ubuntu-19.04 COMPILER=gcc
install:
- travis/install_linux.sh
env: CONFIG=DefaultDebugTravis TASK=TestDocker LINUX=ubuntu-19.04 COMPILER=gcc
before_script:
- python -c "import fcntl; fcntl.fcntl(1, fcntl.F_SETFL, 0)" # Workaround for nonblocking mode
script:
- travis/build_carl.sh
after_success:
- travis/deploy_carl.sh
before_cache:
- docker cp carl:/opt/carl/. .
deploy:
- provider: script
skip_cleanup: true
script: bash travis/deploy_docker.sh carl
# ubuntu-19.04 - DefaultReleaseTravis
- stage: Build Carl
os: linux
compiler: gcc
env: CONFIG=DefaultReleaseTravis LINUX=ubuntu-19.04 COMPILER=gcc
install:
- travis/install_linux.sh
env: CONFIG=DefaultReleaseTravis TASK=TestDockerDoxygen LINUX=ubuntu-19.04 COMPILER=gcc
before_script:
- python -c "import fcntl; fcntl.fcntl(1, fcntl.F_SETFL, 0)" # Workaround for nonblocking mode
script:
- travis/build_carl.sh
after_success:
- travis/deploy_carl.sh
before_cache:
- docker cp carl:/opt/carl/. .
deploy:
- provider: script
skip_cleanup: true
script: bash travis/deploy_docker.sh carl
###
# Stage: Build (1st run)
###
# ubuntu-18.04 - DefaultDebug
- stage: Build (1st run)
os: linux
compiler: gcc
env: CONFIG=DefaultDebug LINUX=ubuntu-18.04 COMPILER=gcc
env: CONFIG=DefaultDebug TASK=Test LINUX=ubuntu-18.04 COMPILER=gcc
install:
- rm -rf build
- travis/install_linux.sh
- travis/skip_test.sh
before_script:
- python -c "import fcntl; fcntl.fcntl(1, fcntl.F_SETFL, 0)" # Workaround for nonblocking mode
script:
@ -91,10 +92,10 @@ jobs:
- stage: Build (1st run)
os: linux
compiler: gcc
env: CONFIG=DefaultRelease LINUX=ubuntu-18.04 COMPILER=gcc
env: CONFIG=DefaultRelease TASK=Test LINUX=ubuntu-18.04 COMPILER=gcc
install:
- rm -rf build
- travis/install_linux.sh
- travis/skip_test.sh
before_script:
- python -c "import fcntl; fcntl.fcntl(1, fcntl.F_SETFL, 0)" # Workaround for nonblocking mode
script:
@ -107,10 +108,10 @@ jobs:
- stage: Build (1st run)
os: linux
compiler: gcc
env: CONFIG=DefaultDebug LINUX=debian-9 COMPILER=gcc
env: CONFIG=DefaultDebug TASK=Test LINUX=debian-9 COMPILER=gcc
install:
- rm -rf build
- travis/install_linux.sh
- travis/skip_test.sh
before_script:
- python -c "import fcntl; fcntl.fcntl(1, fcntl.F_SETFL, 0)" # Workaround for nonblocking mode
script:
@ -123,10 +124,10 @@ jobs:
- stage: Build (1st run)
os: linux
compiler: gcc
env: CONFIG=DefaultRelease LINUX=debian-9 COMPILER=gcc
env: CONFIG=DefaultRelease TASK=Test LINUX=debian-9 COMPILER=gcc
install:
- rm -rf build
- travis/install_linux.sh
- travis/skip_test.sh
before_script:
- python -c "import fcntl; fcntl.fcntl(1, fcntl.F_SETFL, 0)" # Workaround for nonblocking mode
script:
@ -139,10 +140,10 @@ jobs:
- stage: Build (1st run)
os: linux
compiler: gcc
env: CONFIG=DefaultDebug LINUX=ubuntu-18.10 COMPILER=gcc
env: CONFIG=DefaultDebug TASK=Test LINUX=ubuntu-18.10 COMPILER=gcc
install:
- rm -rf build
- travis/install_linux.sh
- travis/skip_test.sh
before_script:
- python -c "import fcntl; fcntl.fcntl(1, fcntl.F_SETFL, 0)" # Workaround for nonblocking mode
script:
@ -155,10 +156,10 @@ jobs:
- stage: Build (1st run)
os: linux
compiler: gcc
env: CONFIG=DefaultRelease LINUX=ubuntu-18.10 COMPILER=gcc
env: CONFIG=DefaultRelease TASK=Test LINUX=ubuntu-18.10 COMPILER=gcc
install:
- rm -rf build
- travis/install_linux.sh
- travis/skip_test.sh
before_script:
- python -c "import fcntl; fcntl.fcntl(1, fcntl.F_SETFL, 0)" # Workaround for nonblocking mode
script:
@ -171,10 +172,10 @@ jobs:
- stage: Build (1st run)
os: linux
compiler: gcc
env: CONFIG=DefaultDebugTravis LINUX=ubuntu-19.04 COMPILER=gcc
env: CONFIG=DefaultDebugTravis TASK=TestDocker LINUX=ubuntu-19.04 COMPILER=gcc
install:
- rm -rf build
- travis/install_linux.sh
- travis/skip_test.sh
before_script:
- python -c "import fcntl; fcntl.fcntl(1, fcntl.F_SETFL, 0)" # Workaround for nonblocking mode
script:
@ -187,10 +188,10 @@ jobs:
- stage: Build (1st run)
os: linux
compiler: gcc
env: CONFIG=DefaultReleaseTravis LINUX=ubuntu-19.04 COMPILER=gcc
env: CONFIG=DefaultReleaseTravis TASK=TestDockerDoxygen LINUX=ubuntu-19.04 COMPILER=gcc
install:
- rm -rf build
- travis/install_linux.sh
- travis/skip_test.sh
before_script:
- python -c "import fcntl; fcntl.fcntl(1, fcntl.F_SETFL, 0)" # Workaround for nonblocking mode
script:
@ -203,14 +204,13 @@ jobs:
###
# Stage: Build (2nd run)
###
# ubuntu-18.04 - DefaultDebug
- stage: Build (2nd run)
os: linux
compiler: gcc
env: CONFIG=DefaultDebug LINUX=ubuntu-18.04 COMPILER=gcc
env: CONFIG=DefaultDebug TASK=Test LINUX=ubuntu-18.04 COMPILER=gcc
install:
- travis/install_linux.sh
- travis/skip_test.sh
before_script:
- python -c "import fcntl; fcntl.fcntl(1, fcntl.F_SETFL, 0)" # Workaround for nonblocking mode
script:
@ -223,9 +223,9 @@ jobs:
- stage: Build (2nd run)
os: linux
compiler: gcc
env: CONFIG=DefaultRelease LINUX=ubuntu-18.04 COMPILER=gcc
env: CONFIG=DefaultRelease TASK=Test LINUX=ubuntu-18.04 COMPILER=gcc
install:
- travis/install_linux.sh
- travis/skip_test.sh
before_script:
- python -c "import fcntl; fcntl.fcntl(1, fcntl.F_SETFL, 0)" # Workaround for nonblocking mode
script:
@ -238,9 +238,9 @@ jobs:
- stage: Build (2nd run)
os: linux
compiler: gcc
env: CONFIG=DefaultDebug LINUX=debian-9 COMPILER=gcc
env: CONFIG=DefaultDebug TASK=Test LINUX=debian-9 COMPILER=gcc
install:
- travis/install_linux.sh
- travis/skip_test.sh
before_script:
- python -c "import fcntl; fcntl.fcntl(1, fcntl.F_SETFL, 0)" # Workaround for nonblocking mode
script:
@ -253,9 +253,9 @@ jobs:
- stage: Build (2nd run)
os: linux
compiler: gcc
env: CONFIG=DefaultRelease LINUX=debian-9 COMPILER=gcc
env: CONFIG=DefaultRelease TASK=Test LINUX=debian-9 COMPILER=gcc
install:
- travis/install_linux.sh
- travis/skip_test.sh
before_script:
- python -c "import fcntl; fcntl.fcntl(1, fcntl.F_SETFL, 0)" # Workaround for nonblocking mode
script:
@ -268,9 +268,9 @@ jobs:
- stage: Build (2nd run)
os: linux
compiler: gcc
env: CONFIG=DefaultDebug LINUX=ubuntu-18.10 COMPILER=gcc
env: CONFIG=DefaultDebug TASK=Test LINUX=ubuntu-18.10 COMPILER=gcc
install:
- travis/install_linux.sh
- travis/skip_test.sh
before_script:
- python -c "import fcntl; fcntl.fcntl(1, fcntl.F_SETFL, 0)" # Workaround for nonblocking mode
script:
@ -283,9 +283,9 @@ jobs:
- stage: Build (2nd run)
os: linux
compiler: gcc
env: CONFIG=DefaultRelease LINUX=ubuntu-18.10 COMPILER=gcc
env: CONFIG=DefaultRelease TASK=Test LINUX=ubuntu-18.10 COMPILER=gcc
install:
- travis/install_linux.sh
- travis/skip_test.sh
before_script:
- python -c "import fcntl; fcntl.fcntl(1, fcntl.F_SETFL, 0)" # Workaround for nonblocking mode
script:
@ -298,9 +298,9 @@ jobs:
- stage: Build (2nd run)
os: linux
compiler: gcc
env: CONFIG=DefaultDebugTravis LINUX=ubuntu-19.04 COMPILER=gcc
env: CONFIG=DefaultDebugTravis TASK=TestDocker LINUX=ubuntu-19.04 COMPILER=gcc
install:
- travis/install_linux.sh
- travis/skip_test.sh
before_script:
- python -c "import fcntl; fcntl.fcntl(1, fcntl.F_SETFL, 0)" # Workaround for nonblocking mode
script:
@ -313,9 +313,9 @@ jobs:
- stage: Build (2nd run)
os: linux
compiler: gcc
env: CONFIG=DefaultReleaseTravis LINUX=ubuntu-19.04 COMPILER=gcc
env: CONFIG=DefaultReleaseTravis TASK=TestDockerDoxygen LINUX=ubuntu-19.04 COMPILER=gcc
install:
- travis/install_linux.sh
- travis/skip_test.sh
before_script:
- python -c "import fcntl; fcntl.fcntl(1, fcntl.F_SETFL, 0)" # Workaround for nonblocking mode
script:
@ -328,14 +328,13 @@ jobs:
###
# Stage: Build (3rd run)
###
# ubuntu-18.04 - DefaultDebug
- stage: Build (3rd run)
os: linux
compiler: gcc
env: CONFIG=DefaultDebug LINUX=ubuntu-18.04 COMPILER=gcc
env: CONFIG=DefaultDebug TASK=Test LINUX=ubuntu-18.04 COMPILER=gcc
install:
- travis/install_linux.sh
- travis/skip_test.sh
before_script:
- python -c "import fcntl; fcntl.fcntl(1, fcntl.F_SETFL, 0)" # Workaround for nonblocking mode
script:
@ -348,9 +347,9 @@ jobs:
- stage: Build (3rd run)
os: linux
compiler: gcc
env: CONFIG=DefaultRelease LINUX=ubuntu-18.04 COMPILER=gcc
env: CONFIG=DefaultRelease TASK=Test LINUX=ubuntu-18.04 COMPILER=gcc
install:
- travis/install_linux.sh
- travis/skip_test.sh
before_script:
- python -c "import fcntl; fcntl.fcntl(1, fcntl.F_SETFL, 0)" # Workaround for nonblocking mode
script:
@ -363,9 +362,9 @@ jobs:
- stage: Build (3rd run)
os: linux
compiler: gcc
env: CONFIG=DefaultDebug LINUX=debian-9 COMPILER=gcc
env: CONFIG=DefaultDebug TASK=Test LINUX=debian-9 COMPILER=gcc
install:
- travis/install_linux.sh
- travis/skip_test.sh
before_script:
- python -c "import fcntl; fcntl.fcntl(1, fcntl.F_SETFL, 0)" # Workaround for nonblocking mode
script:
@ -378,9 +377,9 @@ jobs:
- stage: Build (3rd run)
os: linux
compiler: gcc
env: CONFIG=DefaultRelease LINUX=debian-9 COMPILER=gcc
env: CONFIG=DefaultRelease TASK=Test LINUX=debian-9 COMPILER=gcc
install:
- travis/install_linux.sh
- travis/skip_test.sh
before_script:
- python -c "import fcntl; fcntl.fcntl(1, fcntl.F_SETFL, 0)" # Workaround for nonblocking mode
script:
@ -393,9 +392,9 @@ jobs:
- stage: Build (3rd run)
os: linux
compiler: gcc
env: CONFIG=DefaultDebug LINUX=ubuntu-18.10 COMPILER=gcc
env: CONFIG=DefaultDebug TASK=Test LINUX=ubuntu-18.10 COMPILER=gcc
install:
- travis/install_linux.sh
- travis/skip_test.sh
before_script:
- python -c "import fcntl; fcntl.fcntl(1, fcntl.F_SETFL, 0)" # Workaround for nonblocking mode
script:
@ -408,9 +407,9 @@ jobs:
- stage: Build (3rd run)
os: linux
compiler: gcc
env: CONFIG=DefaultRelease LINUX=ubuntu-18.10 COMPILER=gcc
env: CONFIG=DefaultRelease TASK=Test LINUX=ubuntu-18.10 COMPILER=gcc
install:
- travis/install_linux.sh
- travis/skip_test.sh
before_script:
- python -c "import fcntl; fcntl.fcntl(1, fcntl.F_SETFL, 0)" # Workaround for nonblocking mode
script:
@ -423,9 +422,9 @@ jobs:
- stage: Build (3rd run)
os: linux
compiler: gcc
env: CONFIG=DefaultDebugTravis LINUX=ubuntu-19.04 COMPILER=gcc
env: CONFIG=DefaultDebugTravis TASK=TestDocker LINUX=ubuntu-19.04 COMPILER=gcc
install:
- travis/install_linux.sh
- travis/skip_test.sh
before_script:
- python -c "import fcntl; fcntl.fcntl(1, fcntl.F_SETFL, 0)" # Workaround for nonblocking mode
script:
@ -438,9 +437,9 @@ jobs:
- stage: Build (3rd run)
os: linux
compiler: gcc
env: CONFIG=DefaultReleaseTravis LINUX=ubuntu-19.04 COMPILER=gcc
env: CONFIG=DefaultReleaseTravis TASK=TestDockerDoxygen LINUX=ubuntu-19.04 COMPILER=gcc
install:
- travis/install_linux.sh
- travis/skip_test.sh
before_script:
- python -c "import fcntl; fcntl.fcntl(1, fcntl.F_SETFL, 0)" # Workaround for nonblocking mode
script:
@ -453,14 +452,13 @@ jobs:
###
# Stage: Build (4th run)
###
# ubuntu-18.04 - DefaultDebug
- stage: Build (4th run)
os: linux
compiler: gcc
env: CONFIG=DefaultDebug LINUX=ubuntu-18.04 COMPILER=gcc
env: CONFIG=DefaultDebug TASK=Test LINUX=ubuntu-18.04 COMPILER=gcc
install:
- travis/install_linux.sh
- travis/skip_test.sh
before_script:
- python -c "import fcntl; fcntl.fcntl(1, fcntl.F_SETFL, 0)" # Workaround for nonblocking mode
script:
@ -473,9 +471,9 @@ jobs:
- stage: Build (4th run)
os: linux
compiler: gcc
env: CONFIG=DefaultRelease LINUX=ubuntu-18.04 COMPILER=gcc
env: CONFIG=DefaultRelease TASK=Test LINUX=ubuntu-18.04 COMPILER=gcc
install:
- travis/install_linux.sh
- travis/skip_test.sh
before_script:
- python -c "import fcntl; fcntl.fcntl(1, fcntl.F_SETFL, 0)" # Workaround for nonblocking mode
script:
@ -488,9 +486,9 @@ jobs:
- stage: Build (4th run)
os: linux
compiler: gcc
env: CONFIG=DefaultDebug LINUX=debian-9 COMPILER=gcc
env: CONFIG=DefaultDebug TASK=Test LINUX=debian-9 COMPILER=gcc
install:
- travis/install_linux.sh
- travis/skip_test.sh
before_script:
- python -c "import fcntl; fcntl.fcntl(1, fcntl.F_SETFL, 0)" # Workaround for nonblocking mode
script:
@ -503,9 +501,9 @@ jobs:
- stage: Build (4th run)
os: linux
compiler: gcc
env: CONFIG=DefaultRelease LINUX=debian-9 COMPILER=gcc
env: CONFIG=DefaultRelease TASK=Test LINUX=debian-9 COMPILER=gcc
install:
- travis/install_linux.sh
- travis/skip_test.sh
before_script:
- python -c "import fcntl; fcntl.fcntl(1, fcntl.F_SETFL, 0)" # Workaround for nonblocking mode
script:
@ -518,9 +516,9 @@ jobs:
- stage: Build (4th run)
os: linux
compiler: gcc
env: CONFIG=DefaultDebug LINUX=ubuntu-18.10 COMPILER=gcc
env: CONFIG=DefaultDebug TASK=Test LINUX=ubuntu-18.10 COMPILER=gcc
install:
- travis/install_linux.sh
- travis/skip_test.sh
before_script:
- python -c "import fcntl; fcntl.fcntl(1, fcntl.F_SETFL, 0)" # Workaround for nonblocking mode
script:
@ -533,9 +531,9 @@ jobs:
- stage: Build (4th run)
os: linux
compiler: gcc
env: CONFIG=DefaultRelease LINUX=ubuntu-18.10 COMPILER=gcc
env: CONFIG=DefaultRelease TASK=Test LINUX=ubuntu-18.10 COMPILER=gcc
install:
- travis/install_linux.sh
- travis/skip_test.sh
before_script:
- python -c "import fcntl; fcntl.fcntl(1, fcntl.F_SETFL, 0)" # Workaround for nonblocking mode
script:
@ -548,9 +546,9 @@ jobs:
- stage: Build (4th run)
os: linux
compiler: gcc
env: CONFIG=DefaultDebugTravis LINUX=ubuntu-19.04 COMPILER=gcc
env: CONFIG=DefaultDebugTravis TASK=TestDocker LINUX=ubuntu-19.04 COMPILER=gcc
install:
- travis/install_linux.sh
- travis/skip_test.sh
before_script:
- python -c "import fcntl; fcntl.fcntl(1, fcntl.F_SETFL, 0)" # Workaround for nonblocking mode
script:
@ -563,9 +561,9 @@ jobs:
- stage: Build (4th run)
os: linux
compiler: gcc
env: CONFIG=DefaultReleaseTravis LINUX=ubuntu-19.04 COMPILER=gcc
env: CONFIG=DefaultReleaseTravis TASK=TestDockerDoxygen LINUX=ubuntu-19.04 COMPILER=gcc
install:
- travis/install_linux.sh
- travis/skip_test.sh
before_script:
- python -c "import fcntl; fcntl.fcntl(1, fcntl.F_SETFL, 0)" # Workaround for nonblocking mode
script:
@ -576,147 +574,142 @@ jobs:
- find build -iname '*err*.log' -type f -print -exec cat {} \;
###
# Stage: Test all
# Stage: Tasks
###
# ubuntu-18.04 - DefaultDebug
- stage: Test all
- stage: Tasks
os: linux
compiler: gcc
env: CONFIG=DefaultDebug LINUX=ubuntu-18.04 COMPILER=gcc
env: CONFIG=DefaultDebug TASK=Test LINUX=ubuntu-18.04 COMPILER=gcc
install:
- travis/install_linux.sh
- travis/skip_test.sh
before_script:
- python -c "import fcntl; fcntl.fcntl(1, fcntl.F_SETFL, 0)" # Workaround for nonblocking mode
script:
- travis/build.sh TestAll
- travis/build.sh Tasks
before_cache:
- docker cp storm:/opt/storm/. .
after_failure:
- find build -iname '*err*.log' -type f -print -exec cat {} \;
# ubuntu-18.04 - DefaultRelease
- stage: Test all
- stage: Tasks
os: linux
compiler: gcc
env: CONFIG=DefaultRelease LINUX=ubuntu-18.04 COMPILER=gcc
env: CONFIG=DefaultRelease TASK=Test LINUX=ubuntu-18.04 COMPILER=gcc
install:
- travis/install_linux.sh
- travis/skip_test.sh
before_script:
- python -c "import fcntl; fcntl.fcntl(1, fcntl.F_SETFL, 0)" # Workaround for nonblocking mode
script:
- travis/build.sh TestAll
- travis/build.sh Tasks
before_cache:
- docker cp storm:/opt/storm/. .
after_failure:
- find build -iname '*err*.log' -type f -print -exec cat {} \;
# debian-9 - DefaultDebug
- stage: Test all
- stage: Tasks
os: linux
compiler: gcc
env: CONFIG=DefaultDebug LINUX=debian-9 COMPILER=gcc
env: CONFIG=DefaultDebug TASK=Test LINUX=debian-9 COMPILER=gcc
install:
- travis/install_linux.sh
- travis/skip_test.sh
before_script:
- python -c "import fcntl; fcntl.fcntl(1, fcntl.F_SETFL, 0)" # Workaround for nonblocking mode
script:
- travis/build.sh TestAll
- travis/build.sh Tasks
before_cache:
- docker cp storm:/opt/storm/. .
after_failure:
- find build -iname '*err*.log' -type f -print -exec cat {} \;
# debian-9 - DefaultRelease
- stage: Test all
- stage: Tasks
os: linux
compiler: gcc
env: CONFIG=DefaultRelease LINUX=debian-9 COMPILER=gcc
env: CONFIG=DefaultRelease TASK=Test LINUX=debian-9 COMPILER=gcc
install:
- travis/install_linux.sh
- travis/skip_test.sh
before_script:
- python -c "import fcntl; fcntl.fcntl(1, fcntl.F_SETFL, 0)" # Workaround for nonblocking mode
script:
- travis/build.sh TestAll
- travis/build.sh Tasks
before_cache:
- docker cp storm:/opt/storm/. .
after_failure:
- find build -iname '*err*.log' -type f -print -exec cat {} \;
# ubuntu-18.10 - DefaultDebug
- stage: Test all
- stage: Tasks
os: linux
compiler: gcc
env: CONFIG=DefaultDebug LINUX=ubuntu-18.10 COMPILER=gcc
env: CONFIG=DefaultDebug TASK=Test LINUX=ubuntu-18.10 COMPILER=gcc
install:
- travis/install_linux.sh
- travis/skip_test.sh
before_script:
- python -c "import fcntl; fcntl.fcntl(1, fcntl.F_SETFL, 0)" # Workaround for nonblocking mode
script:
- travis/build.sh TestAll
- travis/build.sh Tasks
before_cache:
- docker cp storm:/opt/storm/. .
after_failure:
- find build -iname '*err*.log' -type f -print -exec cat {} \;
# ubuntu-18.10 - DefaultRelease
- stage: Test all
- stage: Tasks
os: linux
compiler: gcc
env: CONFIG=DefaultRelease LINUX=ubuntu-18.10 COMPILER=gcc
env: CONFIG=DefaultRelease TASK=Test LINUX=ubuntu-18.10 COMPILER=gcc
install:
- travis/install_linux.sh
- travis/skip_test.sh
before_script:
- python -c "import fcntl; fcntl.fcntl(1, fcntl.F_SETFL, 0)" # Workaround for nonblocking mode
script:
- travis/build.sh TestAll
- travis/build.sh Tasks
before_cache:
- docker cp storm:/opt/storm/. .
after_failure:
- find build -iname '*err*.log' -type f -print -exec cat {} \;
# ubuntu-19.04 - DefaultDebugTravis
- stage: Test all
- stage: Tasks
os: linux
compiler: gcc
env: CONFIG=DefaultDebugTravis LINUX=ubuntu-19.04 COMPILER=gcc
env: CONFIG=DefaultDebugTravis TASK=TestDocker LINUX=ubuntu-19.04 COMPILER=gcc
install:
- travis/install_linux.sh
- travis/skip_test.sh
before_script:
- python -c "import fcntl; fcntl.fcntl(1, fcntl.F_SETFL, 0)" # Workaround for nonblocking mode
script:
- travis/build.sh TestAll
- travis/build.sh Tasks
before_cache:
- docker cp storm:/opt/storm/. .
after_failure:
- find build -iname '*err*.log' -type f -print -exec cat {} \;
after_success:
- travis/deploy_storm.sh
deploy:
- provider: script
skip_cleanup: true
script: bash travis/deploy_docker.sh storm
# ubuntu-19.04 - DefaultReleaseTravis
- stage: Test all
- stage: Tasks
os: linux
compiler: gcc
env: CONFIG=DefaultReleaseTravis LINUX=ubuntu-19.04 COMPILER=gcc
env: CONFIG=DefaultReleaseTravis TASK=TestDockerDoxygen LINUX=ubuntu-19.04 COMPILER=gcc
install:
- travis/install_linux.sh
- travis/skip_test.sh
before_script:
- python -c "import fcntl; fcntl.fcntl(1, fcntl.F_SETFL, 0)" # Workaround for nonblocking mode
script:
- travis/build.sh TestAll
- travis/build.sh Tasks
before_cache:
- docker cp storm:/opt/storm/. .
after_failure:
- find build -iname '*err*.log' -type f -print -exec cat {} \;
after_success:
- travis/deploy_storm.sh
allow_failures:
- stage: Build (1st run)
os: linux
env: CONFIG=DefaultReleaseTravis LINUX=ubuntu-19.04 COMPILER=gcc
- stage: Build (2nd run)
os: linux
env: CONFIG=DefaultReleaseTravis LINUX=ubuntu-19.04 COMPILER=gcc
- stage: Build (3rd run)
os: linux
env: CONFIG=DefaultReleaseTravis LINUX=ubuntu-19.04 COMPILER=gcc
- stage: Build (4th run)
os: linux
env: CONFIG=DefaultReleaseTravis LINUX=ubuntu-19.04 COMPILER=gcc
- stage: Test all
os: linux
env: CONFIG=DefaultReleaseTravis LINUX=ubuntu-19.04 COMPILER=gcc
deploy:
- provider: script
skip_cleanup: true
script: bash travis/deploy_docker.sh storm
- provider: pages
skip_cleanup: true
github_token: $GITHUB_TOKEN
local_dir: build/doc/html/
repo: moves-rwth/storm-doc
target_branch: master
on:
branch: master

18
CMakeLists.txt

@ -386,22 +386,8 @@ endif()
# in the the system does not have a library
include(resources/3rdparty/CMakeLists.txt)
#############################################################
##
## Doxygen
##
#############################################################
find_package(Doxygen)
# Add a target to generate API documentation with Doxygen
if(DOXYGEN_FOUND)
set(CMAKE_DOXYGEN_OUTPUT_DIR "${CMAKE_CURRENT_BINARY_DIR}/doc")
string(REGEX REPLACE ";" " " CMAKE_DOXYGEN_INPUT_LIST "${PROJECT_SOURCE_DIR}/src")
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/resources/doxygen/Doxyfile.in" "${CMAKE_CURRENT_BINARY_DIR}/Doxyfile" @ONLY)
add_custom_target(doc ${DOXYGEN_EXECUTABLE} "${CMAKE_CURRENT_BINARY_DIR}/Doxyfile" DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/Doxyfile" COMMENT "Generating API documentation with Doxygen" VERBATIM)
endif(DOXYGEN_FOUND)
# Include Doxygen
include(resources/doxygen/CMakeLists.txt)
#############################################################
##

36
resources/doxygen/CMakeLists.txt

@ -0,0 +1,36 @@
# Enable operator IN_LIST to avoid problems with CMake version 3.12
if(POLICY CMP0057)
cmake_policy(SET CMP0057 NEW)
endif()
find_package(Doxygen)
# Add a target to generate API documentation with Doxygen
if(DOXYGEN_FOUND)
# We use the doxygen command of CMake instead of using the separate config file
set(DOXYGEN_PROJECT_NAME "Storm")
set(DOXYGEN_PROJECT_BRIEF "A Modern Probabilistic Model Checker")
set(DOXYGEN_BRIEF_MEMBER_DESC YES)
set(DOXYGEN_REPEAT_BRIEF YES)
set(DOXYGEN_JAVADOC_AUTOBRIEF YES)
set(DOXYGEN_QT_AUTOBRIEF YES)
set(DOXYGEN_EXTRACT_ALL YES)
set(DOXYGEN_EXTRACT_STATIC YES)
set(DOXYGEN_SOURCE_BROWSER YES)
set(DOXYGEN_GENERATE_TREEVIEW YES)
set(DOXYGEN_CASE_SENSE_NAMES NO)
set(DOXYGEN_HTML_TIMESTAMP YES)
set(DOXYGEN_CREATE_SUBDIRS YES)
set(DOXYGEN_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/doc")
doxygen_add_docs(
doc
"${PROJECT_SOURCE_DIR}/src"
COMMENT "Generating API documentation with Doxygen"
)
# These commands can be used if the separate config files should be used
#set(CMAKE_DOXYGEN_OUTPUT_DIR "${CMAKE_CURRENT_BINARY_DIR}/doc")
#string(REGEX REPLACE ";" " " CMAKE_DOXYGEN_INPUT_LIST "${PROJECT_SOURCE_DIR}/src")
#configure_file("${CMAKE_CURRENT_SOURCE_DIR}/resources/doxygen/Doxyfile.in.new" "${CMAKE_CURRENT_BINARY_DIR}/Doxyfile" @ONLY)
#add_custom_target(doc ${DOXYGEN_EXECUTABLE} "${CMAKE_CURRENT_BINARY_DIR}/Doxyfile" DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/Doxyfile" COMMENT "Generating API documentation with Doxygen" VERBATIM)
endif(DOXYGEN_FOUND)

2891
resources/doxygen/Doxyfile.in
File diff suppressed because it is too large
View File

5
resources/examples/testfiles/dft/cyclic.dft

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

15
resources/examples/testfiles/dft/fdep_bound.dft

@ -0,0 +1,15 @@
toplevel "A";
"A" or "B" "C";
"B" and "D" "L";
"C" and "M" "N";
"D" and "I" "J" "K";
"DEP1" fdep "T" "I" "J" "K";
"DEP2" fdep "D" "L";
"I" lambda=0.5 dorm=0;
"J" lambda=0.5 dorm=0.5;
"K" lambda=0.5 dorm=0.5;
"L" lambda=0.5 dorm=0.5;
"M" lambda=0.5 dorm=0.5;
"N" lambda=0.5 dorm=0.5;
"T" lambda=0.5 dorm=0.5;

40
resources/examples/testfiles/dft/hecs_2_2.dft

@ -0,0 +1,40 @@
toplevel "System";
"System" or "System_1" "System_2";
"System_1" or "PSF_1" "MSF_1" "BSF_1" "IF_1";
"PSF_1" and "P_11" "P_12";
"P_11" wsp "A_11" "A_1S";
"P_12" wsp "A_12" "A_1S";
"MSF_1" 3of5 "M_1_1" "M_1_2" "M_1_3" "M_1_4" "M_1_5";
"BSF_1" and "BUS_11" "BUS_12";
"IF_1" or "HW_1" "SW_1";
"System_2" or "PSF_2" "MSF_2" "BSF_2" "IF_2";
"PSF_2" and "P_21" "P_22";
"P_21" wsp "A_21" "A_2S";
"P_22" wsp "A_22" "A_2S";
"MSF_2" 3of5 "M_2_1" "M_2_2" "M_2_3" "M_2_4" "M_2_5";
"BSF_2" and "BUS_21" "BUS_22";
"IF_2" or "HW_2" "SW_2";
"A_11" lambda=1.0e-4 dorm=0;
"A_12" lambda=1.0e-4 dorm=0;
"A_1S" lambda=1.0e-4 dorm=0;
"M_1_1" lambda=6.0e-5 dorm=0;
"M_1_2" lambda=6.0e-5 dorm=0;
"M_1_3" lambda=6.0e-5 dorm=0;
"M_1_4" lambda=6.0e-5 dorm=0;
"M_1_5" lambda=6.0e-5 dorm=0;
"BUS_11" lambda=1.0e-6 dorm=0;
"BUS_12" lambda=1.0e-6 dorm=0;
"HW_1" lambda=5.0e-5 dorm=0;
"SW_1" lambda=6.0e-5 dorm=0;
"A_21" lambda=1.0e-4 dorm=0;
"A_22" lambda=1.0e-4 dorm=0;
"A_2S" lambda=1.0e-4 dorm=0;
"M_2_1" lambda=6.0e-5 dorm=0;
"M_2_2" lambda=6.0e-5 dorm=0;
"M_2_3" lambda=6.0e-5 dorm=0;
"M_2_4" lambda=6.0e-5 dorm=0;
"M_2_5" lambda=6.0e-5 dorm=0;
"BUS_21" lambda=1.0e-6 dorm=0;
"BUS_22" lambda=1.0e-6 dorm=0;
"HW_2" lambda=5.0e-5 dorm=0;
"SW_2" lambda=6.0e-5 dorm=0;

5
resources/examples/testfiles/dft/seqChild.dft

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

8
resources/examples/testfiles/dft/spare_two_modules.dft

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

24
resources/examples/testfiles/dft/symmetry6.dft

@ -0,0 +1,24 @@
toplevel "A";
"A" or "B" "C";
"B" and "J" "K" "L";
"J" or "J1" "J2";
"K" or "K1" "K2";
"L" or "L1" "L2";
"C" or "M" "N";
"M" and "M1" "M2" "M3" "M4";
"N" and "N1" "N2" "N3" "N4";
"J1" lambda=0.5 dorm=0;
"J2" lambda=0.5 dorm=0;
"K1" lambda=0.5 dorm=0;
"K2" lambda=0.5 dorm=0;
"L1" lambda=0.5 dorm=0;
"L2" lambda=0.5 dorm=0;
"M1" lambda=0.5 dorm=0;
"M2" lambda=0.5 dorm=0;
"M3" lambda=1 dorm=0;
"M4" lambda=1 dorm=0;
"N1" lambda=0.5 dorm=0;
"N2" lambda=0.5 dorm=0;
"N3" lambda=1 dorm=0;
"N4" lambda=1 dorm=0;

13
src/storm-dft-cli/storm-dft.cpp

@ -51,6 +51,12 @@ void processOptions() {
storm::api::exportDFTToJsonFile<ValueType>(*dft, dftIOSettings.getExportJsonFilename());
}
if (dftIOSettings.isExportToSmt()) {
// Export to json
storm::api::exportDFTToSMT<ValueType>(*dft, dftIOSettings.getExportSmtFilename());
return;
}
// Check well-formedness of DFT
std::stringstream stream;
if (!dft->checkWellFormedness(stream)) {
@ -76,8 +82,7 @@ void processOptions() {
if (faultTreeSettings.solveWithSMT()) {
// Solve with SMT
STORM_LOG_DEBUG("Running DFT analysis with use of SMT");
storm::api::exportDFTToSMT(*dft, "test.smt2");
STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Only exported to SMT file 'test.smt2' but analysis is not supported.");
storm::api::analyzeDFTSMT(*dft, true);
return;
}
#endif
@ -148,8 +153,8 @@ void processOptions() {
// Add relevant event names from properties
for (auto atomic : atomicLabels) {
std::string label = atomic->getLabel();
if (label == "failed") {
// Ignore as this label will always be added
if (label == "failed" or label == "skipped") {
// Ignore as these label will always be added if necessary
} else {
// Get name of event
if (boost::ends_with(label, "_failed")) {

33
src/storm-dft/api/storm-dft.cpp

@ -42,6 +42,39 @@ namespace storm {
STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Export to SMT does not support this data type.");
}
template<>
std::vector<storm::solver::SmtSolver::CheckResult>
analyzeDFTSMT(storm::storage::DFT<double> const &dft, bool printOutput) {
storm::modelchecker::DFTASFChecker smtChecker(dft);
smtChecker.toSolver();
std::vector<storm::solver::SmtSolver::CheckResult> results;
results.push_back(smtChecker.checkTleNeverFailed());
uint64_t lower_bound = smtChecker.getLeastFailureBound();
uint64_t upper_bound = smtChecker.getAlwaysFailedBound();
if (printOutput) {
// TODO add suitable output function, maybe add query descriptions for better readability
for (size_t i = 0; i < results.size(); ++i) {
std::string tmp = "unknown";
if (results.at(i) == storm::solver::SmtSolver::CheckResult::Sat) {
tmp = "SAT";
} else if (results.at(i) == storm::solver::SmtSolver::CheckResult::Unsat) {
tmp = "UNSAT";
}
}
std::cout << "Lower bound: " << std::to_string(lower_bound) << std::endl;
std::cout << "Upper bound: " << std::to_string(upper_bound) << std::endl;
}
return results;
}
template<>
std::vector<storm::solver::SmtSolver::CheckResult>
analyzeDFTSMT(storm::storage::DFT<storm::RationalFunction> const &dft, bool printOutput) {
STORM_LOG_THROW(false, storm::exceptions::NotSupportedException,
"Analysis by SMT not supported for this data type.");
}
template<>
std::pair<std::shared_ptr<storm::gspn::GSPN>, uint64_t> transformToGSPN(storm::storage::DFT<double> const& dft) {
storm::settings::modules::FaultTreeSettings const& ftSettings = storm::settings::getModule<storm::settings::modules::FaultTreeSettings>();

11
src/storm-dft/api/storm-dft.h

@ -92,6 +92,17 @@ namespace storm {
return results;
}
/*!
* Analyze the DFT using the SMT encoding
*
* @param dft DFT.
*
* @return Result result vector
*/
template<typename ValueType>
std::vector<storm::solver::SmtSolver::CheckResult>
analyzeDFTSMT(storm::storage::DFT<ValueType> const &dft, bool printOutput);
/*!
* Export DFT to JSON file.
*

8
src/storm-dft/builder/DFTBuilder.cpp

@ -27,6 +27,9 @@ namespace storm {
if (itFind != mElements.end()) {
// Child found
DFTElementPointer childElement = itFind->second;
STORM_LOG_THROW(!childElement->isRestriction(), storm::exceptions::WrongFormatException,
"Restictor " << childElement->name() << " is not allowed as child of gate "
<< gate->name());
if(!childElement->isDependency()) {
gate->pushBackChild(childElement);
childElement->addParent(gate);
@ -81,14 +84,13 @@ namespace storm {
}
}
// Sort elements topologically
DFTElementVector elems = topoSort();
// compute rank
for (auto& elem : mElements) {
for (auto &elem : mElements) {
computeRank(elem.second);
}
DFTElementVector elems = topoSort();
// Set ids
size_t id = 0;
for(DFTElementPointer e : elems) {

2
src/storm-dft/builder/DftExplorationHeuristic.h

@ -22,7 +22,7 @@ namespace storm {
class DFTExplorationHeuristic {
public:
explicit DFTExplorationHeuristic(size_t id) : id(id), expand(true), lowerBound(storm::utility::zero<ValueType>()), upperBound(storm::utility::infinity<ValueType>()), depth(0), probability(storm::utility::one<ValueType>()) {
explicit DFTExplorationHeuristic(size_t id) : id(id), expand(false), lowerBound(storm::utility::zero<ValueType>()), upperBound(storm::utility::infinity<ValueType>()), depth(0), probability(storm::utility::one<ValueType>()) {
// Intentionally left empty
}

25
src/storm-dft/builder/ExplicitDFTModelBuilder.cpp

@ -202,6 +202,13 @@ namespace storm {
STORM_LOG_THROW(false, storm::exceptions::IllegalArgumentException, "Heuristic not known.");
}
}
auto ftSettings = storm::settings::getModule<storm::settings::modules::FaultTreeSettings>();
if (ftSettings.isMaxDepthSet()) {
STORM_LOG_ASSERT(usedHeuristic == storm::builder::ApproximationHeuristic::DEPTH, "MaxDepth requires 'depth' exploration heuristic.");
approximationThreshold = ftSettings.getMaxDepth();
}
exploreStateSpace(approximationThreshold);
size_t stateSize = stateStorage.getNumberOfStates() + (this->uniqueFailedState ? 1 : 0);
@ -376,7 +383,7 @@ namespace storm {
setMarkovian(true);
// Add transition to target state with temporary value 0
// TODO: what to do when there is no unique target state?
STORM_LOG_ASSERT(this->uniqueFailedState, "Approximation only works with unique failed state");
//STORM_LOG_ASSERT(this->uniqueFailedState, "Approximation only works with unique failed state");
matrixBuilder.addTransition(0, storm::utility::zero<ValueType>());
// Remember skipped state
skippedStates[matrixBuilder.getCurrentRowGroup() - 1] = std::make_pair(currentState, currentExplorationHeuristic);
@ -418,8 +425,9 @@ namespace storm {
}
iter->second.second = heuristic;
if (state->hasFailed(dft.getTopLevelIndex()) || state->isFailsafe(dft.getTopLevelIndex()) || state->getFailableElements().hasDependencies() || (!state->getFailableElements().hasDependencies() && !state->getFailableElements().hasBEs())) {
// Do not skip absorbing state or if reached by dependencies
//if (state->hasFailed(dft.getTopLevelIndex()) || state->isFailsafe(dft.getTopLevelIndex()) || state->getFailableElements().hasDependencies() || (!state->getFailableElements().hasDependencies() && !state->getFailableElements().hasBEs())) {
if (state->getFailableElements().hasDependencies() || (!state->getFailableElements().hasDependencies() && !state->getFailableElements().hasBEs())) {
// Do not skip absorbing state or if reached by dependencies
iter->second.second->markExpand();
}
if (usedHeuristic == storm::builder::ApproximationHeuristic::BOUNDDIFFERENCE) {
@ -519,7 +527,16 @@ namespace storm {
template<typename ValueType, typename StateType>
std::shared_ptr<storm::models::sparse::Model<ValueType>> ExplicitDFTModelBuilder<ValueType, StateType>::getModel() {
STORM_LOG_ASSERT(skippedStates.size() == 0, "Concrete model has skipped states");
if (storm::settings::getModule<storm::settings::modules::FaultTreeSettings>().isMaxDepthSet() && skippedStates.size() > 0) {
// Give skipped states separate label "skipped"
modelComponents.stateLabeling.addLabel("skipped");
for (auto it = skippedStates.begin(); it != skippedStates.end(); ++it) {
modelComponents.stateLabeling.addLabelToState("skipped", it->first);
}
} else{
STORM_LOG_ASSERT(skippedStates.size() == 0, "Concrete model has skipped states");
}
return createModel(false);
}

1
src/storm-dft/generator/DftNextStateGenerator.cpp

@ -78,6 +78,7 @@ namespace storm {
// Let BE fail
bool isFirst = true;
while (!state->getFailableElements().isEnd()) {
//TODO outside
if (storm::settings::getModule<storm::settings::modules::FaultTreeSettings>().isTakeFirstDependency() && exploreDependencies && !isFirst) {
// We discard further exploration as we already chose one dependent event
break;

1098
src/storm-dft/modelchecker/dft/DFTASFChecker.cpp
File diff suppressed because it is too large
View File

210
src/storm-dft/modelchecker/dft/DFTASFChecker.h

@ -4,53 +4,153 @@
#include <vector>
#include <unordered_map>
#include "storm/solver/SmtSolver.h"
#include "SmtConstraint.h"
#include "storm-dft/storage/dft/DFT.h"
#include "storm/utility/solver.h"
namespace storm {
namespace modelchecker {
class DFTConstraint {
class SpareAndChildPair {
public:
virtual ~DFTConstraint() {
SpareAndChildPair(uint64_t spareIndex, uint64_t childIndex) : spareIndex(spareIndex), childIndex(childIndex) {
}
virtual std::string toSmtlib2(std::vector<std::string> const& varNames) const = 0;
virtual std::string description() const {
return descript;
friend bool operator<(SpareAndChildPair const& p1, SpareAndChildPair const& p2) {
return p1.spareIndex < p2.spareIndex || (p1.spareIndex == p2.spareIndex && p1.childIndex < p2.childIndex);
}
void setDescription(std::string const& descr) {
descript = descr;
}
private:
std::string descript;
uint64_t spareIndex;
uint64_t childIndex;
};
class SpareAndChildPair {
class DependencyPair {
public:
SpareAndChildPair(uint64_t spareIndex, uint64_t childIndex) : spareIndex(spareIndex), childIndex(childIndex) {
DependencyPair(uint64_t depIndex, uint64_t childIndex) : depIndex(depIndex), childIndex(childIndex) {
}
friend bool operator<(SpareAndChildPair const& p1, SpareAndChildPair const& p2) {
return p1.spareIndex < p2.spareIndex || (p1.spareIndex == p2.spareIndex && p1.childIndex < p2.childIndex);
friend bool operator<(DependencyPair const &p1, DependencyPair const &p2) {
return p1.depIndex < p2.depIndex || (p1.depIndex == p2.depIndex && p1.childIndex < p2.childIndex);
}
private:
uint64_t spareIndex;
uint64_t depIndex;
uint64_t childIndex;
};
class DFTASFChecker {
using ValueType = double;
public:
DFTASFChecker(storm::storage::DFT<ValueType> const&);
/**
* Generate general variables and constraints for the DFT and store them in the corresponding maps and vectors
*
*/
void convert();
void toFile(std::string const&);
/**
* Generates a new solver instance and prepares it for SMT checking of the DFT. Needs to be called before all queries to the solver
*/
void toSolver();
/**
* Check if the TLE of the DFT never fails
*
* @return "Sat" if TLE never fails, "Unsat" if it does, otherwise "Unknown"
*/
storm::solver::SmtSolver::CheckResult checkTleNeverFailed();
/**
* Check if there exists a sequence of BE failures of exactly given length such that the TLE of the DFT fails
*
* @param bound the length of the sequene
* @return "Sat" if such a sequence exists, "Unsat" if it does not, otherwise "Unknown"
*/
storm::solver::SmtSolver::CheckResult checkTleFailsWithEq(uint64_t bound);
/**
* Check if there exists a sequence of BE failures of at least given length such that the TLE of the DFT fails
*
* @param bound the length of the sequence
* @return "Sat" if such a sequence exists, "Unsat" if it does not, otherwise "Unknown"
*/
storm::solver::SmtSolver::CheckResult checkTleFailsWithLeq(uint64_t bound);
/**
* Get the minimal number of BEs necessary for the TLE to fail (lower bound for number of failures to check)
*
* @param timeout timeout for each query in seconds, defaults to 10 seconds
* @return the minimal number
*/
uint64_t getLeastFailureBound(uint_fast64_t timeout = 10);
/**
* Get the number of BE failures for which the TLE always fails (upper bound for number of failures to check).
* Note that the returned value may be higher than the real one when dependencies are present.
*
* @param timeout timeout for each query in seconds, defaults to 10 seconds
* @return the number
*/
uint64_t getAlwaysFailedBound(uint_fast64_t timeout = 10);
/**
* Set the timeout of the solver
*
* @param milliseconds the timeout in milliseconds
*/
void setSolverTimeout(uint_fast64_t milliseconds);
/**
* Unset the timeout for the solver
*/
void unsetSolverTimeout();
private:
/**
* Helper function to check if the TLE fails before or at a given timepoint while visiting exactly
* a given number of non-Markovian states
*
* @param checkbound timepoint to check against
* @param nrNonMarkovian the number of non-Markovian states to check against
* @return "Sat" if a sequence of BE failures exists such that the constraints are satisfied,
* "Unsat" if it does not, otherwise "Unknown"
*/
storm::solver::SmtSolver::CheckResult
checkFailsLeqWithEqNonMarkovianState(uint64_t checkbound, uint64_t nrNonMarkovian);
/**
* Helper function that checks if the DFT can fail at a timepoint while visiting less than a given number of Markovian states
*
* @param timepoint point in time to check
* @return "Sat" if a sequence of BE failures exists such that less than checkNumber Markovian states are visited,
* "Unsat" if it does not, otherwise "Unknown"
*/
storm::solver::SmtSolver::CheckResult checkFailsAtTimepointWithOnlyMarkovianState(uint64_t timepoint);
/**
* Helper function for correction of least failure bound when dependencies are present.
* The main idea is to check if a later point of failure for the TLE than the pre-computed bound exists, but
* up until that point the number of non-Markovian states visited is so large, that less than the pre-computed bound BEs fail by themselves.
* The corrected bound is then (newTLEFailureTimepoint)-(nrNonMarkovianStatesVisited). This term is minimized.
*
* @param bound known lower bound to be corrected
* @param timeout timeout timeout for each query in seconds
* @return the corrected bound
*/
uint64_t correctLowerBound(uint64_t bound, uint_fast64_t timeout);
/**
* Helper function for correction of bound for number of BEs such that the DFT always fails when dependencies are present
*
* @param bound known bound to be corrected
* @param timeout timeout timeout for each query in seconds
* @return the corrected bound
*/
uint64_t correctUpperBound(uint64_t bound, uint_fast64_t timeout);
uint64_t getClaimVariableIndex(uint64_t spareIndex, uint64_t childIndex) const;
/**
@ -63,7 +163,69 @@ namespace storm {
*
* @return Constraint encoding the claiming.
*/
std::shared_ptr<DFTConstraint> generateTryToClaimConstraint(std::shared_ptr<storm::storage::DFTSpare<ValueType> const> spare, uint64_t childIndex, uint64_t timepoint) const;
std::shared_ptr<SmtConstraint>
generateTryToClaimConstraint(std::shared_ptr<storm::storage::DFTSpare<ValueType> const> spare,
uint64_t childIndex, uint64_t timepoint) const;
/**
* Add constraints encoding AND gates.
* This corresponds to constraint (1)
*/
void generateAndConstraint(size_t i, std::vector<uint64_t> childVarIndices,
std::shared_ptr<storm::storage::DFTElement<ValueType> const> element);
/**
* Add constraints encoding OR gates.
* This corresponds to constraint (2)
*/
void generateOrConstraint(size_t i, std::vector<uint64_t> childVarIndices,
std::shared_ptr<storm::storage::DFTElement<ValueType> const> element);
/**
* Add constraints encoding VOT gates.
*/
void generateVotConstraint(size_t i, std::vector<uint64_t> childVarIndices,
std::shared_ptr<storm::storage::DFTElement<ValueType> const> element);
/**
* Add constraints encoding PAND gates.
* This corresponds to constraint (3)
*/
void generatePandConstraint(size_t i, std::vector<uint64_t> childVarIndices,
std::shared_ptr<storm::storage::DFTElement<ValueType> const> element);
/**
* Add constraints encoding POR gates.
*/
void generatePorConstraint(size_t i, std::vector<uint64_t> childVarIndices,
std::shared_ptr<storm::storage::DFTElement<ValueType> const> element);
/**
* Add constraints encoding SEQ gates.
* This corresponds to constraint (4)
*/
void generateSeqConstraint(std::vector<uint64_t> childVarIndices,
std::shared_ptr<storm::storage::DFTElement<ValueType> const> element);
/**
* Add constraints encoding SPARE gates.
* This corresponds to constraints (5),(6),(7)
*/
void generateSpareConstraint(size_t i, std::vector<uint64_t> childVarIndices,
std::shared_ptr<storm::storage::DFTElement<ValueType> const> element);
/**
* Add constraints encoding PDEP gates.
*
*/
void generatePdepConstraint(size_t i, std::vector<uint64_t> childVarIndices,
std::shared_ptr<storm::storage::DFTElement<ValueType> const> element);
/**
* Add constraints encoding claiming rules.
* This corresponds to constraint (8) and addition
*/
void addClaimingConstraints();
/**
* Add constraints encoding Markovian states.
@ -72,10 +234,12 @@ namespace storm {
void addMarkovianConstraints();
storm::storage::DFT<ValueType> const& dft;
std::shared_ptr<storm::solver::SmtSolver> solver = nullptr;
std::vector<std::string> varNames;
std::unordered_map<uint64_t, uint64_t> timePointVariables;
std::vector<std::shared_ptr<DFTConstraint>> constraints;
std::vector<std::shared_ptr<SmtConstraint>> constraints;
std::map<SpareAndChildPair, uint64_t> claimVariables;
std::unordered_map<uint64_t, uint64_t> dependencyVariables;
std::unordered_map<uint64_t, uint64_t> markovianVariables;
std::vector<uint64_t> tmpTimePointVariables;
uint64_t notFailed;

701
src/storm-dft/modelchecker/dft/SmtConstraint.cpp

@ -0,0 +1,701 @@
#include "DFTASFChecker.h"
#include <storm/storage/expressions/ExpressionManager.h>
#include <string>
namespace storm {
namespace modelchecker {
/*
* Variable[VarIndex] is the maximum of the others
*/
class IsMaximum : public SmtConstraint {
public:
IsMaximum(uint64_t varIndex, std::vector<uint64_t> const &varIndices) : varIndex(varIndex),
varIndices(varIndices) {
}
virtual ~IsMaximum() {
}
std::string toSmtlib2(std::vector<std::string> const &varNames) const override {
std::stringstream sstr;
sstr << "(and ";
// assert it is largereq than all values.
for (auto const &ovi : varIndices) {
sstr << "(>= " << varNames.at(varIndex) << " " << varNames.at(ovi) << ") ";
}
// assert it is one of the values.
sstr << "(or ";
for (auto const &ovi : varIndices) {
sstr << "(= " << varNames.at(varIndex) << " " << varNames.at(ovi) << ") ";
}
sstr << ")"; // end of the or
sstr << ")"; // end outer and.
return sstr.str();
}
storm::expressions::Expression toExpression(std::vector<std::string> const &varNames,
std::shared_ptr<storm::expressions::ExpressionManager> manager) const override {
std::vector<storm::expressions::Expression> outerAnd;
std::vector<storm::expressions::Expression> innerOr;
for (auto const &ovi : varIndices) {
outerAnd.push_back((manager->getVariableExpression(varNames.at(varIndex)) >=
manager->getVariableExpression(varNames.at(ovi))));
innerOr.push_back((manager->getVariableExpression(varNames.at(varIndex)) ==
manager->getVariableExpression(varNames.at(ovi))));
}
outerAnd.push_back(disjunction(innerOr));
return conjunction(outerAnd);
}
private:
uint64_t varIndex;
std::vector<uint64_t> varIndices;
};
/*
* First is the minimum of the others
*/
class IsMinimum : public SmtConstraint {
public:
IsMinimum(uint64_t varIndex, std::vector<uint64_t> const &varIndices) : varIndex(varIndex),
varIndices(varIndices) {
}
virtual ~IsMinimum() {
}
std::string toSmtlib2(std::vector<std::string> const &varNames) const override {
std::stringstream sstr;
sstr << "(and ";
// assert it is smallereq than all values.
for (auto const &ovi : varIndices) {
sstr << "(<= " << varNames.at(varIndex) << " " << varNames.at(ovi) << ") ";
}
// assert it is one of the values.
sstr << "(or ";
for (auto const &ovi : varIndices) {
sstr << "(= " << varNames.at(varIndex) << " " << varNames.at(ovi) << ") ";
}
sstr << ")"; // end of the or
sstr << ")"; // end outer and.
return sstr.str();
}
storm::expressions::Expression toExpression(std::vector<std::string> const &varNames,
std::shared_ptr<storm::expressions::ExpressionManager> manager) const override {
std::vector<storm::expressions::Expression> outerAnd;
std::vector<storm::expressions::Expression> innerOr;
for (auto const &ovi : varIndices) {
outerAnd.push_back((manager->getVariableExpression(varNames.at(varIndex)) <=
manager->getVariableExpression(varNames.at(ovi))));
innerOr.push_back((manager->getVariableExpression(varNames.at(varIndex)) ==
manager->getVariableExpression(varNames.at(ovi))));
}
outerAnd.push_back(disjunction(innerOr));
return conjunction(outerAnd);
}
private:
uint64_t varIndex;
std::vector<uint64_t> varIndices;
};
class BetweenValues : public SmtConstraint {
public:
BetweenValues(uint64_t varIndex, uint64_t lower, uint64_t upper) : varIndex(varIndex), upperBound(upper),
lowerBound(lower) {
}
virtual ~BetweenValues() {
}
std::string toSmtlib2(std::vector<std::string> const &varNames) const override {
std::stringstream sstr;
sstr << "(and ";
sstr << "(>= " << varNames.at(varIndex) << " " << lowerBound << ")";
sstr << "(<= " << varNames.at(varIndex) << " " << upperBound << ")";
sstr << ")";
return sstr.str();
}
storm::expressions::Expression toExpression(std::vector<std::string> const &varNames,
std::shared_ptr<storm::expressions::ExpressionManager> manager) const override {
return (manager->getVariableExpression(varNames.at(varIndex)) >= lowerBound) &&
(manager->getVariableExpression(varNames.at(varIndex)) <= upperBound);
}
private:
uint64_t varIndex;
uint64_t upperBound;
uint64_t lowerBound;
};
class And : public SmtConstraint {
public:
And(std::vector<std::shared_ptr<SmtConstraint>> const &constraints) : constraints(constraints) {
}
virtual ~And() {
}
std::string toSmtlib2(std::vector<std::string> const &varNames) const override {
std::stringstream sstr;
if (constraints.empty()) {
sstr << "true";
} else {
sstr << "(and";
for (auto const &c : constraints) {
sstr << " " << c->toSmtlib2(varNames);
}
sstr << ")";
}
return sstr.str();
}
storm::expressions::Expression toExpression(std::vector<std::string> const &varNames,
std::shared_ptr<storm::expressions::ExpressionManager> manager) const override {
if (constraints.empty()) {
return manager->boolean(true);
} else {
std::vector<storm::expressions::Expression> conjuncts;
for (auto const &c : constraints) {
conjuncts.push_back(c->toExpression(varNames, manager));
}
return conjunction(conjuncts);
}
}
private:
std::vector<std::shared_ptr<SmtConstraint>> constraints;
};
class Or : public SmtConstraint {
public:
Or(std::vector<std::shared_ptr<SmtConstraint>> const &constraints) : constraints(constraints) {
}
virtual ~Or() {
}
std::string toSmtlib2(std::vector<std::string> const &varNames) const override {
std::stringstream sstr;
if (constraints.empty()) {
sstr << "false";
} else {
sstr << "(or";
for (auto const &c : constraints) {
sstr << " " << c->toSmtlib2(varNames);
}
sstr << ")";
}
return sstr.str();
}
storm::expressions::Expression toExpression(std::vector<std::string> const &varNames,
std::shared_ptr<storm::expressions::ExpressionManager> manager) const override {
if (constraints.empty()) {
return manager->boolean(false);
} else {
std::vector<storm::expressions::Expression> disjuncts;
for (auto const &c : constraints) {
disjuncts.push_back(c->toExpression(varNames, manager));
}
return disjunction(disjuncts);
}
}
private:
std::vector<std::shared_ptr<SmtConstraint>> constraints;
};
class Implies : public SmtConstraint {
public:
Implies(std::shared_ptr<SmtConstraint> l, std::shared_ptr<SmtConstraint> r) : lhs(l), rhs(r) {
}
std::string toSmtlib2(std::vector<std::string> const &varNames) const override {
std::stringstream sstr;
sstr << "(=> " << lhs->toSmtlib2(varNames) << " " << rhs->toSmtlib2(varNames) << ")";
return sstr.str();
}
storm::expressions::Expression toExpression(std::vector<std::string> const &varNames,
std::shared_ptr<storm::expressions::ExpressionManager> manager) const override {
return implies(lhs->toExpression(varNames, manager), rhs->toExpression(varNames, manager));
}
private:
std::shared_ptr<SmtConstraint> lhs;
std::shared_ptr<SmtConstraint> rhs;
};
class Iff : public SmtConstraint {
public:
Iff(std::shared_ptr<SmtConstraint> l, std::shared_ptr<SmtConstraint> r) : lhs(l), rhs(r) {
}
std::string toSmtlib2(std::vector<std::string> const &varNames) const override {
std::stringstream sstr;
sstr << "(= " << lhs->toSmtlib2(varNames) << " " << rhs->toSmtlib2(varNames) << ")";
return sstr.str();
}
storm::expressions::Expression toExpression(std::vector<std::string> const &varNames,
std::shared_ptr<storm::expressions::ExpressionManager> manager) const override {
return iff(lhs->toExpression(varNames, manager), rhs->toExpression(varNames, manager));
}
private:
std::shared_ptr<SmtConstraint> lhs;
std::shared_ptr<SmtConstraint> rhs;
};
class IsTrue : public SmtConstraint {
public:
IsTrue(bool val) : value(val) {
}
virtual ~IsTrue() {
}
std::string toSmtlib2(std::vector<std::string> const &varNames) const override {
std::stringstream sstr;
sstr << (value ? "true" : "false");
return sstr.str();
}
storm::expressions::Expression toExpression(std::vector<std::string> const &varNames,
std::shared_ptr<storm::expressions::ExpressionManager> manager) const override {
return manager->boolean(value);
}
private:
bool value;
};
class IsBoolValue : public SmtConstraint {
public:
IsBoolValue(uint64_t varIndex, bool val) : varIndex(varIndex), value(val) {
}
virtual ~IsBoolValue() {
}
std::string toSmtlib2(std::vector<std::string> const &varNames) const override {
std::stringstream sstr;
assert(varIndex < varNames.size());
if (value) {
sstr << varNames.at(varIndex);
} else {
sstr << "(not " << varNames.at(varIndex) << ")";
}
return sstr.str();
}
storm::expressions::Expression toExpression(std::vector<std::string> const &varNames,
std::shared_ptr<storm::expressions::ExpressionManager> manager) const override {
if (value) {
return manager->getVariableExpression(varNames.at(varIndex));
} else {
return !(manager->getVariableExpression(varNames.at(varIndex)));
}
}
private:
uint64_t varIndex;
bool value;
};
class IsConstantValue : public SmtConstraint {
public:
IsConstantValue(uint64_t varIndex, uint64_t val) : varIndex(varIndex), value(val) {
}
virtual ~IsConstantValue() {
}
std::string toSmtlib2(std::vector<std::string> const &varNames) const override {
std::stringstream sstr;
assert(varIndex < varNames.size());
sstr << "(= " << varNames.at(varIndex) << " " << value << ")";
return sstr.str();
}
storm::expressions::Expression toExpression(std::vector<std::string> const &varNames,
std::shared_ptr<storm::expressions::ExpressionManager> manager) const override {
return manager->getVariableExpression(varNames.at(varIndex)) == manager->integer(value);
}
private:
uint64_t varIndex;
uint64_t value;
};
class IsLessConstant : public SmtConstraint {
public:
IsLessConstant(uint64_t varIndex, uint64_t val) : varIndex(varIndex), value(val) {
}
virtual ~IsLessConstant() {
}
std::string toSmtlib2(std::vector<std::string> const &varNames) const override {
std::stringstream sstr;
assert(varIndex < varNames.size());
sstr << "(< " << varNames.at(varIndex) << " " << value << ")";
return sstr.str();
}
storm::expressions::Expression toExpression(std::vector<std::string> const &varNames,
std::shared_ptr<storm::expressions::ExpressionManager> manager) const override {
return manager->getVariableExpression(varNames.at(varIndex)) < value;
}
private:
uint64_t varIndex;
uint64_t value;
};
class IsGreaterConstant : public SmtConstraint {
public:
IsGreaterConstant(uint64_t varIndex, uint64_t val) : varIndex(varIndex), value(val) {
}
virtual ~IsGreaterConstant() {
}
std::string toSmtlib2(std::vector<std::string> const &varNames) const override {
std::stringstream sstr;
assert(varIndex < varNames.size());
sstr << "(< " << value << " " << varNames.at(varIndex) << ")";
return sstr.str();
}
storm::expressions::Expression toExpression(std::vector<std::string> const &varNames,
std::shared_ptr<storm::expressions::ExpressionManager> manager) const override {
return manager->getVariableExpression(varNames.at(varIndex)) > value;
}
private:
uint64_t varIndex;
uint64_t value;
};
class IsLessEqualConstant : public SmtConstraint {
public:
IsLessEqualConstant(uint64_t varIndex, uint64_t val) : varIndex(varIndex), value(val) {
}
virtual ~IsLessEqualConstant() {
}
std::string toSmtlib2(std::vector<std::string> const &varNames) const override {
std::stringstream sstr;
assert(varIndex < varNames.size());
sstr << "(<= " << varNames.at(varIndex) << " " << value << ")";
return sstr.str();
}
storm::expressions::Expression toExpression(std::vector<std::string> const &varNames,
std::shared_ptr<storm::expressions::ExpressionManager> manager) const override {
return manager->getVariableExpression(varNames.at(varIndex)) <= value;
}
private:
uint64_t varIndex;
uint64_t value;
};
class IsGreaterEqualConstant : public SmtConstraint {
public:
IsGreaterEqualConstant(uint64_t varIndex, uint64_t val) : varIndex(varIndex), value(val) {
}
virtual ~IsGreaterEqualConstant() {
}
std::string toSmtlib2(std::vector<std::string> const &varNames) const override {
std::stringstream sstr;
assert(varIndex < varNames.size());
sstr << "(<= " << value << " " << varNames.at(varIndex) << ")";
return sstr.str();
}
storm::expressions::Expression toExpression(std::vector<std::string> const &varNames,
std::shared_ptr<storm::expressions::ExpressionManager> manager) const override {
return manager->getVariableExpression(varNames.at(varIndex)) >= value;
}
private:
uint64_t varIndex;
uint64_t value;
};
class IsEqual : public SmtConstraint {
public:
IsEqual(uint64_t varIndex1, uint64_t varIndex2) : var1Index(varIndex1), var2Index(varIndex2) {
}
virtual ~IsEqual() {
}
std::string toSmtlib2(std::vector<std::string> const &varNames) const override {
return "(= " + varNames.at(var1Index) + " " + varNames.at(var2Index) + ")";
}
storm::expressions::Expression toExpression(std::vector<std::string> const &varNames,
std::shared_ptr<storm::expressions::ExpressionManager> manager) const override {
return manager->getVariableExpression(varNames.at(var1Index)) ==
manager->getVariableExpression(varNames.at(var2Index));
}
private:
uint64_t var1Index;
uint64_t var2Index;
};
class IsLess : public SmtConstraint {
public:
IsLess(uint64_t varIndex1, uint64_t varIndex2) : var1Index(varIndex1), var2Index(varIndex2) {
}
virtual ~IsLess() {
}
std::string toSmtlib2(std::vector<std::string> const &varNames) const override {
return "(< " + varNames.at(var1Index) + " " + varNames.at(var2Index) + ")";
}
storm::expressions::Expression toExpression(std::vector<std::string> const &varNames,
std::shared_ptr<storm::expressions::ExpressionManager> manager) const override {
return manager->getVariableExpression(varNames.at(var1Index)) <
manager->getVariableExpression(varNames.at(var2Index));
}
private:
uint64_t var1Index;
uint64_t var2Index;
};
class PairwiseDifferent : public SmtConstraint {
public:
PairwiseDifferent(std::vector<uint64_t> const &indices) : varIndices(indices) {
}
virtual ~PairwiseDifferent() {
}
std::string toSmtlib2(std::vector<std::string> const &varNames) const override {
std::stringstream sstr;
sstr << "(distinct";
// for(uint64_t i = 0; i < varIndices.size(); ++i) {
// for(uint64_t j = i + 1; j < varIndices.size(); ++j) {
// sstr << "()";
// }
// }
for (auto const &varIndex : varIndices) {
sstr << " " << varNames.at(varIndex);
}
sstr << ")";
return sstr.str();
}
storm::expressions::Expression toExpression(std::vector<std::string> const &varNames,
std::shared_ptr<storm::expressions::ExpressionManager> manager) const override {
std::vector<storm::expressions::Expression> conjuncts;
for (uint64_t i = 0; i < varIndices.size(); ++i) {
for (uint64_t j = i + 1; j < varIndices.size(); ++j) {
// check all elements pairwise for inequality
conjuncts.push_back(manager->getVariableExpression(varNames.at(varIndices.at(i))) !=
manager->getVariableExpression(varNames.at(varIndices.at(j))));
}
}
// take the conjunction of all pairwise inequalities
return conjunction(conjuncts);
}
private:
std::vector<uint64_t> varIndices;
};
class Sorted : public SmtConstraint {
public:
Sorted(std::vector<uint64_t> varIndices) : varIndices(varIndices) {
}
virtual ~Sorted() {
}
std::string toSmtlib2(std::vector<std::string> const &varNames) const override {
std::stringstream sstr;
sstr << "(and ";
for (uint64_t i = 1; i < varIndices.size(); ++i) {
sstr << "(<= " << varNames.at(varIndices.at(i - 1)) << " " << varNames.at(varIndices.at(i)) << ")";
}
sstr << ") ";
return sstr.str();
}
storm::expressions::Expression toExpression(std::vector<std::string> const &varNames,
std::shared_ptr<storm::expressions::ExpressionManager> manager) const override {
std::vector<storm::expressions::Expression> conjuncts;
for (uint64_t i = 1; i < varIndices.size(); ++i) {
conjuncts.push_back(manager->getVariableExpression(varNames.at(varIndices.at(i - 1))) <=
manager->getVariableExpression(varNames.at(varIndices.at(i))));
}
// take the conjunction of all pairwise inequalities
return conjunction(conjuncts);
}
private:
std::vector<uint64_t> varIndices;
};
class IfThenElse : public SmtConstraint {
public:
IfThenElse(std::shared_ptr<SmtConstraint> ifC, std::shared_ptr<SmtConstraint> thenC,
std::shared_ptr<SmtConstraint> elseC) : ifConstraint(ifC), thenConstraint(thenC),
elseConstraint(elseC) {
}
std::string toSmtlib2(std::vector<std::string> const &varNames) const override {
std::stringstream sstr;
sstr << "(ite " << ifConstraint->toSmtlib2(varNames) << " " << thenConstraint->toSmtlib2(varNames)
<< " " << elseConstraint->toSmtlib2(varNames) << ")";
return sstr.str();
}
storm::expressions::Expression toExpression(std::vector<std::string> const &varNames,
std::shared_ptr<storm::expressions::ExpressionManager> manager) const override {
return ite(ifConstraint->toExpression(varNames, manager),
thenConstraint->toExpression(varNames, manager),
elseConstraint->toExpression(varNames, manager));
}
private:
std::shared_ptr<SmtConstraint> ifConstraint;
std::shared_ptr<SmtConstraint> thenConstraint;
std::shared_ptr<SmtConstraint> elseConstraint;
};
class TrueCountIsLessConstant : public SmtConstraint {
public:
TrueCountIsLessConstant(std::vector<uint64_t> varIndices, uint64_t val) : varIndices(varIndices),
value(val) {
}
std::string toSmtlib2(std::vector<std::string> const &varNames) const override {
std::stringstream sstr;
sstr << "(< (+ ";
for (uint64_t i = 0; i < varIndices.size(); ++i) {
sstr << "(ite " << varNames.at(varIndices.at(i)) << " 1 0 )";
}
sstr << ") " << value << " )";
return sstr.str();
}
storm::expressions::Expression toExpression(std::vector<std::string> const &varNames,
std::shared_ptr<storm::expressions::ExpressionManager> manager) const override {
std::vector<storm::expressions::Expression> boolToInt;
for (uint64_t i = 0; i < varIndices.size(); ++i) {
boolToInt.push_back(
ite(manager->getVariableExpression(varNames.at(varIndices.at(i))), // If variable is true
manager->integer(1), // set 1
manager->integer(0))); // else 0
}
return sum(boolToInt) < manager->integer(value);
}
private:
std::vector<uint64_t> varIndices;
uint64_t value;
};
class FalseCountIsEqualConstant : public SmtConstraint {
public:
FalseCountIsEqualConstant(std::vector<uint64_t> varIndices, uint64_t val) : varIndices(varIndices),
value(val) {
}
std::string toSmtlib2(std::vector<std::string> const &varNames) const override {
std::stringstream sstr;
sstr << "(= (+ ";
for (uint64_t i = 0; i < varIndices.size(); ++i) {
sstr << "(ite " << varNames.at(varIndices.at(i)) << " 0 1 )";
}
sstr << ") " << value << " )";
return sstr.str();
}
storm::expressions::Expression toExpression(std::vector<std::string> const &varNames,
std::shared_ptr<storm::expressions::ExpressionManager> manager) const override {
std::vector<storm::expressions::Expression> boolToInt;
for (uint64_t i = 0; i < varIndices.size(); ++i) {
boolToInt.push_back(
ite(manager->getVariableExpression(varNames.at(varIndices.at(i))), // If variable is true
manager->integer(0), // set 0
manager->integer(1))); // else 1
}
return sum(boolToInt) == manager->integer(value);
}
private:
std::vector<uint64_t> varIndices;
uint64_t value;
};
class TrueCountIsConstantValue : public SmtConstraint {
public:
TrueCountIsConstantValue(std::vector<uint64_t> varIndices, uint64_t val) : varIndices(varIndices),
value(val) {
}
std::string toSmtlib2(std::vector<std::string> const &varNames) const override {
std::stringstream sstr;
sstr << "(= (+ ";
for (uint64_t i = 0; i < varIndices.size(); ++i) {
sstr << "(ite " << varNames.at(varIndices.at(i)) << " 1 0 )";
}
sstr << ") " << value << " )";
return sstr.str();
}
storm::expressions::Expression toExpression(std::vector<std::string> const &varNames,
std::shared_ptr<storm::expressions::ExpressionManager> manager) const override {
std::vector<storm::expressions::Expression> boolToInt;
for (uint64_t i = 0; i < varIndices.size(); ++i) {
boolToInt.push_back(
ite(manager->getVariableExpression(varNames.at(varIndices.at(i))), // If variable is true
manager->integer(1), // set 1
manager->integer(0))); // else 0
}
return sum(boolToInt) == manager->integer(value);
}
private:
std::vector<uint64_t> varIndices;
uint64_t value;
};
}
}

39
src/storm-dft/modelchecker/dft/SmtConstraint.h

@ -0,0 +1,39 @@
#include <string>
#include <storm/storage/expressions/Expression.h>
namespace storm {
namespace modelchecker {
class SmtConstraint {
public:
virtual ~SmtConstraint() {
}
/** Generate a string describing the constraint in Smtlib2 format
*
* @param varNames vector of variable names
* @return Smtlib2 format string
*/
virtual std::string toSmtlib2(std::vector<std::string> const &varNames) const = 0;
/** Generate an expression describing the constraint in Storm format
*
* @param varNames vector of variable names
* @param manager the expression manager used to handle the expressions
* @return the expression
*/
virtual storm::expressions::Expression toExpression(std::vector<std::string> const &varNames,
std::shared_ptr<storm::expressions::ExpressionManager> manager) const = 0;
virtual std::string description() const {
return descript;
}
void setDescription(std::string const &descr) {
descript = descr;
}
private:
std::string descript;
};
}
}

14
src/storm-dft/settings/modules/DftIOSettings.cpp

@ -25,6 +25,7 @@ namespace storm {
const std::string DftIOSettings::minValueOptionName = "min";
const std::string DftIOSettings::maxValueOptionName = "max";
const std::string DftIOSettings::exportToJsonOptionName = "export-json";
const std::string DftIOSettings::exportToSmtOptionName = "export-smt";
const std::string DftIOSettings::displayStatsOptionName = "show-dft-stats";
@ -56,6 +57,11 @@ namespace storm {
this->addOption(storm::settings::OptionBuilder(moduleName, exportToJsonOptionName, false, "Export the model to the Cytoscape JSON format.")
.addArgument(storm::settings::ArgumentBuilder::createStringArgument("filename", "The name of the JSON file to export to.").build())
.build());
this->addOption(storm::settings::OptionBuilder(moduleName, exportToSmtOptionName, false,
"Export the model as SMT encoding to the smtlib2 format.")
.addArgument(storm::settings::ArgumentBuilder::createStringArgument("filename",
"The name of the smtlib2 file to export to.").build())
.build());
this->addOption(storm::settings::OptionBuilder(moduleName, displayStatsOptionName, false, "Print stats to stdout").build());
}
@ -122,6 +128,14 @@ namespace storm {
return this->getOption(exportToJsonOptionName).getArgumentByName("filename").getValueAsString();
}
bool DftIOSettings::isExportToSmt() const {
return this->getOption(exportToSmtOptionName).getHasOptionBeenSet();
}
std::string DftIOSettings::getExportSmtFilename() const {
return this->getOption(exportToSmtOptionName).getArgumentByName("filename").getValueAsString();
}
bool DftIOSettings::isDisplayStatsSet() const {
return this->getOption(displayStatsOptionName).getHasOptionBeenSet();
}

15
src/storm-dft/settings/modules/DftIOSettings.h

@ -108,6 +108,13 @@ namespace storm {
*/
bool isExportToJson() const;
/*!
* Retrieves whether the export to smtlib2 file option was set.
*
* @return True if the export to smtlib2 file option was set.
*/
bool isExportToSmt() const;
/*!
* Retrieves the name of the json file to export to.
*
@ -115,6 +122,13 @@ namespace storm {
*/
std::string getExportJsonFilename() const;
/*!
* Retrieves the name of the smtlib2 file to export to.
*
* @return The name of the smtlib2 file to export to.
*/
std::string getExportSmtFilename() const;
/*!
* Retrieves whether statistics for the DFT should be displayed.
*
@ -142,6 +156,7 @@ namespace storm {
static const std::string minValueOptionName;
static const std::string maxValueOptionName;
static const std::string exportToJsonOptionName;
static const std::string exportToSmtOptionName;
static const std::string displayStatsOptionName;
};

40
src/storm-dft/settings/modules/FaultTreeSettings.cpp

@ -24,24 +24,35 @@ namespace storm {
const std::string FaultTreeSettings::approximationErrorOptionName = "approximation";
const std::string FaultTreeSettings::approximationErrorOptionShortName = "approx";
const std::string FaultTreeSettings::approximationHeuristicOptionName = "approximationheuristic";
const std::string FaultTreeSettings::maxDepthOptionName = "maxdepth";
const std::string FaultTreeSettings::firstDependencyOptionName = "firstdep";
#ifdef STORM_HAVE_Z3
const std::string FaultTreeSettings::solveWithSmtOptionName = "smt";
#endif
FaultTreeSettings::FaultTreeSettings() : ModuleSettings(moduleName) {
this->addOption(storm::settings::OptionBuilder(moduleName, symmetryReductionOptionName, false, "Exploit symmetric structure of model.").setShortName(symmetryReductionOptionShortName).build());
this->addOption(storm::settings::OptionBuilder(moduleName, symmetryReductionOptionName, false, "Exploit symmetric structure of model.").setShortName(
symmetryReductionOptionShortName).build());
this->addOption(storm::settings::OptionBuilder(moduleName, modularisationOptionName, false, "Use modularisation (not applicable for expected time).").build());
this->addOption(storm::settings::OptionBuilder(moduleName, disableDCOptionName, false, "Disable Don't Care propagation.").build());
this->addOption(storm::settings::OptionBuilder(moduleName, firstDependencyOptionName, false, "Avoid non-determinism by always taking the first possible dependency.").build());
this->addOption(storm::settings::OptionBuilder(moduleName, firstDependencyOptionName, false,
"Avoid non-determinism by always taking the first possible dependency.").build());
this->addOption(storm::settings::OptionBuilder(moduleName, relevantEventsOptionName, false, "Specifies the relevant events from the DFT.")
.addArgument(storm::settings::ArgumentBuilder::createStringArgument("values", "A comma separated list of names of relevant events. 'all' marks all events as relevant, The default '' or 'none' marks only the top level event as relevant.").setDefaultValueString("").build()).build());
.addArgument(storm::settings::ArgumentBuilder::createStringArgument("values",
"A comma separated list of names of relevant events. 'all' marks all events as relevant, The default '' or 'none' marks only the top level event as relevant.").setDefaultValueString(
"").build()).build());
this->addOption(storm::settings::OptionBuilder(moduleName, allowDCRelevantOptionName, false, "Allow Don't Care propagation for relevant events.").build());
this->addOption(storm::settings::OptionBuilder(moduleName, approximationErrorOptionName, false, "Approximation error allowed.").setShortName(approximationErrorOptionShortName).addArgument(storm::settings::ArgumentBuilder::createDoubleArgument("error", "The relative approximation error to use.").addValidatorDouble(ArgumentValidatorFactory::createDoubleGreaterEqualValidator(0.0)).build()).build());
this->addOption(storm::settings::OptionBuilder(moduleName, approximationErrorOptionName, false, "Approximation error allowed.").setShortName(
approximationErrorOptionShortName).addArgument(
storm::settings::ArgumentBuilder::createDoubleArgument("error", "The relative approximation error to use.").addValidatorDouble(
ArgumentValidatorFactory::createDoubleGreaterEqualValidator(0.0)).build()).build());
this->addOption(storm::settings::OptionBuilder(moduleName, approximationHeuristicOptionName, false, "Set the heuristic used for approximation.")
.addArgument(storm::settings::ArgumentBuilder::createStringArgument("heuristic", "The name of the heuristic used for approximation.")
.setDefaultValueString("depth")
.addValidatorString(ArgumentValidatorFactory::createMultipleChoiceValidator({"depth", "probability", "bounddifference"})).build()).build());
.addArgument(storm::settings::ArgumentBuilder::createStringArgument("heuristic", "The name of the heuristic used for approximation.")
.setDefaultValueString("depth")
.addValidatorString(ArgumentValidatorFactory::createMultipleChoiceValidator(
{"depth", "probability", "bounddifference"})).build()).build());
this->addOption(storm::settings::OptionBuilder(moduleName, maxDepthOptionName, false, "Maximal depth for state space exploration.").addArgument(
storm::settings::ArgumentBuilder::createUnsignedIntegerArgument("depth", "The maximal depth.").build()).build());
#ifdef STORM_HAVE_Z3
this->addOption(storm::settings::OptionBuilder(moduleName, solveWithSmtOptionName, true, "Solve the DFT with SMT.").build());
#endif
@ -64,7 +75,8 @@ namespace storm {
}
bool FaultTreeSettings::areRelevantEventsSet() const {
return this->getOption(relevantEventsOptionName).getHasOptionBeenSet() && (this->getOption(relevantEventsOptionName).getArgumentByName("values").getValueAsString() != "");
return this->getOption(relevantEventsOptionName).getHasOptionBeenSet() &&
(this->getOption(relevantEventsOptionName).getArgumentByName("values").getValueAsString() != "");
}
std::vector<std::string> FaultTreeSettings::getRelevantEvents() const {
@ -91,14 +103,24 @@ namespace storm {
STORM_LOG_THROW(false, storm::exceptions::IllegalArgumentValueException, "Illegal value '" << heuristicAsString << "' set as heuristic for approximation.");
}
bool FaultTreeSettings::isMaxDepthSet() const {
return this->getOption(maxDepthOptionName).getHasOptionBeenSet();
}
uint_fast64_t FaultTreeSettings::getMaxDepth() const {
return this->getOption(maxDepthOptionName).getArgumentByName("depth").getValueAsUnsignedInteger();
}
bool FaultTreeSettings::isTakeFirstDependency() const {
return this->getOption(firstDependencyOptionName).getHasOptionBeenSet();
}
#ifdef STORM_HAVE_Z3
bool FaultTreeSettings::solveWithSMT() const {
return this->getOption(solveWithSmtOptionName).getHasOptionBeenSet();
}
#endif
void FaultTreeSettings::finalize() {
@ -107,6 +129,8 @@ namespace storm {
bool FaultTreeSettings::check() const {
// Ensure that disableDC and relevantEvents are not set at the same time
STORM_LOG_THROW(!isDisableDC() || !areRelevantEventsSet(), storm::exceptions::InvalidSettingsException, "DisableDC and relevantSets can not both be set.");
STORM_LOG_THROW(!isMaxDepthSet() || getApproximationHeuristic() == storm::builder::ApproximationHeuristic::DEPTH, storm::exceptions::InvalidSettingsException,
"Maximal depth requires approximation heuristic depth.");
return true;
}

15
src/storm-dft/settings/modules/FaultTreeSettings.h

@ -82,6 +82,20 @@ namespace storm {
*/
storm::builder::ApproximationHeuristic getApproximationHeuristic() const;
/*!
* Retrieves whether the option to set a maximal exploration depth is set.
*
* @return True iff the option was set.
*/
bool isMaxDepthSet() const;
/*!
* Retrieves the maximal exploration depth.
*
* @return The maximal exploration depth.
*/
uint_fast64_t getMaxDepth() const;
/*!
* Retrieves whether the non-determinism should be avoided by always taking the first possible dependency.
*
@ -118,6 +132,7 @@ namespace storm {
static const std::string approximationErrorOptionName;
static const std::string approximationErrorOptionShortName;
static const std::string approximationHeuristicOptionName;
static const std::string maxDepthOptionName;
static const std::string firstDependencyOptionName;
#ifdef STORM_HAVE_Z3
static const std::string solveWithSmtOptionName;

13
src/storm-dft/storage/dft/DFT.cpp

@ -17,14 +17,13 @@ namespace storm {
namespace storage {
template<typename ValueType>
DFT<ValueType>::DFT(DFTElementVector const& elements, DFTElementPointer const& tle) : mElements(elements), mNrOfBEs(0), mNrOfSpares(0), mTopLevelIndex(tle->id()), mMaxSpareChildCount(0) {
DFT<ValueType>::DFT(DFTElementVector const& elements, DFTElementPointer const& tle) : mElements(elements), mNrOfBEs(0), mNrOfSpares(0), mNrRepresentatives(0), mTopLevelIndex(tle->id()), mMaxSpareChildCount(0) {
// Check that ids correspond to indices in the element vector
STORM_LOG_ASSERT(elementIndicesCorrect(), "Ids incorrect.");
size_t nrRepresentatives = 0;
for (auto& elem : mElements) {
if (isRepresentative(elem->id())) {
++nrRepresentatives;
++mNrRepresentatives;
}
if(elem->isBasicElement()) {
++mNrOfBEs;
@ -81,13 +80,12 @@ namespace storm {
//Reserve space for failed spares
++mMaxSpareChildCount;
size_t usageInfoBits = storm::utility::math::uint64_log2(mMaxSpareChildCount) + 1;
mStateVectorSize = nrElements() * 2 + mNrOfSpares * usageInfoBits + nrRepresentatives;
mStateVectorSize = DFTStateGenerationInfo::getStateVectorSize(nrElements(), mNrOfSpares, mNrRepresentatives, mMaxSpareChildCount);
}
template<typename ValueType>
DFTStateGenerationInfo DFT<ValueType>::buildStateGenerationInfo(storm::storage::DFTIndependentSymmetries const& symmetries) const {
DFTStateGenerationInfo generationInfo(nrElements(), mMaxSpareChildCount);
DFTStateGenerationInfo generationInfo(nrElements(), mNrOfSpares, mNrRepresentatives, mMaxSpareChildCount);
// Generate Pre and Post info for restrictions, and mutexes
for(auto const& elem : mElements) {
@ -199,7 +197,8 @@ namespace storm {
STORM_LOG_TRACE(generationInfo);
STORM_LOG_ASSERT(stateIndex == mStateVectorSize, "Id incorrect.");
STORM_LOG_ASSERT(visited.full(), "Not all elements considered.");
generationInfo.checkSymmetries();
return generationInfo;
}

1
src/storm-dft/storage/dft/DFT.h

@ -58,6 +58,7 @@ namespace storm {
DFTElementVector mElements;
size_t mNrOfBEs;
size_t mNrOfSpares;
size_t mNrRepresentatives;
size_t mTopLevelIndex;
size_t mStateVectorSize;
size_t mMaxSpareChildCount;

2
src/storm-dft/storage/dft/DFTState.cpp

@ -522,6 +522,8 @@ namespace storm {
do {
tmp = 0;
for (size_t i = 1; i < n; ++i) {
STORM_LOG_ASSERT(symmetryIndices[i-1] + length <= mStatus.size(), "Symmetry index "<< symmetryIndices[i-1] << " + length " << length << " is larger than status vector " << mStatus.size());
STORM_LOG_ASSERT(symmetryIndices[i] + length <= mStatus.size(), "Symmetry index "<< symmetryIndices[i] << " + length " << length << " is larger than status vector " << mStatus.size());
if (mStatus.compareAndSwap(symmetryIndices[i-1], symmetryIndices[i], length)) {
tmp = i;
changed = true;

70
src/storm-dft/storage/dft/DFTStateGenerationInfo.h

@ -5,36 +5,59 @@ namespace storm {
class DFTStateGenerationInfo {
private:
const size_t mUsageInfoBits;
const size_t stateIndexSize;
std::map<size_t, size_t> mSpareUsageIndex; // id spare -> index first bit in state
std::map<size_t, size_t> mSpareActivationIndex; // id spare representative -> index in state
std::vector<size_t> mIdToStateIndex; // id -> index first bit in state
std::map<size_t, std::vector<size_t>> mSeqRestrictionPreElements; // id -> list of restriction pre elements
std::map<size_t, std::vector<size_t>> mSeqRestrictionPostElements; // id -> list of restriction post elements
std::map<size_t, std::vector<size_t>> mMutexRestrictionElements; // id -> list of elments in the same mutexes
std::map<size_t, std::vector<size_t>> mMutexRestrictionElements; // id -> list of elements in the same mutexes
std::vector<std::pair<size_t, std::vector<size_t>>> mSymmetries; // pair (length of symmetry group, vector indicating the starting points of the symmetry groups)
public:
DFTStateGenerationInfo(size_t nrElements, size_t maxSpareChildCount) :
mUsageInfoBits(storm::utility::math::uint64_log2(maxSpareChildCount) + 1),
mIdToStateIndex(nrElements)
{
DFTStateGenerationInfo(size_t nrElements, size_t nrOfSpares, size_t nrRepresentatives, size_t maxSpareChildCount) :
mUsageInfoBits(getUsageInfoBits(maxSpareChildCount)),
stateIndexSize(getStateVectorSize(nrElements, nrOfSpares, nrRepresentatives, maxSpareChildCount)),
mIdToStateIndex(nrElements) {
STORM_LOG_ASSERT(maxSpareChildCount < pow(2, mUsageInfoBits), "Bit length incorrect.");
}
/*!
* Get number of bits required to store claiming information for spares in binary format.
* @param maxSpareChildCount Maximal number of children of a spare.
* @return Number of bits required to store claiming information.
*/
static size_t getUsageInfoBits(size_t maxSpareChildCount) {
return storm::utility::math::uint64_log2(maxSpareChildCount) + 1;
}
/*!
* Get length of BitVector capturing DFT state.
* @param nrElements Number of DFT elements.
* @param nrOfSpares Number of Spares (needed for claiming).
* @param nrRepresentatives Number of representatives (needed for activation).
* @param maxSpareChildCount Maximal number of children of a spare.
* @return Length of required BitVector.
*/
static size_t getStateVectorSize(size_t nrElements, size_t nrOfSpares, size_t nrRepresentatives, size_t maxSpareChildCount) {
return nrElements * 2 + nrOfSpares * getUsageInfoBits(maxSpareChildCount) + nrRepresentatives;
}
size_t usageInfoBits() const {
return mUsageInfoBits;
}
void addStateIndex(size_t id, size_t index) {
STORM_LOG_ASSERT(id < mIdToStateIndex.size(), "Id invalid.");
STORM_LOG_ASSERT(index < stateIndexSize, "Index invalid");
mIdToStateIndex[id] = index;
}
void setRestrictionPreElements(size_t id, std::vector<size_t> const& elems) {
mSeqRestrictionPreElements[id] = elems;
}
void setRestrictionPostElements(size_t id, std::vector<size_t> const& elems) {
mSeqRestrictionPostElements[id] = elems;
}
@ -47,7 +70,7 @@ namespace storm {
STORM_LOG_ASSERT(mSeqRestrictionPreElements.count(index) > 0, "Index invalid.");
return mSeqRestrictionPreElements.at(index);
}
std::vector<size_t> const& seqRestrictionPostElements(size_t index) const {
STORM_LOG_ASSERT(mSeqRestrictionPostElements.count(index) > 0, "Index invalid.");
return mSeqRestrictionPostElements.at(index);
@ -57,12 +80,14 @@ namespace storm {
STORM_LOG_ASSERT(mMutexRestrictionElements.count(index) > 0, "Index invalid.");
return mMutexRestrictionElements.at(index);
}
void addSpareActivationIndex(size_t id, size_t index) {
STORM_LOG_ASSERT(index < stateIndexSize, "Index invalid");
mSpareActivationIndex[id] = index;
}
void addSpareUsageIndex(size_t id, size_t index) {
STORM_LOG_ASSERT(index < stateIndexSize, "Index invalid");
mSpareUsageIndex[id] = index;
}
@ -84,7 +109,7 @@ namespace storm {
void addSymmetry(size_t length, std::vector<size_t>& startingIndices) {
mSymmetries.push_back(std::make_pair(length, startingIndices));
}
/**
* Generate more symmetries by combining two symmetries
*/
@ -94,21 +119,25 @@ namespace storm {
size_t childStart = mSymmetries[i].second[0];
size_t childLength = mSymmetries[i].first;
// Iterate over possible parents
for (size_t j = i+1; j < mSymmetries.size(); ++j) {
for (size_t j = i + 1; j < mSymmetries.size(); ++j) {
size_t parentStart = mSymmetries[j].second[0];
size_t parentLength = mSymmetries[j].first;
// Check if child lies in parent
if (parentStart <= childStart && childStart + childLength < parentStart + parentLength) {
// We add the symmetry of the child to all symmetric elements in the parent
std::vector<std::vector<size_t>> newSymmetries;
// Start iteration at 1, because symmetry for child at 0 is already included
for (size_t index = 1; index < mSymmetries[j].second.size(); ++index) {
// Get symmetric start by applying the bijection
std::vector<size_t> newStarts;
// Apply child symmetry to all symmetric elements of parent
for (size_t symmetryStarts : mSymmetries[i].second) {
newStarts.push_back(symmetryStarts + mSymmetries[j].second[index]);
// Get symmetric element by applying the bijection
size_t symmetryOffset = symmetryStarts - parentStart;
newStarts.push_back(mSymmetries[j].second[index] + symmetryOffset);
}
newSymmetries.push_back(newStarts);
}
// Insert after child
// Insert new symmetry after child
for (size_t index = 0; index < newSymmetries.size(); ++index) {
mSymmetries.insert(mSymmetries.begin() + i + 1 + index, std::make_pair(childLength, newSymmetries[index]));
}
@ -119,10 +148,21 @@ namespace storm {
}
}
void checkSymmetries() {
for (auto pair : mSymmetries) {
STORM_LOG_ASSERT(pair.first > 0, "Empty symmetry.");
STORM_LOG_ASSERT(pair.first < stateIndexSize, "Symmetry too long.");
for (size_t index : pair.second) {
STORM_LOG_ASSERT(index < stateIndexSize, "Symmetry starting point " << index << " invalid.");
STORM_LOG_ASSERT(index + pair.first < stateIndexSize, "Symmetry ending point " << index << " invalid.");
}
}
}
size_t getSymmetrySize() const {
return mSymmetries.size();
}
bool hasSymmetries() const {
return !mSymmetries.empty();
}
@ -138,6 +178,8 @@ namespace storm {
}
friend std::ostream& operator<<(std::ostream& os, DFTStateGenerationInfo const& info) {
os << "StateGenerationInfo:" << std::endl;
os << "Length of state vector: " << info.stateIndexSize << std::endl;
os << "Id to state index:" << std::endl;
for (size_t id = 0; id < info.mIdToStateIndex.size(); ++id) {
os << id << " -> " << info.getStateIndex(id) << std::endl;

9
src/storm-pars/modelchecker/region/SparseDtmcParameterLiftingModelChecker.cpp

@ -149,8 +149,8 @@ namespace storm {
lowerResultBound = storm::utility::zero<ConstantType>();
upperResultBound = storm::utility::one<ConstantType>();
// The solution of the min-max equation system will always be unique (assuming graph-preserving instantiations).
auto req = solverFactory->getRequirements(env, true, boost::none, true);
// The solution of the min-max equation system will always be unique (assuming graph-preserving instantiations, every induced DTMC has the same graph structure).
auto req = solverFactory->getRequirements(env, true, true, boost::none, true);
req.clearBounds();
STORM_LOG_THROW(!req.hasEnabledCriticalRequirement(), storm::exceptions::UncheckedRequirementException, "Solver requirements " + req.getEnabledRequirementsAsString() + " not checked.");
solverFactory->setRequirementsChecked(true);
@ -188,8 +188,8 @@ namespace storm {
// We only know a lower bound for the result
lowerResultBound = storm::utility::zero<ConstantType>();
// The solution of the min-max equation system will always be unique (assuming graph-preserving instantiations).
auto req = solverFactory->getRequirements(env, true, boost::none, true);
// The solution of the min-max equation system will always be unique (assuming graph-preserving instantiations, every induced DTMC has the same graph structure).
auto req = solverFactory->getRequirements(env, true, true, boost::none, true);
req.clearLowerBounds();
if (req.upperBounds()) {
solvingRequiresUpperRewardBounds = true;
@ -258,6 +258,7 @@ namespace storm {
} else {
auto solver = solverFactory->create(env, parameterLifter->getMatrix());
solver->setHasUniqueSolution();
solver->setHasNoEndComponents();
if (lowerResultBound) solver->setLowerBound(lowerResultBound.get());
if (upperResultBound) {
solver->setUpperBound(upperResultBound.get());

5
src/storm/builder/DdJaniModelBuilder.cpp

@ -1975,13 +1975,13 @@ namespace storm {
std::vector<storm::expressions::Variable> rewardVariables;
if (options.isBuildAllRewardModelsSet()) {
for (auto const& rewExpr : model.getAllRewardModelExpressions()) {
STORM_LOG_ERROR_COND(rewExpr.second.isVariable(), "The DD-builder can not build the non-trivial reward expression '" << rewExpr.second << "'.");
STORM_LOG_THROW(!model.isNonTrivialRewardModelExpression(rewExpr.first), storm::exceptions::NotSupportedException, "The DD-builder can not build the non-trivial reward expression '" << rewExpr.second << "'.");
rewardVariables.push_back(rewExpr.second.getBaseExpression().asVariableExpression().getVariable());
}
} else {
for (auto const& rewardModelName : options.getRewardModelNames()) {
STORM_LOG_THROW(!model.isNonTrivialRewardModelExpression(rewardModelName), storm::exceptions::NotSupportedException, "The DD-builder can not build the non-trivial reward expression '" << rewardModelName << "'.");
auto const& rewExpr = model.getRewardModelExpression(rewardModelName);
STORM_LOG_ERROR_COND(rewExpr.isVariable(), "The DD-builder can not build the non-trivial reward expression '" << rewExpr << "'.");
rewardVariables.push_back(rewExpr.getBaseExpression().asVariableExpression().getVariable());
}
}
@ -2070,6 +2070,7 @@ namespace storm {
// Lift the transient edge destinations. We can do so, as we know that there are no assignment levels (because that's not supported anyway).
if (preparedModel.hasTransientEdgeDestinationAssignments()) {
// This operation is correct as we are asserting that there are no assignment levels and no non-trivial reward expressions.
preparedModel.liftTransientEdgeDestinationAssignments();
}

62
src/storm/generator/JaniNextStateGenerator.cpp

@ -40,7 +40,7 @@ namespace storm {
}
template<typename ValueType, typename StateType>
JaniNextStateGenerator<ValueType, StateType>::JaniNextStateGenerator(storm::jani::Model const& model, NextStateGeneratorOptions const& options, bool) : NextStateGenerator<ValueType, StateType>(model.getExpressionManager(), options), model(model), rewardExpressions(), hasStateActionRewards(false) {
JaniNextStateGenerator<ValueType, StateType>::JaniNextStateGenerator(storm::jani::Model const& model, NextStateGeneratorOptions const& options, bool) : NextStateGenerator<ValueType, StateType>(model.getExpressionManager(), options), model(model), rewardExpressions(), hasStateActionRewards(false), evaluateRewardExpressionsAtEdges(false), evaluateRewardExpressionsAtDestinations(false) {
STORM_LOG_THROW(!this->options.isBuildChoiceLabelsSet(), storm::exceptions::InvalidSettingsException, "JANI next-state generator cannot generate choice labels.");
auto features = this->model.getModelFeatures();
@ -54,11 +54,26 @@ namespace storm {
}
STORM_LOG_THROW(features.empty(), storm::exceptions::InvalidSettingsException, "The explicit next-state generator does not support the following model feature(s): " << features.toString() << ".");
// Preprocess the edge assignments:
if (this->model.usesAssignmentLevels()) {
// Get the reward expressions to be build. Also find out whether there is a non-trivial one.
bool hasNonTrivialRewardExpressions = false;
if (this->options.isBuildAllRewardModelsSet()) {
rewardExpressions = this->model.getAllRewardModelExpressions();
hasNonTrivialRewardExpressions = this->model.hasNonTrivialRewardExpression();
} else {
// Extract the reward models from the model based on the names we were given.
for (auto const& rewardModelName : this->options.getRewardModelNames()) {
rewardExpressions.emplace_back(rewardModelName, this->model.getRewardModelExpression(rewardModelName));
hasNonTrivialRewardExpressions = hasNonTrivialRewardExpressions || this->model.isNonTrivialRewardModelExpression(rewardModelName);
}
}
// We try to lift the edge destination assignments to the edges as this reduces the number of evaluator calls.
// However, this will only be helpful if there are no assignment levels and only trivial reward expressions.
if (hasNonTrivialRewardExpressions || this->model.usesAssignmentLevels()) {
this->model.pushEdgeAssignmentsToDestinations();
} else {
this->model.liftTransientEdgeDestinationAssignments(storm::jani::AssignmentLevelFinder().getLowestAssignmentLevel(this->model));
evaluateRewardExpressionsAtEdges = true;
}
// Create all synchronization-related information, e.g. the automata that are put in parallel.
@ -71,18 +86,10 @@ namespace storm {
this->transientVariableInformation = TransientVariableInformation<ValueType>(this->model, this->parallelAutomata);
this->transientVariableInformation.registerArrayVariableReplacements(arrayEliminatorData);
// Create a proper evalator.
// Create a proper evaluator.
this->evaluator = std::make_unique<storm::expressions::ExpressionEvaluator<ValueType>>(this->model.getManager());
this->transientVariableInformation.setDefaultValuesInEvaluator(*this->evaluator);
if (this->options.isBuildAllRewardModelsSet()) {
rewardExpressions = this->model.getAllRewardModelExpressions();
} else {
// Extract the reward models from the model based on the names we were given.
for (auto const& rewardModelName : this->options.getRewardModelNames()) {
rewardExpressions.emplace_back(rewardModelName, this->model.getRewardModelExpression(rewardModelName));
}
}
// Build the information structs for the reward models.
buildRewardModelInformation();
@ -541,18 +548,19 @@ namespace storm {
}
Choice<ValueType> choice(edge.getActionIndex(), static_cast<bool>(exitRate));
std::vector<ValueType> stateActionRewards;
// Perform the transient edge assignments and create the state action rewards
TransientVariableValuation<ValueType> transientVariableValuation;
if (!edge.getAssignments().empty()) {
if (!evaluateRewardExpressionsAtEdges || edge.getAssignments().empty()) {
stateActionRewards.resize(rewardModelInformation.size(), storm::utility::zero<ValueType>());
} else {
for (int64_t assignmentLevel = edge.getAssignments().getLowestLevel(true); assignmentLevel <= edge.getAssignments().getHighestLevel(true); ++assignmentLevel) {
transientVariableValuation.clear();
applyTransientUpdate(transientVariableValuation, edge.getAssignments().getTransientAssignments(assignmentLevel), *this->evaluator);
transientVariableValuation.setInEvaluator(*this->evaluator, this->getOptions().isExplorationChecksSet());
}
}
std::vector<ValueType> stateActionRewards = evaluateRewardExpressions();
if (!edge.getAssignments().empty()) {
stateActionRewards = evaluateRewardExpressions();
transientVariableInformation.setDefaultValuesInEvaluator(*this->evaluator);
}
@ -591,8 +599,11 @@ namespace storm {
}
}
}
addEvaluatedRewardExpressions(stateActionRewards, probability);
if (evaluateRewardExpressionsAtDestinations) {
unpackStateIntoEvaluator(newState, this->variableInformation, *this->evaluator);
evaluatorChanged = true;
addEvaluatedRewardExpressions(stateActionRewards, probability);
}
if (evaluatorChanged) {
// Restore the old variable valuation
@ -650,7 +661,7 @@ namespace storm {
// Perform the edge assignments (if there are any)
TransientVariableValuation<ValueType> transientVariableValuation;
if (lowestEdgeAssignmentLevel <= highestEdgeAssignmentLevel) {
if (evaluateRewardExpressionsAtEdges && lowestEdgeAssignmentLevel <= highestEdgeAssignmentLevel) {
for (int64_t assignmentLevel = lowestEdgeAssignmentLevel; assignmentLevel <= highestEdgeAssignmentLevel; ++assignmentLevel) {
transientVariableValuation.clear();
for (uint_fast64_t i = 0; i < iteratorList.size(); ++i) {
@ -718,7 +729,11 @@ namespace storm {
evaluatorChanged = true;
transientVariableValuation.setInEvaluator(*this->evaluator, this->getOptions().isExplorationChecksSet());
}
addEvaluatedRewardExpressions(stateActionRewards, successorProbability);
if (evaluateRewardExpressionsAtDestinations) {
unpackStateIntoEvaluator(successorState, this->variableInformation, *this->evaluator);
evaluatorChanged = true;
addEvaluatedRewardExpressions(stateActionRewards, successorProbability);
}
if (evaluatorChanged) {
// Restore the old state information
unpackStateIntoEvaluator(state, this->variableInformation, *this->evaluator);
@ -977,11 +992,18 @@ namespace storm {
storm::jani::RewardModelInformation info(this->model, rewardModel.second);
rewardModelInformation.emplace_back(rewardModel.first, info.hasStateRewards(), false, false);
STORM_LOG_THROW(this->options.isScaleAndLiftTransitionRewardsSet() || !info.hasTransitionRewards(), storm::exceptions::NotSupportedException, "Transition rewards are not supported and a reduction to action-based rewards was not possible.");
if (info.hasTransitionRewards()) {
evaluateRewardExpressionsAtDestinations = true;
}
if (info.hasActionRewards() || (this->options.isScaleAndLiftTransitionRewardsSet() && info.hasTransitionRewards())) {
hasStateActionRewards = true;
rewardModelInformation.back().setHasStateActionRewards();
}
}
if (!hasStateActionRewards) {
evaluateRewardExpressionsAtDestinations = false;
evaluateRewardExpressionsAtEdges = false;
}
}
template<typename ValueType, typename StateType>

6
src/storm/generator/JaniNextStateGenerator.h

@ -167,6 +167,12 @@ namespace storm {
/// A flag that stores whether at least one of the selected reward models has state-action rewards.
bool hasStateActionRewards;
/// A flag that stores whether we shall evaluate reward expressions at edges
bool evaluateRewardExpressionsAtEdges;
/// A flag that stores whether we shall evaluate reward expressions at edge destinations
bool evaluateRewardExpressionsAtDestinations;
/// Data from eliminated array expressions. These are required to keep references to array variables in LValues alive.
storm::jani::ArrayEliminatorData arrayEliminatorData;

2
src/storm/logic/EventuallyFormula.cpp

@ -57,10 +57,10 @@ namespace storm {
std::ostream& EventuallyFormula::writeToStream(std::ostream& out) const {
out << "F ";
this->getSubformula().writeToStream(out);
if (hasRewardAccumulation()) {
out << "[" << getRewardAccumulation() << "]";
}
this->getSubformula().writeToStream(out);
return out;
}
}

14
src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp

@ -310,13 +310,14 @@ namespace storm {
// Create solver.
storm::solver::GeneralMinMaxLinearEquationSolverFactory<ValueType> minMaxLinearEquationSolverFactory;
storm::solver::MinMaxLinearEquationSolverRequirements requirements = minMaxLinearEquationSolverFactory.getRequirements(env, true, dir);
storm::solver::MinMaxLinearEquationSolverRequirements requirements = minMaxLinearEquationSolverFactory.getRequirements(env, true, true, dir);
requirements.clearBounds();
STORM_LOG_THROW(!requirements.hasEnabledCriticalRequirement(), storm::exceptions::UncheckedRequirementException, "Solver requirements " + requirements.getEnabledRequirementsAsString() + " not checked.");
if (numberOfProbabilisticChoices > 0) {
solver = minMaxLinearEquationSolverFactory.create(env, probMatrix);
solver->setHasUniqueSolution();
solver->setHasNoEndComponents();
solver->setBounds(storm::utility::zero<ValueType>(), storm::utility::one<ValueType>());
solver->setRequirementsChecked();
solver->setCachingEnabled(true);
@ -486,14 +487,15 @@ namespace storm {
}
// Check for requirements of the solver.
// The solution is unique as we assume non-zeno MAs.
// The min-max system has no end components as we assume non-zeno MAs.
storm::solver::GeneralMinMaxLinearEquationSolverFactory<ValueType> minMaxLinearEquationSolverFactory;
storm::solver::MinMaxLinearEquationSolverRequirements requirements = minMaxLinearEquationSolverFactory.getRequirements(env, true, dir);
storm::solver::MinMaxLinearEquationSolverRequirements requirements = minMaxLinearEquationSolverFactory.getRequirements(env, true, true, dir);
requirements.clearBounds();
STORM_LOG_THROW(!requirements.hasEnabledCriticalRequirement(), storm::exceptions::UncheckedRequirementException, "Solver requirements " + requirements.getEnabledRequirementsAsString() + " not checked.");
std::unique_ptr<storm::solver::MinMaxLinearEquationSolver<ValueType>> solver = minMaxLinearEquationSolverFactory.create(env, aProbabilistic);
solver->setHasUniqueSolution();
solver->setHasNoEndComponents();
solver->setBounds(storm::utility::zero<ValueType>(), storm::utility::one<ValueType>());
solver->setRequirementsChecked();
solver->setCachingEnabled(true);
@ -819,12 +821,13 @@ namespace storm {
// Check for requirements of the solver.
storm::solver::GeneralMinMaxLinearEquationSolverFactory<ValueType> minMaxLinearEquationSolverFactory;
storm::solver::MinMaxLinearEquationSolverRequirements requirements = minMaxLinearEquationSolverFactory.getRequirements(underlyingSolverEnvironment, true, dir);
storm::solver::MinMaxLinearEquationSolverRequirements requirements = minMaxLinearEquationSolverFactory.getRequirements(underlyingSolverEnvironment, true, true, dir);
requirements.clearBounds();
STORM_LOG_THROW(!requirements.hasEnabledCriticalRequirement(), storm::exceptions::UncheckedRequirementException, "Solver requirements " + requirements.getEnabledRequirementsAsString() + " not checked.");
std::unique_ptr<storm::solver::MinMaxLinearEquationSolver<ValueType>> solver = minMaxLinearEquationSolverFactory.create(underlyingSolverEnvironment, sspMatrix);
solver->setHasUniqueSolution();
solver->setHasNoEndComponents();
solver->setLowerBound(storm::utility::zero<ValueType>());
solver->setUpperBound(*std::max_element(lraValuesForEndComponents.begin(), lraValuesForEndComponents.end()));
solver->setRequirementsChecked();
@ -1053,13 +1056,14 @@ namespace storm {
// Check for requirements of the solver.
// The solution is unique as we assume non-zeno MAs.
storm::solver::GeneralMinMaxLinearEquationSolverFactory<ValueType> minMaxLinearEquationSolverFactory;
storm::solver::MinMaxLinearEquationSolverRequirements requirements = minMaxLinearEquationSolverFactory.getRequirements(env, true, dir);
storm::solver::MinMaxLinearEquationSolverRequirements requirements = minMaxLinearEquationSolverFactory.getRequirements(env, true, true, dir);
requirements.clearLowerBounds();
STORM_LOG_THROW(!requirements.hasEnabledCriticalRequirement(), storm::exceptions::UncheckedRequirementException, "Solver requirements " + requirements.getEnabledRequirementsAsString() + " not checked.");
solver = minMaxLinearEquationSolverFactory.create(env, std::move(aProbabilistic));
solver->setLowerBound(storm::utility::zero<ValueType>());
solver->setHasUniqueSolution(true);
solver->setHasNoEndComponents(true);
solver->setRequirementsChecked(true);
solver->setCachingEnabled(true);
}

313
src/storm/modelchecker/multiobjective/deterministicScheds/DeterministicSchedsLpChecker.cpp

@ -9,6 +9,7 @@
#include "storm/settings/modules/MultiObjectiveSettings.h"
#include "storm/storage/SparseMatrix.h"
#include "storm/storage/MaximalEndComponentDecomposition.h"
#include "storm/storage/Scheduler.h"
#include "storm/utility/graph.h"
#include "storm/utility/solver.h"
@ -155,7 +156,7 @@ namespace storm {
std::vector<Point> foundPoints;
std::vector<Polytope> infeasableAreas;
checkRecursive(polytopeTree, eps, foundPoints, infeasableAreas, 0);
checkRecursive(env, polytopeTree, eps, foundPoints, infeasableAreas, 0);
swCheck.stop();
std::cout << " done!" << std::endl;
@ -202,91 +203,144 @@ namespace storm {
return processed;
}
template <typename ValueType>
std::map<uint64_t, storm::expressions::Expression> processEc(storm::storage::MaximalEndComponent const& ec, storm::storage::SparseMatrix<ValueType> const& transitions, std::string const& varNameSuffix, std::vector<storm::expressions::Expression> const& choiceVars, storm::solver::LpSolver<ValueType>& lpModel) {
std::map<uint64_t, storm::expressions::Expression> ecStateVars, ecChoiceVars, ecFlowChoiceVars;
// Compute an upper bound on the expected number of visits of the states in this ec.
// First get a lower bound l on the probability of a path that leaves this MEC. 1-l is an upper bound on Pr_s(X F s).
// The desired upper bound is thus 1/(1-(1-l)) = 1/l. See Baier et al., CAV'17
ValueType expVisitsUpperBound = storm::utility::one<ValueType>();
uint64_t numStates = 0;
for (auto const& stateChoices : ec) {
++numStates;
ValueType minProb = storm::utility::one<ValueType>();
for (auto const& choice : stateChoices.second) {
for (auto const& transition : transitions.getRow(choice)) {
if (!storm::utility::isZero(transition.getValue())) {
minProb = std::min(minProb, transition.getValue());
}
}
}
expVisitsUpperBound *= minProb;
}
expVisitsUpperBound = storm::utility::one<ValueType>() / expVisitsUpperBound;
std::cout << "expVisits upper bound is " << expVisitsUpperBound << "." << std::endl;
// create variables
for (auto const& stateChoices : ec) {
ecStateVars.emplace(stateChoices.first, lpModel.addBoundedIntegerVariable("e" + std::to_string(stateChoices.first) + varNameSuffix, storm::utility::zero<ValueType>(), storm::utility::one<ValueType>()).getExpression());
for (auto const& choice : stateChoices.second) {
ecChoiceVars.emplace(choice, lpModel.addBoundedIntegerVariable("ec" + std::to_string(choice) + varNameSuffix, storm::utility::zero<ValueType>(), storm::utility::one<ValueType>()).getExpression());
ecFlowChoiceVars.emplace(choice, lpModel.addBoundedContinuousVariable("f" + std::to_string(choice) + varNameSuffix, storm::utility::zero<ValueType>(), expVisitsUpperBound).getExpression());
}
}
// create constraints
std::map<uint64_t, std::vector<storm::expressions::Expression>> ins, outs;
for (auto const& stateChoices : ec) {
std::vector<storm::expressions::Expression> ecChoiceVarsAtState;
std::vector<storm::expressions::Expression> out;
for (auto const& choice : stateChoices.second) {
if (choiceVars[choice].isInitialized()) {
lpModel.addConstraint("", ecChoiceVars[choice] <= choiceVars[choice]);
lpModel.addConstraint("", ecFlowChoiceVars[choice] <= lpModel.getConstant(expVisitsUpperBound) * choiceVars[choice]);
}
ecChoiceVarsAtState.push_back(ecChoiceVars[choice]);
out.push_back(ecFlowChoiceVars[choice]);
for (auto const& transition : transitions.getRow(choice)) {
if (!storm::utility::isZero(transition.getValue())) {
lpModel.addConstraint("", ecChoiceVars[choice] <= ecStateVars[transition.getColumn()]);
ins[transition.getColumn()].push_back(lpModel.getConstant(transition.getValue()) * ecFlowChoiceVars[choice]);
}
}
}
lpModel.addConstraint("", ecStateVars[stateChoices.first] == storm::expressions::sum(ecChoiceVarsAtState));
out.push_back(lpModel.getConstant(expVisitsUpperBound) * ecStateVars[stateChoices.first]);
// Iterate over choices that leave the ec
for (uint64_t choice = transitions.getRowGroupIndices()[stateChoices.first]; choice < transitions.getRowGroupIndices()[stateChoices.first + 1]; ++choice) {
if (stateChoices.second.find(choice) == stateChoices.second.end()) {
assert(choiceVars[choice].isInitialized());
out.push_back(lpModel.getConstant(expVisitsUpperBound) * choiceVars[choice]);
}
}
outs.emplace(stateChoices.first, out);
}
for (auto const& stateChoices : ec) {
auto in = ins.find(stateChoices.first);
STORM_LOG_ASSERT(in != ins.end(), "ec state does not seem to have an incoming transition.");
// Assume a uniform initial distribution
in->second.push_back(lpModel.getConstant(storm::utility::one<ValueType>() / storm::utility::convertNumber<ValueType>(numStates)));
auto out = outs.find(stateChoices.first);
STORM_LOG_ASSERT(out != outs.end(), "out flow of ec state was not set.");
lpModel.addConstraint("", storm::expressions::sum(in->second)<= storm::expressions::sum(out->second));
}
return ecStateVars;
}
template <typename ModelType, typename GeometryValueType>
std::vector<std::vector<storm::expressions::Variable>> DeterministicSchedsLpChecker<ModelType, GeometryValueType>::createEcVariables(std::vector<storm::expressions::Expression> const& choiceVars) {
auto one = lpModel->getConstant(storm::utility::one<ValueType>());
std::vector<std::vector<storm::expressions::Variable>> result(model.getNumberOfStates());
storm::storage::MaximalEndComponentDecomposition<ValueType> mecs(model);
std::vector<std::vector<storm::expressions::Expression>> DeterministicSchedsLpChecker<ModelType, GeometryValueType>::createEcVariables() {
std::vector<std::vector<storm::expressions::Expression>> result(objectiveHelper.size(), std::vector<storm::expressions::Expression>(model.getNumberOfStates()));
uint64_t ecCounter = 0;
auto backwardTransitions = model.getBackwardTransitions();
// Get the choices that do not induce a value (i.e. reward) for all objectives
storm::storage::BitVector choicesWithValueZero(model.getNumberOfChoices(), true);
for (auto const& objHelper : objectiveHelper) {
for (auto const& value : objHelper.getChoiceValueOffsets()) {
STORM_LOG_ASSERT(!storm::utility::isZero(value.second), "Expected non-zero choice-value offset.");
choicesWithValueZero.set(value.first, false);
}
}
storm::storage::MaximalEndComponentDecomposition<ValueType> mecs(model.getTransitionMatrix(), backwardTransitions, storm::storage::BitVector(model.getNumberOfStates(), true), choicesWithValueZero);
for (auto const& mec : mecs) {
// Create a submatrix for the current mec as well as a mapping to map back to the original states.
storm::storage::BitVector mecStatesAsBitVector(model.getNumberOfStates(), false);
storm::storage::BitVector mecChoicesAsBitVector(model.getNumberOfChoices(), false);
for (auto const& stateChoices : mec) {
mecStatesAsBitVector.set(stateChoices.first, true);
for (auto const& choice : stateChoices.second) {
mecChoicesAsBitVector.set(choice, true);
std::map<std::set<uint64_t>, std::vector<uint64_t>> excludedStatesToObjIndex;
for (uint64_t objIndex = 0; objIndex < objectiveHelper.size(); ++objIndex) {
std::set<uint64_t> excludedStates;
for (auto const& stateChoices : mec) {
auto schedIndValueIt = objectiveHelper[objIndex].getSchedulerIndependentStateValues().find(stateChoices.first);
if (schedIndValueIt != objectiveHelper[objIndex].getSchedulerIndependentStateValues().end() && !storm::utility::isZero(schedIndValueIt->second)) {
excludedStates.insert(stateChoices.first);
}
}
excludedStatesToObjIndex[excludedStates].push_back(objIndex);
}
std::vector<uint64_t> toGlobalStateIndexMapping(mecStatesAsBitVector.begin(), mecStatesAsBitVector.end());
std::vector<uint64_t> toGlobalChoiceIndexMapping(mecChoicesAsBitVector.begin(), mecChoicesAsBitVector.end());
//std::cout << "mec choices of ec" << ecCounter << ": " << mecChoicesAsBitVector << std::endl;
storm::storage::SparseMatrix<ValueType> mecTransitions = model.getTransitionMatrix().getSubmatrix(false, mecChoicesAsBitVector, mecStatesAsBitVector);
// Create a variable for each subEC and add it for the corresponding states.
// Also assert that not every state takes an ec choice.
auto subEcs = getSubEndComponents(mecTransitions);
for (auto const& subEc : subEcs) {
// get the choices of the current EC with some non-zero value (i.e. reward).
// std::cout << "sub ec choices of ec" << ecCounter << ": " << subEc.second << std::endl;
storm::storage::BitVector subEcChoicesWithValueZero = subEc.second;
for (auto const& localSubEcChoiceIndex : subEc.second) {
uint64_t subEcChoice = toGlobalChoiceIndexMapping[localSubEcChoiceIndex];
for (auto const& objHelper : objectiveHelper) {
if (objHelper.getChoiceValueOffsets().count(subEcChoice) > 0) {
STORM_LOG_ASSERT(!storm::utility::isZero(objHelper.getChoiceValueOffsets().at(subEcChoice)), "Expected non-zero choice-value offset.");
subEcChoicesWithValueZero.set(localSubEcChoiceIndex, false);
break;
for (auto const& exclStates : excludedStatesToObjIndex) {
if (exclStates.first.empty()) {
auto ecVars = processEc(mec, model.getTransitionMatrix(), "", choiceVariables, *lpModel);
++ecCounter;
for (auto const& stateVar : ecVars) {
for (auto const& objIndex : exclStates.second) {
result[objIndex][stateVar.first] = stateVar.second;
}
}
}
// Check whether each state has at least one zero-valued choice
bool zeroValueSubEc = true;
for (auto const& state : subEc.first) {
if (subEcChoicesWithValueZero.getNextSetIndex(mecTransitions.getRowGroupIndices()[state]) >= mecTransitions.getRowGroupIndices()[state + 1]) {
zeroValueSubEc = false;
break;
}
}
if (zeroValueSubEc) {
// Create a variable that is one iff upon entering this subEC no more choice value is collected.
auto ecVar = lpModel->addBoundedIntegerVariable("ec" + std::to_string(ecCounter++), storm::utility::zero<ValueType>(), storm::utility::one<ValueType>());
// assign this variable to every state in the ec
for (auto const& localSubEcStateIndex : subEc.first) {
uint64_t subEcState = toGlobalStateIndexMapping[localSubEcStateIndex];
result[subEcState].push_back(ecVar);
}
// Create the sum over all choice vars that induce zero choice value
std::vector<storm::expressions::Expression> ecChoiceVars;
uint64_t numSubEcStatesWithMultipleChoices = subEc.first.getNumberOfSetBits();
for (auto const& localSubEcChoiceIndex : subEcChoicesWithValueZero) {
uint64_t subEcChoice = toGlobalChoiceIndexMapping[localSubEcChoiceIndex];
if (choiceVars[subEcChoice].isInitialized()) {
ecChoiceVars.push_back(choiceVars[subEcChoice]);
} else {
// If there is no choiceVariable, it means that this corresponds to a state with just one choice.
assert(numSubEcStatesWithMultipleChoices > 0);
--numSubEcStatesWithMultipleChoices;
} else {
// Compute sub-end components
storm::storage::BitVector subEcStates(model.getNumberOfStates(), false), subEcChoices(model.getNumberOfChoices(), false);
for (auto const& stateChoices : mec) {
if (exclStates.first.count(stateChoices.first) == 0) {
subEcStates.set(stateChoices.first, true);
for (auto const& choice : stateChoices.second) {
subEcChoices.set(choice, true);
}
}
}
// Assert that the ecVar is one iff the sum over the zero-value-choice variables equals the number of states in this ec
storm::expressions::Expression ecVarBound = one - lpModel->getConstant(storm::utility::convertNumber<ValueType>(numSubEcStatesWithMultipleChoices)).simplify();
if (!ecChoiceVars.empty()) {
ecVarBound = ecVarBound + storm::expressions::sum(ecChoiceVars);
}
if (inOutEncoding()) {
lpModel->addConstraint("", ecVar <= ecVarBound);
} else {
lpModel->addConstraint("", ecVar >= ecVarBound);
storm::storage::MaximalEndComponentDecomposition<ValueType> subEcs(model.getTransitionMatrix(), backwardTransitions, subEcStates, subEcChoices);
for (auto const& subEc : subEcs) {
auto ecVars = processEc(subEc, model.getTransitionMatrix(), "o" + std::to_string(*exclStates.second.begin()), choiceVariables, *lpModel);
++ecCounter;
for (auto const& stateVar : ecVars) {
for (auto const& objIndex : exclStates.second) {
result[objIndex][stateVar.first] = stateVar.second;
}
}
}
}
}
}
STORM_LOG_TRACE("Found " << ecCounter << " end components.");
std::cout << "found " << ecCounter << "many ECs" << std::endl;
return result;
}
@ -306,12 +360,11 @@ namespace storm {
auto one = lpModel->getConstant(storm::utility::one<ValueType>());
auto const& groups = model.getTransitionMatrix().getRowGroupIndices();
// Create choice variables.
std::vector<storm::expressions::Expression> choiceVars;
choiceVars.reserve(model.getNumberOfChoices());
choiceVariables.reserve(model.getNumberOfChoices());
for (uint64_t state = 0; state < numStates; ++state) {
uint64_t numChoices = model.getNumberOfChoices(state);
if (numChoices == 1) {
choiceVars.emplace_back();
choiceVariables.emplace_back();
} else {
std::vector<storm::expressions::Expression> localChoices;
if (choiceVarReduction()) {
@ -319,23 +372,28 @@ namespace storm {
}
for (uint64_t choice = 0; choice < numChoices; ++choice) {
localChoices.push_back(lpModel->addBoundedIntegerVariable("c" + std::to_string(state) + "_" + std::to_string(choice), 0, 1).getExpression());
choiceVars.push_back(localChoices.back());
choiceVariables.push_back(localChoices.back());
}
storm::expressions::Expression localChoicesSum = storm::expressions::sum(localChoices);
if (choiceVarReduction()) {
lpModel->addConstraint("", localChoicesSum <= one);
choiceVars.push_back(one - localChoicesSum);
choiceVariables.push_back(one - localChoicesSum);
} else {
lpModel->addConstraint("", localChoicesSum == one);
}
}
}
// Create ec Variables and assert for each sub-ec that not all choice variables stay there
auto ecVars = createEcVariables(choiceVars);
// Create ec Variables for each state/objective
auto ecVars = createEcVariables();
bool hasEndComponents = false;
for (auto const& stateEcVars : ecVars) {
if (!stateEcVars.empty()) {
hasEndComponents = true;
for (auto const& objEcVars : ecVars) {
for (auto const& ecVar : objEcVars) {
if (ecVar.isInitialized()) {
hasEndComponents = true;
break;
}
}
if (hasEndComponents) {
break;
}
}
@ -365,7 +423,7 @@ namespace storm {
for (uint64_t globalChoice = groups[state]; globalChoice < groups[state + 1]; ++globalChoice) {
choiceValVars[globalChoice] = lpModel->addBoundedContinuousVariable("y" + std::to_string(globalChoice), storm::utility::zero<ValueType>(), visitingTimesUpperBounds[state]).getExpression();
if (model.getNumberOfChoices(state) > 1) {;
lpModel->addConstraint("", choiceValVars[globalChoice] <= lpModel->getConstant(visitingTimesUpperBounds[state]) * choiceVars[globalChoice]);
lpModel->addConstraint("", choiceValVars[globalChoice] <= lpModel->getConstant(visitingTimesUpperBounds[state]) * choiceVariables[globalChoice]);
}
}
}
@ -373,13 +431,10 @@ namespace storm {
std::vector<storm::expressions::Expression> ecValVars(model.getNumberOfStates());
if (hasEndComponents) {
for (auto const& state : nonBottomStates) {
if (!ecVars[state].empty()) {
// For the in-out-encoding, all objectives have the same ECs. Hence, we only care for the variables of the first objective.
if (ecVars.front()[state].isInitialized()) {
ecValVars[state] = lpModel->addBoundedContinuousVariable("z" + std::to_string(state), storm::utility::zero<ValueType>(), visitingTimesUpperBounds[state]).getExpression();
std::vector<storm::expressions::Expression> ecValueSum;
for (auto const& ecVar : ecVars[state]) {
ecValueSum.push_back(lpModel->getConstant(visitingTimesUpperBounds[state]) * ecVar.getExpression());
}
lpModel->addConstraint("", ecValVars[state] <= storm::expressions::sum(ecValueSum));
lpModel->addConstraint("", ecValVars[state] <= lpModel->getConstant(visitingTimesUpperBounds[state]) * ecVars.front()[state]);
}
}
}
@ -439,7 +494,6 @@ namespace storm {
auto const& schedulerIndependentStates = objectiveHelper[objIndex].getSchedulerIndependentStateValues();
// Create state variables and store variables of ecs which contain a state with a scheduler independent value
std::vector<storm::expressions::Expression> stateVars;
std::set<storm::expressions::Variable> ecVarsWithValue;
stateVars.reserve(numStates);
for (uint64_t state = 0; state < numStates; ++state) {
auto valIt = schedulerIndependentStates.find(state);
@ -455,11 +509,6 @@ namespace storm {
value = -value;
}
stateVars.push_back(lpModel->getConstant(value));
if (hasEndComponents) {
for (auto const& ecVar : ecVars[state]) {
ecVarsWithValue.insert(ecVar);
}
}
}
if (state == initialState) {
initialStateResults.push_back(stateVars.back());
@ -500,7 +549,7 @@ namespace storm {
} else {
uint64_t globalChoiceIndex = groups[state] + choice;
if (isMaxDiffEncoding()) {
storm::expressions::Expression maxDiff = upperValueBoundAtState * (one - choiceVars[globalChoiceIndex]);
storm::expressions::Expression maxDiff = upperValueBoundAtState * (one - choiceVariables[globalChoiceIndex]);
if (objectiveHelper[objIndex].minimizing()) {
lpModel->addConstraint("", stateVars[state] >= choiceValue - maxDiff);
} else {
@ -517,14 +566,14 @@ namespace storm {
if (objectiveHelper[objIndex].minimizing()) {
if (isMinNegativeEncoding()) {
lpModel->addConstraint("", choiceValVar <= choiceValue);
lpModel->addConstraint("", choiceValVar <= -upperValueBoundAtState * (one - choiceVars[globalChoiceIndex]));
lpModel->addConstraint("", choiceValVar <= -upperValueBoundAtState * (one - choiceVariables[globalChoiceIndex]));
} else {
lpModel->addConstraint("", choiceValVar + (upperValueBoundAtState * (one - choiceVars[globalChoiceIndex])) >= choiceValue);
lpModel->addConstraint("", choiceValVar + (upperValueBoundAtState * (one - choiceVariables[globalChoiceIndex])) >= choiceValue);
// Optional: lpModel->addConstraint("", choiceValVar <= choiceValue);
}
} else {
lpModel->addConstraint("", choiceValVar <= choiceValue);
lpModel->addConstraint("", choiceValVar <= upperValueBoundAtState * choiceVars[globalChoiceIndex]);
lpModel->addConstraint("", choiceValVar <= upperValueBoundAtState * choiceVariables[globalChoiceIndex]);
}
if (choice == 0) {
stateValue = choiceValVar;
@ -543,34 +592,31 @@ namespace storm {
} else {
lpModel->addConstraint("", stateVars[state] <= stateValue);
}
if (numChoices > 1) {
for (auto const& ecVar : ecVars[state]) {
if (ecVarsWithValue.count(ecVar) == 0) {
// if this ec is taken, make sure to assign a value of zero
if (objectiveHelper[objIndex].minimizing()) {
// TODO: these are optional
if (isMinNegativeEncoding()) {
lpModel->addConstraint("", stateVars[state] >= (ecVar.getExpression() - one) * lpModel->getConstant(objectiveHelper[objIndex].getUpperValueBoundAtState(env, state)));
} else {
lpModel->addConstraint("", stateVars[state] <= (one - ecVar.getExpression()) * lpModel->getConstant(objectiveHelper[objIndex].getUpperValueBoundAtState(env, state)));
}
if (numChoices > 1 && hasEndComponents) {
auto& ecVar = ecVars[objIndex][state];
if (ecVar.isInitialized()) {
// if this state is part of an ec, make sure to assign a value of zero.
if (objectiveHelper[objIndex].minimizing()) {
// TODO: these are optional
if (isMinNegativeEncoding()) {
lpModel->addConstraint("", stateVars[state] >= (ecVar - one) * lpModel->getConstant(objectiveHelper[objIndex].getUpperValueBoundAtState(env, state)));
} else {
lpModel->addConstraint("", stateVars[state] <= (one - ecVar.getExpression()) * lpModel->getConstant(objectiveHelper[objIndex].getUpperValueBoundAtState(env, state)));
lpModel->addConstraint("", stateVars[state] <= (one - ecVar) * lpModel->getConstant(objectiveHelper[objIndex].getUpperValueBoundAtState(env, state)));
}
} else {
lpModel->addConstraint("", stateVars[state] <= (one - ecVar) * lpModel->getConstant(objectiveHelper[objIndex].getUpperValueBoundAtState(env, state)));
}
}
}
}
}
}
swAux.start();
lpModel->update();
swAux.stop();
STORM_LOG_INFO("Done initializing LP model.");
}
template <typename ModelType, typename GeometryValueType>
void DeterministicSchedsLpChecker<ModelType, GeometryValueType>::checkRecursive(storm::storage::geometry::PolytopeTree <GeometryValueType>& polytopeTree, GeometryValueType const& eps, std::vector<Point>& foundPoints, std::vector<Polytope>& infeasableAreas, uint64_t const& depth) {
void DeterministicSchedsLpChecker<ModelType, GeometryValueType>::checkRecursive(Environment const& env, storm::storage::geometry::PolytopeTree <GeometryValueType>& polytopeTree, GeometryValueType const& eps, std::vector<Point>& foundPoints, std::vector<Polytope>& infeasableAreas, uint64_t const& depth) {
std::cout << ".";
std::cout.flush();
STORM_LOG_ASSERT(!polytopeTree.isEmpty(), "Tree node is empty");
@ -602,6 +648,8 @@ namespace storm {
polytopeTree.clear();
} else {
STORM_LOG_ASSERT(!lpModel->isUnbounded(), "LP result is unbounded.");
// TODO: only for debugging
validateCurrentModel(env);
Point newPoint;
for (auto const& objVar : currentObjectiveVariables) {
newPoint.push_back(storm::utility::convertNumber<GeometryValueType>(lpModel->getContinuousValue(objVar)));
@ -642,14 +690,14 @@ namespace storm {
}
swAux.stop();
if (!polytopeTree.isEmpty()) {
checkRecursive(polytopeTree, eps, foundPoints, infeasableAreas, depth);
checkRecursive(env, polytopeTree, eps, foundPoints, infeasableAreas, depth);
}
}
} else {
// Traverse all the children.
for (uint64_t childId = 0; childId < polytopeTree.getChildren().size(); ++childId) {
uint64_t newPointIndex = foundPoints.size();
checkRecursive(polytopeTree.getChildren()[childId], eps, foundPoints, infeasableAreas, depth + 1);
checkRecursive(env, polytopeTree.getChildren()[childId], eps, foundPoints, infeasableAreas, depth + 1);
STORM_LOG_ASSERT(polytopeTree.getChildren()[childId].isEmpty(), "expected empty children.");
// Make the new points known to the right siblings
for (; newPointIndex < foundPoints.size(); ++newPointIndex) {
@ -669,6 +717,41 @@ namespace storm {
swLpBuild.stop();
}
template <typename ModelType, typename GeometryValueType>
void DeterministicSchedsLpChecker<ModelType, GeometryValueType>::validateCurrentModel(Environment const& env) const {
storm::storage::Scheduler<ValueType> scheduler(model.getNumberOfStates());
for (uint64_t state = 0; state < model.getNumberOfStates(); ++state) {
uint64_t numChoices = model.getNumberOfChoices(state);
if (numChoices == 1) {
scheduler.setChoice(0, state);
} else {
uint64_t globalChoiceOffset = model.getTransitionMatrix().getRowGroupIndices()[state];
bool choiceFound = false;
for (uint64_t localChoice = 0; localChoice < numChoices; ++localChoice) {
if (lpModel->getIntegerValue(choiceVariables[globalChoiceOffset + localChoice].getBaseExpression().asVariableExpression().getVariable()) == 1) {
STORM_LOG_THROW(!choiceFound, storm::exceptions::UnexpectedException, "Multiple choices selected at state " << state);
scheduler.setChoice(localChoice, state);
choiceFound = true;
}
}
STORM_LOG_THROW(choiceFound, storm::exceptions::UnexpectedException, "No choice selected at state " << state);
}
}
auto inducedModel = model.applyScheduler(scheduler)->template as<ModelType>();
for (uint64_t objIndex = 0; objIndex < objectiveHelper.size(); ++objIndex) {
ValueType expectedValue = lpModel->getContinuousValue(currentObjectiveVariables[objIndex]);
if (objectiveHelper[objIndex].minimizing()) {
expectedValue = -expectedValue;
}
ValueType actualValue = objectiveHelper[objIndex].evaluateOnModel(env, *inducedModel);
std::cout << "obj" << objIndex << ": LpSolver: " << storm::utility::convertNumber<double>(expectedValue) << " (" << expectedValue << ")" << std::endl;
std::cout << "obj" << objIndex << ": model checker: " << storm::utility::convertNumber<double>(actualValue) << " (" << actualValue << ")" << std::endl;
STORM_LOG_THROW(storm::utility::convertNumber<double>(storm::utility::abs<ValueType>(actualValue - expectedValue)) <= 1e-4, storm::exceptions::UnexpectedException, "Invalid value for objective " << objIndex << ": expected " << expectedValue << " but got " << actualValue);
}
std::cout << std::endl;
}
template class DeterministicSchedsLpChecker<storm::models::sparse::Mdp<double>, storm::RationalNumber>;
template class DeterministicSchedsLpChecker<storm::models::sparse::Mdp<storm::RationalNumber>, storm::RationalNumber>;
template class DeterministicSchedsLpChecker<storm::models::sparse::MarkovAutomaton<double>, storm::RationalNumber>;

10
src/storm/modelchecker/multiobjective/deterministicScheds/DeterministicSchedsLpChecker.h

@ -46,18 +46,20 @@ namespace storm {
std::pair<std::vector<Point>, std::vector<Polytope>> check(storm::Environment const& env, storm::storage::geometry::PolytopeTree<GeometryValueType>& polytopeTree, GeometryValueType const& eps);
private:
std::vector<std::vector<storm::expressions::Variable>> createEcVariables(std::vector<storm::expressions::Expression> const& choiceVars);
std::vector<std::vector<storm::expressions::Expression>> createEcVariables();
void initializeLpModel(Environment const& env);
void checkRecursive(storm::storage::geometry::PolytopeTree<GeometryValueType>& polytopeTree, GeometryValueType const& eps, std::vector<Point>& foundPoints, std::vector<Polytope>& infeasableAreas, uint64_t const& depth);
// Builds the induced markov chain of the current model and checks whether the resulting value coincide with the result of the lp solver.
void validateCurrentModel(Environment const& env) const;
void checkRecursive(storm::Environment const& env, storm::storage::geometry::PolytopeTree<GeometryValueType>& polytopeTree, GeometryValueType const& eps, std::vector<Point>& foundPoints, std::vector<Polytope>& infeasableAreas, uint64_t const& depth);
ModelType const& model;
std::vector<DeterministicSchedsObjectiveHelper<ModelType>> const& objectiveHelper;
std::unique_ptr<storm::solver::LpSolver<ValueType>> lpModel;
storm::solver::GurobiLpSolver<ValueType>* gurobiLpModel;
std::vector<storm::expressions::Expression> choiceVariables;
std::vector<storm::expressions::Expression> initialStateResults;
std::vector<storm::expressions::Variable> currentObjectiveVariables;
std::vector<GeometryValueType> currentWeightVector;

4
src/storm/modelchecker/multiobjective/deterministicScheds/DeterministicSchedsObjectiveHelper.cpp

@ -333,6 +333,10 @@ namespace storm {
return visitingTimesUpperBounds;
}
template <typename ModelType>
typename ModelType::ValueType DeterministicSchedsObjectiveHelper<ModelType>::evaluateOnModel(Environment const& env, ModelType const& evaluatedModel) const {
return evaluateOperatorFormula(env, evaluatedModel, *objective.formula)[*evaluatedModel.getInitialStates().begin()];
}
template class DeterministicSchedsObjectiveHelper<storm::models::sparse::Mdp<double>>;
template class DeterministicSchedsObjectiveHelper<storm::models::sparse::Mdp<storm::RationalNumber>>;

2
src/storm/modelchecker/multiobjective/deterministicScheds/DeterministicSchedsObjectiveHelper.h

@ -44,6 +44,8 @@ namespace storm {
*/
bool isTotalRewardObjective() const;
ValueType evaluateOnModel(Environment const& env, ModelType const& evaluatedModel) const;
static std::vector<ValueType> computeUpperBoundOnExpectedVisitingTimes(storm::storage::SparseMatrix<ValueType> const& modelTransitions, storm::storage::BitVector const& bottomStates, storm::storage::BitVector const& nonBottomStates, bool hasEndComponents);
private:

2
src/storm/modelchecker/multiobjective/deterministicScheds/DeterministicSchedsParetoExplorer.cpp

@ -426,7 +426,7 @@ namespace storm {
f.addPoint(p.first, p.second);
}
}
STORM_LOG_ASSERT(std::count(f.getHalfspace().normalVector().begin(), f.getHalfspace().normalVector().end(), storm::utility::zero<GeometryValueType>()) + f.getNumberOfPoints() == objectives.size(), "Unexpected number of points on facet.");
STORM_LOG_ASSERT(std::count(f.getHalfspace().normalVector().begin(), f.getHalfspace().normalVector().end(), storm::utility::zero<GeometryValueType>()) + f.getNumberOfPoints() >= objectives.size(), "Not enough points on facet.");
unprocessedFacets.push(std::move(f));
}

1
src/storm/modelchecker/multiobjective/pcaa/RewardBoundedMdpPcaaWeightVectorChecker.cpp

@ -320,6 +320,7 @@ namespace storm {
storm::solver::GeneralMinMaxLinearEquationSolverFactory<ValueType> minMaxSolverFactory;
cachedData.minMaxSolver = minMaxSolverFactory.create(env, epochModel.epochMatrix);
cachedData.minMaxSolver->setHasUniqueSolution();
cachedData.minMaxSolver->setHasNoEndComponents();
cachedData.minMaxSolver->setTrackScheduler(true);
cachedData.minMaxSolver->setCachingEnabled(true);
auto req = cachedData.minMaxSolver->getRequirements(env);

1
src/storm/modelchecker/multiobjective/pcaa/StandardMaPcaaWeightVectorChecker.cpp

@ -301,6 +301,7 @@ namespace storm {
storm::solver::GeneralMinMaxLinearEquationSolverFactory<ValueType> minMaxSolverFactory;
result->solver = minMaxSolverFactory.create(env, PS.toPS);
result->solver->setHasUniqueSolution(true);
result->solver->setHasNoEndComponents(true); // Non-zeno MA
result->solver->setTrackScheduler(true);
result->solver->setCachingEnabled(true);
auto req = result->solver->getRequirements(env, storm::solver::OptimizationDirection::Maximize, false);

48
src/storm/modelchecker/multiobjective/pcaa/StandardPcaaWeightVectorChecker.cpp

@ -163,6 +163,50 @@ namespace storm {
return result;
}
template <typename ValueType>
std::vector<uint64_t> computeValidInitialScheduler(storm::storage::SparseMatrix<ValueType> const& matrix, storm::storage::BitVector const& rowsWithSumLessOne) {
std::vector<uint64_t> result(matrix.getRowGroupCount());
auto const& groups = matrix.getRowGroupIndices();
auto backwardsTransitions = matrix.transpose(true);
storm::storage::BitVector processedStates(result.size(), false);
for (uint64_t state = 0; state < result.size(); ++state) {
if (rowsWithSumLessOne.getNextSetIndex(groups[state]) < groups[state + 1]) {
result[state] = rowsWithSumLessOne.getNextSetIndex(groups[state]) - groups[state];
processedStates.set(state, true);
}
}
std::vector<uint64_t> stack(processedStates.begin(), processedStates.end());
while (!stack.empty()) {
uint64_t current = stack.back();
stack.pop_back();
STORM_LOG_ASSERT(processedStates.get(current), "states on the stack shall be processed.");
for (auto const& entry : backwardsTransitions.getRow(current)) {
uint64_t pred = entry.getColumn();
if (!processedStates.get(pred)) {
// Find a choice that leads to a processed state
uint64_t predChoice = groups[pred];
bool foundSuccessor = false;
for (; predChoice < groups[pred + 1]; ++predChoice) {
for (auto const& predEntry : matrix.getRow(predChoice)) {
if (processedStates.get(predEntry.getColumn())) {
foundSuccessor = true;
break;
}
}
if (foundSuccessor) {
break;
}
}
STORM_LOG_ASSERT(foundSuccessor && predChoice < groups[pred + 1], "Predecessor of a processed state should have a processed successor");
result[pred] = predChoice - groups[pred];
processedStates.set(pred, true);
stack.push_back(pred);
}
}
}
return result;
}
template <class SparseModelType>
void StandardPcaaWeightVectorChecker<SparseModelType>::unboundedWeightedPhase(Environment const& env, std::vector<ValueType> const& weightedRewardVector, std::vector<ValueType> const& weightVector) {
@ -189,6 +233,10 @@ namespace storm {
if (solver->hasUpperBound()) {
req.clearUpperBounds();
}
if (req.validInitialScheduler()) {
solver->setInitialScheduler(computeValidInitialScheduler(ecQuotient->matrix, ecQuotient->rowsWithSumLessOne));
req.clearValidInitialScheduler();
}
STORM_LOG_THROW(!req.hasEnabledCriticalRequirement(), storm::exceptions::UncheckedRequirementException, "Solver requirements " + req.getEnabledRequirementsAsString() + " not checked.");
solver->setRequirementsChecked(true);

52
src/storm/modelchecker/prctl/helper/HybridMdpPrctlHelper.cpp

@ -146,22 +146,23 @@ namespace storm {
} else {
// If there are maybe states, we need to solve an equation system.
if (!maybeStates.isZero()) {
// If we minimize, we know that the solution to the equation system is unique.
bool uniqueSolution = dir == storm::solver::OptimizationDirection::Minimize;
// If we minimize, we know that the solution to the equation system has no end components
bool hasNoEndComponents = dir == storm::solver::OptimizationDirection::Minimize;
// Check for requirements of the solver early so we can adjust the maybe state computation accordingly.
storm::solver::GeneralMinMaxLinearEquationSolverFactory<ValueType> linearEquationSolverFactory;
storm::solver::MinMaxLinearEquationSolverRequirements requirements = linearEquationSolverFactory.getRequirements(env, uniqueSolution, dir);
storm::solver::MinMaxLinearEquationSolverRequirements requirements = linearEquationSolverFactory.getRequirements(env, hasNoEndComponents, hasNoEndComponents, dir);
storm::solver::MinMaxLinearEquationSolverRequirements clearedRequirements = requirements;
SolverRequirementsData<ValueType> solverRequirementsData;
bool extendMaybeStates = false;
if (clearedRequirements.hasEnabledRequirement()) {
if (clearedRequirements.noEndComponents()) {
STORM_LOG_DEBUG("Scheduling EC elimination, because the solver requires it.");
if (clearedRequirements.uniqueSolution()) {
STORM_LOG_DEBUG("Scheduling EC elimination, because the solver requires a unique solution.");
extendMaybeStates = true;
clearedRequirements.clearNoEndComponents();
clearedRequirements.clearUniqueSolution();
hasNoEndComponents = true;
}
if (clearedRequirements.validInitialScheduler()) {
if (clearedRequirements.validInitialScheduler() && !hasNoEndComponents) {
STORM_LOG_DEBUG("Scheduling valid scheduler computation, because the solver requires it.");
clearedRequirements.clearValidInitialScheduler();
}
@ -210,8 +211,6 @@ namespace storm {
// Eliminate the end components and remove the states that are not interesting (target or non-filter).
eliminateEndComponentsAndExtendedStatesUntilProbabilities(explicitRepresentation, solverRequirementsData, targetStates);
// The solution becomes unique after end components have been eliminated.
uniqueSolution = true;
} else {
// Then compute the vector that contains the one-step probabilities to a state with probability 1 for all
// maybe states.
@ -240,8 +239,9 @@ namespace storm {
std::unique_ptr<storm::solver::MinMaxLinearEquationSolver<ValueType>> solver = linearEquationSolverFactory.create(env, std::move(explicitRepresentation.first));
// Set whether the equation system will have a unique solution
solver->setHasUniqueSolution(uniqueSolution);
// Set whether the equation system will have a unique solution / no end components
solver->setHasUniqueSolution(hasNoEndComponents);
solver->setHasNoEndComponents(hasNoEndComponents);
if (solverRequirementsData.initialScheduler) {
solver->setInitialScheduler(std::move(solverRequirementsData.initialScheduler.get()));
@ -251,7 +251,7 @@ namespace storm {
solver->solveEquations(env, dir, x, explicitRepresentation.second);
// If we included some target and non-filter states in the ODD, we need to expand the result from the solver.
if (requirements.noEndComponents() && solverRequirementsData.ecInformation) {
if (requirements.uniqueSolution() && solverRequirementsData.ecInformation) {
std::vector<ValueType> extendedVector(solverRequirementsData.properMaybeStates.getNumberOfSetBits());
solverRequirementsData.ecInformation.get().setValues(extendedVector, solverRequirementsData.properMaybeStates, x);
x = std::move(extendedVector);
@ -543,17 +543,20 @@ namespace storm {
// If there are maybe states, we need to solve an equation system.
if (!maybeStates.isZero()) {
// If we maximize, we know that the solution to the equation system is unique.
bool uniqueSolution = dir == storm::solver::OptimizationDirection::Maximize;
bool hasNoEndComponents = dir == storm::solver::OptimizationDirection::Maximize;
bool hasUniqueSolution = hasNoEndComponents;
// Check for requirements of the solver this early so we can adapt the maybe states accordingly.
storm::solver::GeneralMinMaxLinearEquationSolverFactory<ValueType> linearEquationSolverFactory;
storm::solver::MinMaxLinearEquationSolverRequirements requirements = linearEquationSolverFactory.getRequirements(env, uniqueSolution, dir);
storm::solver::MinMaxLinearEquationSolverRequirements requirements = linearEquationSolverFactory.getRequirements(env, hasUniqueSolution, hasNoEndComponents, dir);
storm::solver::MinMaxLinearEquationSolverRequirements clearedRequirements = requirements;
bool extendMaybeStates = false;
if (clearedRequirements.hasEnabledRequirement()) {
if (clearedRequirements.noEndComponents()) {
if (clearedRequirements.uniqueSolution()) {
STORM_LOG_DEBUG("Scheduling EC elimination, because the solver requires it.");
extendMaybeStates = true;
clearedRequirements.clearNoEndComponents();
clearedRequirements.clearUniqueSolution();
hasUniqueSolution = true;
// There might still be end components in which reward is collected.
}
if (clearedRequirements.validInitialScheduler()) {
STORM_LOG_DEBUG("Computing valid scheduler, because the solver requires it.");
@ -611,11 +614,15 @@ namespace storm {
storm::storage::BitVector targetStates = computeTargetStatesForReachabilityRewardsFromExplicitRepresentation(explicitRepresentation.first);
solverRequirementsData.properMaybeStates = ~targetStates;
if (requirements.noEndComponents()) {
if (requirements.uniqueSolution()) {
STORM_LOG_THROW(!requirements.validInitialScheduler(), storm::exceptions::UncheckedRequirementException, "The underlying solver requires a unique solution and an initial valid scheduler. This is currently not supported for expected reward properties.");
// eliminate the end components with reward 0.
// Note that this may also compute the oneStepTargetProbabilities if upper bounds are required.
eliminateEndComponentsAndTargetStatesReachabilityRewards(explicitRepresentation, solverRequirementsData, targetStates, requirements.upperBounds());
// The solution becomes unique after end components have been eliminated.
uniqueSolution = true;
} else {
hasUniqueSolution = true;
}
else {
if (requirements.validInitialScheduler()) {
// Compute a valid initial scheduler.
solverRequirementsData.initialScheduler = computeValidInitialSchedulerForReachabilityRewards<ValueType>(explicitRepresentation.first, solverRequirementsData.properMaybeStates, targetStates);
@ -637,8 +644,9 @@ namespace storm {
// Now solve the resulting equation system.
std::unique_ptr<storm::solver::MinMaxLinearEquationSolver<ValueType>> solver = linearEquationSolverFactory.create(env);
// Set whether the equation system will have a unique solution
solver->setHasUniqueSolution(uniqueSolution);
// Set whether the equation system will have a unique solution / no end components
solver->setHasUniqueSolution(hasUniqueSolution);
solver->setHasNoEndComponents(hasNoEndComponents);
// If the solver requires upper bounds, compute them now.
if (requirements.upperBounds()) {
@ -657,7 +665,7 @@ namespace storm {
solver->solveEquations(env, dir, x, explicitRepresentation.second);
// If we eliminated end components, we need to extend the solution vector.
if (requirements.noEndComponents() && solverRequirementsData.ecInformation) {
if (requirements.uniqueSolution() && solverRequirementsData.ecInformation) {
std::vector<ValueType> extendedVector(solverRequirementsData.properMaybeStates.getNumberOfSetBits());
solverRequirementsData.ecInformation.get().setValues(extendedVector, solverRequirementsData.properMaybeStates, x);
x = std::move(extendedVector);

36
src/storm/modelchecker/prctl/helper/SparseMdpPrctlHelper.cpp

@ -205,7 +205,7 @@ namespace storm {
template<typename ValueType>
struct SparseMdpHintType {
SparseMdpHintType() : eliminateEndComponents(false), computeUpperBounds(false), uniqueSolution(false) {
SparseMdpHintType() : eliminateEndComponents(false), computeUpperBounds(false), uniqueSolution(false), noEndComponents(false) {
// Intentionally left empty.
}
@ -265,6 +265,10 @@ namespace storm {
return uniqueSolution;
}
bool hasNoEndComponents() const {
return noEndComponents;
}
boost::optional<std::vector<uint64_t>> schedulerHint;
boost::optional<std::vector<ValueType>> valueHint;
boost::optional<ValueType> lowerResultBound;
@ -273,6 +277,7 @@ namespace storm {
bool eliminateEndComponents;
bool computeUpperBounds;
bool uniqueSolution;
bool noEndComponents;
};
template<typename ValueType>
@ -329,29 +334,36 @@ namespace storm {
SparseMdpHintType<ValueType> computeHints(Environment const& env, SolutionType const& type, ModelCheckerHint const& hint, storm::OptimizationDirection const& dir, storm::storage::SparseMatrix<ValueType> const& transitionMatrix, storm::storage::SparseMatrix<ValueType> const& backwardTransitions, storm::storage::BitVector const& maybeStates, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& targetStates, bool produceScheduler, boost::optional<storm::storage::BitVector> const& selectedChoices = boost::none) {
SparseMdpHintType<ValueType> result;
// The solution to the min-max equation system is unique if we minimize until probabilities or
// maximize reachability rewards or if the hint tells us that there are no end-compontnes.
result.uniqueSolution = (dir == storm::solver::OptimizationDirection::Minimize && type == SolutionType::UntilProbabilities)
// There are no end components if we minimize until probabilities or
// maximize reachability rewards or if the hint tells us so.
result.noEndComponents = (dir == storm::solver::OptimizationDirection::Minimize && type == SolutionType::UntilProbabilities)
|| (dir == storm::solver::OptimizationDirection::Maximize && type == SolutionType::ExpectedRewards)
|| (hint.isExplicitModelCheckerHint() && hint.asExplicitModelCheckerHint<ValueType>().getNoEndComponentsInMaybeStates());
// If there are no end components, the solution is unique. (Note that the other direction does not hold,
// e.g., end components in which infinite reward is collected.
result.uniqueSolution = result.hasNoEndComponents();
// Check for requirements of the solver.
bool hasSchedulerHint = hint.isExplicitModelCheckerHint() && hint.template asExplicitModelCheckerHint<ValueType>().hasSchedulerHint();
storm::solver::GeneralMinMaxLinearEquationSolverFactory<ValueType> minMaxLinearEquationSolverFactory;
storm::solver::MinMaxLinearEquationSolverRequirements requirements = minMaxLinearEquationSolverFactory.getRequirements(env, result.uniqueSolution, dir, hasSchedulerHint, produceScheduler);
storm::solver::MinMaxLinearEquationSolverRequirements requirements = minMaxLinearEquationSolverFactory.getRequirements(env, result.uniqueSolution, result.noEndComponents, dir, hasSchedulerHint, produceScheduler);
if (requirements.hasEnabledRequirement()) {
// If the solver still requires no end-components, we have to eliminate them later.
if (requirements.noEndComponents()) {
if (requirements.uniqueSolution()) {
STORM_LOG_ASSERT(!result.hasUniqueSolution(), "The solver requires to eliminate the end components although the solution is already assumed to be unique.");
STORM_LOG_DEBUG("Scheduling EC elimination, because the solver requires it.");
STORM_LOG_DEBUG("Scheduling EC elimination, because the solver requires a unique solution.");
result.eliminateEndComponents = true;
// If end components have been eliminated we can assume a unique solution.
result.uniqueSolution = true;
requirements.clearNoEndComponents();
requirements.clearUniqueSolution();
// If we compute until probabilities, we can even assume the absence of end components.
// Note that in the case of minimizing expected rewards there might still be end components in which reward is collected.
result.noEndComponents = (type == SolutionType::UntilProbabilities);
}
// If the solver requires an initial scheduler, compute one now.
if (requirements.validInitialScheduler()) {
// If the solver requires an initial scheduler, compute one now. Note that any scheduler is valid if there are no end components.
if (requirements.validInitialScheduler() && !result.noEndComponents) {
STORM_LOG_DEBUG("Computing valid scheduler, because the solver requires it.");
result.schedulerHint = computeValidSchedulerHint(env, type, transitionMatrix, backwardTransitions, maybeStates, phiStates, targetStates);
requirements.clearValidInitialScheduler();
@ -429,6 +441,7 @@ namespace storm {
std::unique_ptr<storm::solver::MinMaxLinearEquationSolver<ValueType>> solver = storm::solver::configureMinMaxLinearEquationSolver(env, std::move(goal), minMaxLinearEquationSolverFactory, std::move(submatrix));
solver->setRequirementsChecked();
solver->setHasUniqueSolution(hint.hasUniqueSolution());
solver->setHasNoEndComponents(hint.hasNoEndComponents());
if (hint.hasLowerResultBound()) {
solver->setLowerBound(hint.getLowerResultBound());
}
@ -1348,7 +1361,7 @@ namespace storm {
// Check for requirements of the solver.
storm::solver::GeneralMinMaxLinearEquationSolverFactory<ValueType> minMaxLinearEquationSolverFactory;
storm::solver::MinMaxLinearEquationSolverRequirements requirements = minMaxLinearEquationSolverFactory.getRequirements(underlyingSolverEnvironment, true, goal.direction());
storm::solver::MinMaxLinearEquationSolverRequirements requirements = minMaxLinearEquationSolverFactory.getRequirements(underlyingSolverEnvironment, true, true, goal.direction());
requirements.clearBounds();
STORM_LOG_THROW(!requirements.hasEnabledCriticalRequirement(), storm::exceptions::UncheckedRequirementException, "Solver requirements " + requirements.getEnabledRequirementsAsString() + " not checked.");
@ -1359,6 +1372,7 @@ namespace storm {
solver->setLowerBound(storm::utility::zero<ValueType>());
solver->setUpperBound(*std::max_element(lraValuesForEndComponents.begin(), lraValuesForEndComponents.end()));
solver->setHasUniqueSolution();
solver->setHasNoEndComponents();
solver->setRequirementsChecked();
solver->solveEquations(underlyingSolverEnvironment, sspResult, b);

8
src/storm/modelchecker/prctl/helper/SymbolicMdpPrctlHelper.cpp

@ -82,10 +82,10 @@ namespace storm {
requirements.clearValidInitialScheduler();
}
requirements.clearBounds();
if (requirements.noEndComponents()) {
if (requirements.uniqueSolution()) {
// Check whether there are end components
if (storm::utility::graph::performProb0E(model, transitionMatrix.notZero(), maybeStates, !maybeStates && model.getReachableStates()).isZero()) {
requirements.clearNoEndComponents();
requirements.clearUniqueSolution();
}
}
STORM_LOG_THROW(!requirements.hasEnabledCriticalRequirement(), storm::exceptions::UncheckedRequirementException, "Solver requirements " + requirements.getEnabledRequirementsAsString() + " not checked.");
@ -253,10 +253,10 @@ namespace storm {
requirements.clearValidInitialScheduler();
}
requirements.clearLowerBounds();
if (requirements.noEndComponents()) {
if (requirements.uniqueSolution()) {
// Check whether there are end components
if (storm::utility::graph::performProb0E(model, transitionMatrixBdd, maybeStates, !maybeStates && model.getReachableStates()).isZero()) {
requirements.clearNoEndComponents();
requirements.clearUniqueSolution();
}
}
STORM_LOG_THROW(!requirements.hasEnabledCriticalRequirement(), storm::exceptions::UncheckedRequirementException, "Solver requirements " + requirements.getEnabledRequirementsAsString() + " not checked.");

1
src/storm/modelchecker/prctl/helper/rewardbounded/EpochModel.cpp

@ -140,6 +140,7 @@ namespace storm {
storm::solver::GeneralMinMaxLinearEquationSolverFactory<ValueType> minMaxLinearEquationSolverFactory;
minMaxSolver = minMaxLinearEquationSolverFactory.create(env, epochModel.epochMatrix);
minMaxSolver->setHasUniqueSolution();
minMaxSolver->setHasNoEndComponents();
minMaxSolver->setOptimizationDirection(dir);
minMaxSolver->setCachingEnabled(true);
minMaxSolver->setTrackScheduler(true);

20
src/storm/modelchecker/results/ParetoCurveCheckResult.cpp

@ -65,13 +65,25 @@ namespace storm {
out << points.size() << " Pareto optimal points found:" << std::endl;
for(auto const& p : points) {
out << " (";
for(auto it = p.begin(); it != p.end(); ++it){
if(it != p.begin()){
for (auto it = p.begin(); it != p.end(); ++it){
if (it != p.begin()){
out << ", ";
}
out << std::setw(10) << *it;
out << std::setw(storm::NumberTraits<ValueType>::IsExact ? 20 : 11) << *it;
}
out << " )" << std::endl;
out << " )";
if (storm::NumberTraits<ValueType>::IsExact) {
out << " approx. ";
out << " (";
for (auto it = p.begin(); it != p.end(); ++it) {
if(it != p.begin()){
out << ", ";
}
out << std::setw(11) << storm::utility::convertNumber<double>(*it);
}
out << " )";
}
out << std::endl;
}
return out;
}

27
src/storm/solver/GurobiLpSolver.cpp

@ -86,6 +86,9 @@ namespace storm {
// Enable the following line to force Gurobi to be as precise about the binary variables as required by the given precision option.
error = GRBsetdblparam(env, "IntFeasTol", storm::settings::getModule<storm::settings::modules::GurobiSettings>().getIntegerTolerance());
STORM_LOG_THROW(error == 0, storm::exceptions::InvalidStateException, "Unable to set Gurobi Parameter IntFeasTol (" << GRBgeterrormsg(env) << ", error code " << error << ").");
// error = GRBsetintparam(env, "NumericFocus", 3);
// STORM_LOG_THROW(error == 0, storm::exceptions::InvalidStateException, "Unable to set Gurobi Parameter NumericFocus (" << GRBgeterrormsg(env) << ", error code " << error << ").");
}
template<typename ValueType>
@ -342,9 +345,9 @@ namespace storm {
double value = 0;
int error = GRBgetdblattrelement(model, GRB_DBL_ATTR_X, variableIndexPair->second, &value);
STORM_LOG_THROW(error == 0, storm::exceptions::InvalidStateException, "Unable to get Gurobi solution (" << GRBgeterrormsg(env) << ", error code " << error << ").");
STORM_LOG_THROW(std::abs(static_cast<int>(value) - value) <= storm::settings::getModule<storm::settings::modules::GurobiSettings>().getIntegerTolerance(), storm::exceptions::InvalidStateException, "Illegal value for integer variable in Gurobi solution (" << value << ").");
STORM_LOG_THROW(std::abs(std::round(value) - value) <= storm::settings::getModule<storm::settings::modules::GurobiSettings>().getIntegerTolerance(), storm::exceptions::InvalidStateException, "Illegal value for integer variable in Gurobi solution (" << value << ").");
return static_cast<int_fast64_t>(value);
return static_cast<int_fast64_t>(std::round(value));
}
template<typename ValueType>
@ -363,12 +366,12 @@ namespace storm {
STORM_LOG_THROW(error == 0, storm::exceptions::InvalidStateException, "Unable to get Gurobi solution (" << GRBgeterrormsg(env) << ", error code " << error << ").");
if (value > 0.5) {
STORM_LOG_THROW(std::abs(static_cast<int>(value) - 1) <= storm::settings::getModule<storm::settings::modules::GurobiSettings>().getIntegerTolerance(), storm::exceptions::InvalidStateException, "Illegal value for integer variable in Gurobi solution (" << value << ").");
STORM_LOG_THROW(std::abs(value - 1.0) <= storm::settings::getModule<storm::settings::modules::GurobiSettings>().getIntegerTolerance(), storm::exceptions::InvalidStateException, "Illegal value for integer variable in Gurobi solution (" << value << ").");
return true;
} else {
STORM_LOG_THROW(value <= storm::settings::getModule<storm::settings::modules::GurobiSettings>().getIntegerTolerance(), storm::exceptions::InvalidStateException, "Illegal value for integer variable in Gurobi solution (" << value << ").");
STORM_LOG_THROW(std::abs(value) <= storm::settings::getModule<storm::settings::modules::GurobiSettings>().getIntegerTolerance(), storm::exceptions::InvalidStateException, "Illegal value for integer variable in Gurobi solution (" << value << ").");
return false;
}
return static_cast<bool>(value);
}
template<typename ValueType>
@ -496,9 +499,9 @@ namespace storm {
STORM_LOG_THROW(error == 0, storm::exceptions::InvalidStateException, "Unable to set Gurobi solution index (" << GRBgeterrormsg(env) << ", error code " << error << ").");
error = GRBgetdblattrelement(model, GRB_DBL_ATTR_Xn, variableIndexPair->second, &value);
STORM_LOG_THROW(error == 0, storm::exceptions::InvalidStateException, "Unable to get Gurobi solution (" << GRBgeterrormsg(env) << ", error code " << error << ").");
STORM_LOG_THROW(std::abs(static_cast<int>(value) - value) <= storm::settings::getModule<storm::settings::modules::GurobiSettings>().getIntegerTolerance(), storm::exceptions::InvalidStateException, "Illegal value for integer variable in Gurobi solution (" << value << ").");
STORM_LOG_THROW(std::abs(std::round(value) - value) <= storm::settings::getModule<storm::settings::modules::GurobiSettings>().getIntegerTolerance(), storm::exceptions::InvalidStateException, "Illegal value for integer variable in Gurobi solution (" << value << ").");
return static_cast<int_fast64_t>(value);
return static_cast<int_fast64_t>(std::round(value));
}
template<typename ValueType>
@ -520,12 +523,12 @@ namespace storm {
STORM_LOG_THROW(error == 0, storm::exceptions::InvalidStateException, "Unable to get Gurobi solution (" << GRBgeterrormsg(env) << ", error code " << error << ").");
if (value > 0.5) {
STORM_LOG_THROW(std::abs(static_cast<int>(value) - 1) <= storm::settings::getModule<storm::settings::modules::GurobiSettings>().getIntegerTolerance(), storm::exceptions::InvalidStateException, "Illegal value for integer variable in Gurobi solution (" << value << ").");
STORM_LOG_THROW(std::abs(value - 1) <= storm::settings::getModule<storm::settings::modules::GurobiSettings>().getIntegerTolerance(), storm::exceptions::InvalidStateException, "Illegal value for integer variable in Gurobi solution (" << value << ").");
return true;
} else {
STORM_LOG_THROW(value <= storm::settings::getModule<storm::settings::modules::GurobiSettings>().getIntegerTolerance(), storm::exceptions::InvalidStateException, "Illegal value for integer variable in Gurobi solution (" << value << ").");
STORM_LOG_THROW(std::abs(value) <= storm::settings::getModule<storm::settings::modules::GurobiSettings>().getIntegerTolerance(), storm::exceptions::InvalidStateException, "Illegal value for integer variable in Gurobi solution (" << value << ").");
return false;
}
return static_cast<bool>(value);
}
template<typename ValueType>

16
src/storm/solver/IterativeMinMaxLinearEquationSolver.cpp

@ -241,7 +241,7 @@ namespace storm {
if (!this->hasUniqueSolution()) { // Traditional value iteration has no requirements if the solution is unique.
// Computing a scheduler is only possible if the solution is unique
if (this->isTrackSchedulerSet()) {
requirements.requireNoEndComponents();
requirements.requireUniqueSolution();
} else {
// As we want the smallest (largest) solution for maximizing (minimizing) equation systems, we have to approach the solution from below (above).
if (!direction || direction.get() == OptimizationDirection::Maximize) {
@ -255,7 +255,7 @@ namespace storm {
} else if (method == MinMaxMethod::IntervalIteration) {
// Interval iteration requires a unique solution and lower+upper bounds
if (!this->hasUniqueSolution()) {
requirements.requireNoEndComponents();
requirements.requireUniqueSolution();
}
requirements.requireBounds();
} else if (method == MinMaxMethod::RationalSearch) {
@ -263,22 +263,22 @@ namespace storm {
requirements.requireLowerBounds();
// The solution needs to be unique in case of minimizing or in cases where we want a scheduler.
if (!this->hasUniqueSolution() && (!direction || direction.get() == OptimizationDirection::Minimize || this->isTrackSchedulerSet())) {
requirements.requireNoEndComponents();
requirements.requireUniqueSolution();
}
} else if (method == MinMaxMethod::PolicyIteration) {
if (!this->hasUniqueSolution()) {
// The initial scheduler shall not select an end component
if (!this->hasNoEndComponents()) {
requirements.requireValidInitialScheduler();
}
} else if (method == MinMaxMethod::SoundValueIteration) {
if (!this->hasUniqueSolution()) {
requirements.requireNoEndComponents();
requirements.requireUniqueSolution();
}
requirements.requireBounds(false);
} else if (method == MinMaxMethod::ViToPi) {
// Since we want to use value iteration to extract an initial scheduler, it helps to eliminate all end components first.
// TODO: We might get around this, as the initial value iteration scheduler is only a heuristic.
// Since we want to use value iteration to extract an initial scheduler, the solution has to be unique.
if (!this->hasUniqueSolution()) {
requirements.requireNoEndComponents();
requirements.requireUniqueSolution();
}
} else {
STORM_LOG_THROW(false, storm::exceptions::InvalidEnvironmentException, "Unsupported technique for iterative MinMax linear equation solver.");

2
src/storm/solver/LpMinMaxLinearEquationSolver.cpp

@ -117,7 +117,7 @@ namespace storm {
// In case we need to retrieve a scheduler, the solution has to be unique
if (!this->hasUniqueSolution() && this->isTrackSchedulerSet()) {
requirements.requireNoEndComponents();
requirements.requireUniqueSolution();
}
requirements.requireBounds(false);

17
src/storm/solver/MinMaxLinearEquationSolver.cpp

@ -19,7 +19,7 @@ namespace storm {
namespace solver {
template<typename ValueType>
MinMaxLinearEquationSolver<ValueType>::MinMaxLinearEquationSolver(OptimizationDirectionSetting direction) : direction(direction), trackScheduler(false), uniqueSolution(false), cachingEnabled(false), requirementsChecked(false) {
MinMaxLinearEquationSolver<ValueType>::MinMaxLinearEquationSolver(OptimizationDirectionSetting direction) : direction(direction), trackScheduler(false), uniqueSolution(false), noEndComponents(false), cachingEnabled(false), requirementsChecked(false) {
// Intentionally left empty.
}
@ -57,7 +57,17 @@ namespace storm {
template<typename ValueType>
bool MinMaxLinearEquationSolver<ValueType>::hasUniqueSolution() const {
return uniqueSolution;
return uniqueSolution || noEndComponents;
}
template<typename ValueType>
void MinMaxLinearEquationSolver<ValueType>::setHasNoEndComponents(bool value) {
noEndComponents = value;
}
template<typename ValueType>
bool MinMaxLinearEquationSolver<ValueType>::hasNoEndComponents() const {
return noEndComponents;
}
template<typename ValueType>
@ -161,11 +171,12 @@ namespace storm {
}
template<typename ValueType>
MinMaxLinearEquationSolverRequirements MinMaxLinearEquationSolverFactory<ValueType>::getRequirements(Environment const& env, bool hasUniqueSolution, boost::optional<storm::solver::OptimizationDirection> const& direction, bool hasInitialScheduler, bool trackScheduler) const {
MinMaxLinearEquationSolverRequirements MinMaxLinearEquationSolverFactory<ValueType>::getRequirements(Environment const& env, bool hasUniqueSolution, bool hasNoEndComponents, boost::optional<storm::solver::OptimizationDirection> const& direction, bool hasInitialScheduler, bool trackScheduler) const {
// Create dummy solver and ask it for requirements.
std::unique_ptr<MinMaxLinearEquationSolver<ValueType>> solver = this->create(env);
solver->setTrackScheduler(trackScheduler);
solver->setHasUniqueSolution(hasUniqueSolution);
solver->setHasNoEndComponents(hasNoEndComponents);
return solver->getRequirements(env, direction, hasInitialScheduler);
}

21
src/storm/solver/MinMaxLinearEquationSolver.h

@ -76,10 +76,24 @@ namespace storm {
void setHasUniqueSolution(bool value = true);
/*!
* Retrieves whether the solution to the min max equation system is assumed to be unique
* Retrieves whether the solution to the min max equation system is assumed to be unique.
* Note that having no end components implies that the solution is unique. Thus, this also returns true if
* `hasNoEndComponents()` returns true.
* Also note that a unique solution does not imply the absence of ECs, because, e.g. in Rmin properties there
* can still be ECs in which infinite reward is collected.
*/
bool hasUniqueSolution() const;
/*!
* Sets whether the min max equation system is known to not have any end components
*/
void setHasNoEndComponents(bool value = true);
/*!
* Retrieves whether the min max equation system is known to not have any end components
*/
bool hasNoEndComponents() const;
/*!
* Sets whether schedulers are generated when solving equation systems. If the argument is false, the currently
* stored scheduler (if any) is deleted.
@ -173,6 +187,9 @@ namespace storm {
/// Whether the solver can assume that the min-max equation system has a unique solution
bool uniqueSolution;
/// Whether the solver can assume that the min-max equation system has no end components
bool noEndComponents;
/// Whether some of the generated data during solver calls should be cached.
bool cachingEnabled;
@ -194,7 +211,7 @@ namespace storm {
* Retrieves the requirements of the solver that would be created when calling create() right now. The
* requirements are guaranteed to be ordered according to their appearance in the SolverRequirement type.
*/
MinMaxLinearEquationSolverRequirements getRequirements(Environment const& env, bool hasUniqueSolution = false, boost::optional<storm::solver::OptimizationDirection> const& direction = boost::none, bool hasInitialScheduler = false, bool trackScheduler = false) const;
MinMaxLinearEquationSolverRequirements getRequirements(Environment const& env, bool hasUniqueSolution = false, bool hasNoEndComponents = false, boost::optional<storm::solver::OptimizationDirection> const& direction = boost::none, bool hasInitialScheduler = false, bool trackScheduler = false) const;
void setRequirementsChecked(bool value = true);
bool isRequirementsCheckedSet() const;

25
src/storm/solver/MinMaxLinearEquationSolverRequirements.cpp

@ -7,8 +7,8 @@ namespace storm {
// Intentionally left empty.
}
MinMaxLinearEquationSolverRequirements& MinMaxLinearEquationSolverRequirements::requireNoEndComponents(bool critical) {
noEndComponentsRequirement.enable(critical);
MinMaxLinearEquationSolverRequirements& MinMaxLinearEquationSolverRequirements::requireUniqueSolution(bool critical) {
uniqueSolutionRequirement.enable(critical);
return *this;
}
@ -33,8 +33,8 @@ namespace storm {
return *this;
}
SolverRequirement const& MinMaxLinearEquationSolverRequirements::noEndComponents() const {
return noEndComponentsRequirement;
SolverRequirement const& MinMaxLinearEquationSolverRequirements::uniqueSolution() const {
return uniqueSolutionRequirement;
}
SolverRequirement const& MinMaxLinearEquationSolverRequirements::validInitialScheduler() const {
@ -51,16 +51,15 @@ namespace storm {
SolverRequirement const& MinMaxLinearEquationSolverRequirements::get(Element const& element) const {
switch (element) {
case Element::NoEndComponents: return noEndComponents(); break;
case Element::UniqueSolution: return uniqueSolution(); break;
case Element::ValidInitialScheduler: return validInitialScheduler(); break;
case Element::LowerBounds: return lowerBounds(); break;
case Element::UpperBounds: return upperBounds(); break;
}
}
void MinMaxLinearEquationSolverRequirements::clearNoEndComponents() {
noEndComponentsRequirement.clear();
validInitialSchedulerRequirement.clear();
void MinMaxLinearEquationSolverRequirements::clearUniqueSolution() {
uniqueSolutionRequirement.clear();
}
void MinMaxLinearEquationSolverRequirements::clearValidInitialScheduler() {
@ -81,20 +80,20 @@ namespace storm {
}
bool MinMaxLinearEquationSolverRequirements::hasEnabledRequirement() const {
return noEndComponentsRequirement || validInitialSchedulerRequirement || lowerBoundsRequirement || upperBoundsRequirement;
return uniqueSolutionRequirement || validInitialSchedulerRequirement || lowerBoundsRequirement || upperBoundsRequirement;
}
bool MinMaxLinearEquationSolverRequirements::hasEnabledCriticalRequirement() const {
return noEndComponentsRequirement.isCritical() || validInitialSchedulerRequirement.isCritical() || lowerBoundsRequirement.isCritical() || upperBoundsRequirement.isCritical();
return uniqueSolutionRequirement.isCritical() || validInitialSchedulerRequirement.isCritical() || lowerBoundsRequirement.isCritical() || upperBoundsRequirement.isCritical();
}
std::string MinMaxLinearEquationSolverRequirements::getEnabledRequirementsAsString() const {
std::string res = "[";
bool first = true;
if (noEndComponents()) {
if (uniqueSolution()) {
if (!first) { res += ", "; } else {first = false;}
res += "NoEndComponents";
if (noEndComponents().isCritical()) {
res += "UniqueSolution";
if (uniqueSolution().isCritical()) {
res += "(mandatory)";
}
}

10
src/storm/solver/MinMaxLinearEquationSolverRequirements.h

@ -15,7 +15,7 @@ namespace storm {
// Requirements that are related to the graph structure of the system. Note that the requirements in this
// category are to be interpreted incrementally in the following sense: whenever the system has no end
// components then automatically both requirements are fulfilled.
NoEndComponents,
UniqueSolution,
ValidInitialScheduler,
// Requirements that are related to bounds for the actual solution.
@ -27,19 +27,19 @@ namespace storm {
MinMaxLinearEquationSolverRequirements(LinearEquationSolverRequirements const& linearEquationSolverRequirements = LinearEquationSolverRequirements());
MinMaxLinearEquationSolverRequirements& requireNoEndComponents(bool critical = true);
MinMaxLinearEquationSolverRequirements& requireUniqueSolution(bool critical = true);
MinMaxLinearEquationSolverRequirements& requireValidInitialScheduler(bool critical = true);
MinMaxLinearEquationSolverRequirements& requireLowerBounds(bool critical = true);
MinMaxLinearEquationSolverRequirements& requireUpperBounds(bool critical = true);
MinMaxLinearEquationSolverRequirements& requireBounds(bool critical = true);
SolverRequirement const& noEndComponents() const;
SolverRequirement const& uniqueSolution() const;
SolverRequirement const& validInitialScheduler() const;
SolverRequirement const& lowerBounds() const;
SolverRequirement const& upperBounds() const;
SolverRequirement const& get(Element const& element) const;
void clearNoEndComponents();
void clearUniqueSolution();
void clearValidInitialScheduler();
void clearLowerBounds();
void clearUpperBounds();
@ -54,7 +54,7 @@ namespace storm {
std::string getEnabledRequirementsAsString() const;
private:
SolverRequirement noEndComponentsRequirement;
SolverRequirement uniqueSolutionRequirement;
SolverRequirement validInitialSchedulerRequirement;
SolverRequirement lowerBoundsRequirement;
SolverRequirement upperBoundsRequirement;

2
src/storm/solver/SmtSolver.h

@ -50,7 +50,7 @@ namespace storm {
storm::expressions::ExpressionManager const& getManager() const;
private:
// The expression manager responsible for the variableswhose value can be requested via this model
// The expression manager responsible for the variables whose value can be requested via this model
// reference.
storm::expressions::ExpressionManager const& manager;
};

2
src/storm/solver/SymbolicMinMaxLinearEquationSolver.cpp

@ -455,7 +455,7 @@ namespace storm {
} else if (method == MinMaxMethod::RationalSearch) {
requirements.requireLowerBounds();
if (!this->hasUniqueSolution() && (!direction || direction.get() == storm::solver::OptimizationDirection::Minimize)) {
requirements.requireNoEndComponents();
requirements.requireUniqueSolution();
}
} else {
STORM_LOG_THROW(false, storm::exceptions::InvalidEnvironmentException, "The selected min max technique is not supported by this solver.");

17
src/storm/solver/TopologicalMinMaxLinearEquationSolver.cpp

@ -181,6 +181,7 @@ namespace storm {
}
this->sccSolver->setMatrix(*this->A);
this->sccSolver->setHasUniqueSolution(this->hasUniqueSolution());
this->sccSolver->setHasNoEndComponents(this->hasNoEndComponents());
this->sccSolver->setBoundsFromOtherSolver(*this);
this->sccSolver->setTrackScheduler(this->isTrackSchedulerSet());
if (this->hasInitialScheduler()) {
@ -194,10 +195,12 @@ namespace storm {
if (req.lowerBounds() && this->hasLowerBound()) {
req.clearLowerBounds();
}
// If all requirements of the underlying solver have been passed as requirements to the calling site, we can
// assume that the system has no end components if the underlying solver requires this.
req.clearNoEndComponents();
if (req.validInitialScheduler() && this->hasInitialScheduler()) {
req.clearValidInitialScheduler();
}
if (req.uniqueSolution() && this->hasUniqueSolution()) {
req.clearUniqueSolution();
}
STORM_LOG_THROW(!req.hasEnabledCriticalRequirement(), storm::exceptions::UncheckedRequirementException, "Solver requirements " + req.getEnabledRequirementsAsString() + " not checked.");
this->sccSolver->setRequirementsChecked(true);
@ -217,6 +220,7 @@ namespace storm {
this->sccSolver->setCachingEnabled(true);
}
this->sccSolver->setHasUniqueSolution(this->hasUniqueSolution());
this->sccSolver->setHasNoEndComponents(this->hasNoEndComponents());
this->sccSolver->setTrackScheduler(this->isTrackSchedulerSet());
// SCC Matrix
@ -269,6 +273,9 @@ namespace storm {
if (req.validInitialScheduler() && this->hasInitialScheduler()) {
req.clearValidInitialScheduler();
}
if (req.uniqueSolution() && this->hasUniqueSolution()) {
req.clearUniqueSolution();
}
STORM_LOG_THROW(!req.hasEnabledCriticalRequirement(), storm::exceptions::UncheckedRequirementException, "Solver requirements " + req.getEnabledRequirementsAsString() + " not checked.");
this->sccSolver->setRequirementsChecked(true);
@ -291,7 +298,7 @@ namespace storm {
template<typename ValueType>
MinMaxLinearEquationSolverRequirements TopologicalMinMaxLinearEquationSolver<ValueType>::getRequirements(Environment const& env, boost::optional<storm::solver::OptimizationDirection> const& direction, bool const& hasInitialScheduler) const {
// Return the requirements of the underlying solver
return GeneralMinMaxLinearEquationSolverFactory<ValueType>().getRequirements(getEnvironmentForUnderlyingSolver(env), this->hasUniqueSolution(), direction, hasInitialScheduler);
return GeneralMinMaxLinearEquationSolverFactory<ValueType>().getRequirements(getEnvironmentForUnderlyingSolver(env), this->hasUniqueSolution(), this->hasNoEndComponents(), direction, hasInitialScheduler, this->isTrackSchedulerSet());
}
template<typename ValueType>

3
src/storm/storage/Qvbs.cpp

@ -97,7 +97,8 @@ namespace storm {
}
} else {
constantDefinitions.push_back("");
janiFiles.push_back(janiFileName);
janiFiles.push_back(modelPath + "/" + janiFileName);
instanceInfos.push_back(janiFileName);
}
}
}

9
src/storm/storage/expressions/UnaryNumericalFunctionExpression.cpp

@ -71,10 +71,13 @@ namespace storm {
if (operandSimplified->hasIntegerType()) {
int_fast64_t value = operandSimplified->evaluateAsInt();
switch (this->getOperatorType()) {
case OperatorType::Minus: value = -value; break;
case OperatorType::Minus:
value = -value;
break;
// Nothing to be done for the other cases:
// case OperatorType::Floor:
// case OperatorType::Ceil:
case OperatorType::Floor:
case OperatorType::Ceil:
break;
}
return std::shared_ptr<BaseExpression>(new IntegerLiteralExpression(this->getManager(), value));
} else {

11
src/storm/storage/jani/Model.cpp

@ -789,10 +789,19 @@ namespace storm {
return *expressionManager;
}
bool Model::hasNonTrivialRewardExpression() const {
return !nonTrivialRewardModels.empty();
}
bool Model::isNonTrivialRewardModelExpression(std::string const& identifier) const {
return nonTrivialRewardModels.count(identifier) > 0;
}
bool Model::addNonTrivialRewardExpression(std::string const& identifier, storm::expressions::Expression const& rewardExpression) {
if (nonTrivialRewardModels.count(identifier) > 0) {
if (isNonTrivialRewardModelExpression(identifier)) {
return false;
} else {
STORM_LOG_THROW(!globalVariables.hasVariable(identifier) || !globalVariables.getVariable(identifier).isTransient(), storm::exceptions::InvalidArgumentException, "Non trivial reward expression with identifier '" << identifier << "' clashes with global transient variable of the same name.");
nonTrivialRewardModels.emplace(identifier, rewardExpression);
return true;
}

16
src/storm/storage/jani/Model.h

@ -285,9 +285,19 @@ namespace storm {
* Retrieves the manager responsible for the expressions in the JANI model.
*/
storm::expressions::ExpressionManager& getExpressionManager() const;
/*!
* Returns true iff there is a non-trivial reward model, i.e., a reward model that does not consist of a single, global, numerical, transient variable.
*/
bool hasNonTrivialRewardExpression() const;
/*!
* Returns true iff the given identifier corresponds to a non-trivial reward expression i.e., a reward model that does not consist of a single, global, numerical, transient variable.
*/
bool isNonTrivialRewardModelExpression(std::string const& identifier) const;
/*!
* Adds a (non-trivial) reward model, i.e., a reward model that does not consist of a single, global, numerical variable.
* Adds a reward expression, i.e., a reward model that does not consist of a single, global, numerical, transient variable.
* @return true if a new reward model was added and false if a reward model with this identifier is already present in the model (in which case no reward model is added)
*/
bool addNonTrivialRewardExpression(std::string const& identifier, storm::expressions::Expression const& rewardExpression);
@ -577,7 +587,7 @@ namespace storm {
bool undefinedConstantsAreGraphPreserving() const;
/*!
* Lifts the common edge destination assignments to edge assignments.
* Lifts the common edge destination assignments of transient variables to edge assignments.
* @param maxLevel the maximum level of assignments that are to be lifted.
*/
void liftTransientEdgeDestinationAssignments(int64_t maxLevel = 0);

9
src/storm/storm.cpp

@ -1,3 +1,12 @@
/*! \mainpage Storm - A Modern Probabilistic Model Checker
*
* This document contains the Doxygen documentation of the Storm source code.
*
* \section more_info More information
* For more information, installation guides and tutorials on how to use Storm, visit the Storm website: http://www.stormchecker.org.
*/
#include "storm/utility/macros.h"
#include "storm/exceptions/BaseException.h"

41
src/test/storm-dft/api/DftModelCheckerTest.cpp

@ -11,6 +11,7 @@ namespace {
bool useSR;
bool useMod;
bool useDC;
bool allowDCForRelevantEvents;
};
class NoOptimizationsConfig {
@ -18,7 +19,7 @@ namespace {
typedef double ValueType;
static DftAnalysisConfig createConfig() {
return DftAnalysisConfig{false, false, false};
return DftAnalysisConfig{false, false, false, true};
}
};
@ -27,7 +28,7 @@ namespace {
typedef double ValueType;
static DftAnalysisConfig createConfig() {
return DftAnalysisConfig{false, false, true};
return DftAnalysisConfig{false, false, true, true};
}
};
@ -36,7 +37,7 @@ namespace {
typedef double ValueType;
static DftAnalysisConfig createConfig() {
return DftAnalysisConfig{false, true, false};
return DftAnalysisConfig{false, true, false, true};
}
};
@ -45,7 +46,7 @@ namespace {
typedef double ValueType;
static DftAnalysisConfig createConfig() {
return DftAnalysisConfig{true, false, false};
return DftAnalysisConfig{true, false, false, true};
}
};
@ -54,7 +55,7 @@ namespace {
typedef double ValueType;
static DftAnalysisConfig createConfig() {
return DftAnalysisConfig{true, true, true};
return DftAnalysisConfig{true, true, true, true};
}
};
@ -77,11 +78,26 @@ namespace {
std::string property = "Tmin=? [F \"failed\"]";
std::vector<std::shared_ptr<storm::logic::Formula const>> properties = storm::api::extractFormulasFromProperties(storm::api::parseProperties(property));
std::set<size_t> relevantEvents;
if (config.useDC) {
if (!config.useDC) {
relevantEvents = dft->getAllIds();
}
typename storm::modelchecker::DFTModelChecker<double>::dft_results results = storm::api::analyzeDFT<double>(*dft, properties, config.useSR, config.useMod,
relevantEvents, true);
relevantEvents, config.allowDCForRelevantEvents);
return boost::get<double>(results[0]);
}
double analyzeReliability(std::string const& file, double bound) {
std::shared_ptr<storm::storage::DFT<double>> dft = storm::api::loadDFTGalileoFile<double>(file);
EXPECT_TRUE(storm::api::isWellFormed(*dft));
std::string property = "Pmin=? [F<=" + std::to_string(bound) + " \"failed\"]";
std::vector<std::shared_ptr<storm::logic::Formula const>> properties = storm::api::extractFormulasFromProperties(
storm::api::parseProperties(property));
std::set<size_t> relevantEvents;
if (!config.useDC) {
relevantEvents = dft->getAllIds();
}
typename storm::modelchecker::DFTModelChecker<double>::dft_results results = storm::api::analyzeDFT<double>(*dft, properties, config.useSR, config.useMod,
relevantEvents, config.allowDCForRelevantEvents);
return boost::get<double>(results[0]);
}
@ -205,4 +221,15 @@ namespace {
EXPECT_FLOAT_EQ(result, storm::utility::infinity<double>());
}
TYPED_TEST(DftModelCheckerTest, Symmetry) {
double result = this->analyzeMTTF(STORM_TEST_RESOURCES_DIR "/dft/symmetry6.dft");
EXPECT_FLOAT_EQ(result, 1.373226284);
result = this->analyzeReliability(STORM_TEST_RESOURCES_DIR "/dft/symmetry6.dft", 1.0);
EXPECT_FLOAT_EQ(result, 0.3421934224);
}
TYPED_TEST(DftModelCheckerTest, HecsReliability) {
double result = this->analyzeReliability(STORM_TEST_RESOURCES_DIR "/dft/hecs_2_2.dft", 1.0);
EXPECT_FLOAT_EQ(result, 0.00021997582);
}
}

10
src/test/storm-dft/api/DftParserTest.cpp

@ -20,4 +20,14 @@ namespace {
EXPECT_EQ(2ul, dft->nrBasicElements());
EXPECT_TRUE(storm::api::isWellFormed(*dft));
}
TEST(DftParserTest, CatchCycles) {
std::string file = STORM_TEST_RESOURCES_DIR "/dft/cyclic.dft";
EXPECT_THROW(storm::api::loadDFTGalileoFile<double>(file), storm::exceptions::WrongFormatException);
}
TEST(DftParserTest, CatchSeqChildren) {
std::string file = STORM_TEST_RESOURCES_DIR "/dft/seqChild.dft";
EXPECT_THROW(storm::api::loadDFTGalileoFile<double>(file), storm::exceptions::WrongFormatException);
}
}

59
src/test/storm-dft/api/DftSmtTest.cpp

@ -0,0 +1,59 @@
#include "gtest/gtest.h"
#include "storm-config.h"
#include "storm-dft/api/storm-dft.h"
namespace {
TEST(DftSmtTest, AndTest) {
std::shared_ptr<storm::storage::DFT<double>> dft =
storm::api::loadDFTGalileoFile<double>(STORM_TEST_RESOURCES_DIR "/dft/and.dft");
EXPECT_TRUE(storm::api::isWellFormed(*dft));
storm::modelchecker::DFTASFChecker smtChecker(*dft);
smtChecker.convert();
smtChecker.toSolver();
EXPECT_EQ(smtChecker.checkTleNeverFailed(), storm::solver::SmtSolver::CheckResult::Unsat);
}
TEST(DftSmtTest, PandTest) {
std::shared_ptr<storm::storage::DFT<double>> dft =
storm::api::loadDFTGalileoFile<double>(STORM_TEST_RESOURCES_DIR "/dft/pand.dft");
EXPECT_TRUE(storm::api::isWellFormed(*dft));
storm::modelchecker::DFTASFChecker smtChecker(*dft);
smtChecker.convert();
smtChecker.toSolver();
EXPECT_EQ(smtChecker.checkTleNeverFailed(), storm::solver::SmtSolver::CheckResult::Sat);
}
TEST(DftSmtTest, SpareTest) {
std::shared_ptr<storm::storage::DFT<double>> dft =
storm::api::loadDFTGalileoFile<double>(STORM_TEST_RESOURCES_DIR "/dft/spare_two_modules.dft");
EXPECT_TRUE(storm::api::isWellFormed(*dft));
storm::modelchecker::DFTASFChecker smtChecker(*dft);
smtChecker.convert();
smtChecker.toSolver();
EXPECT_EQ(smtChecker.checkTleFailsWithLeq(2), storm::solver::SmtSolver::CheckResult::Unsat);
EXPECT_EQ(smtChecker.checkTleFailsWithEq(3), storm::solver::SmtSolver::CheckResult::Sat);
}
TEST(DftSmtTest, BoundTest) {
std::shared_ptr<storm::storage::DFT<double>> dft =
storm::api::loadDFTGalileoFile<double>(STORM_TEST_RESOURCES_DIR "/dft/spare5.dft");
EXPECT_TRUE(storm::api::isWellFormed(*dft));
storm::modelchecker::DFTASFChecker smtChecker(*dft);
smtChecker.convert();
smtChecker.toSolver();
EXPECT_EQ(smtChecker.getLeastFailureBound(30), uint64_t(2));
EXPECT_EQ(smtChecker.getAlwaysFailedBound(30), uint64_t(4));
}
TEST(DftSmtTest, FDEPBoundTest) {
std::shared_ptr<storm::storage::DFT<double>> dft =
storm::api::loadDFTGalileoFile<double>(STORM_TEST_RESOURCES_DIR "/dft/fdep_bound.dft");
EXPECT_TRUE(storm::api::isWellFormed(*dft));
storm::modelchecker::DFTASFChecker smtChecker(*dft);
smtChecker.convert();
smtChecker.toSolver();
EXPECT_EQ(smtChecker.getLeastFailureBound(30), uint64_t(1));
EXPECT_EQ(smtChecker.getAlwaysFailedBound(30), uint64_t(5));
}
}

1
src/test/storm/solver/MinMaxLinearEquationSolverTest.cpp

@ -149,6 +149,7 @@ namespace {
auto factory = storm::solver::GeneralMinMaxLinearEquationSolverFactory<ValueType>();
auto solver = factory.create(this->env(), A);
solver->setHasUniqueSolution(true);
solver->setHasNoEndComponents(true);
solver->setBounds(this->parseNumber("0"), this->parseNumber("2"));
storm::solver::MinMaxLinearEquationSolverRequirements req = solver->getRequirements(this->env());
req.clearBounds();

33
src/test/storm/transformer/EndComponentEliminatorTest.cpp

@ -7,26 +7,26 @@ TEST(NeutralECRemover, SimpleModelTest) {
storm::storage::SparseMatrixBuilder<double> builder(12, 5, 19, true, true, 5);
ASSERT_NO_THROW(builder.newRowGroup(0));
ASSERT_NO_THROW(builder.newRowGroup(0)); // Transitions for state 0:
ASSERT_NO_THROW(builder.addNextValue(0, 0, 1.0));
ASSERT_NO_THROW(builder.addNextValue(1, 1, 0.3));
ASSERT_NO_THROW(builder.addNextValue(1, 2, 0.1));
ASSERT_NO_THROW(builder.addNextValue(1, 3, 0.4));
ASSERT_NO_THROW(builder.addNextValue(1, 4, 0.2));
ASSERT_NO_THROW(builder.newRowGroup(2));
ASSERT_NO_THROW(builder.newRowGroup(2)); // Transitions for state 1:
ASSERT_NO_THROW(builder.addNextValue(2, 1, 0.7));
ASSERT_NO_THROW(builder.addNextValue(2, 3, 0.3));
ASSERT_NO_THROW(builder.addNextValue(3, 1, 0.1));
ASSERT_NO_THROW(builder.addNextValue(3, 4, 0.9));
ASSERT_NO_THROW(builder.addNextValue(4, 1, 0.2));
ASSERT_NO_THROW(builder.addNextValue(4, 4, 0.8));
ASSERT_NO_THROW(builder.newRowGroup(5));
ASSERT_NO_THROW(builder.newRowGroup(5)); // Transitions for state 2:
ASSERT_NO_THROW(builder.addNextValue(5, 2, 1.0));
ASSERT_NO_THROW(builder.newRowGroup(6));
ASSERT_NO_THROW(builder.newRowGroup(6)); // Transitions for state 3:
ASSERT_NO_THROW(builder.addNextValue(6, 1, 1.0));
ASSERT_NO_THROW(builder.addNextValue(7, 2, 1.0));
ASSERT_NO_THROW(builder.addNextValue(8, 3, 1.0));
ASSERT_NO_THROW(builder.newRowGroup(9));
ASSERT_NO_THROW(builder.newRowGroup(9)); // Transitions for state 4:
ASSERT_NO_THROW(builder.addNextValue(9, 4, 1.0));
ASSERT_NO_THROW(builder.addNextValue(10, 1, 0.4));
ASSERT_NO_THROW(builder.addNextValue(10, 4, 0.6));
@ -48,28 +48,31 @@ TEST(NeutralECRemover, SimpleModelTest) {
allowEmptyRows.set(1, false);
allowEmptyRows.set(4, false);
auto res = storm::transformer::EndComponentEliminator<double>::transform(matrix, subsystem, possibleEcRows, allowEmptyRows);
// Expected data
// State 0 is a singleton EC that is replaced by state 2
// States 1,4 build an EC that will be eliminated and replaced by state 1.
// State 2 is not part of the subsystem and thus disregarded
// State 3 is the only state that is kept as it is (except of the transition to 2) and will now be represented by state 0
storm::storage::SparseMatrixBuilder<double> expectedBuilder(8, 3, 8, true, true, 3);
ASSERT_NO_THROW(expectedBuilder.newRowGroup(0));
ASSERT_NO_THROW(expectedBuilder.addNextValue(0, 2, 1.0));
ASSERT_NO_THROW(expectedBuilder.addNextValue(0, 1, 1.0));
ASSERT_NO_THROW(expectedBuilder.addNextValue(2, 0, 1.0));
ASSERT_NO_THROW(expectedBuilder.newRowGroup(3));
ASSERT_NO_THROW(expectedBuilder.addNextValue(3, 0, 0.4));
ASSERT_NO_THROW(expectedBuilder.addNextValue(3, 2, 0.5));
ASSERT_NO_THROW(expectedBuilder.newRowGroup(5));
ASSERT_NO_THROW(expectedBuilder.addNextValue(3, 0, 0.3));
ASSERT_NO_THROW(expectedBuilder.addNextValue(3, 1, 0.7));
ASSERT_NO_THROW(expectedBuilder.addNextValue(4, 1, 1.0));
ASSERT_NO_THROW(expectedBuilder.addNextValue(5, 0, 1.0));
ASSERT_NO_THROW(expectedBuilder.addNextValue(6, 0, 0.3));
ASSERT_NO_THROW(expectedBuilder.addNextValue(6, 2, 0.7));
ASSERT_NO_THROW(expectedBuilder.addNextValue(7, 2, 1.0));
ASSERT_NO_THROW(expectedBuilder.newRowGroup(6));
ASSERT_NO_THROW(expectedBuilder.addNextValue(6, 0, 0.4));
ASSERT_NO_THROW(expectedBuilder.addNextValue(6, 1, 0.5));
storm::storage::SparseMatrix<double> expectedMatrix;
ASSERT_NO_THROW(expectedMatrix = expectedBuilder.build());
std::vector<uint_fast64_t> expectedNewToOldRowMapping = {6,7,8,1,0,11,2,3};
std::vector<uint_fast64_t> expectedNewToOldRowMapping = {6,7,8,2,3,11,1,0};
std::vector<uint_fast64_t> expectedOldToNewStateMapping = {1,2,std::numeric_limits<uint_fast64_t>::max(), 0, 2};
std::vector<uint_fast64_t> expectedOldToNewStateMapping = {2,1,std::numeric_limits<uint_fast64_t>::max(), 0, 1};
// Note that there are other possible solutions that yield equivalent matrices / vectors.
// In particular, the ordering within the row groups depends on the MEC decomposition implementation.

9
travis/build.sh

@ -37,6 +37,11 @@ linux)
docker run -d -it --name storm --privileged movesrwth/storm-basesystem:$LINUX
;;
esac
# Install doxygen if necessary
if [[ "$TASK" == *Doxygen* ]]
then
docker exec storm apt-get install -qq -y doxygen graphviz
fi
# Copy local content into container
docker exec storm mkdir /opt/storm
docker cp . storm:/opt/storm
@ -45,6 +50,7 @@ linux)
# Execute main process
docker exec storm bash -c "
export CONFIG=$CONFIG;
export TASK=$TASK;
export COMPILER=$COMPILER;
export N_JOBS=$N_JOBS;
export STLARG=;
@ -57,7 +63,8 @@ linux)
osx)
# Mac OSX
STLARG="-stdlib=libc++"
export CONFIG=$CONFIG
export CONFIG
export TASK
export COMPILER
export N_JOBS
export STLARG

59
travis/build_helper.sh

@ -53,27 +53,44 @@ run() {
fi
;;
TestAll)
# Test all
travis_fold start test_all
cd build
ctest test --output-on-failure
travis_fold end test_all
# Check correctness of build types
echo "Checking correctness of build types"
case "$CONFIG" in
DefaultDebug*)
./bin/storm --version | grep "with flags .* -g" || (echo "Error: Missing flag '-g' for debug build." && return 1)
;;
DefaultRelease*)
./bin/storm --version | grep "with flags .* -O3" || (echo "Error: Missing flag '-O3' for release build." && return 1)
./bin/storm --version | grep "with flags .* -DNDEBUG" || (echo "Error: Missing flag '-DNDEBUG' for release build." && return 1)
;;
*)
echo "Unrecognized value of CONFIG: $CONFIG"; exit 1
;;
esac
Tasks)
# Perform tasks
if [[ "$TASK" == *Test* ]]
then
# Test all
travis_fold start test_all
cd build
ctest test --output-on-failure
travis_fold end test_all
# Check correctness of build types
echo "Checking correctness of build types"
case "$CONFIG" in
DefaultDebug*)
./bin/storm --version | grep "with flags .* -g" || (echo "Error: Missing flag '-g' for debug build." && return 1)
;;
DefaultRelease*)
./bin/storm --version | grep "with flags .* -O3" || (echo "Error: Missing flag '-O3' for release build." && return 1)
./bin/storm --version | grep "with flags .* -DNDEBUG" || (echo "Error: Missing flag '-DNDEBUG' for release build." && return 1)
;;
*)
echo "Unrecognized value of CONFIG: $CONFIG"
exit 1
esac
cd ..
fi
if [[ "$TASK" == *Doxygen* ]]
then
# Generate doxygen doc
travis_fold start make_doc
cd build
make -j$N_JOBS doc
# Disable jekyll as otherwise files with starting underscore are not published
echo "" > doc/html/.nojekyll
cd ..
travis_fold end make_doc
fi
;;
*)

13
travis/deploy_carl.sh → travis/deploy_docker.sh

@ -15,18 +15,20 @@ if [ "${TRAVIS_PULL_REQUEST}" != "false" ]; then
exit 0;
fi
echo "Deploying $1 to Dockerhub"
case $OS in
linux)
echo "$DOCKER_PASSWORD" | docker login -u "$DOCKER_USERNAME" --password-stdin
# Deploy as debug/release
case "$CONFIG" in
*DebugTravis)
docker commit carl movesrwth/carl:travis-debug
docker push movesrwth/carl:travis-debug
docker commit $1 movesrwth/$1:travis-debug
docker push movesrwth/$1:travis-debug
;;
*ReleaseTravis)
docker commit carl movesrwth/carl:travis
docker push movesrwth/carl:travis
docker commit $1 movesrwth/$1:travis
docker push movesrwth/$1:travis
;;
*)
echo "Unrecognized value of CONFIG: $CONFIG"; exit 1
@ -35,7 +37,7 @@ linux)
;;
osx)
echo "Building carl on Mac OSX not used."
echo "Docker deployment on Mac OSX not used."
exit 1
;;
@ -44,4 +46,3 @@ osx)
echo "Unsupported OS: $OS"
exit 1
esac

47
travis/deploy_storm.sh

@ -1,47 +0,0 @@
#!/bin/bash -x
set -e
OS=$TRAVIS_OS_NAME
# Do not deploy if credentials are not given
if [ "${TRAVIS_SECURE_ENV_VARS}" == "false" ]; then
echo "WARNING: Not deploying as no credentials are given."
exit 0;
fi
# Do not deploy for pull requests
if [ "${TRAVIS_PULL_REQUEST}" != "false" ]; then
exit 0;
fi
case $OS in
linux)
echo "$DOCKER_PASSWORD" | docker login -u "$DOCKER_USERNAME" --password-stdin
# Deploy as debug/release
case "$CONFIG" in
*DebugTravis)
docker commit storm movesrwth/storm:travis-debug
docker push movesrwth/storm:travis-debug
;;
*ReleaseTravis)
docker commit storm movesrwth/storm:travis
docker push movesrwth/storm:travis
;;
*)
echo "Unrecognized value of CONFIG: $CONFIG"; exit 1
;;
esac
;;
osx)
echo "Building Storm on Mac OSX not used."
exit 1
;;
*)
# Unknown OS
echo "Unsupported OS: $OS"
exit 1
esac

151
travis/generate_travis.py

@ -1,38 +1,37 @@
# Generate .travis.yml automatically
# Configuration for Linux
configs_linux = [
# OS, compiler, build type
("ubuntu-18.04", "gcc", "DefaultDebug"),
("ubuntu-18.04", "gcc", "DefaultRelease"),
("debian-9", "gcc", "DefaultDebug"),
("debian-9", "gcc", "DefaultRelease"),
("ubuntu-18.10", "gcc", "DefaultDebug"),
("ubuntu-18.10", "gcc", "DefaultRelease"),
("ubuntu-19.04", "gcc", "DefaultDebugTravis"),
("ubuntu-19.04", "gcc", "DefaultReleaseTravis"),
]
# Configurations for Mac
configs_mac = [
# OS, compiler, build type
# ("osx", "clang", "DefaultDebug"),
# ("osx", "clang", "DefaultRelease"),
configs = [
# OS, OS version, compiler, build type, task
("ubuntu", "18.04", "gcc", "DefaultDebug", "Test"),
("ubuntu", "18.04", "gcc", "DefaultRelease", "Test"),
("debian", "9", "gcc", "DefaultDebug", "Test"),
("debian", "9", "gcc", "DefaultRelease", "Test"),
("ubuntu", "18.10", "gcc", "DefaultDebug", "Test"),
("ubuntu", "18.10", "gcc", "DefaultRelease", "Test"),
("ubuntu", "19.04", "gcc", "DefaultDebugTravis", "TestDocker"),
("ubuntu", "19.04", "gcc", "DefaultReleaseTravis", "TestDockerDoxygen"),
# ("osx", "xcode9.3", "clang", "DefaultDebug", "Test"),
# ("osx", "xcode9.3", "clang", "DefaultRelease", "Test"),
]
# Stages in travis
stages = [
build_stages = [
("Build (1st run)", "Build1"),
("Build (2nd run)", "Build2"),
("Build (3rd run)", "Build3"),
("Build (4th run)", "BuildLast"),
("Test all", "TestAll"),
("Tasks", "Tasks"),
]
def get_env_string(os, os_version, compiler, build_type, task):
if os == "osx":
return "CONFIG={} TASK={} COMPILER={} STL=libc++\n".format(build_type, task, compiler)
else:
return "CONFIG={} TASK={} LINUX={} COMPILER={}\n".format(build_type, task, "{}-{}".format(os, os_version), compiler)
if __name__ == "__main__":
allow_failures = []
if __name__ == "__main__":
s = ""
# Initial config
s += "#\n"
@ -43,7 +42,6 @@ if __name__ == "__main__":
s += " - master\n"
s += " - stable\n"
s += "sudo: required\n"
s += "dist: trusty\n"
s += "language: cpp\n"
s += "\n"
s += "git:\n"
@ -79,97 +77,80 @@ if __name__ == "__main__":
s += " ###\n"
s += " # Stage: Build Carl\n"
s += " ###\n"
s += "\n"
for config in configs_linux:
linux = config[0]
compiler = config[1]
build_type = config[2]
for config in configs:
os, os_version, compiler, build_type, task = config
os_type = "osx" if os == "osx" else "linux"
if "Travis" in build_type:
s += " # {} - {}\n".format(linux, build_type)
s += " # {}-{} - {}\n".format(os, os_version, build_type)
buildConfig = ""
buildConfig += " - stage: Build Carl\n"
buildConfig += " os: linux\n"
buildConfig += " os: {}\n".format(os_type)
buildConfig += " compiler: {}\n".format(compiler)
buildConfig += " env: CONFIG={} LINUX={} COMPILER={}\n".format(build_type, linux, compiler)
buildConfig += " install:\n"
buildConfig += " - travis/install_linux.sh\n"
buildConfig += " env: {}".format(get_env_string(os, os_version, compiler, build_type, task))
buildConfig += " before_script:\n"
buildConfig += ' - python -c "import fcntl; fcntl.fcntl(1, fcntl.F_SETFL, 0)" # Workaround for nonblocking mode\n'
buildConfig += " script:\n"
buildConfig += " - travis/build_carl.sh\n"
buildConfig += " before_cache:\n"
buildConfig += " - docker cp carl:/opt/carl/. .\n"
# Upload to DockerHub
buildConfig += " after_success:\n"
buildConfig += " - travis/deploy_carl.sh\n"
buildConfig += " deploy:\n"
buildConfig += " - provider: script\n"
buildConfig += " skip_cleanup: true\n"
buildConfig += " script: bash travis/deploy_docker.sh carl\n"
s += buildConfig
# Generate all configurations
for stage in stages:
# Generate all build configurations
for stage in build_stages:
s += "\n"
s += " ###\n"
s += " # Stage: {}\n".format(stage[0])
s += " ###\n"
s += "\n"
# Mac OS X
for config in configs_mac:
osx = config[0]
compiler = config[1]
build_type = config[2]
s += " # {} - {}\n".format(osx, build_type)
for config in configs:
os, os_version, compiler, build_type, task = config
os_type = "osx" if os == "osx" else "linux"
s += " # {}-{} - {}\n".format(os, os_version, build_type)
buildConfig = ""
buildConfig += " - stage: {}\n".format(stage[0])
buildConfig += " os: osx\n"
buildConfig += " osx_image: xcode9.1\n"
buildConfig += " os: {}\n".format(os_type)
if os_type == "osx":
buildConfig += " osx_image: {}\n".format(os_version)
buildConfig += " compiler: {}\n".format(compiler)
buildConfig += " env: CONFIG={} COMPILER={} STL=libc++\n".format(build_type, compiler)
buildConfig += " env: {}".format(get_env_string(os, os_version, compiler, build_type, task))
buildConfig += " install:\n"
if stage[1] == "Build1":
buildConfig += " - rm -rf build\n"
buildConfig += " - travis/install_osx.sh\n"
buildConfig += " - travis/skip_test.sh\n"
if os_type == "osx":
buildConfig += " - travis/install_osx.sh\n"
buildConfig += " before_script:\n"
buildConfig += ' - python -c "import fcntl; fcntl.fcntl(1, fcntl.F_SETFL, 0)" # Workaround for nonblocking mode\n'
buildConfig += " script:\n"
buildConfig += " - travis/build.sh {}\n".format(stage[1])
if os_type == "linux":
buildConfig += " before_cache:\n"
buildConfig += " - docker cp storm:/opt/storm/. .\n"
buildConfig += " after_failure:\n"
buildConfig += " - find build -iname '*err*.log' -type f -print -exec cat {} \;\n"
s += buildConfig
# Linux via Docker
for config in configs_linux:
allow_fail = ""
linux = config[0]
compiler = config[1]
build_type = config[2]
s += " # {} - {}\n".format(linux, build_type)
buildConfig = ""
buildConfig += " - stage: {}\n".format(stage[0])
allow_fail += " - stage: {}\n".format(stage[0])
buildConfig += " os: linux\n"
allow_fail += " os: linux\n"
buildConfig += " compiler: {}\n".format(compiler)
buildConfig += " env: CONFIG={} LINUX={} COMPILER={}\n".format(build_type, linux, compiler)
allow_fail += " env: CONFIG={} LINUX={} COMPILER={}\n".format(build_type, linux, compiler)
buildConfig += " install:\n"
if stage[1] == "Build1":
buildConfig += " - rm -rf build\n"
buildConfig += " - travis/install_linux.sh\n"
buildConfig += " before_script:\n"
buildConfig += ' - python -c "import fcntl; fcntl.fcntl(1, fcntl.F_SETFL, 0)" # Workaround for nonblocking mode\n'
buildConfig += " script:\n"
buildConfig += " - travis/build.sh {}\n".format(stage[1])
buildConfig += " before_cache:\n"
buildConfig += " - docker cp storm:/opt/storm/. .\n"
buildConfig += " after_failure:\n"
buildConfig += " - find build -iname '*err*.log' -type f -print -exec cat {} \;\n"
# Upload to DockerHub
if stage[1] == "TestAll" and "Travis" in build_type:
buildConfig += " after_success:\n"
buildConfig += " - travis/deploy_storm.sh\n"
# Deployment
if stage[1] == "Tasks":
if "Docker" in task or "Doxygen" in task:
buildConfig += " deploy:\n"
if "Docker" in task:
buildConfig += " - provider: script\n"
buildConfig += " skip_cleanup: true\n"
buildConfig += " script: bash travis/deploy_docker.sh storm\n"
if "Doxygen" in task:
buildConfig += " - provider: pages\n"
buildConfig += " skip_cleanup: true\n"
buildConfig += " github_token: $GITHUB_TOKEN\n"
buildConfig += " local_dir: build/doc/html/\n"
buildConfig += " repo: moves-rwth/storm-doc\n"
buildConfig += " target_branch: master\n"
buildConfig += " on:\n"
buildConfig += " branch: master\n"
s += buildConfig
if "Travis" in build_type and "Release" in build_type:
allow_failures.append(allow_fail)
if len(allow_failures) > 0:
s += " allow_failures:\n"
for fail in allow_failures:
s += fail
print(s)

3
travis/mtime_cache/globs.txt

@ -1,5 +1,8 @@
src/**/*.{%{cpp}}
src/**/*.{in}
src/**/CMakeLists.txt
CMakeLists.txt
*.{in}
resources/3rdparty/**/*.{%{cpp}}
resources/3rdparty/eigen-3.3-beta1/StormEigen/**/*
resources/3rdparty/eigen-3.3-beta1/unsupported/**/*

5
travis/install_linux.sh → travis/skip_test.sh

@ -1,11 +1,6 @@
#!/bin/bash
set -e
# Skip this run?
if [ -f build/skip.txt ]
then
exit 0
fi
#sudo apt-get install -qq -y docker
|||||||
100:0
Loading…
Cancel
Save